perf(directories): SQL-фильтрация/пагинация справочников, N+1, лимиты column-values
Шаги 1.1 и 1.2 плана production-готовности: - getDataTableRowsPaged: фильтры/поиск/сортировка/пагинация в SQL (values->>N) - getDataTablesWithAccess и list_directories без N+1 - /column-values: limit (дефолт 20, кап 1000), убраны debug-логи с горячего пути - tree-режим и legacy-путь TableEditor сохранены 1:1 - 10 новых тестов (88/88)
This commit is contained in:
39
server/utils/data-table-rows-query.ts
Normal file
39
server/utils/data-table-rows-query.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
// Хелперы для SQL-пагинации строк справочников (data_table_rows).
|
||||
// Чистые функции без доступа к БД — покрыты юнит-тестами.
|
||||
|
||||
/** Дефолтный лимит строк на страницу */
|
||||
export const DIRECTORY_ROWS_DEFAULT_LIMIT = 100;
|
||||
/** Максимальный лимит строк на страницу */
|
||||
export const DIRECTORY_ROWS_MAX_LIMIT = 1000;
|
||||
|
||||
/**
|
||||
* Экранирует спецсимволы LIKE/ILIKE (\, %, _) в пользовательской подстроке,
|
||||
* чтобы поиск работал как «содержит подстроку», а не как паттерн.
|
||||
* Используется вместе с `ESCAPE '\'` в SQL.
|
||||
*/
|
||||
export function escapeIlikePattern(value: string): string {
|
||||
return value.replace(/[\\%_]/g, (ch) => '\\' + ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Приводит лимит к допустимому диапазону.
|
||||
* Невалидные/неположительные значения → defaultLimit, сверху капается maxLimit.
|
||||
*/
|
||||
export function clampDirectoryRowsLimit(
|
||||
raw: unknown,
|
||||
defaultLimit: number = DIRECTORY_ROWS_DEFAULT_LIMIT,
|
||||
maxLimit: number = DIRECTORY_ROWS_MAX_LIMIT,
|
||||
): number {
|
||||
const n = typeof raw === 'number' ? raw : parseInt(String(raw ?? ''), 10);
|
||||
if (!Number.isFinite(n) || n <= 0) return defaultLimit;
|
||||
return Math.min(Math.floor(n), maxLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Приводит offset к неотрицательному целому. Невалидное → 0.
|
||||
*/
|
||||
export function clampDirectoryRowsOffset(raw: unknown): number {
|
||||
const n = typeof raw === 'number' ? raw : parseInt(String(raw ?? ''), 10);
|
||||
if (!Number.isFinite(n) || n < 0) return 0;
|
||||
return Math.floor(n);
|
||||
}
|
||||
Reference in New Issue
Block a user