mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat: buildFindMany (#159)
This commit is contained in:
parent
5b404e2b2e
commit
e8908c3b24
2 changed files with 96 additions and 0 deletions
55
packages/core/src/database/find-many.test.ts
Normal file
55
packages/core/src/database/find-many.test.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
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"\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"\nfrom "users"\nwhere "id"=$1'
|
||||
);
|
||||
const findMany = buildFindMany(pool, Users);
|
||||
await findMany({ where: { id: '123' } });
|
||||
});
|
||||
|
||||
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"\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"\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"\nfrom "users"'
|
||||
);
|
||||
const findMany = buildFindMany(pool, Users);
|
||||
await findMany({ offset: 0 });
|
||||
});
|
||||
|
||||
it('matches expected sql with where conditions, limit and offset', async () => {
|
||||
const pool = createTestPool(
|
||||
'select "id", "username", "primary_email", "primary_phone", "password_encrypted", "password_encryption_method", "password_encryption_salt"\nfrom "users"\nwhere "id"=$1\nlimit $2\noffset $3'
|
||||
);
|
||||
const findMany = buildFindMany(pool, Users);
|
||||
await findMany({ where: { id: '123' }, limit: 20, offset: 20 });
|
||||
});
|
||||
});
|
41
packages/core/src/database/find-many.ts
Normal file
41
packages/core/src/database/find-many.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { SchemaLike, GeneratedSchema } from '@logto/schemas';
|
||||
import { notFalsy, Truthy } from '@silverhand/essentials';
|
||||
import { DatabasePoolType, sql } from 'slonik';
|
||||
|
||||
import { isKeyOf } from '@/utils/schema';
|
||||
|
||||
import { conditionalSql, convertToIdentifiers, convertToPrimitiveOrSql } from './utils';
|
||||
|
||||
export type FindManyData<Schema extends SchemaLike> = {
|
||||
where?: Partial<Schema>;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
};
|
||||
|
||||
export const buildFindMany = <Schema extends SchemaLike, ReturnType extends SchemaLike>(
|
||||
pool: DatabasePoolType,
|
||||
schema: GeneratedSchema<Schema>
|
||||
) => {
|
||||
const { table, fields } = convertToIdentifiers(schema);
|
||||
const isKeyOfSchema = isKeyOf(schema);
|
||||
const connectKeyValueWithEqualSign = (data: Partial<Schema>) =>
|
||||
Object.entries(data)
|
||||
.map(
|
||||
([key, value]) =>
|
||||
isKeyOfSchema(key) && sql`${fields[key]}=${convertToPrimitiveOrSql(key, value)}`
|
||||
)
|
||||
.filter((value): value is Truthy<typeof value> => notFalsy(value));
|
||||
|
||||
return async ({ where, limit, offset }: FindManyData<Schema> = {}) => {
|
||||
return pool.any<ReturnType>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`, `)}
|
||||
from ${table}
|
||||
${conditionalSql(
|
||||
where,
|
||||
(where) => sql`where ${sql.join(connectKeyValueWithEqualSign(where), sql` and `)}`
|
||||
)}
|
||||
${conditionalSql(limit, (limit) => sql`limit ${limit}`)}
|
||||
${conditionalSql(offset, (offset) => sql`offset ${offset}`)}
|
||||
`);
|
||||
};
|
||||
};
|
Loading…
Reference in a new issue