import { QueryBuilder, Model } from 'objection'; import { ModelHasRelationsError } from '@/common/exceptions/ModelHasRelations.exception'; interface PaginationResult { results: M[]; pagination: { total: number; page: number; pageSize: number; }; } export type PaginationQueryBuilderType = QueryBuilder< M, PaginationResult >; export class PaginationQueryBuilder< M extends Model, R = M[], > extends QueryBuilder { pagination(page: number, pageSize: number): PaginationQueryBuilderType { const query = super.page(page, pageSize); return query.runAfter(({ results, total }) => { return { results, pagination: { total, page: page + 1, pageSize, }, }; }) as unknown as PaginationQueryBuilderType; } async deleteIfNoRelations({ type, message, }: { type?: string; message?: string; }) { const relationMappings = this.modelClass().relationMappings; const relationNames = Object.keys(relationMappings || {}); if (relationNames.length === 0) { // No relations defined return this.delete(); } const recordQuery = this.clone(); relationNames.forEach((relationName: string) => { recordQuery.withGraphFetched(relationName); }); const record = await recordQuery; const hasRelations = relationNames.some((name) => { const val = record[name]; return Array.isArray(val) ? val.length > 0 : val != null; }); if (!hasRelations) { return this.clone().delete(); } else { throw new ModelHasRelationsError(type, message); } } } export class BaseQueryBuilder< M extends Model, R = M[], > extends PaginationQueryBuilder { changeAmount(whereAttributes, attribute, amount) { const changeMethod = amount > 0 ? 'increment' : 'decrement'; return this.where(whereAttributes)[changeMethod]( attribute, Math.abs(amount), ); } } export class BaseModel extends Model { public readonly id: number; public readonly tableName: string; QueryBuilderType!: BaseQueryBuilder; static QueryBuilder = BaseQueryBuilder; }