UNPKG

@anpdgovbr/shared-types

Version:

Biblioteca central de tipos TypeScript compartilhados para os projetos da ANPD (BETA)

209 lines (208 loc) 6.56 kB
"use strict"; /** * @fileoverview * Utilitários e helpers para trabalhar com paginação de resultados. * * @remarks * Este módulo fornece funções auxiliares para calcular metadados de paginação, * validar parâmetros e criar respostas paginadas padronizadas. * * @module interfaces/pagination.helpers * @public */ Object.defineProperty(exports, "__esModule", { value: true }); exports.calculatePaginationMeta = calculatePaginationMeta; exports.validatePaginationParams = validatePaginationParams; exports.createPaginatedResponse = createPaginatedResponse; exports.calculateOffset = calculateOffset; exports.isValidPage = isValidPage; exports.getPageRange = getPageRange; exports.createEmptyPaginatedResponse = createEmptyPaginatedResponse; const constants_1 = require("../base/constants"); /** * Calcula os metadados de paginação. * * @param page Número da página atual (1-indexed) * @param pageSize Tamanho da página * @param totalItems Total de itens disponíveis * @returns Metadados calculados da paginação * * @example * ```typescript * const meta = calculatePaginationMeta(2, 20, 150) * console.log(meta.totalPages) // 8 * console.log(meta.hasNext) // true * console.log(meta.hasPrevious) // true * ``` */ function calculatePaginationMeta(page, pageSize, totalItems) { const totalPages = Math.ceil(totalItems / pageSize); const startIndex = (page - 1) * pageSize; const endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1); return { totalPages, currentPage: page, pageSize, hasNext: page < totalPages, hasPrevious: page > 1, startIndex, endIndex, totalItems, }; } /** * Valida e normaliza parâmetros de paginação. * * @param params Parâmetros de consulta recebidos * @returns Parâmetros validados e normalizados * * @remarks * - Garante que `page` seja >= 1 * - Garante que `pageSize` esteja entre MIN_PAGE_SIZE e MAX_PAGE_SIZE * - Aplica valores padrão quando não especificados * * @example * ```typescript * const params = validatePaginationParams({ page: 0, pageSize: 1000 }) * console.log(params.page) // 1 (corrigido) * console.log(params.pageSize) // 100 (limitado ao máximo) * ``` */ function validatePaginationParams(params) { const page = Math.max(params.page || constants_1.PAGINATION_LIMITS.MIN_PAGE, constants_1.PAGINATION_LIMITS.MIN_PAGE); const pageSize = Math.min(Math.max(params.pageSize || constants_1.PAGINATION_LIMITS.DEFAULT_PAGE_SIZE, constants_1.PAGINATION_LIMITS.MIN_PAGE_SIZE), constants_1.PAGINATION_LIMITS.MAX_PAGE_SIZE); const result = { page, pageSize, }; if (params.search !== undefined) { result.search = params.search; } if (params.orderBy !== undefined) { result.orderBy = params.orderBy; } if (params.ascending !== undefined) { result.ascending = params.ascending; } return result; } /** * Cria uma resposta paginada padronizada. * * @template T Tipo dos itens da página * @param data Array de itens da página atual * @param page Número da página atual * @param pageSize Tamanho da página * @param total Total de itens disponíveis * @returns Resposta paginada completa com metadados * * @example * ```typescript * const usuarios = [{ id: 1, nome: "João" }, { id: 2, nome: "Maria" }] * const response = createPaginatedResponse(usuarios, 1, 20, 50) * console.log(response.hasNext) // true * console.log(response.total) // 50 * ``` */ function createPaginatedResponse(data, page, pageSize, total) { const meta = calculatePaginationMeta(page, pageSize, total); return { data, total, page: meta.currentPage, pageSize: meta.pageSize, hasNext: meta.hasNext, hasPrevious: meta.hasPrevious, }; } /** * Calcula o offset (skip) para consultas ao banco de dados. * * @param page Número da página (1-indexed) * @param pageSize Tamanho da página * @returns Número de registros a pular (offset) * * @example * ```typescript * const offset = calculateOffset(3, 20) * console.log(offset) // 40 (pula as 2 primeiras páginas) * ``` */ function calculateOffset(page, pageSize) { return (page - 1) * pageSize; } /** * Verifica se a página solicitada existe dado o total de itens. * * @param page Número da página * @param pageSize Tamanho da página * @param totalItems Total de itens disponíveis * @returns `true` se a página existe, `false` caso contrário * * @example * ```typescript * const exists = isValidPage(10, 20, 150) * console.log(exists) // false (apenas 8 páginas disponíveis) * ``` */ function isValidPage(page, pageSize, totalItems) { if (page < 1) return false; if (totalItems === 0) return page === 1; const totalPages = Math.ceil(totalItems / pageSize); return page <= totalPages; } /** * Calcula o range de páginas a serem exibidas em uma paginação de UI. * * @param currentPage Página atual * @param totalPages Total de páginas * @param maxVisible Número máximo de páginas a exibir (padrão: 7) * @returns Array com números de páginas a exibir * * @remarks * Útil para criar componentes de paginação no frontend. * * @example * ```typescript * const pages = getPageRange(5, 10, 5) * console.log(pages) // [3, 4, 5, 6, 7] * ``` */ function getPageRange(currentPage, totalPages, maxVisible = 7) { if (totalPages <= maxVisible) { return Array.from({ length: totalPages }, (_, i) => i + 1); } const halfVisible = Math.floor(maxVisible / 2); let startPage = Math.max(currentPage - halfVisible, 1); const endPage = Math.min(startPage + maxVisible - 1, totalPages); // Ajusta startPage se estamos próximos ao final if (endPage - startPage < maxVisible - 1) { startPage = Math.max(endPage - maxVisible + 1, 1); } return Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i); } /** * Cria uma resposta vazia paginada (quando não há resultados). * * @template T Tipo dos itens (inferido) * @returns Resposta paginada vazia * * @example * ```typescript * const empty = createEmptyPaginatedResponse<Usuario>() * console.log(empty.total) // 0 * console.log(empty.data) // [] * ``` */ function createEmptyPaginatedResponse() { return { data: [], total: 0, page: 1, pageSize: constants_1.PAGINATION_LIMITS.DEFAULT_PAGE_SIZE, hasNext: false, hasPrevious: false, }; }