diff --git a/packages/core/src/database/find-many.test.ts b/packages/core/src/database/find-many.test.ts deleted file mode 100644 index dd4a6049b..000000000 --- a/packages/core/src/database/find-many.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Users } from '@logto/schemas'; - -import { createTestPool } from '@/utils/test-utils'; - -import { buildFindMany } from './find-many'; - -describe('buildFindMany()', () => { - it('matches expected sql', async () => { - const pool = createTestPool( - 'select "id", "username", "primary_email", "primary_phone", "password_encrypted", "password_encryption_method", "password_encryption_salt", "name", "avatar", "role_names", "identities", "custom_data"\nfrom "users"' - ); - const findMany = buildFindMany(pool, Users); - await findMany(); - }); - - it('matches expected sql with where conditions', async () => { - const pool = createTestPool( - 'select "id", "username", "primary_email", "primary_phone", "password_encrypted", "password_encryption_method", "password_encryption_salt", "name", "avatar", "role_names", "identities", "custom_data"\nfrom "users"\nwhere "id"=$1' - ); - const findMany = buildFindMany(pool, Users); - await findMany({ where: { id: '123' } }); - }); - - it('matches expected sql with orderBy', async () => { - const pool = createTestPool( - 'select "id", "username", "primary_email", "primary_phone", "password_encrypted", "password_encryption_method", "password_encryption_salt", "name", "avatar", "role_names", "identities", "custom_data"\nfrom "users"\norder by "id" asc, "username" desc' - ); - const findMany = buildFindMany(pool, Users); - await findMany({ orderBy: { id: 'asc', username: 'desc' } }); - }); - - it('matches expected sql with limit', async () => { - const pool = createTestPool( - 'select "id", "username", "primary_email", "primary_phone", "password_encrypted", "password_encryption_method", "password_encryption_salt", "name", "avatar", "role_names", "identities", "custom_data"\nfrom "users"\nlimit $1' - ); - const findMany = buildFindMany(pool, Users); - await findMany({ limit: 10 }); - }); - - it('matches expected sql with offset', async () => { - const pool = createTestPool( - 'select "id", "username", "primary_email", "primary_phone", "password_encrypted", "password_encryption_method", "password_encryption_salt", "name", "avatar", "role_names", "identities", "custom_data"\nfrom "users"\noffset $1' - ); - const findMany = buildFindMany(pool, Users); - await findMany({ offset: 10 }); - }); - - it('matches expected sql with offset 0', async () => { - const pool = createTestPool( - 'select "id", "username", "primary_email", "primary_phone", "password_encrypted", "password_encryption_method", "password_encryption_salt", "name", "avatar", "role_names", "identities", "custom_data"\nfrom "users"' - ); - const findMany = buildFindMany(pool, Users); - await findMany({ offset: 0 }); - }); - - it('matches expected sql with where conditions, orderBy, limit, and offset', async () => { - const pool = createTestPool( - 'select "id", "username", "primary_email", "primary_phone", "password_encrypted", "password_encryption_method", "password_encryption_salt", "name", "avatar", "role_names", "identities", "custom_data"\nfrom "users"\nwhere "id"=$1\norder by "id" desc, "username" asc\nlimit $2\noffset $3' - ); - const findMany = buildFindMany(pool, Users); - await findMany({ - where: { id: '123' }, - orderBy: { id: 'desc', username: 'asc' }, - limit: 20, - offset: 20, - }); - }); -}); diff --git a/packages/core/src/database/find-many.ts b/packages/core/src/database/find-many.ts deleted file mode 100644 index eed188b10..000000000 --- a/packages/core/src/database/find-many.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { GeneratedSchema, SchemaLike } from '@logto/schemas'; -import { notFalsy } from '@silverhand/essentials'; -import { DatabasePoolType, sql } from 'slonik'; - -import { isKeyOf } from '@/utils/schema'; - -import { FindManyData, OrderBy } from './types'; -import { conditionalSql, convertToIdentifiers, convertToPrimitiveOrSql } from './utils'; - -export const buildFindMany = ( - pool: DatabasePoolType, - schema: GeneratedSchema -) => { - const { table, fields } = convertToIdentifiers(schema); - const isKeyOfSchema = isKeyOf(schema); - const connectKeyValueWithEqualSign = (partialSchema: Partial) => - Object.entries(partialSchema) - .map( - ([key, value]) => - isKeyOfSchema(key) && sql`${fields[key]}=${convertToPrimitiveOrSql(key, value)}` - ) - .filter((entry) => notFalsy(entry)); - - const buildOrderBy = (orderBySchema: OrderBy) => - Object.entries(orderBySchema) - .map(([key, order]) => { - if (!isKeyOfSchema(key)) { - return false; - } - - const orderDirection = order === 'asc' ? sql`asc` : sql`desc`; - - return sql`${fields[key]} ${orderDirection}`; - }) - .filter((entry) => notFalsy(entry)); - - return async ({ where, orderBy, limit, offset }: FindManyData = {}) => - pool.any(sql` - select ${sql.join(Object.values(fields), sql`, `)} - from ${table} - ${conditionalSql( - where, - (where) => sql`where ${sql.join(connectKeyValueWithEqualSign(where), sql` and `)}` - )} - ${conditionalSql( - orderBy, - (orderBy) => sql`order by ${sql.join(buildOrderBy(orderBy), sql`, `)}` - )} - ${conditionalSql(limit, (limit) => sql`limit ${limit}`)} - ${conditionalSql(offset, (offset) => sql`offset ${offset}`)} - `); -}; diff --git a/packages/core/src/queries/application.ts b/packages/core/src/queries/application.ts index b1015d701..c9379ddee 100644 --- a/packages/core/src/queries/application.ts +++ b/packages/core/src/queries/application.ts @@ -1,21 +1,29 @@ import { Application, CreateApplication, 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, getTotalRowCount } from '@/database/utils'; +import { + convertToIdentifiers, + OmitAutoSetFields, + getTotalRowCount, + conditionalSql, +} from '@/database/utils'; import { DeletionError } from '@/errors/SlonikError'; const { table, fields } = convertToIdentifiers(Applications); export const findTotalNumberOfApplications = async () => getTotalRowCount(table); -const findApplicationMany = buildFindMany(pool, Applications); - export const findAllApplications = async (limit: number, offset: number) => - findApplicationMany({ orderBy: { createdAt: 'desc' }, limit, offset }); + pool.many(sql` + select ${sql.join(Object.values(fields), sql`, `)} + from ${table} + order by ${fields.createdAt} desc + ${conditionalSql(limit, (limit) => sql`limit ${limit}`)} + ${conditionalSql(offset, (offset) => sql`offset ${offset}`)} + `); export const findApplicationById = async (id: string) => pool.one(sql` diff --git a/packages/core/src/queries/resource.ts b/packages/core/src/queries/resource.ts index 90b81b442..97713f611 100644 --- a/packages/core/src/queries/resource.ts +++ b/packages/core/src/queries/resource.ts @@ -1,21 +1,28 @@ import { Resource, CreateResource, Resources } 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, getTotalRowCount } from '@/database/utils'; +import { + convertToIdentifiers, + OmitAutoSetFields, + getTotalRowCount, + conditionalSql, +} from '@/database/utils'; import { DeletionError } from '@/errors/SlonikError'; const { table, fields } = convertToIdentifiers(Resources); export const findTotalNumberOfResources = async () => getTotalRowCount(table); -const findResourcesMany = buildFindMany(pool, Resources); - export const findAllResources = async (limit: number, offset: number) => - findResourcesMany({ limit, offset }); + pool.many(sql` + select ${sql.join(Object.values(fields), sql`, `)} + from ${table} + ${conditionalSql(limit, (limit) => sql`limit ${limit}`)} + ${conditionalSql(offset, (offset) => sql`offset ${offset}`)} + `); export const findResourceByIndicator = async (indicator: string) => pool.maybeOne(sql`