Enhance pagination and ordering capabilities in API responses
- Updated pagination-response and read-write-controllers documentation to include `orderBy` and `orderType` parameters for sorting results. - Introduced new `order-clause` module to handle ordering logic, including validation for order types and columns. - Enhanced `PaginationQueryDto` to support ordering fields in API requests. - Updated various repository and service classes to implement ordering in database queries. - Added unit tests for new ordering functionality and ensured existing tests cover the updated behavior. - Refactored related DTOs to include user and code relations for better data representation in responses.
This commit is contained in:
@@ -82,6 +82,8 @@ export type ListBranchesFilters = {
|
||||
readonly workingHoursStart?: string;
|
||||
readonly workingHoursEnd?: string;
|
||||
readonly search?: string;
|
||||
readonly orderBy?: string;
|
||||
readonly orderType?: string;
|
||||
readonly limit: number;
|
||||
readonly offset: number;
|
||||
};
|
||||
|
||||
@@ -5,7 +5,8 @@ import {
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { and, asc, count, eq, ilike, inArray, or, SQL } from 'drizzle-orm';
|
||||
import { and, count, eq, ilike, inArray, or, SQL } from 'drizzle-orm';
|
||||
import { toOrderClauses } from '../../../common/http/response';
|
||||
import { alias } from 'drizzle-orm/pg-core';
|
||||
import { DateTime } from '../../../common/value-objects/date-time/date-time';
|
||||
import { PhoneNumber } from '../../../common/value-objects/phone-number/phone-number';
|
||||
@@ -24,6 +25,18 @@ import type {
|
||||
UpdateBranchInput,
|
||||
} from './branch';
|
||||
|
||||
const BRANCH_ORDER_COLUMNS = {
|
||||
id: branches.id,
|
||||
code: branches.code,
|
||||
name: branches.name,
|
||||
phone: branches.phone,
|
||||
address: branches.address,
|
||||
nfcId: branches.nfcId,
|
||||
status: branches.status,
|
||||
createdAt: branches.createdAt,
|
||||
updatedAt: branches.updatedAt,
|
||||
};
|
||||
|
||||
const createdByUsers = alias(users, 'created_by_users');
|
||||
const updatedByUsers = alias(users, 'updated_by_users');
|
||||
|
||||
@@ -52,7 +65,11 @@ export class BranchesRepository {
|
||||
qb = this.extendListQuery(qb, filters);
|
||||
const rows = await qb
|
||||
.where(where)
|
||||
.orderBy(asc(branches.code))
|
||||
.orderBy(
|
||||
...toOrderClauses(BRANCH_ORDER_COLUMNS, filters, [
|
||||
{ column: 'code', type: 'ASC' },
|
||||
]),
|
||||
)
|
||||
.limit(filters.limit)
|
||||
.offset(filters.offset);
|
||||
|
||||
|
||||
@@ -4,7 +4,12 @@ import {
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import type { PaginationResponse } from '../../../common/http/response';
|
||||
import { toListPage } from '../../../common/http/response';
|
||||
import {
|
||||
pickRelation,
|
||||
pickUserRelation,
|
||||
DEFAULT_RELATION_FIELDS,
|
||||
toListPage,
|
||||
} from '../../../common/http/response';
|
||||
import { InvalidPhoneNumberError } from '../../../common/value-objects/phone-number/invalid-phone-number.error';
|
||||
import { PhoneNumber } from '../../../common/value-objects/phone-number/phone-number';
|
||||
import { Status } from '../../../common/value-objects/status/status';
|
||||
@@ -36,6 +41,8 @@ export type ListBranchesQuery = {
|
||||
readonly workingHoursStart?: string;
|
||||
readonly workingHoursEnd?: string;
|
||||
readonly search?: string;
|
||||
readonly orderBy?: string;
|
||||
readonly orderType?: string;
|
||||
readonly page?: number;
|
||||
readonly limit?: number;
|
||||
readonly offset?: number;
|
||||
@@ -94,6 +101,8 @@ export class BranchesService {
|
||||
workingHoursStart: query.workingHoursStart,
|
||||
workingHoursEnd: query.workingHoursEnd,
|
||||
search: query.search,
|
||||
orderBy: query.orderBy,
|
||||
orderType: query.orderType,
|
||||
limit: page.limit,
|
||||
offset: page.offset,
|
||||
});
|
||||
@@ -341,31 +350,15 @@ export class BranchesService {
|
||||
workingHoursStart: branch.workingHoursStart,
|
||||
workingHoursEnd: branch.workingHoursEnd,
|
||||
nfcId: branch.nfcId,
|
||||
division: this.toDivisionItem(branch.division),
|
||||
division: pickRelation(branch.division, DEFAULT_RELATION_FIELDS),
|
||||
status: branch.status.value,
|
||||
createdAt: branch.createdAt.value,
|
||||
updatedAt: branch.updatedAt.value,
|
||||
createdBy: this.toUserItem(branch.createdByUser),
|
||||
updatedBy: this.toUserItem(branch.updatedByUser),
|
||||
createdBy: pickUserRelation(branch.createdByUser),
|
||||
updatedBy: pickUserRelation(branch.updatedByUser),
|
||||
};
|
||||
}
|
||||
|
||||
private toDivisionItem(
|
||||
division: { id: string; code: string; name: string } | null,
|
||||
): { id: string; code: string; name: string } | null {
|
||||
if (division == null) {
|
||||
return null;
|
||||
}
|
||||
return { id: division.id, code: division.code, name: division.name };
|
||||
}
|
||||
|
||||
private toUserItem(user: { id: string; username: string }): {
|
||||
id: string;
|
||||
username: string;
|
||||
} {
|
||||
return { id: user.id, username: user.username };
|
||||
}
|
||||
|
||||
get visibleFields(): readonly string[] {
|
||||
return VISIBLE_FIELDS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user