Skip to content

Commit 828a8f3

Browse files
TinySqlQuery --> jsDoc complete for now.
1 parent 6dea805 commit 828a8f3

File tree

2 files changed

+51
-24
lines changed

2 files changed

+51
-24
lines changed

src/TinySqlQuery.mjs

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,22 @@ const { Client } = pg;
77
const clientBase = new Client();
88

99
/**
10-
* @typedef {FreeObj} TagCriteria
10+
* Tag group definition used to build dynamic SQL clauses for tag filtering.
11+
*
12+
* @typedef {Object} TagCriteria - Tag group definition to build the clause from.
13+
* @property {string} [group.column] - SQL column name for tag data (defaults to `this.getColumnName()`).
14+
* @property {string} [group.valueName] - Alias used for JSON values (defaults to `this.defaultValueName`).
15+
* @property {boolean} [group.allowWildcards=false] - Whether wildcards are allowed in matching.
16+
* @property {Array<string|string[]>} [group.include=[]] - Tag values or grouped OR conditions to include.
17+
*/
18+
19+
/**
20+
* Represents the result of a paginated query.
21+
*
22+
* @typedef {Object} PaginationResult
23+
* @property {unknown[]} items - Array of items returned for the current page.
24+
* @property {number} totalPages - Total number of available pages based on the query and per-page limit.
25+
* @property {number} totalItems - Total number of items matching the query without pagination.
1126
*/
1227

1328
/**
@@ -21,7 +36,7 @@ const clientBase = new Client();
2136
* values?: string[]; // List of column names to select.
2237
* boost?: { // Boost configuration for weighted ranking.
2338
* alias?: string; // The alias to associate with the boost configuration.
24-
* value?: boostValue[]; // List of boost rules to apply.
39+
* value?: BoostValue[]; // List of boost rules to apply.
2540
* };
2641
* } |
2742
* null
@@ -61,7 +76,7 @@ const clientBase = new Client();
6176
/**
6277
* Represents a boosting rule for weighted query ranking.
6378
*
64-
* @typedef {Object} boostValue
79+
* @typedef {Object} BoostValue
6580
* @property {string[]} columns - List of columns to apply the boost on.
6681
* @property {string} operator - Operator used in the condition (e.g., '=', 'LIKE').
6782
* @property {string} value - Value to match in the condition.
@@ -74,7 +89,7 @@ const clientBase = new Client();
7489
* - `compare`: The ON clause condition.
7590
* - `type` (optional): One of the supported JOIN types (e.g., 'left', 'inner'). Defaults to 'left'.
7691
*
77-
* @typedef {{ table: string; compare: string; type?: string; }} joinObj
92+
* @typedef {{ table: string; compare: string; type?: string; }} JoinObj
7893
*/
7994

