bb-inspired
Version:
Core library for BB-inspired NestJS backend
203 lines • 8.75 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var QueryTransformationPipe_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueryTransformationPipe = void 0;
const common_1 = require("@nestjs/common");
const logger_1 = require("../utils/logger");
let QueryTransformationPipe = QueryTransformationPipe_1 = class QueryTransformationPipe {
constructor(options = {}) {
this.options = options;
this.logger = new logger_1.AppLogger(QueryTransformationPipe_1.name);
this.options = {
defaultLimit: 10,
maxLimit: 100,
...options,
};
}
transform(value) {
if (!value || typeof value !== 'object') {
return {};
}
const transformed = { ...value };
transformed.pagination = this.transformPagination(value);
transformed.sort = this.transformSort(value);
transformed.filter = this.transformFilter(value);
this.applyAdditionalTransformations(transformed, value);
return transformed;
}
transformPagination(query) {
const { page, limit, offset } = query;
const pagination = {};
pagination.page = page !== undefined ? Math.max(1, parseInt(page, 10) || 1) : 1;
let parsedLimit = limit !== undefined ? parseInt(limit, 10) : this.options.defaultLimit;
parsedLimit = Math.min(Math.max(1, parsedLimit), this.options.maxLimit);
pagination.limit = parsedLimit;
if (offset !== undefined) {
pagination.offset = Math.max(0, parseInt(offset, 10) || 0);
}
else {
pagination.offset = (pagination.page - 1) * pagination.limit;
}
return pagination;
}
transformSort(query) {
const { sort, sortDir } = query;
if (!sort && this.options.defaultSort) {
return this.parseSortString(this.options.defaultSort);
}
if (!sort) {
return {};
}
if (typeof sort === 'string' && !sort.includes(',')) {
const field = this.validateSortField(sort);
const direction = this.parseSortDirection(sortDir);
if (field) {
return { [field]: direction };
}
return {};
}
if (typeof sort === 'string' && sort.includes(',')) {
return this.parseSortString(sort);
}
return {};
}
parseSortDirection(dir) {
if (!dir) {
return 1;
}
const lowerDir = dir.toLowerCase();
return (lowerDir === 'desc' || lowerDir === 'descending' || lowerDir === '-1') ? -1 : 1;
}
parseSortString(sortStr) {
const sortObj = {};
sortStr.split(',').forEach(part => {
const isDesc = part.startsWith('-');
const field = isDesc ? part.substring(1) : part;
const validField = this.validateSortField(field);
if (validField) {
sortObj[validField] = isDesc ? -1 : 1;
}
});
return sortObj;
}
validateSortField(field) {
if (!this.options.allowedSortFields || this.options.allowedSortFields.length === 0) {
return field;
}
return this.options.allowedSortFields.includes(field) ? field : undefined;
}
transformFilter(query) {
const filter = {};
if (!query || !this.options.allowedFilterFields || this.options.allowedFilterFields.length === 0) {
return filter;
}
this.options.allowedFilterFields.forEach(field => {
if (query[field] !== undefined) {
filter[field] = this.parseFilterValue(field, query[field]);
}
});
this.processSpecialFilters(filter, query);
return filter;
}
parseFilterValue(field, value) {
if (value === 'true' || value === 'false') {
return value === 'true';
}
if (!isNaN(Number(value)) && value !== '') {
return Number(value);
}
if (typeof value === 'string' && value.includes(',')) {
return { $in: value.split(',').map(v => this.parseFilterValue(field, v.trim())) };
}
if (typeof value === 'string') {
if (value.startsWith('>')) {
const numVal = Number(value.substring(1));
if (!isNaN(numVal)) {
return { $gt: numVal };
}
}
if (value.startsWith('<')) {
const numVal = Number(value.substring(1));
if (!isNaN(numVal)) {
return { $lt: numVal };
}
}
if (value.endsWith('*')) {
const prefix = value.substring(0, value.length - 1);
return { $regex: `^${this.escapeRegExp(prefix)}`, $options: 'i' };
}
if (value.startsWith('*') && value.endsWith('*')) {
const term = value.substring(1, value.length - 1);
return { $regex: this.escapeRegExp(term), $options: 'i' };
}
}
return value;
}
processSpecialFilters(filter, query) {
var _a;
if (query.search && typeof query.search === 'string' && query.search.trim() !== '') {
const searchValue = query.search.trim();
if (query.searchFields && typeof query.searchFields === 'string') {
const searchFields = query.searchFields.split(',')
.filter(field => { var _a; return (_a = this.options.allowedFilterFields) === null || _a === void 0 ? void 0 : _a.includes(field); });
if (searchFields.length > 0) {
filter.$or = searchFields.map(field => ({
[field]: { $regex: this.escapeRegExp(searchValue), $options: 'i' }
}));
}
}
else if (((_a = this.options.allowedFilterFields) === null || _a === void 0 ? void 0 : _a.length) > 0) {
filter.$or = this.options.allowedFilterFields.map(field => ({
[field]: { $regex: this.escapeRegExp(searchValue), $options: 'i' }
}));
}
}
this.processDateRangeFilters(filter, query);
}
processDateRangeFilters(filter, query) {
const dateRangePatterns = [
{ start: 'startDate', end: 'endDate', field: 'date' },
{ start: 'createdAtStart', end: 'createdAtEnd', field: 'createdAt' },
{ start: 'updatedAtStart', end: 'updatedAtEnd', field: 'updatedAt' },
];
dateRangePatterns.forEach(pattern => {
var _a;
if ((query[pattern.start] || query[pattern.end]) &&
((_a = this.options.allowedFilterFields) === null || _a === void 0 ? void 0 : _a.includes(pattern.field))) {
filter[pattern.field] = filter[pattern.field] || {};
if (query[pattern.start]) {
filter[pattern.field].$gte = new Date(query[pattern.start]);
}
if (query[pattern.end]) {
filter[pattern.field].$lte = new Date(query[pattern.end]);
}
}
});
}
applyAdditionalTransformations(transformed, original) {
const booleanFlags = ['includeDeleted', 'includeInactive', 'onlyActive', 'withRelated'];
booleanFlags.forEach(flag => {
if (original[flag] !== undefined) {
transformed[flag] = original[flag] === 'true' || original[flag] === true;
}
});
}
escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
};
exports.QueryTransformationPipe = QueryTransformationPipe;
exports.QueryTransformationPipe = QueryTransformationPipe = QueryTransformationPipe_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [Object])
], QueryTransformationPipe);
//# sourceMappingURL=query-transformation.pipe.js.map