diff --git a/packages/core/src/database/utils.ts b/packages/core/src/database/utils.ts index e7e0fbce6..275f61629 100644 --- a/packages/core/src/database/utils.ts +++ b/packages/core/src/database/utils.ts @@ -1,8 +1,9 @@ import { SchemaValuePrimitive, SchemaValue } from '@logto/schemas'; import { Falsy, notFalsy } from '@silverhand/essentials'; import dayjs from 'dayjs'; -import { sql, SqlSqlTokenType, SqlTokenType } from 'slonik'; +import { sql, SqlSqlTokenType, SqlTokenType, IdentifierSqlTokenType } from 'slonik'; +import pool from './pool'; import { FieldIdentifiers, Table } from './types'; export const conditionalSql = ( @@ -70,3 +71,9 @@ export const convertToIdentifiers = ( }); export const convertToTimestamp = (time = dayjs()) => sql`to_timestamp(${time.valueOf() / 1000})`; + +export const getTotalRowCount = async (table: IdentifierSqlTokenType) => + pool.one<{ count: number }>(sql` + select count(*) + from ${table} + `); diff --git a/packages/core/src/queries/application.ts b/packages/core/src/queries/application.ts index 0f00d8c43..f8de23a16 100644 --- a/packages/core/src/queries/application.ts +++ b/packages/core/src/queries/application.ts @@ -1,19 +1,21 @@ import { Application, ApplicationDBEntry, Applications } from '@logto/schemas'; import { sql } from 'slonik'; +import { buildFindMany } from '@/database/find-many'; import { buildInsertInto } from '@/database/insert-into'; import pool from '@/database/pool'; import { buildUpdateWhere } from '@/database/update-where'; -import { convertToIdentifiers, OmitAutoSetFields } from '@/database/utils'; +import { convertToIdentifiers, OmitAutoSetFields, getTotalRowCount } from '@/database/utils'; import RequestError from '@/errors/RequestError'; const { table, fields } = convertToIdentifiers(Applications); -export const findAllApplications = async () => - pool.many(sql` - select ${sql.join(Object.values(fields), sql`, `)} - from ${table} - `); +export const findTotalNumberOfApplications = async () => getTotalRowCount(table); + +const findApplicationMany = buildFindMany(pool, Applications); + +export const findAllApplications = async (limit: number, offset: number) => + findApplicationMany({ limit, offset }); export const findApplicationById = async (id: string) => pool.one(sql` diff --git a/packages/core/src/routes/application.ts b/packages/core/src/routes/application.ts index fbfd0e73c..521d83fc9 100644 --- a/packages/core/src/routes/application.ts +++ b/packages/core/src/routes/application.ts @@ -2,6 +2,7 @@ import { Applications } from '@logto/schemas'; import { object, string } from 'zod'; import koaGuard from '@/middleware/koa-guard'; +import koaPagination from '@/middleware/koa-pagination'; import { buildOidcClientMetadata } from '@/oidc/utils'; import { deleteApplicationById, @@ -9,6 +10,7 @@ import { findAllApplications, insertApplication, updateApplicationById, + findTotalNumberOfApplications, } from '@/queries/application'; import { buildIdGenerator } from '@/utils/id'; @@ -17,8 +19,18 @@ import { AuthedRouter } from './types'; const applicationId = buildIdGenerator(21); export default function applicationRoutes(router: T) { - router.get('/applications', async (ctx, next) => { - ctx.body = await findAllApplications(); + router.get('/applications', koaPagination(), async (ctx, next) => { + const { limit, offset } = ctx.pagination; + + const [{ count }, applications] = await Promise.all([ + findTotalNumberOfApplications(), + findAllApplications(limit, offset), + ]); + + // Return totalCount to pagination middleware + ctx.pagination.totalCount = count; + ctx.body = applications; + return next(); });