@starbemtech/star-db-query-builder 1.3.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/.claude/skills/star-db-query-builder/SKILL.md +104 -0
  2. package/CHANGELOG.md +107 -55
  3. package/LICENSE +21 -0
  4. package/README.md +92 -1391
  5. package/bin/install-skill.js +53 -0
  6. package/dist/src/core/repository.d.ts +125 -10
  7. package/dist/src/core/repository.js +336 -43
  8. package/dist/src/core/repository.js.map +1 -1
  9. package/dist/src/core/types.d.ts +29 -6
  10. package/dist/src/core/utils.d.ts +119 -0
  11. package/dist/src/core/utils.js +353 -82
  12. package/dist/src/core/utils.js.map +1 -1
  13. package/dist/src/db/IDatabaseClient.d.ts +14 -4
  14. package/dist/src/db/initDb.d.ts +60 -50
  15. package/dist/src/db/initDb.js +96 -64
  16. package/dist/src/db/initDb.js.map +1 -1
  17. package/dist/src/db/mysqlClient.d.ts +3 -8
  18. package/dist/src/db/mysqlClient.js +10 -11
  19. package/dist/src/db/mysqlClient.js.map +1 -1
  20. package/dist/src/db/pgClient.js +1 -2
  21. package/dist/src/db/pgClient.js.map +1 -1
  22. package/dist/src/monitor/monitor.js +7 -0
  23. package/dist/src/monitor/monitor.js.map +1 -1
  24. package/package.json +32 -24
  25. package/.github/workflows/publish.yml +0 -118
  26. package/.prettierignore +0 -3
  27. package/.prettierrc +0 -5
  28. package/ARCHITECTURE.md +0 -313
  29. package/coverage/base.css +0 -224
  30. package/coverage/block-navigation.js +0 -87
  31. package/coverage/favicon.png +0 -0
  32. package/coverage/index.html +0 -131
  33. package/coverage/lcov-report/base.css +0 -224
  34. package/coverage/lcov-report/block-navigation.js +0 -87
  35. package/coverage/lcov-report/favicon.png +0 -0
  36. package/coverage/lcov-report/index.html +0 -131
  37. package/coverage/lcov-report/mysqlClient.ts.html +0 -685
  38. package/coverage/lcov-report/pgClient.ts.html +0 -823
  39. package/coverage/lcov-report/prettify.css +0 -1
  40. package/coverage/lcov-report/prettify.js +0 -2
  41. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  42. package/coverage/lcov-report/sorter.js +0 -210
  43. package/coverage/lcov.info +0 -533
  44. package/coverage/mysqlClient.ts.html +0 -685
  45. package/coverage/pgClient.ts.html +0 -823
  46. package/coverage/prettify.css +0 -1
  47. package/coverage/prettify.js +0 -2
  48. package/coverage/sort-arrow-sprite.png +0 -0
  49. package/coverage/sorter.js +0 -210
  50. package/dist/src/setupTests.d.ts +0 -26
  51. package/dist/src/setupTests.js +0 -43
  52. package/dist/src/setupTests.js.map +0 -1
  53. package/docs/INDEX.md +0 -145
  54. package/docs/methods/findFirst.md +0 -394
  55. package/docs/methods/findMany.md +0 -587
  56. package/docs/methods/insert.md +0 -536
  57. package/docs/methods/insertMany.md +0 -627
  58. package/docs/methods/joins.md +0 -781
  59. package/docs/methods/rawQuery.md +0 -284
  60. package/docs/methods/transactions.md +0 -737
  61. package/eslint.config.mjs +0 -77
  62. package/index.ts +0 -16
  63. package/jest.config.ts +0 -194
  64. package/scripts/release.sh +0 -123
  65. package/src/core/repository.ts +0 -865
  66. package/src/core/types.ts +0 -97
  67. package/src/core/utils.ts +0 -357
  68. package/src/db/IDatabaseClient.ts +0 -16
  69. package/src/db/__tests__/mysqlClient.test.ts +0 -262
  70. package/src/db/__tests__/pgClient.test.ts +0 -260
  71. package/src/db/initDb.ts +0 -181
  72. package/src/db/mysqlClient.ts +0 -200
  73. package/src/db/pgClient.ts +0 -246
  74. package/src/monitor/monitor.ts +0 -16
  75. package/src/setupTests.ts +0 -45
  76. package/tsconfig.test.json +0 -21
