@starbemtech/star-db-query-builder 1.3.1 → 1.4.0
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.
- package/.claude/skills/star-db-query-builder/SKILL.md +104 -0
- package/CHANGELOG.md +82 -45
- package/LICENSE +21 -0
- package/README.md +194 -94
- package/bin/install-skill.js +53 -0
- package/dist/src/core/repository.d.ts +92 -9
- package/dist/src/core/repository.js +275 -27
- package/dist/src/core/repository.js.map +1 -1
- package/dist/src/core/types.d.ts +16 -1
- package/dist/src/core/utils.d.ts +102 -0
- package/dist/src/core/utils.js +287 -70
- package/dist/src/core/utils.js.map +1 -1
- package/dist/src/db/initDb.d.ts +60 -50
- package/dist/src/db/initDb.js +96 -64
- package/dist/src/db/initDb.js.map +1 -1
- package/dist/src/db/mysqlClient.d.ts +3 -8
- package/dist/src/db/mysqlClient.js +9 -11
- package/dist/src/db/mysqlClient.js.map +1 -1
- package/dist/src/db/pgClient.js +0 -2
- package/dist/src/db/pgClient.js.map +1 -1
- package/dist/src/monitor/monitor.js +7 -0
- package/dist/src/monitor/monitor.js.map +1 -1
- package/package.json +27 -19
- package/.github/workflows/publish.yml +0 -118
- package/.prettierignore +0 -3
- package/.prettierrc +0 -5
- package/ARCHITECTURE.md +0 -313
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -131
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/mysqlClient.ts.html +0 -685
- package/coverage/lcov-report/pgClient.ts.html +0 -823
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -533
- package/coverage/mysqlClient.ts.html +0 -685
- package/coverage/pgClient.ts.html +0 -823
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/dist/src/setupTests.d.ts +0 -26
- package/dist/src/setupTests.js +0 -43
- package/dist/src/setupTests.js.map +0 -1
- package/docs/INDEX.md +0 -145
- package/docs/methods/findFirst.md +0 -394
- package/docs/methods/findMany.md +0 -587
- package/docs/methods/insert.md +0 -536
- package/docs/methods/insertMany.md +0 -627
- package/docs/methods/joins.md +0 -781
- package/docs/methods/rawQuery.md +0 -284
- package/docs/methods/transactions.md +0 -737
- package/eslint.config.mjs +0 -77
- package/index.ts +0 -16
- package/jest.config.ts +0 -194
- package/scripts/release.sh +0 -123
- package/src/core/repository.ts +0 -865
- package/src/core/types.ts +0 -97
- package/src/core/utils.ts +0 -357
- package/src/db/IDatabaseClient.ts +0 -16
- package/src/db/__tests__/mysqlClient.test.ts +0 -262
- package/src/db/__tests__/pgClient.test.ts +0 -260
- package/src/db/initDb.ts +0 -181
- package/src/db/mysqlClient.ts +0 -200
- package/src/db/pgClient.ts +0 -246
- package/src/monitor/monitor.ts +0 -16
- package/src/setupTests.ts +0 -45
- package/tsconfig.test.json +0 -21
package/dist/src/core/utils.d.ts
CHANGED
|
@@ -1,4 +1,106 @@
|
|
|
1
1
|
import { Conditions, OrderBy, DBClients } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Maximum number of values accepted in a single `IN`/`NOT IN`/`BETWEEN`
|
|
4
|
+
* condition array.
|
|
5
|
+
*
|
|
6
|
+
* This guards two real failure modes, both triggered by callers building a
|
|
7
|
+
* WHERE condition from an unbounded list (e.g. forwarding a large search
|
|
8
|
+
* result as an `IN` filter): pg's own wire protocol rejects a query with more
|
|
9
|
+
* than 65535 total bound parameters, and — well before that limit — building
|
|
10
|
+
* the values array with `values.push(...value)` throws
|
|
11
|
+
* `RangeError: Maximum call stack size exceeded` once `value.length` is large
|
|
12
|
+
* enough to overflow the JS engine's function-call argument limit. Chunk the
|
|
13
|
+
* list (e.g. multiple `IN` queries unioned, or a temp table / `= ANY($1::type[])`
|
|
14
|
+
* for pg) instead of growing a single condition past this size.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAX_IN_LIST_SIZE = 10000;
|
|
17
|
+
/**
|
|
18
|
+
* pg's wire protocol rejects a query with more than 65535 total bound
|
|
19
|
+
* parameters ("bind message has N parameter formats but M parameters" /
|
|
20
|
+
* "too many parameters"). Any function that can build a bind-parameter list
|
|
21
|
+
* proportional to caller input (a large `ids` array, a large batch insert)
|
|
22
|
+
* should check its total against this before building the query, rather
|
|
23
|
+
* than letting the database reject it with a cryptic protocol error.
|
|
24
|
+
*/
|
|
25
|
+
export declare const MAX_BIND_PARAMS = 65535;
|
|
26
|
+
/**
|
|
27
|
+
* Rejects a query that would exceed the maximum number of bind parameters
|
|
28
|
+
* a database driver accepts in a single statement
|
|
29
|
+
*
|
|
30
|
+
* @param count - The total number of bind parameters the query would use
|
|
31
|
+
* @param label - A human-readable label used in the error message
|
|
32
|
+
* @throws {Error} When `count` exceeds `MAX_BIND_PARAMS`
|
|
33
|
+
*/
|
|
34
|
+
export declare const assertWithinBindParamLimit: (count: number, label: string) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Validates that a value is a safe, bare SQL identifier
|
|
37
|
+
*
|
|
38
|
+
* This function throws when the value is anything other than a plain
|
|
39
|
+
* identifier (letters, digits, underscore, optionally schema/table-qualified
|
|
40
|
+
* with a single dot). It exists to stop identifiers coming from untrusted
|
|
41
|
+
* input (table names, column names) from being used to inject arbitrary SQL,
|
|
42
|
+
* since this library interpolates identifiers directly into the query string.
|
|
43
|
+
*
|
|
44
|
+
* @param value - The identifier to validate
|
|
45
|
+
* @param label - A human-readable label used in the error message
|
|
46
|
+
* @throws {Error} When the value is not a valid identifier
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* assertValidIdentifier('users', 'table name') // ok
|
|
50
|
+
* assertValidIdentifier('users; DROP TABLE users', 'table name') // throws
|
|
51
|
+
*/
|
|
52
|
+
export declare const assertValidIdentifier: (value: string, label: string) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Validates that a raw SQL fragment does not contain statement terminators,
|
|
55
|
+
* comment markers or backticks
|
|
56
|
+
*
|
|
57
|
+
* Some parts of a query (SELECT fields, JOIN ON conditions) are allowed to
|
|
58
|
+
* be full SQL expressions (e.g. "COUNT(*) as total"), so they cannot be
|
|
59
|
+
* restricted to bare identifiers. This function instead blocks the
|
|
60
|
+
* characters that have no legitimate use in those positions and that are
|
|
61
|
+
* the building blocks of stacked-query and comment-based SQL injection.
|
|
62
|
+
*
|
|
63
|
+
* @param value - The SQL fragment to validate
|
|
64
|
+
* @param label - A human-readable label used in the error message
|
|
65
|
+
* @throws {Error} When the fragment contains disallowed characters
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* assertSafeSqlFragment('COUNT(*) as total', 'select field') // ok
|
|
69
|
+
* assertSafeSqlFragment('id; DROP TABLE users; --', 'select field') // throws
|
|
70
|
+
*/
|
|
71
|
+
export declare const assertSafeSqlFragment: (value: string, label: string) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Quotes a column identifier using the target database's quoting convention
|
|
74
|
+
*
|
|
75
|
+
* This wraps a validated identifier in double quotes for PostgreSQL or
|
|
76
|
+
* backticks for MySQL, so reserved words (e.g. "order", "group", "user",
|
|
77
|
+
* "authorization") can be used as column names without a per-column special
|
|
78
|
+
* case.
|
|
79
|
+
*
|
|
80
|
+
* @param identifier - The already-validated column identifier
|
|
81
|
+
* @param clientType - The type of database client
|
|
82
|
+
* @returns The quoted identifier
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* quoteIdentifier('order', 'pg') // '"order"'
|
|
86
|
+
* quoteIdentifier('order', 'mysql') // '`order`'
|
|
87
|
+
*/
|
|
88
|
+
export declare const quoteIdentifier: (identifier: string, clientType: DBClients) => string;
|
|
89
|
+
/**
|
|
90
|
+
* Rejects a caller-supplied column list that includes a column the function
|
|
91
|
+
* manages itself (`id`, `updated_at`)
|
|
92
|
+
*
|
|
93
|
+
* Without this check, a `data` object containing `id` or `updated_at` ended
|
|
94
|
+
* up duplicated in the generated column list (e.g.
|
|
95
|
+
* `INSERT INTO t ("id", "id", ...)`), which the database rejects with a
|
|
96
|
+
* confusing syntax/duplicate-column error instead of a clear one from this
|
|
97
|
+
* library.
|
|
98
|
+
*
|
|
99
|
+
* @param keys - The column names from the caller-supplied `data` object
|
|
100
|
+
* @param fnName - The name of the calling function, used in the error message
|
|
101
|
+
* @throws {Error} When `keys` includes `id` or `updated_at`
|
|
102
|
+
*/
|
|
103
|
+
export declare const assertNoAutoManagedColumns: (keys: string[], fnName: string) => void;
|
|
2
104
|
/**
|
|
3
105
|
* Creates a SELECT clause for a query
|
|
4
106
|
*
|
package/dist/src/core/utils.js
CHANGED
|
@@ -1,6 +1,173 @@
|
|
|
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.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,
|
|
7
|
+
* GROUP BY / ORDER BY fields, join tables and delete-by fields, since
|
|
8
|
+
* those are always plain identifiers and never need SQL expressions.
|
|
9
|
+
*/
|
|
10
|
+
const IDENTIFIER_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)?$/;
|
|
11
|
+
/**
|
|
12
|
+
* Matches characters that have no legitimate use inside a SELECT
|
|
13
|
+
* expression or a JOIN ON condition (statement terminators, comment
|
|
14
|
+
* markers, backticks) but that are the building blocks of classic
|
|
15
|
+
* SQL injection (stacked queries, comment-based truncation).
|
|
16
|
+
*/
|
|
17
|
+
const DANGEROUS_SQL_PATTERN = /(;|--|\/\*|\*\/|`)/;
|
|
18
|
+
/**
|
|
19
|
+
* Maximum number of values accepted in a single `IN`/`NOT IN`/`BETWEEN`
|
|
20
|
+
* condition array.
|
|
21
|
+
*
|
|
22
|
+
* This guards two real failure modes, both triggered by callers building a
|
|
23
|
+
* WHERE condition from an unbounded list (e.g. forwarding a large search
|
|
24
|
+
* result as an `IN` filter): pg's own wire protocol rejects a query with more
|
|
25
|
+
* than 65535 total bound parameters, and — well before that limit — building
|
|
26
|
+
* the values array with `values.push(...value)` throws
|
|
27
|
+
* `RangeError: Maximum call stack size exceeded` once `value.length` is large
|
|
28
|
+
* enough to overflow the JS engine's function-call argument limit. Chunk the
|
|
29
|
+
* list (e.g. multiple `IN` queries unioned, or a temp table / `= ANY($1::type[])`
|
|
30
|
+
* for pg) instead of growing a single condition past this size.
|
|
31
|
+
*/
|
|
32
|
+
exports.MAX_IN_LIST_SIZE = 10000;
|
|
33
|
+
/**
|
|
34
|
+
* pg's wire protocol rejects a query with more than 65535 total bound
|
|
35
|
+
* parameters ("bind message has N parameter formats but M parameters" /
|
|
36
|
+
* "too many parameters"). Any function that can build a bind-parameter list
|
|
37
|
+
* proportional to caller input (a large `ids` array, a large batch insert)
|
|
38
|
+
* should check its total against this before building the query, rather
|
|
39
|
+
* than letting the database reject it with a cryptic protocol error.
|
|
40
|
+
*/
|
|
41
|
+
exports.MAX_BIND_PARAMS = 65535;
|
|
42
|
+
/**
|
|
43
|
+
* Rejects a query that would exceed the maximum number of bind parameters
|
|
44
|
+
* a database driver accepts in a single statement
|
|
45
|
+
*
|
|
46
|
+
* @param count - The total number of bind parameters the query would use
|
|
47
|
+
* @param label - A human-readable label used in the error message
|
|
48
|
+
* @throws {Error} When `count` exceeds `MAX_BIND_PARAMS`
|
|
49
|
+
*/
|
|
50
|
+
const assertWithinBindParamLimit = (count, label) => {
|
|
51
|
+
if (count > exports.MAX_BIND_PARAMS) {
|
|
52
|
+
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.`);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
exports.assertWithinBindParamLimit = assertWithinBindParamLimit;
|
|
56
|
+
/**
|
|
57
|
+
* Every operator `createWhereClause` knows how to render. Kept in sync with
|
|
58
|
+
* `OperatorCondition['operator']` in `types.ts` — this is the runtime side of
|
|
59
|
+
* that compile-time union, since `key`/`operator` reach this function as
|
|
60
|
+
* plain strings regardless of what TypeScript enforced at the call site.
|
|
61
|
+
*/
|
|
62
|
+
const WHERE_OPERATOR_WHITELIST = new Set([
|
|
63
|
+
'ILIKE',
|
|
64
|
+
'LIKE',
|
|
65
|
+
'=',
|
|
66
|
+
'>',
|
|
67
|
+
'<',
|
|
68
|
+
'IN',
|
|
69
|
+
'BETWEEN',
|
|
70
|
+
'!=',
|
|
71
|
+
'<=',
|
|
72
|
+
'>=',
|
|
73
|
+
'NOT IN',
|
|
74
|
+
'NOT LIKE',
|
|
75
|
+
'IS NULL',
|
|
76
|
+
'IS NOT NULL',
|
|
77
|
+
'NOT EXISTS',
|
|
78
|
+
]);
|
|
79
|
+
/**
|
|
80
|
+
* Validates that a value is a safe, bare SQL identifier
|
|
81
|
+
*
|
|
82
|
+
* This function throws when the value is anything other than a plain
|
|
83
|
+
* identifier (letters, digits, underscore, optionally schema/table-qualified
|
|
84
|
+
* with a single dot). It exists to stop identifiers coming from untrusted
|
|
85
|
+
* input (table names, column names) from being used to inject arbitrary SQL,
|
|
86
|
+
* since this library interpolates identifiers directly into the query string.
|
|
87
|
+
*
|
|
88
|
+
* @param value - The identifier to validate
|
|
89
|
+
* @param label - A human-readable label used in the error message
|
|
90
|
+
* @throws {Error} When the value is not a valid identifier
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* assertValidIdentifier('users', 'table name') // ok
|
|
94
|
+
* assertValidIdentifier('users; DROP TABLE users', 'table name') // throws
|
|
95
|
+
*/
|
|
96
|
+
const assertValidIdentifier = (value, label) => {
|
|
97
|
+
if (typeof value !== 'string' || !IDENTIFIER_PATTERN.test(value)) {
|
|
98
|
+
throw new Error(`Invalid ${label}: "${value}". Only letters, numbers, underscores and a single dot (schema.table or table.column) are allowed.`);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
exports.assertValidIdentifier = assertValidIdentifier;
|
|
102
|
+
/**
|
|
103
|
+
* Validates that a raw SQL fragment does not contain statement terminators,
|
|
104
|
+
* comment markers or backticks
|
|
105
|
+
*
|
|
106
|
+
* Some parts of a query (SELECT fields, JOIN ON conditions) are allowed to
|
|
107
|
+
* be full SQL expressions (e.g. "COUNT(*) as total"), so they cannot be
|
|
108
|
+
* restricted to bare identifiers. This function instead blocks the
|
|
109
|
+
* characters that have no legitimate use in those positions and that are
|
|
110
|
+
* the building blocks of stacked-query and comment-based SQL injection.
|
|
111
|
+
*
|
|
112
|
+
* @param value - The SQL fragment to validate
|
|
113
|
+
* @param label - A human-readable label used in the error message
|
|
114
|
+
* @throws {Error} When the fragment contains disallowed characters
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* assertSafeSqlFragment('COUNT(*) as total', 'select field') // ok
|
|
118
|
+
* assertSafeSqlFragment('id; DROP TABLE users; --', 'select field') // throws
|
|
119
|
+
*/
|
|
120
|
+
const assertSafeSqlFragment = (value, label) => {
|
|
121
|
+
if (typeof value !== 'string' || DANGEROUS_SQL_PATTERN.test(value)) {
|
|
122
|
+
throw new Error(`Invalid ${label}: "${value}" contains disallowed characters (; -- /* */ \`).`);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
exports.assertSafeSqlFragment = assertSafeSqlFragment;
|
|
126
|
+
/**
|
|
127
|
+
* Quotes a column identifier using the target database's quoting convention
|
|
128
|
+
*
|
|
129
|
+
* This wraps a validated identifier in double quotes for PostgreSQL or
|
|
130
|
+
* backticks for MySQL, so reserved words (e.g. "order", "group", "user",
|
|
131
|
+
* "authorization") can be used as column names without a per-column special
|
|
132
|
+
* case.
|
|
133
|
+
*
|
|
134
|
+
* @param identifier - The already-validated column identifier
|
|
135
|
+
* @param clientType - The type of database client
|
|
136
|
+
* @returns The quoted identifier
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* quoteIdentifier('order', 'pg') // '"order"'
|
|
140
|
+
* quoteIdentifier('order', 'mysql') // '`order`'
|
|
141
|
+
*/
|
|
142
|
+
const quoteIdentifier = (identifier, clientType) => (clientType === 'pg' ? `"${identifier}"` : `\`${identifier}\``);
|
|
143
|
+
exports.quoteIdentifier = quoteIdentifier;
|
|
144
|
+
/**
|
|
145
|
+
* Columns that `insert`/`insertMany`/`upsert` always add themselves
|
|
146
|
+
* (a generated `id` and a refreshed `updated_at`) and therefore must not
|
|
147
|
+
* also appear in the caller-supplied `data`.
|
|
148
|
+
*/
|
|
149
|
+
const AUTO_MANAGED_COLUMNS = new Set(['id', 'updated_at']);
|
|
150
|
+
/**
|
|
151
|
+
* Rejects a caller-supplied column list that includes a column the function
|
|
152
|
+
* manages itself (`id`, `updated_at`)
|
|
153
|
+
*
|
|
154
|
+
* Without this check, a `data` object containing `id` or `updated_at` ended
|
|
155
|
+
* up duplicated in the generated column list (e.g.
|
|
156
|
+
* `INSERT INTO t ("id", "id", ...)`), which the database rejects with a
|
|
157
|
+
* confusing syntax/duplicate-column error instead of a clear one from this
|
|
158
|
+
* library.
|
|
159
|
+
*
|
|
160
|
+
* @param keys - The column names from the caller-supplied `data` object
|
|
161
|
+
* @param fnName - The name of the calling function, used in the error message
|
|
162
|
+
* @throws {Error} When `keys` includes `id` or `updated_at`
|
|
163
|
+
*/
|
|
164
|
+
const assertNoAutoManagedColumns = (keys, fnName) => {
|
|
165
|
+
const found = keys.filter((key) => AUTO_MANAGED_COLUMNS.has(key));
|
|
166
|
+
if (found.length > 0) {
|
|
167
|
+
throw new Error(`${fnName}: data must not include [${found.join(', ')}] — ${fnName} manages these columns itself (generates "id", refreshes "updated_at").`);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
exports.assertNoAutoManagedColumns = assertNoAutoManagedColumns;
|
|
4
171
|
/**
|
|
5
172
|
* Converts an array of strings to a comma-separated string with quotes
|
|
6
173
|
*
|
|
@@ -67,9 +234,10 @@ const mysqlPlaceholderGenerator = () => `?`;
|
|
|
67
234
|
* // result will be: "id, name, email"
|
|
68
235
|
*/
|
|
69
236
|
const createSelectFields = (fields = [], clientType) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
237
|
+
if (!fields || fields.length === 0)
|
|
238
|
+
return '*';
|
|
239
|
+
fields.forEach((field) => (0, exports.assertSafeSqlFragment)(field, 'select field'));
|
|
240
|
+
return arrayToStringWithQuotes(fields, clientType);
|
|
73
241
|
};
|
|
74
242
|
exports.createSelectFields = createSelectFields;
|
|
75
243
|
/**
|
|
@@ -141,54 +309,86 @@ const createWhereClause = (conditions = {}, startIndex = 1, clientType, unaccent
|
|
|
141
309
|
const whereParts = [];
|
|
142
310
|
const values = [];
|
|
143
311
|
const processCondition = (key, condition) => {
|
|
144
|
-
if (typeof condition
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
312
|
+
if (typeof condition !== 'object' ||
|
|
313
|
+
condition === null ||
|
|
314
|
+
!('operator' in condition) ||
|
|
315
|
+
!('value' in condition)) {
|
|
316
|
+
// A plain value (e.g. `{ status: 'active' }`) used to be silently
|
|
317
|
+
// dropped here instead of throwing — every field using that shape
|
|
318
|
+
// vanished from the WHERE clause with no error, which is how
|
|
319
|
+
// `updateMany`/`deleteMany` calls that meant to scope a write ended up
|
|
320
|
+
// running against the entire table. Fail loud instead.
|
|
321
|
+
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.`);
|
|
322
|
+
}
|
|
323
|
+
const { value } = condition;
|
|
324
|
+
// Normalized so callers that pass a lowercase/mixed-case operator (e.g.
|
|
325
|
+
// 'ilike', supported pre-1.4.0 since the operator used to be interpolated
|
|
326
|
+
// as-is) keep working instead of silently failing the whitelist check.
|
|
327
|
+
const operator = String(condition.operator).toUpperCase();
|
|
328
|
+
(0, exports.assertValidIdentifier)(key, 'where field');
|
|
329
|
+
if (!WHERE_OPERATOR_WHITELIST.has(operator)) {
|
|
330
|
+
throw new Error(`Invalid where operator: "${operator}". Only ${[...WHERE_OPERATOR_WHITELIST].join(', ')} are allowed.`);
|
|
331
|
+
}
|
|
332
|
+
if (operator === 'NOT EXISTS') {
|
|
333
|
+
if (typeof value !== 'string') {
|
|
334
|
+
throw new Error(`Where condition on "${key}" uses operator "NOT EXISTS" with a non-string value. NOT EXISTS requires a raw subquery string.`);
|
|
335
|
+
}
|
|
336
|
+
(0, exports.assertSafeSqlFragment)(value, 'where NOT EXISTS subquery');
|
|
337
|
+
whereParts.push(`NOT EXISTS (${value})`);
|
|
338
|
+
}
|
|
339
|
+
else if (operator.includes('NULL')) {
|
|
340
|
+
whereParts.push(`${key} ${operator}`);
|
|
341
|
+
}
|
|
342
|
+
else if (Array.isArray(value)) {
|
|
343
|
+
if (operator === 'BETWEEN' && value.length !== 2) {
|
|
344
|
+
throw new Error(`Where condition on "${key}" uses operator "BETWEEN" with ${value.length} values — BETWEEN requires exactly 2 (start and end).`);
|
|
345
|
+
}
|
|
346
|
+
if (value.length > exports.MAX_IN_LIST_SIZE) {
|
|
347
|
+
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.`);
|
|
348
|
+
}
|
|
349
|
+
const placeholders = value
|
|
350
|
+
.map(() => clientType === 'pg'
|
|
351
|
+
? pgPlaceholderGenerator(index++)
|
|
352
|
+
: mysqlPlaceholderGenerator())
|
|
353
|
+
.join(', ');
|
|
354
|
+
if (operator === 'BETWEEN') {
|
|
355
|
+
whereParts.push(`${key} ${operator} ${placeholders.replace(', ', ' AND ')}`);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
whereParts.push(`${key} ${operator} (${placeholders})`);
|
|
359
|
+
}
|
|
360
|
+
// Not `values.push(...value)`: spreading a large array into a
|
|
361
|
+
// function call can itself throw `RangeError: Maximum call stack
|
|
362
|
+
// size exceeded` (V8's function-call argument limit), independent
|
|
363
|
+
// of the MAX_IN_LIST_SIZE guard above catching merely-large lists.
|
|
364
|
+
for (const item of value) {
|
|
365
|
+
values.push(item);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
if (unaccent && clientType === 'pg') {
|
|
370
|
+
if (operator.toUpperCase() === 'ILIKE') {
|
|
371
|
+
whereParts.push(`unaccent(${key}::text) ILIKE unaccent(${pgPlaceholderGenerator(index)})`);
|
|
169
372
|
}
|
|
170
373
|
else {
|
|
171
|
-
|
|
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);
|
|
374
|
+
whereParts.push(`unaccent(${key}::text) ${operator} unaccent(${pgPlaceholderGenerator(index)})`);
|
|
186
375
|
}
|
|
187
376
|
}
|
|
377
|
+
else {
|
|
378
|
+
whereParts.push(clientType === 'pg'
|
|
379
|
+
? `${key} ${operator} ${pgPlaceholderGenerator(index)}`
|
|
380
|
+
: `${key} ${operator} ${mysqlPlaceholderGenerator()}`);
|
|
381
|
+
}
|
|
382
|
+
index++;
|
|
383
|
+
values.push(value);
|
|
188
384
|
}
|
|
189
385
|
};
|
|
386
|
+
Object.entries(conditions).forEach(([key, value]) => {
|
|
387
|
+
if (key === 'JOINS' || key === 'OR' || key === 'AND')
|
|
388
|
+
return;
|
|
389
|
+
processCondition(key, value);
|
|
390
|
+
});
|
|
190
391
|
if ('JOINS' in conditions) {
|
|
191
|
-
const logicalOperator = conditions.JOINS ? 'AND' : 'OR';
|
|
192
392
|
const compositeConditions = conditions.JOINS;
|
|
193
393
|
if (Array.isArray(compositeConditions)) {
|
|
194
394
|
const subWhereParts = compositeConditions
|
|
@@ -205,32 +405,34 @@ const createWhereClause = (conditions = {}, startIndex = 1, clientType, unaccent
|
|
|
205
405
|
return '';
|
|
206
406
|
})
|
|
207
407
|
.filter((part) => part);
|
|
208
|
-
whereParts.push(`(${subWhereParts.join(
|
|
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
|
-
})
|
|
230
|
-
.filter((part) => part);
|
|
231
|
-
whereParts.push(`(${subWhereParts.join(` ${logicalOperator} `)})`);
|
|
408
|
+
whereParts.push(`(${subWhereParts.join(' AND ')})`);
|
|
232
409
|
}
|
|
233
410
|
}
|
|
411
|
+
const pushLogicalGroup = (compositeConditions, logicalOperator) => {
|
|
412
|
+
if (!Array.isArray(compositeConditions))
|
|
413
|
+
return;
|
|
414
|
+
const subWhereParts = compositeConditions
|
|
415
|
+
.map((subCondition) => {
|
|
416
|
+
if (typeof subCondition === 'object' &&
|
|
417
|
+
!Array.isArray(subCondition) &&
|
|
418
|
+
subCondition !== null) {
|
|
419
|
+
const key = Object.keys(subCondition)[0];
|
|
420
|
+
const condition = subCondition[key];
|
|
421
|
+
processCondition(key, condition); // Certifica que o unaccent é processado aqui também
|
|
422
|
+
return whereParts.pop();
|
|
423
|
+
}
|
|
424
|
+
return '';
|
|
425
|
+
})
|
|
426
|
+
.filter((part) => part);
|
|
427
|
+
whereParts.push(`(${subWhereParts.join(` ${logicalOperator} `)})`);
|
|
428
|
+
};
|
|
429
|
+
// Each processed independently — a `where` with both `OR` and `AND` groups
|
|
430
|
+
// used to only render whichever one `conditions.OR ? 'OR' : 'AND'` picked,
|
|
431
|
+
// silently dropping the other group from the generated SQL.
|
|
432
|
+
if ('OR' in conditions)
|
|
433
|
+
pushLogicalGroup(conditions.OR, 'OR');
|
|
434
|
+
if ('AND' in conditions)
|
|
435
|
+
pushLogicalGroup(conditions.AND, 'AND');
|
|
234
436
|
const whereClause = whereParts.length > 0 ? ` WHERE ${whereParts.join(' AND ')}` : '';
|
|
235
437
|
return [whereClause, values, index];
|
|
236
438
|
};
|
|
@@ -252,7 +454,15 @@ exports.createWhereClause = createWhereClause;
|
|
|
252
454
|
const createOrderByClause = (orderBy) => {
|
|
253
455
|
if (!orderBy || orderBy.length === 0)
|
|
254
456
|
return '';
|
|
255
|
-
const clause = orderBy
|
|
457
|
+
const clause = orderBy
|
|
458
|
+
.map((o) => {
|
|
459
|
+
(0, exports.assertSafeSqlFragment)(o.field, 'orderBy field');
|
|
460
|
+
if (o.direction !== 'ASC' && o.direction !== 'DESC') {
|
|
461
|
+
throw new Error(`Invalid orderBy direction: "${o.direction}". Only ASC or DESC are allowed.`);
|
|
462
|
+
}
|
|
463
|
+
return `${o.field} ${o.direction}`;
|
|
464
|
+
})
|
|
465
|
+
.join(', ');
|
|
256
466
|
return ` ORDER BY ${clause}`;
|
|
257
467
|
};
|
|
258
468
|
exports.createOrderByClause = createOrderByClause;
|
|
@@ -273,6 +483,7 @@ exports.createOrderByClause = createOrderByClause;
|
|
|
273
483
|
const createGroupByClause = (groupBy) => {
|
|
274
484
|
if (!groupBy || groupBy.length === 0)
|
|
275
485
|
return '';
|
|
486
|
+
groupBy.forEach((field) => (0, exports.assertSafeSqlFragment)(field, 'groupBy field'));
|
|
276
487
|
return ` GROUP BY ${groupBy.join(', ')}`;
|
|
277
488
|
};
|
|
278
489
|
exports.createGroupByClause = createGroupByClause;
|
|
@@ -293,6 +504,9 @@ exports.createGroupByClause = createGroupByClause;
|
|
|
293
504
|
const createLimitClause = (limit) => {
|
|
294
505
|
if (!limit)
|
|
295
506
|
return '';
|
|
507
|
+
if (!Number.isInteger(limit) || limit <= 0) {
|
|
508
|
+
throw new Error(`Invalid limit: "${limit}". Must be a positive integer.`);
|
|
509
|
+
}
|
|
296
510
|
return ` LIMIT ${limit}`;
|
|
297
511
|
};
|
|
298
512
|
exports.createLimitClause = createLimitClause;
|
|
@@ -313,6 +527,9 @@ exports.createLimitClause = createLimitClause;
|
|
|
313
527
|
const createOffsetClause = (offset) => {
|
|
314
528
|
if (!offset)
|
|
315
529
|
return '';
|
|
530
|
+
if (!Number.isInteger(offset) || offset < 0) {
|
|
531
|
+
throw new Error(`Invalid offset: "${offset}". Must be a non-negative integer.`);
|
|
532
|
+
}
|
|
316
533
|
return ` OFFSET ${offset}`;
|
|
317
534
|
};
|
|
318
535
|
exports.createOffsetClause = createOffsetClause;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/core/utils.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,uBAAuB,GAAG,CAC9B,KAAe,EACf,UAAqB,EACb,EAAE;IACV,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACzC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAC5C,CAAA;IACD,OAAO,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACnC,CAAC,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,sBAAsB,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAA;AAE7D;;;;;;;;;;;GAWG;AACH,MAAM,yBAAyB,GAAG,GAAG,EAAE,CAAC,GAAG,CAAA;AAE3C;;;;;;;;;;;;;;;GAeG;AACI,MAAM,kBAAkB,GAAG,CAChC,SAAmB,EAAE,EACrB,UAAqB,EACb,EAAE;IACV,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/core/utils.ts"],"names":[],"mappings":"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"}
|