From 900b87b9a5edb2b512dc89c3d63a8c6496a3fd07 Mon Sep 17 00:00:00 2001 From: wangsijie Date: Thu, 12 Jan 2023 17:28:23 +0800 Subject: [PATCH] feat(core): add pagination and search to role users (#2927) --- packages/core/src/queries/user.ts | 25 +++++++++++++++---- packages/core/src/routes/role.test.ts | 2 ++ packages/core/src/routes/role.ts | 35 +++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/packages/core/src/queries/user.ts b/packages/core/src/queries/user.ts index 82312c365..e915fc504 100644 --- a/packages/core/src/queries/user.ts +++ b/packages/core/src/queries/user.ts @@ -105,7 +105,7 @@ export const createUserQueries = (pool: CommonQueryMethods) => { ` ); - const buildUserConditions = (search: Search, excludeUserIds: string[]) => { + const buildUserConditions = (search: Search, excludeUserIds: string[], userIds?: string[]) => { const hasSearch = search.matches.length > 0; const searchFields = [ Users.fields.id, @@ -127,6 +127,16 @@ export const createUserQueries = (pool: CommonQueryMethods) => { `; } + if (userIds) { + return sql` + where ${fields.id} in (${userIds.length > 0 ? sql.join(userIds, sql`, `) : sql`null`}) + ${conditionalSql( + hasSearch, + () => sql`and (${buildConditionsFromSearch(search, searchFields)})` + )} + `; + } + return conditionalSql( hasSearch, () => sql`where ${buildConditionsFromSearch(search, searchFields)}` @@ -135,18 +145,23 @@ export const createUserQueries = (pool: CommonQueryMethods) => { const defaultUserSearch = { matches: [], isCaseSensitive: false, joint: SearchJointMode.Or }; - const countUsers = async (search: Search = defaultUserSearch, excludeUserIds: string[] = []) => + const countUsers = async ( + search: Search = defaultUserSearch, + excludeUserIds: string[] = [], + userIds?: string[] + ) => pool.one<{ count: number }>(sql` select count(*) from ${table} - ${buildUserConditions(search, excludeUserIds)} + ${buildUserConditions(search, excludeUserIds, userIds)} `); const findUsers = async ( limit: number, offset: number, search: Search, - excludeUserIds: string[] = [] + excludeUserIds: string[] = [], + userIds?: string[] ) => pool.any( sql` @@ -155,7 +170,7 @@ export const createUserQueries = (pool: CommonQueryMethods) => { sql`,` )} from ${table} - ${buildUserConditions(search, excludeUserIds)} + ${buildUserConditions(search, excludeUserIds, userIds)} limit ${limit} offset ${offset} ` diff --git a/packages/core/src/routes/role.test.ts b/packages/core/src/routes/role.test.ts index 67ef9952d..9f8f0d7d5 100644 --- a/packages/core/src/routes/role.test.ts +++ b/packages/core/src/routes/role.test.ts @@ -44,6 +44,8 @@ const { insertRolesScopes } = rolesScopes; const users = { findUsersByIds: jest.fn(), findUserById: jest.fn(), + countUsers: jest.fn(async () => ({ count: 1 })), + findUsers: jest.fn(async () => [mockUser]), }; const { findUsersByIds } = users; diff --git a/packages/core/src/routes/role.ts b/packages/core/src/routes/role.ts index 1e0099ca0..b0957ad4e 100644 --- a/packages/core/src/routes/role.ts +++ b/packages/core/src/routes/role.ts @@ -30,7 +30,7 @@ export default function roleRoutes( updateRoleById, }, scopes: { findScopeById }, - users: { findUserById, findUsersByIds }, + users: { findUserById, findUsersByIds, countUsers, findUsers }, usersRoles: { countUsersRolesByRoleId, deleteUsersRolesByUserIdAndRoleId, @@ -190,6 +190,7 @@ export default function roleRoutes( router.get( '/roles/:id/users', + koaPagination(), koaGuard({ params: object({ id: string().min(1) }), }), @@ -197,13 +198,37 @@ export default function roleRoutes( const { params: { id }, } = ctx.guard; + const { limit, offset } = ctx.pagination; + const { searchParams } = ctx.request.URL; await findRoleById(id); - const usersRoles = await findUsersRolesByRoleId(id); - const users = await findUsersByIds(usersRoles.map(({ userId }) => userId)); - ctx.body = users.map((user) => pick(user, ...userInfoSelectFields)); - return next(); + return tryThat( + async () => { + const search = parseSearchParamsForSearch(searchParams); + const usersRoles = await findUsersRolesByRoleId(id); + const userIds = usersRoles.map(({ userId }) => userId); + + const [{ count }, users] = await Promise.all([ + countUsers(search, undefined, userIds), + findUsers(limit, offset, search, undefined, userIds), + ]); + + ctx.pagination.totalCount = count; + ctx.body = users.map((user) => pick(user, ...userInfoSelectFields)); + + return next(); + }, + (error) => { + if (error instanceof TypeError) { + throw new RequestError( + { code: 'request.invalid_input', details: error.message }, + error + ); + } + throw error; + } + ); } );