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