8095
/**
@@ -488,7 +503,7 @@ class PuddySqlQuery {
488503
/**
489504
* Boost parser helper
490505
*
491-
* @param {boostValue[]} boostArray
506+
* @param {BoostValue[]} boostArray
492507
* @param {string} alias
493508
* @returns {string}
494509
*/
@@ -1129,8 +1144,9 @@ class PuddySqlQuery {
11291144
escapeValuesFix(v, name) {
11301145
const column = this.#table?.[name];
11311146
const type = column.type || '';
1132-
if (typeof this.#jsonEscapeFix[type] !== 'function') return v;
1133-
else return this.#jsonEscapeFix[type](v);
1147+
const func = this.#jsonEscapeFix[type];
1148+
if (typeof func !== 'function') return v;
1149+
else return func(v);
11341150
}
11351151

11361152
/**
@@ -1414,7 +1430,7 @@ class PuddySqlQuery {
14141430
* @param {number} perPage - The number of items per page.
14151431
* @param {number} page - The current page number (starting from 1).
14161432
* @param {string} queryName - The query name to insert into the sql debug.
1417-
* @returns {Promise<{ items: any[], totalPages: number, totalItems: number }>}
1433+
* @returns {Promise<PaginationResult>}
14181434
*/
14191435
async execPagination(query, params, perPage, page, queryName = '') {
14201436
if (typeof query !== 'string')
@@ -1434,18 +1450,27 @@ class PuddySqlQuery {
14341450

14351451
// Count total items
14361452
const countQuery = `SELECT COUNT(*) as total FROM (${query}) AS count_wrapper`;
1437-
// @ts-ignore
1438-
const { total } = !isZero
1453+
const countResult = !isZero
14391454
? await db.get(countQuery, params, `pagination-${queryName}`)
14401455
: { total: 0 };
14411456

1457+
const total = isJsonObject(countResult)
1458+
? typeof countResult.total === 'number' &&
1459+
!Number.isNaN(countResult.total) &&
1460+
Number.isFinite(countResult.total) &&
1461+
countResult.total >= 0
1462+
? countResult.total
1463+
: 0
1464+
: 0;
1465+
14421466
// Fetch paginated items
14431467
const paginatedQuery = `${query} LIMIT ? OFFSET ?`;
14441468
const items = !isZero
14451469
? await db.all(paginatedQuery, [...params, perPage, offset], `pagination-${queryName}`)
14461470
: [];
14471471

14481472
const totalPages = !isZero ? Math.ceil(total / perPage) : 0;
1473+
for (const index in items) this.resultChecker(items[index]);
14491474

14501475
return {
14511476
items,
@@ -1654,12 +1679,12 @@ class PuddySqlQuery {
16541679
* - If `join` is an array of objects: generates multiple JOINs with aliases (`j1`, `j2`, ...).
16551680
* - If `join` is invalid or empty: falls back to `insertJoin()` using internal settings.
16561681
*
1657-
* @param {joinObj|joinObj[]|string|null} [join] - The join configuration(s).
1682+
* @param {JoinObj|JoinObj[]|string|null} [join] - The join configuration(s).
16581683
* @returns {string} One or more JOIN SQL snippets.
16591684
*/
16601685
parseJoin(join) {
16611686
/**
1662-
* @param {joinObj} j
1687+
* @param {JoinObj} j
16631688
* @param {number} idx
16641689
* @returns {string}
16651690
*/
@@ -1687,6 +1712,10 @@ class PuddySqlQuery {
16871712
: this.insertJoin();
16881713
}
16891714

1715+
/**
1716+
* @typedef {{ page: number, pages: number, total: number, position: number, item?: FreeObj }} FindResult
1717+
*/
1718+
16901719
/**
16911720
* Finds the first item matching the filter, along with its position, page, and total info.
16921721
* Uses a single SQL query to calculate everything efficiently.
@@ -1700,8 +1729,8 @@ class PuddySqlQuery {
17001729
* @param {number} [searchData.perPage] - Number of items per page.
17011730
* @param {SelectQuery} [searchData.select='*'] - Which columns to select. Set to null to skip item data.
17021731
* @param {string} [searchData.order] - SQL ORDER BY clause. Defaults to configured order.
1703-
* @param {string|joinObj|joinObj[]} [searchData.join] - JOIN definitions with table, compare, and optional type.
1704-
* @returns {Promise<{ page: number, pages: number, total: number, position: number, item?: object } | null>}
1732+
* @param {string|JoinObj|JoinObj[]} [searchData.join] - JOIN definitions with table, compare, and optional type.
1733+
* @returns {Promise<FindResult | null>}
17051734
*/
17061735
async find(searchData = {}) {
17071736
const db = this.getDb();
@@ -1779,6 +1808,7 @@ class PuddySqlQuery {
17791808
const position = parseInt(row.position);
17801809
const page = Math.floor((position - 1) / perPage) + 1;
17811810

1811+
/** @type {FindResult} */
17821812
const response = { page, pages, total, position };
17831813

17841814
// If selectValue is NOT null, return the item
@@ -1805,16 +1835,16 @@ class PuddySqlQuery {
18051835
* @param {Object} [searchData={}] - Main search configuration.
18061836
* @param {FreeObj} [searchData.q={}] - Nested criteria object.
18071837
* Can be a flat object style or grouped with `{ group: 'AND'|'OR', conditions: [...] }`.
1808-
* @param {TagCriteria[]|TagCriteria|null} [searchData.tagCriteria] - One or multiple tag criteria groups.
1809-
* @param {string[]} [searchData.tagCriteriaOps] - Optional logical operators between tag groups (e.g., ['AND', 'OR']).
1838+
* @param {TagCriteria[]|TagCriteria|null} [searchData.tagsQ] - One or multiple tag criteria groups.
1839+
* @param {string[]} [searchData.tagsOpsQ] - Optional logical operators between tag groups (e.g., ['AND', 'OR']).
18101840
* @param {SelectQuery} [searchData.select='*'] - Defines which columns or expressions should be selected in the query.
18111841
* @param {number|null} [searchData.perPage=null] - Number of results per page. If set, pagination is applied.
18121842
* @param {number} [searchData.page=1] - Page number to retrieve when `perPage` is used.
18131843
* @param {string} [searchData.order] - Custom `ORDER BY` clause (e.g. `'created_at DESC'`).
1814-
* @param {string|joinObj|joinObj[]} [searchData.join] - A string for single join or array of objects for multiple joins.
1844+
* @param {string|JoinObj|JoinObj[]} [searchData.join] - A string for single join or array of objects for multiple joins.
18151845
* Each object should contain `{ table: 'name', compare: 'ON clause' }`.
18161846
* @param {number} [searchData.limit] - Max number of results to return (ignored when `perPage` is used).
1817-
* @returns {Promise<FreeObj[]>} - Result rows matching the query.
1847+
* @returns {Promise<FreeObj[]|PaginationResult>} - Result rows matching the query.
18181848
*
18191849
* @example
18201850
* // Flat search:
@@ -1878,7 +1908,7 @@ class PuddySqlQuery {
18781908
const operators = Array.isArray(tagCriteriaOps) ? tagCriteriaOps : [];
18791909

18801910
tagCriteria.forEach((group, i) => {
1881-
const column = group?.column || 'tags'; // default name if not set
1911+
const column = typeof group.column === 'string' ? group.column : 'tags'; // default name if not set
18821912
const tag = this.getTagEditor(column);
18831913
if (!tag) return;
18841914

src/TinySqlTags.mjs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { isJsonObject } from 'tiny-essentials';
22

33
/** @typedef {{ title: string; parser?: function(string): string }} SpecialQuery */
44
/** @typedef {import('./TinySqlQuery.mjs').Pcache} Pcache */
5+
/** @typedef {import('./TinySqlQuery.mjs').TagCriteria} TagCriteria */
56

67
/**
78
* @class PuddySqlTags
@@ -266,11 +267,7 @@ class PuddySqlTags {
266267
* with the filtered values in proper order for parameterized queries.
267268
*
268269
* @param {Pcache} [pCache={ index: 1, values: [] }] - Placeholder cache object.
269-
* @param {Object} [group={}] - Tag group definition to build the clause from.
270-
* @param {string} [group.column] - SQL column name for tag data (defaults to `this.getColumnName()`).
271-
* @param {string} [group.valueName] - Alias used for JSON values (defaults to `this.defaultValueName`).
272-
* @param {boolean} [group.allowWildcards=false] - Whether wildcards are allowed in matching.
273-
* @param {Array<string|string[]>} [group.include=[]] - Tag values or grouped OR conditions to include.
270+
* @param {TagCriteria} [group={}] - Tag group definition to build the clause from.
274271
*
275272
* @returns {string} The generated SQL condition string (e.g., `(EXISTS (...)) AND (NOT EXISTS (...))`).
276273
*/

0 commit comments

Comments
 (0)