@@ -1,6 +1,206 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createOffsetClause = exports.createLimitClause = exports.createGroupByClause = exports.createOrderByClause = exports.createWhereClause = exports.generateSetClause = exports.generatePlaceholders = exports.createSelectFields = void 0;
3
+ exports.createOffsetClause = exports.createLimitClause = exports.createGroupByClause = exports.createOrderByClause = exports.createWhereClause = exports.generateSetClause = exports.generatePlaceholders = exports.createSelectFields = exports.assertNoAutoManagedColumns = exports.quoteIdentifier = exports.assertSafeSqlFragment = exports.assertValidIdentifier = exports.stripUndefinedValues = exports.assertWithinBindParamLimit = exports.MAX_BIND_PARAMS = exports.MAX_IN_LIST_SIZE = void 0;
4
+ /**
5
+ * Matches a bare SQL identifier, optionally schema/table-qualified
6
+ * (e.g. "id", "users", "users.id"). Used to validate table names, join
7
+ * tables, `where` field keys and delete-by fields, since those are always
8
+ * plain identifiers and never need SQL expressions. GROUP BY / ORDER BY
9
+ * fields are intentionally *not* restricted to this — they go through
10
+ * `assertSafeSqlFragment` instead, since both are documented to accept a
11
+ * full SQL expression (e.g. `COUNT(*) as total`), not just a bare column.
12
+ */
13
+ const IDENTIFIER_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)?$/;
14
+ /**
15
+ * Matches characters that have no legitimate use inside a SELECT
16
+ * expression or a JOIN ON condition (statement terminators, comment
17
+ * markers, backticks) but that are the building blocks of classic
18
+ * SQL injection (stacked queries, comment-based truncation). Includes `#`,
19
+ * MySQL's own single-line comment marker (distinct from the `--`/`/* *‍/`
20
+ * forms both dialects share) — previously missing here, so a fragment like
21
+ * `id # , (SELECT ...)` on a MySQL connection passed this check untouched.
22
+ */
23
+ const DANGEROUS_SQL_PATTERN = /(;|--|\/\*|\*\/|`|#)/;
24
+ /**
25
+ * Maximum number of values accepted in a single `IN`/`NOT IN`/`BETWEEN`
26
+ * condition array.
27
+ *
28
+ * This guards two real failure modes, both triggered by callers building a
29
+ * WHERE condition from an unbounded list (e.g. forwarding a large search
30
+ * result as an `IN` filter): pg's own wire protocol rejects a query with more
31
+ * than 65535 total bound parameters, and — well before that limit — building
32
+ * the values array with `values.push(...value)` throws
33
+ * `RangeError: Maximum call stack size exceeded` once `value.length` is large
34
+ * enough to overflow the JS engine's function-call argument limit. Chunk the
35
+ * list (e.g. multiple `IN` queries unioned, or a temp table / `= ANY($1::type[])`
36
+ * for pg) instead of growing a single condition past this size.
37
+ */
38
+ exports.MAX_IN_LIST_SIZE = 10000;
39
+ /**
40
+ * pg's wire protocol rejects a query with more than 65535 total bound
41
+ * parameters ("bind message has N parameter formats but M parameters" /
42
+ * "too many parameters"). Any function that can build a bind-parameter list
43
+ * proportional to caller input (a large `ids` array, a large batch insert)
44
+ * should check its total against this before building the query, rather
45
+ * than letting the database reject it with a cryptic protocol error.
46
+ */
47
+ exports.MAX_BIND_PARAMS = 65535;
48
+ /**
49
+ * Rejects a query that would exceed the maximum number of bind parameters
50
+ * a database driver accepts in a single statement
51
+ *
52
+ * @param count - The total number of bind parameters the query would use
53
+ * @param label - A human-readable label used in the error message
54
+ * @throws {Error} When `count` exceeds `MAX_BIND_PARAMS`
55
+ */
56
+ const assertWithinBindParamLimit = (count, label) => {
57
+ if (count > exports.MAX_BIND_PARAMS) {
58
+ throw new Error(`${label} would use ${count} bind parameters, exceeding the maximum of ${exports.MAX_BIND_PARAMS} supported by the database driver. Chunk the operation into smaller batches.`);
59
+ }
60
+ };
61
+ exports.assertWithinBindParamLimit = assertWithinBindParamLimit;
62
+ /**
63
+ * Every operator `createWhereClause` knows how to render. Kept in sync with
64
+ * `OperatorCondition['operator']` in `types.ts` — this is the runtime side of
65
+ * that compile-time union, since `key`/`operator` reach this function as
66
+ * plain strings regardless of what TypeScript enforced at the call site.
67
+ */
68
+ const WHERE_OPERATOR_WHITELIST = new Set([
69
+ 'ILIKE',
70
+ 'LIKE',
71
+ '=',
72
+ '>',
73
+ '<',
74
+ 'IN',
75
+ 'BETWEEN',
76
+ '!=',
77
+ '<=',
78
+ '>=',
79
+ 'NOT IN',
80
+ 'NOT LIKE',
81
+ 'IS NULL',
82
+ 'IS NOT NULL',
83
+ 'NOT EXISTS',
84
+ ]);
85
+ /**
86
+ * Drops every key whose value is `undefined` from a write payload (`update`
87
+ * / `updateMany`'s `data`).
88
+ *
89
+ * A partial DTO built by spreading an object with an optional, unset field
90
+ * (`{ ...partial }`) routinely carries an explicit `undefined` for that key
91
+ * rather than omitting it — `Object.keys`/`Object.values` still see it. Left
92
+ * in, it reaches the driver as a real bind parameter: node-postgres silently
93
+ * coerces it to SQL `NULL` (overwriting the column instead of leaving it
94
+ * untouched), while mysql2 rejects it outright. Filtering it out here makes
95
+ * "didn't pass a value" behave the same way on both drivers: the column is
96
+ * left alone, matching how a plain REST PATCH body treats a missing field.
97
+ *
98
+ * @param data - The write payload to filter
99
+ * @returns A shallow copy of `data` with every `undefined`-valued key removed
100
+ */
101
+ const stripUndefinedValues = (data) => {
102
+ const result = {};
103
+ for (const [key, value] of Object.entries(data)) {
104
+ if (value !== undefined) {
105
+ ;
106
+ result[key] = value;
107
+ }
108
+ }
109
+ return result;
110
+ };
111
+ exports.stripUndefinedValues = stripUndefinedValues;
112
+ /**
113
+ * Validates that a value is a safe, bare SQL identifier
114
+ *
115
+ * This function throws when the value is anything other than a plain
116
+ * identifier (letters, digits, underscore, optionally schema/table-qualified
117
+ * with a single dot). It exists to stop identifiers coming from untrusted
118
+ * input (table names, column names) from being used to inject arbitrary SQL,
119
+ * since this library interpolates identifiers directly into the query string.
120
+ *
121
+ * @param value - The identifier to validate
122
+ * @param label - A human-readable label used in the error message
123
+ * @throws {Error} When the value is not a valid identifier
124
+ *
125
+ * @example
126
+ * assertValidIdentifier('users', 'table name') // ok
127
+ * assertValidIdentifier('users; DROP TABLE users', 'table name') // throws
128
+ */
129
+ const assertValidIdentifier = (value, label) => {
130
+ if (typeof value !== 'string' || !IDENTIFIER_PATTERN.test(value)) {
131
+ throw new Error(`Invalid ${label}: "${value}". Only letters, numbers, underscores and a single dot (schema.table or table.column) are allowed.`);
132
+ }
133
+ };
134
+ exports.assertValidIdentifier = assertValidIdentifier;
135
+ /**
136
+ * Validates that a raw SQL fragment does not contain statement terminators,
137
+ * comment markers or backticks
138
+ *
139
+ * Some parts of a query (SELECT fields, JOIN ON conditions) are allowed to
140
+ * be full SQL expressions (e.g. "COUNT(*) as total"), so they cannot be
141
+ * restricted to bare identifiers. This function instead blocks the
142
+ * characters that have no legitimate use in those positions and that are
143
+ * the building blocks of stacked-query and comment-based SQL injection.
144
+ *
145
+ * @param value - The SQL fragment to validate
146
+ * @param label - A human-readable label used in the error message
147
+ * @throws {Error} When the fragment contains disallowed characters
148
+ *
149
+ * @example
150
+ * assertSafeSqlFragment('COUNT(*) as total', 'select field') // ok
151
+ * assertSafeSqlFragment('id; DROP TABLE users; --', 'select field') // throws
152
+ */
153
+ const assertSafeSqlFragment = (value, label) => {
154
+ if (typeof value !== 'string' || DANGEROUS_SQL_PATTERN.test(value)) {
155
+ throw new Error(`Invalid ${label}: "${value}" contains disallowed characters (; -- /* */ \`).`);
156
+ }
157
+ };
158
+ exports.assertSafeSqlFragment = assertSafeSqlFragment;
159
+ /**
160
+ * Quotes a column identifier using the target database's quoting convention
161
+ *
162
+ * This wraps a validated identifier in double quotes for PostgreSQL or
163
+ * backticks for MySQL, so reserved words (e.g. "order", "group", "user",
164
+ * "authorization") can be used as column names without a per-column special
165
+ * case.
166
+ *
167
+ * @param identifier - The already-validated column identifier
168
+ * @param clientType - The type of database client
169
+ * @returns The quoted identifier
170
+ *
171
+ * @example
172
+ * quoteIdentifier('order', 'pg') // '"order"'
173
+ * quoteIdentifier('order', 'mysql') // '`order`'
174
+ */
175
+ const quoteIdentifier = (identifier, clientType) => (clientType === 'pg' ? `"${identifier}"` : `\`${identifier}\``);
176
+ exports.quoteIdentifier = quoteIdentifier;
177
+ /**
178
+ * Columns that `insert`/`insertMany`/`upsert` always add themselves
179
+ * (a generated `id` and a refreshed `updated_at`) and therefore must not
180
+ * also appear in the caller-supplied `data`.
181
+ */
182
+ const AUTO_MANAGED_COLUMNS = new Set(['id', 'updated_at']);
183
+ /**
184
+ * Rejects a caller-supplied column list that includes a column the function
185
+ * manages itself (`id`, `updated_at`)
186
+ *
187
+ * Without this check, a `data` object containing `id` or `updated_at` ended
188
+ * up duplicated in the generated column list (e.g.
189
+ * `INSERT INTO t ("id", "id", ...)`), which the database rejects with a
190
+ * confusing syntax/duplicate-column error instead of a clear one from this
191
+ * library.
192
+ *
193
+ * @param keys - The column names from the caller-supplied `data` object
194
+ * @param fnName - The name of the calling function, used in the error message
195
+ * @throws {Error} When `keys` includes `id` or `updated_at`
196
+ */
197
+ const assertNoAutoManagedColumns = (keys, fnName) => {
198
+ const found = keys.filter((key) => AUTO_MANAGED_COLUMNS.has(key));
199
+ if (found.length > 0) {
200
+ throw new Error(`${fnName}: data must not include [${found.join(', ')}] — ${fnName} manages these columns itself (generates "id", refreshes "updated_at").`);
201
+ }
202
+ };
203
+ exports.assertNoAutoManagedColumns = assertNoAutoManagedColumns;
4
204
  /**
5
205
  * Converts an array of strings to a comma-separated string with quotes
6
206
  *
@@ -67,9 +267,10 @@ const mysqlPlaceholderGenerator = () => `?`;
67
267
  * // result will be: "id, name, email"
68
268
  */
