UNPKG

@kitstack/nest-powertools

Version:

A comprehensive collection of NestJS powertools, decorators, and utilities to supercharge your backend development

343 lines 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PaginationHelper = exports.ResponseFormatter = void 0; const enums_1 = require("../types/enums"); class ResponseFormatter { static generateRequestId() { return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } static getTimestamp() { return new Date().toISOString(); } static success(data, message, metadata) { return { success: true, status: enums_1.ResponseStatus.SUCCESS, code: enums_1.ResponseCodes.OPERATION_SUCCESSFUL, data, message, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), metadata, }; } static error(message, code = enums_1.ResponseCodes.INTERNAL_ERROR, details, field) { return { success: false, status: enums_1.ResponseStatus.ERROR, code, error: { message, details, field, }, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), }; } static warning(data, message, code = enums_1.ResponseCodes.OPERATION_SUCCESSFUL, metadata) { return { success: true, status: enums_1.ResponseStatus.WARNING, code, data, message, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), metadata, }; } static paginated(data, total, page, limit, message) { const totalPages = Math.ceil(total / limit); const hasNext = page < totalPages; const hasPrevious = page > 1; return { data, pagination: { total, page, limit, totalPages, hasNext, hasPrevious, }, status: enums_1.ResponseStatus.SUCCESS, timestamp: this.getTimestamp(), message, }; } static validationError(errors) { return { success: false, status: enums_1.ResponseStatus.ERROR, code: enums_1.ResponseCodes.VALIDATION_FAILED, error: { message: 'Validation failed', details: errors, }, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), }; } static authenticationError(message = 'Authentication required') { return { success: false, status: enums_1.ResponseStatus.ERROR, code: enums_1.ResponseCodes.AUTHENTICATION_REQUIRED, error: { message, }, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), }; } static authorizationError(message = 'Insufficient permissions') { return { success: false, status: enums_1.ResponseStatus.ERROR, code: enums_1.ResponseCodes.AUTHORIZATION_FAILED, error: { message, }, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), }; } static notFound(resource) { const message = resource ? `${resource} not found` : 'Resource not found'; return { success: false, status: enums_1.ResponseStatus.ERROR, code: enums_1.ResponseCodes.RESOURCE_NOT_FOUND, error: { message, }, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), }; } static conflict(message = 'Resource conflict') { return { success: false, status: enums_1.ResponseStatus.ERROR, code: enums_1.ResponseCodes.RESOURCE_CONFLICT, error: { message, }, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), }; } static rateLimitExceeded(message = 'Rate limit exceeded') { return { success: false, status: enums_1.ResponseStatus.ERROR, code: enums_1.ResponseCodes.RATE_LIMIT_EXCEEDED, error: { message, }, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), }; } static custom(success, status, code, data, message, metadata) { return { success, status, code, data, message, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), metadata, }; } static transform(data, options) { const { message, status = enums_1.ResponseStatus.SUCCESS, code = enums_1.ResponseCodes.OPERATION_SUCCESSFUL, metadata, } = options || {}; return { success: true, status, code, data, message, timestamp: this.getTimestamp(), requestId: this.generateRequestId(), metadata, }; } } exports.ResponseFormatter = ResponseFormatter; class PaginationHelper { static paginate(data, total, pagination, message) { const { page, limit, sortBy, sortOrder, search, filters, offset } = pagination; const totalPages = limit === -1 ? 1 : Math.ceil(total / limit); const hasNext = limit === -1 ? false : page < totalPages; const hasPrevious = page > 1; return { data, pagination: { total, page, limit, totalPages, hasNext, hasPrevious, offset, sortBy, sortOrder, search, filters, }, status: enums_1.ResponseStatus.SUCCESS, timestamp: new Date().toISOString(), message, }; } static getSkipTake(pagination) { const { page, limit } = pagination; if (limit === -1) { return { skip: 0, take: -1 }; } const skip = (page - 1) * limit; return { skip, take: limit }; } static getOffsetLimit(pagination) { const { page, limit } = pagination; if (limit === -1) { return { offset: 0, limit: -1 }; } const offset = (page - 1) * limit; return { offset, limit }; } static createLinks(pagination, total, baseUrl) { const { page, limit, sortBy, sortOrder, search, filters } = pagination; const totalPages = limit === -1 ? 1 : Math.ceil(total / limit); const buildUrl = (targetPage) => { const params = new URLSearchParams(); params.set('page', targetPage.toString()); params.set('limit', limit.toString()); params.set('sortBy', sortBy); params.set('sortOrder', sortOrder); if (search) params.set('search', search); if (filters) params.set('filters', JSON.stringify(filters)); return `${baseUrl}?${params.toString()}`; }; const links = { first: buildUrl(1), last: buildUrl(totalPages), self: buildUrl(page), }; if (page > 1) { links.prev = buildUrl(page - 1); } if (page < totalPages && limit !== -1) { links.next = buildUrl(page + 1); } return links; } static validate(pagination, options = {}) { const errors = []; const { page, limit, sortBy, search } = pagination; if (page < 1) { errors.push('Page must be greater than 0'); } if (limit !== -1) { if (limit < 1) { errors.push('Limit must be greater than 0'); } if (options.maxLimit && limit > options.maxLimit) { errors.push(`Limit cannot exceed ${options.maxLimit}`); } } if (options.allowedSortFields && !options.allowedSortFields.includes(sortBy)) { errors.push(`Invalid sort field: ${sortBy}. Allowed fields: ${options.allowedSortFields.join(', ')}`); } if (options.requireSearch && (!search || search.trim().length === 0)) { errors.push('Search parameter is required'); } return { valid: errors.length === 0, errors, }; } static forPrisma(pagination) { const { skip, take } = this.getSkipTake(pagination); const { sortBy, sortOrder } = pagination; return { skip: skip, take: take === -1 ? undefined : take, orderBy: { [sortBy]: sortOrder.toLowerCase(), }, }; } static forTypeORM(pagination) { const { skip, take } = this.getSkipTake(pagination); const { sortBy, sortOrder } = pagination; return { skip: skip, take: take === -1 ? undefined : take, order: { [sortBy]: sortOrder, }, }; } static forMongoose(pagination) { const { skip, take } = this.getSkipTake(pagination); const { sortBy, sortOrder } = pagination; const sort = { [sortBy]: sortOrder === 'ASC' ? 1 : -1 }; return { skip, limit: take === -1 ? 0 : take, sort, }; } static createCursor(data, cursorField, pagination) { const { limit } = pagination; const hasNext = data.length > limit; const hasPrevious = false; const resultData = hasNext ? data.slice(0, limit) : data; const nextCursor = hasNext && resultData.length > 0 ? String(resultData[resultData.length - 1][cursorField]) : undefined; return { data: resultData, hasNext, hasPrevious, nextCursor, }; } static getStats(pagination, total) { const { page, limit } = pagination; if (limit === -1) { return { totalItems: total, totalPages: 1, currentPage: 1, itemsPerPage: total, startIndex: 1, endIndex: total, isFirstPage: true, isLastPage: true, }; } const totalPages = Math.ceil(total / limit); const startIndex = (page - 1) * limit + 1; const endIndex = Math.min(page * limit, total); return { totalItems: total, totalPages, currentPage: page, itemsPerPage: limit, startIndex, endIndex, isFirstPage: page === 1, isLastPage: page === totalPages, }; } } exports.PaginationHelper = PaginationHelper; //# sourceMappingURL=response-formatter.js.map