UNPKG

bb-inspired

Version:

Core library for BB-inspired NestJS backend

203 lines 8.75 kB
"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