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:
parent
a702d92c49
commit
4eb2c6ca42
5 changed files with 48 additions and 13 deletions
|
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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}`)}
|
||||
`);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
`;
|
||||
|
|
|
@ -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`
|
||||
|
|
Loading…
Reference in a new issue