@anpdgovbr/shared-types
Version:
Biblioteca central de tipos TypeScript compartilhados para os projetos da ANPD (BETA)
209 lines (208 loc) • 6.56 kB
JavaScript
;
/**
* @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,
};
}