0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-06 20:40:08 -05:00

feat(core): findAllApplications order by createdAt desc (#344)

* feat(core): find many data order by

* test(core): find many data order by

* feat(core): findAllApplications order by createdAt desc

* test(core): findAllApplications order by createdAt desc
This commit is contained in:
IceHe.xyz 2022-03-10 15:50:05 +08:00 committed by GitHub
parent a702d92c49
commit 4eb2c6ca42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 48 additions and 13 deletions

View file

@ -21,6 +21,14 @@ describe('buildFindMany()', () => {
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'
@ -45,11 +53,16 @@ describe('buildFindMany()', () => {
await findMany({ offset: 0 });
});
it('matches expected sql with where conditions, limit and offset', async () => {
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\nlimit $2\noffset $3'
'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' }, limit: 20, offset: 20 });
await findMany({
where: { id: '123' },
orderBy: { id: 'desc', username: 'asc' },
limit: 20,
offset: 20,
});
});
});

View file

@ -1,10 +1,10 @@
import { SchemaLike, GeneratedSchema } from '@logto/schemas';
import { notFalsy, Truthy } from '@silverhand/essentials';
import { GeneratedSchema, SchemaLike } from '@logto/schemas';
import { notFalsy } from '@silverhand/essentials';
import { DatabasePoolType, sql } from 'slonik';
import { isKeyOf } from '@/utils/schema';
import { FindManyData } from './types';
import { FindManyData, OrderBy } from './types';
import { conditionalSql, convertToIdentifiers, convertToPrimitiveOrSql } from './utils';
export const buildFindMany = <Schema extends SchemaLike, ReturnType extends SchemaLike>(
@ -13,24 +13,40 @@ export const buildFindMany = <Schema extends SchemaLike, ReturnType extends Sche
) => {
const { table, fields } = convertToIdentifiers(schema);
const isKeyOfSchema = isKeyOf(schema);
const connectKeyValueWithEqualSign = (data: Partial<Schema>) =>
Object.entries(data)
const connectKeyValueWithEqualSign = (partialSchema: Partial<Schema>) =>
Object.entries(partialSchema)
.map(
([key, value]) =>
isKeyOfSchema(key) && sql`${fields[key]}=${convertToPrimitiveOrSql(key, value)}`
)
.filter((value): value is Truthy<typeof value> => notFalsy(value));
.filter((entry) => notFalsy(entry));
return async ({ where, limit, offset }: FindManyData<Schema> = {}) => {
return pool.any<ReturnType>(sql`
const buildOrderBy = (orderBySchema: OrderBy<Schema>) =>
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<Schema> = {}) =>
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(
orderBy,
(orderBy) => sql`order by ${sql.join(buildOrderBy(orderBy), sql`, `)}`
)}
${conditionalSql(limit, (limit) => sql`limit ${limit}`)}
${conditionalSql(offset, (offset) => sql`offset ${offset}`)}
`);
};
};

View file

@ -6,8 +6,13 @@ export type FieldIdentifiers<Key extends string | number | symbol> = {
[key in Key]: IdentifierSqlTokenType;
};
export type OrderDirection = 'asc' | 'desc';
export type OrderBy<Schema extends SchemaLike> = Partial<Record<keyof Schema, OrderDirection>>;
export type FindManyData<Schema extends SchemaLike> = {
where?: Partial<Schema>;
orderBy?: OrderBy<Schema>;
limit?: number;
offset?: number;
};

View file

@ -57,6 +57,7 @@ describe('application query', () => {
const expectSql = sql`
select ${sql.join(Object.values(fields), sql`, `)}
from ${table}
order by "created_at" desc
limit $1
offset $2
`;

View file

@ -15,7 +15,7 @@ export const findTotalNumberOfApplications = async () => getTotalRowCount(table)
const findApplicationMany = buildFindMany<CreateApplication, Application>(pool, Applications);
export const findAllApplications = async (limit: number, offset: number) =>
findApplicationMany({ limit, offset });
findApplicationMany({ orderBy: { createdAt: 'desc' }, limit, offset });
export const findApplicationById = async (id: string) =>
pool.one<Application>(sql`