69
269
  const createSelectFields = (fields = [], clientType) => {
70
- return fields && fields.length > 0
71
- ? arrayToStringWithQuotes(fields, clientType)
72
- : '*';
270
+ if (!fields || fields.length === 0)
271
+ return '*';
272
+ fields.forEach((field) => (0, exports.assertSafeSqlFragment)(field, 'select field'));
273
+ return arrayToStringWithQuotes(fields, clientType);
73
274
  };
74
275
  exports.createSelectFields = createSelectFields;
75
276
  /**
@@ -141,96 +342,151 @@ const createWhereClause = (conditions = {}, startIndex = 1, clientType, unaccent
141
342
  const whereParts = [];
142
343
  const values = [];
143
344
  const processCondition = (key, condition) => {
144
- if (typeof condition === 'object' && condition !== null) {
145
- if ('operator' in condition && 'value' in condition) {
146
- const { operator, value } = condition;
147
- if (operator === 'NOT EXISTS' && typeof value === 'string') {
148
- whereParts.push(`NOT EXISTS (${value})`);
149
- }
150
- else if (operator.includes('NULL')) {
151
- whereParts.push(`${key} ${operator}`);
152
- }
153
- else if (Array.isArray(value)) {
154
- const placeholders = value
155
- .map(() => clientType === 'pg'
156
- ? pgPlaceholderGenerator(index++)
157
- : mysqlPlaceholderGenerator())
158
- .join(', ');
159
- if (operator === 'BETWEEN') {
160
- whereParts.push(`${key} ${operator} ${placeholders.replace(', ', ' AND ')}`);
161
- }
162
- else if (operator === 'IN') {
163
- whereParts.push(`${key} ${operator} (${placeholders})`);
164
- }
165
- else {
166
- whereParts.push(`${key} ${operator} (${placeholders})`);
167
- }
168
- values.push(...value);
345
+ if (typeof condition !== 'object' ||
346
+ condition === null ||
347
+ !('operator' in condition) ||
348
+ !('value' in condition)) {
349
+ // A plain value (e.g. `{ status: 'active' }`) used to be silently
350
+ // dropped here instead of throwing — every field using that shape
351
+ // vanished from the WHERE clause with no error, which is how
352
+ // `updateMany`/`deleteMany` calls that meant to scope a write ended up
353
+ // running against the entire table. Fail loud instead.
354
+ throw new Error(`Invalid where condition for "${key}": expected { operator, value }, got ${JSON.stringify(condition)}. A plain value is not a supported shape — use { ${key}: { operator: '=', value: ... } } instead.`);
355
+ }
356
+ const { value } = condition;
357
+ // Normalized so callers that pass a lowercase/mixed-case operator (e.g.
358
+ // 'ilike', supported pre-1.4.0 since the operator used to be interpolated
359
+ // as-is) keep working instead of silently failing the whitelist check.
360
+ const operator = String(condition.operator).toUpperCase();
361
+ (0, exports.assertValidIdentifier)(key, 'where field');
362
+ if (!WHERE_OPERATOR_WHITELIST.has(operator)) {
363
+ throw new Error(`Invalid where operator: "${operator}". Only ${[...WHERE_OPERATOR_WHITELIST].join(', ')} are allowed.`);
364
+ }
365
+ if (operator === 'NOT EXISTS') {
366
+ if (typeof value !== 'string') {
367
+ throw new Error(`Where condition on "${key}" uses operator "NOT EXISTS" with a non-string value. NOT EXISTS requires a raw subquery string.`);
368
+ }
369
+ (0, exports.assertSafeSqlFragment)(value, 'where NOT EXISTS subquery');
370
+ whereParts.push(`NOT EXISTS (${value})`);
371
+ }
372
+ else if (operator.includes('NULL')) {
373
+ whereParts.push(`${key} ${operator}`);
374
+ }
375
+ else if (Array.isArray(value)) {
376
+ if (operator === 'BETWEEN' && value.length !== 2) {
377
+ throw new Error(`Where condition on "${key}" uses operator "BETWEEN" with ${value.length} values — BETWEEN requires exactly 2 (start and end).`);
378
+ }
379
+ if (value.length === 0 && operator !== 'BETWEEN') {
380
+ // `key IN ()` / `key NOT IN ()` is a SQL syntax error on both pg and
381
+ // MySQL (the list must have at least one element) — fail with a
382
+ // clear message instead of handing the caller that opaque driver
383
+ // error once the query reaches the database.
384
+ throw new Error(`Where condition on "${key}" uses operator "${operator}" with an empty array — this has no valid SQL translation. Pass at least one value, or omit the condition entirely if there is nothing to filter by.`);
385
+ }
386
+ if (value.length > exports.MAX_IN_LIST_SIZE) {
387
+ throw new Error(`Where condition on "${key}" has ${value.length} values for operator "${operator}", exceeding the maximum of ${exports.MAX_IN_LIST_SIZE}. Chunk the query instead of growing a single condition this large.`);
388
+ }
389
+ const placeholders = value
390
+ .map(() => clientType === 'pg'
391
+ ? pgPlaceholderGenerator(index++)
392
+ : mysqlPlaceholderGenerator())
393
+ .join(', ');
394
+ if (operator === 'BETWEEN') {
395
+ whereParts.push(`${key} ${operator} ${placeholders.replace(', ', ' AND ')}`);
396
+ }
397
+ else {
398
+ whereParts.push(`${key} ${operator} (${placeholders})`);
399
+ }
400
+ // Not `values.push(...value)`: spreading a large array into a
401
+ // function call can itself throw `RangeError: Maximum call stack
402
+ // size exceeded` (V8's function-call argument limit), independent
403
+ // of the MAX_IN_LIST_SIZE guard above catching merely-large lists.
404
+ for (const item of value) {
405
+ values.push(item);
406
+ }
407
+ }
408
+ else {
409
+ if (unaccent && clientType === 'pg') {
410
+ if (operator.toUpperCase() === 'ILIKE') {
411
+ whereParts.push(`unaccent(${key}::text) ILIKE unaccent(${pgPlaceholderGenerator(index)})`);
169
412
  }
170
413
  else {
171
- if (unaccent && clientType === 'pg') {
172
- if (operator.toUpperCase() === 'ILIKE') {
173
- whereParts.push(`unaccent(${key}::text) ILIKE unaccent(${pgPlaceholderGenerator(index)})`);
174
- }
175
- else {
176
- whereParts.push(`unaccent(${key}::text) ${operator} unaccent(${pgPlaceholderGenerator(index)})`);
177
- }
178
- }
179
- else {
180
- whereParts.push(clientType === 'pg'
181
- ? `${key} ${operator} ${pgPlaceholderGenerator(index)}`
182
- : `${key} ${operator} ${mysqlPlaceholderGenerator()}`);
183
- }
184
- index++;
185
- values.push(value);
414
+ whereParts.push(`unaccent(${key}::text) ${operator} unaccent(${pgPlaceholderGenerator(index)})`);
186
415
  }
187
416
  }
417
+ else {
418
+ whereParts.push(clientType === 'pg'
419
+ ? `${key} ${operator} ${pgPlaceholderGenerator(index)}`
420
+ : `${key} ${operator} ${mysqlPlaceholderGenerator()}`);
421
+ }
422
+ index++;
423
+ values.push(value);
424
+ }
425
+ };
426
+ Object.entries(conditions).forEach(([key, value]) => {
427
+ if (key === 'JOINS' || key === 'OR' || key === 'AND')
428
+ return;
429
+ processCondition(key, value);
430
+ });
431
+ // A group element (one entry of an `OR`/`AND`/`JOINS` array) can carry more
432
+ // than one key, e.g. `{ status: ..., tenant_id: ... }` — those sibling keys
433
+ // are ANDed together, same as sibling keys at the top level of `where`.
434
+ // Only ever reading `Object.keys(subCondition)[0]` here used to silently
435
+ // drop every key past the first, which is how a scoping condition (e.g.
436
+ // `tenant_id`) placed alongside another key inside the same group element
437
+ // could vanish from the generated SQL with no error.
438
+ const processGroupElement = (subCondition) => {
439
+ if (typeof subCondition !== 'object' ||
440
+ Array.isArray(subCondition) ||
441
+ subCondition === null) {
442
+ return '';
443
+ }
444
+ const parts = Object.entries(subCondition).map(([key, condition]) => {
445
+ // Adiciona o tratamento de unaccent nas condições do grupo também
446
+ processCondition(key, condition);
447
+ return whereParts.pop();
448
+ });
449
+ // Parenthesized whenever there's more than one key so this element's
450
+ // AND binds as a unit regardless of the surrounding logical operator
451
+ // (matters when this element sits inside an `OR` group).
452
+ return parts.length > 1 ? `(${parts.join(' AND ')})` : parts.join(' AND ');
453
+ };
454
+ // An empty `AND`/`OR`/`JOINS` array has no unambiguous SQL meaning (and
455
+ // isn't valid SQL syntax either way) — it used to silently render as the
456
+ // bare fragment "()", producing a query like `WHERE ()` or `WHERE a = $1
457
+ // AND ()`. Fail loud instead of handing the caller that syntax error once
458
+ // it reaches the database.
459
+ const assertNonEmptyGroup = (compositeConditions, label) => {
460
+ if (compositeConditions.length === 0) {
461
+ throw new Error(`Where condition "${label}" is an empty array — remove the key instead of passing an empty group.`);
188
462
  }
189
463
  };
190
464
  if ('JOINS' in conditions) {
191
- const logicalOperator = conditions.JOINS ? 'AND' : 'OR';
192
465
  const compositeConditions = conditions.JOINS;
193
466
  if (Array.isArray(compositeConditions)) {
467
+ assertNonEmptyGroup(compositeConditions, 'JOINS');
194
468
  const subWhereParts = compositeConditions
195
- .map((subCondition) => {
196
- if (typeof subCondition === 'object' &&
197
- !Array.isArray(subCondition) &&
198
- subCondition !== null) {
199
- const key = Object.keys(subCondition)[0];
200
- const condition = subCondition[key];
201
- // Adiciona o tratamento de unaccent nas condições de JOINS
202
- processCondition(key, condition);
203
- return whereParts.pop();
204
- }
205
- return '';
206
- })
207
- .filter((part) => part);
208
- whereParts.push(`(${subWhereParts.join(` ${logicalOperator} `)})`);
209
- }
210
- }
211
- else {
212
- Object.entries(conditions).forEach(([key, value]) => processCondition(key, value));
213
- }
214
- if ('OR' in conditions || 'AND' in conditions) {
215
- const logicalOperator = conditions.OR ? 'OR' : 'AND';
216
- const compositeConditions = conditions.OR || conditions.AND;
217
- if (Array.isArray(compositeConditions)) {
218
- const subWhereParts = compositeConditions
219
- .map((subCondition) => {
220
- if (typeof subCondition === 'object' &&
221
- !Array.isArray(subCondition) &&
222
- subCondition !== null) {
223
- const key = Object.keys(subCondition)[0];
224
- const condition = subCondition[key];
225
- processCondition(key, condition); // Certifica que o unaccent é processado aqui também
226
- return whereParts.pop();
227
- }
228
- return '';
229
- })
469
+ .map(processGroupElement)
230
470
  .filter((part) => part);
231
- whereParts.push(`(${subWhereParts.join(` ${logicalOperator} `)})`);
471
+ whereParts.push(`(${subWhereParts.join(' AND ')})`);
232
472
  }
233
473
  }
474
+ const pushLogicalGroup = (compositeConditions, logicalOperator) => {
475
+ if (!Array.isArray(compositeConditions))
476
+ return;
477
+ assertNonEmptyGroup(compositeConditions, logicalOperator);
478
+ const subWhereParts = compositeConditions
479
+ .map(processGroupElement)
480
+ .filter((part) => part);
481
+ whereParts.push(`(${subWhereParts.join(` ${logicalOperator} `)})`);
482
+ };
483
+ // Each processed independently — a `where` with both `OR` and `AND` groups
484
+ // used to only render whichever one `conditions.OR ? 'OR' : 'AND'` picked,
485
+ // silently dropping the other group from the generated SQL.
486
+ if ('OR' in conditions)
487
+ pushLogicalGroup(conditions.OR, 'OR');
488
+ if ('AND' in conditions)
489
+ pushLogicalGroup(conditions.AND, 'AND');
234
490
  const whereClause = whereParts.length > 0 ? ` WHERE ${whereParts.join(' AND ')}` : '';
235
491
  return [whereClause, values, index];
236
492
  };
@@ -252,7 +508,15 @@ exports.createWhereClause = createWhereClause;
252
508
  const createOrderByClause = (orderBy) => {
253
509
  if (!orderBy || orderBy.length === 0)
254
510
  return '';
255
- const clause = orderBy.map((o) => `${o.field} ${o.direction}`).join(', ');
511
+ const clause = orderBy
512
+ .map((o) => {
513
+ (0, exports.assertSafeSqlFragment)(o.field, 'orderBy field');
514
+ if (o.direction !== 'ASC' && o.direction !== 'DESC') {
515
+ throw new Error(`Invalid orderBy direction: "${o.direction}". Only ASC or DESC are allowed.`);
516
+ }
517
+ return `${o.field} ${o.direction}`;
518
+ })
519
+ .join(', ');
256
520
  return ` ORDER BY ${clause}`;
257
521
  };
258
522
  exports.createOrderByClause = createOrderByClause;
@@ -273,6 +537,7 @@ exports.createOrderByClause = createOrderByClause;
273
537
  const createGroupByClause = (groupBy) => {
274
538
  if (!groupBy || groupBy.length === 0)
275
539
  return '';
540
+ groupBy.forEach((field) => (0, exports.assertSafeSqlFragment)(field, 'groupBy field'));
276
541
  return ` GROUP BY ${groupBy.join(', ')}`;
277
542
  };
278
543
  exports.createGroupByClause = createGroupByClause;
@@ -293,6 +558,9 @@ exports.createGroupByClause = createGroupByClause;
293
558
  const createLimitClause = (limit) => {
294
559
  if (!limit)
295
560
  return '';
561
+ if (!Number.isInteger(limit) || limit <= 0) {
562
+ throw new Error(`Invalid limit: "${limit}". Must be a positive integer.`);
563
+ }
296
564
  return ` LIMIT ${limit}`;
297
565
  };
298
566
  exports.createLimitClause = createLimitClause;
@@ -313,6 +581,9 @@ exports.createLimitClause = createLimitClause;
313
581
  const createOffsetClause = (offset) => {
314
582
  if (!offset)
315
583
  return '';
584
+ if (!Number.isInteger(offset) || offset < 0) {
585
+ throw new Error(`Invalid offset: "${offset}". Must be a non-negative integer.`);
586
+ }
316
587
  return ` OFFSET ${offset}`;
317
588
  };
318
589
  exports.createOffsetClause = createOffsetClause;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/core/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/core/utils.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,24 @@
1
1
  import { DBClients } from '../core/types';
2
- export interface ITransactionClient {
2
+ /**
3
+ * What every query-executing function in `repository.ts` (`findFirst`,
4
+ * `insert`, `update`, ...) actually needs from a client: `clientType` (to
5
+ * pick the right placeholder/quoting dialect) and `query`. Kept separate
6
+ * from `IDatabaseClient` so a transaction client — which has no
7
+ * `beginTransaction` of its own — can be passed as `dbClient` to these
8
+ * functions too (`withTransaction(dbClient, (tx) => insert({ dbClient: tx, ... }))`,
9
+ * the pattern documented in `docs/methods/transactions.md` and the README).
10
+ */
11
+ export interface IQueryClient {
12
+ clientType: DBClients;
3
13
  query: <T>(sql: string, params?: any[]) => Promise<T>;
14
+ }
15
+ export interface ITransactionClient extends IQueryClient {
4
16
  commit: () => Promise<void>;
5
17
  rollback: () => Promise<void>;
6
18
  }
7
19
  /**
8
20
  * Database client interface
9
21
  */
10
- export type IDatabaseClient = {
11
- clientType: DBClients;
12
- query: <T>(sql: string, params?: any[]) => Promise<T>;
22
+ export type IDatabaseClient = IQueryClient & {
13
23
  beginTransaction: () => Promise<ITransactionClient>;
14
24
  };