turbine-orm 0.81.0 → 0.90.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/README.md +26 -25
- package/dist/checkout.d.ts +27 -2
- package/dist/checkout.js +75 -4
- package/dist/cjs/checkout.d.ts +27 -2
- package/dist/cjs/checkout.js +76 -3
- package/dist/cjs/cli/code-first-tags.d.ts +62 -0
- package/dist/cjs/cli/code-first-tags.js +124 -0
- package/dist/cjs/cli/compile-query.js +9 -0
- package/dist/cjs/cli/config.d.ts +35 -6
- package/dist/cjs/cli/config.js +17 -1
- package/dist/cjs/cli/destructive.d.ts +7 -4
- package/dist/cjs/cli/destructive.js +224 -20
- package/dist/cjs/cli/error-catalog.js +36 -0
- package/dist/cjs/cli/error-text.d.ts +15 -0
- package/dist/cjs/cli/error-text.js +40 -0
- package/dist/cjs/cli/index.d.ts +62 -4
- package/dist/cjs/cli/index.js +568 -108
- package/dist/cjs/cli/local-server-guard.d.ts +53 -0
- package/dist/cjs/cli/local-server-guard.js +119 -0
- package/dist/cjs/cli/local-server-output.d.ts +41 -0
- package/dist/cjs/cli/local-server-output.js +103 -0
- package/dist/cjs/cli/mcp.d.ts +8 -0
- package/dist/cjs/cli/mcp.js +121 -32
- package/dist/cjs/cli/migrate.d.ts +113 -5
- package/dist/cjs/cli/migrate.js +270 -21
- package/dist/cjs/cli/observe.d.ts +6 -1
- package/dist/cjs/cli/observe.js +85 -55
- package/dist/cjs/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cjs/cli/pii-predicate-guard.js +98 -37
- package/dist/cjs/cli/prisma-resolve.js +17 -13
- package/dist/cjs/cli/prisma-schema.js +12 -4
- package/dist/cjs/cli/studio-ui.generated.js +1 -1
- package/dist/cjs/cli/studio.d.ts +14 -2
- package/dist/cjs/cli/studio.js +244 -69
- package/dist/cjs/cli/ui.d.ts +1 -1
- package/dist/cjs/client.d.ts +558 -85
- package/dist/cjs/client.js +1270 -395
- package/dist/cjs/connection-guard.d.ts +13 -0
- package/dist/cjs/connection-guard.js +28 -0
- package/dist/cjs/connection-url.d.ts +51 -16
- package/dist/cjs/connection-url.js +67 -34
- package/dist/cjs/diagnostics.d.ts +81 -0
- package/dist/cjs/diagnostics.js +147 -0
- package/dist/cjs/dialect.d.ts +449 -20
- package/dist/cjs/dialect.js +117 -76
- package/dist/cjs/engine-config.d.ts +7 -6
- package/dist/cjs/errors.d.ts +126 -6
- package/dist/cjs/errors.js +256 -13
- package/dist/cjs/generate.d.ts +57 -7
- package/dist/cjs/generate.js +635 -279
- package/dist/cjs/global-filters-config.d.ts +59 -0
- package/dist/cjs/global-filters-config.js +367 -0
- package/dist/cjs/index.d.ts +9 -4
- package/dist/cjs/index.js +10 -2
- package/dist/cjs/introspect.d.ts +31 -6
- package/dist/cjs/introspect.js +108 -50
- package/dist/cjs/log-codes.d.ts +12 -0
- package/dist/cjs/log-codes.js +77 -0
- package/dist/cjs/logger.d.ts +87 -0
- package/dist/cjs/logger.js +98 -0
- package/dist/cjs/mssql.d.ts +8 -5
- package/dist/cjs/mssql.js +352 -65
- package/dist/cjs/mysql.d.ts +3 -5
- package/dist/cjs/mysql.js +420 -70
- package/dist/cjs/nested-write.d.ts +3 -0
- package/dist/cjs/nested-write.js +179 -114
- package/dist/cjs/pipeline-submittable.d.ts +12 -0
- package/dist/cjs/pipeline-submittable.js +118 -44
- package/dist/cjs/pipeline.js +21 -26
- package/dist/cjs/powdb-introspect.d.ts +5 -2
- package/dist/cjs/powdb-introspect.js +20 -15
- package/dist/cjs/powdb-shared.d.ts +36 -5
- package/dist/cjs/powdb-shared.js +67 -8
- package/dist/cjs/powdb.d.ts +4 -0
- package/dist/cjs/powdb.js +183 -51
- package/dist/cjs/powql.d.ts +394 -51
- package/dist/cjs/powql.js +1829 -284
- package/dist/cjs/prisma-compat.d.ts +23 -15
- package/dist/cjs/prisma-compat.js +507 -372
- package/dist/cjs/query/aggregates.d.ts +17 -1
- package/dist/cjs/query/aggregates.js +261 -29
- package/dist/cjs/query/batched-loader.d.ts +25 -6
- package/dist/cjs/query/batched-loader.js +103 -20
- package/dist/cjs/query/builder.d.ts +325 -184
- package/dist/cjs/query/builder.js +1452 -490
- package/dist/cjs/query/column-ref.d.ts +61 -0
- package/dist/cjs/query/column-ref.js +73 -0
- package/dist/cjs/query/compound-unique.d.ts +21 -0
- package/dist/cjs/query/compound-unique.js +98 -18
- package/dist/cjs/query/deferred.d.ts +53 -16
- package/dist/cjs/query/expr.d.ts +217 -0
- package/dist/cjs/query/expr.js +859 -0
- package/dist/cjs/query/filters.d.ts +155 -53
- package/dist/cjs/query/filters.js +613 -76
- package/dist/cjs/query/index.d.ts +2 -0
- package/dist/cjs/query/index.js +7 -1
- package/dist/cjs/query/json-value.d.ts +43 -0
- package/dist/cjs/query/json-value.js +59 -0
- package/dist/cjs/query/normalize-args.d.ts +87 -0
- package/dist/cjs/query/normalize-args.js +527 -0
- package/dist/cjs/query/option-surface.d.ts +16 -4
- package/dist/cjs/query/option-surface.js +57 -14
- package/dist/cjs/query/relation-names.d.ts +14 -0
- package/dist/cjs/query/relation-names.js +77 -18
- package/dist/cjs/query/relations.d.ts +30 -3
- package/dist/cjs/query/relations.js +219 -63
- package/dist/cjs/query/row-lock.d.ts +49 -0
- package/dist/cjs/query/row-lock.js +138 -0
- package/dist/cjs/query/sql-comment.d.ts +161 -0
- package/dist/cjs/query/sql-comment.js +381 -0
- package/dist/cjs/query/stream-idle.d.ts +132 -0
- package/dist/cjs/query/stream-idle.js +212 -0
- package/dist/cjs/query/table-client.d.ts +101 -0
- package/dist/cjs/query/table-client.js +74 -0
- package/dist/cjs/query/types.d.ts +677 -298
- package/dist/cjs/query/utils.d.ts +105 -6
- package/dist/cjs/query/utils.js +426 -19
- package/dist/cjs/query/warn-registry.d.ts +18 -0
- package/dist/cjs/query/warn-registry.js +18 -0
- package/dist/cjs/query/where-compile.d.ts +138 -14
- package/dist/cjs/query/where-compile.js +513 -29
- package/dist/cjs/query/where.d.ts +159 -59
- package/dist/cjs/query/where.js +716 -246
- package/dist/cjs/query/writes.d.ts +112 -50
- package/dist/cjs/query/writes.js +1498 -200
- package/dist/cjs/query-events.d.ts +4 -2
- package/dist/cjs/query-events.js +3 -1
- package/dist/cjs/realtime.d.ts +7 -3
- package/dist/cjs/realtime.js +13 -2
- package/dist/cjs/schema-builder.d.ts +55 -4
- package/dist/cjs/schema-builder.js +382 -18
- package/dist/cjs/schema-metadata.d.ts +21 -1
- package/dist/cjs/schema-metadata.js +29 -7
- package/dist/cjs/schema-sql.d.ts +75 -5
- package/dist/cjs/schema-sql.js +497 -45
- package/dist/cjs/schema.d.ts +26 -5
- package/dist/cjs/schema.js +110 -13
- package/dist/cjs/sql-placeholders.d.ts +56 -0
- package/dist/cjs/sql-placeholders.js +204 -0
- package/dist/cjs/sqlite.d.ts +75 -20
- package/dist/cjs/sqlite.js +593 -95
- package/dist/cjs/supplied-pool-types.d.ts +48 -0
- package/dist/cjs/supplied-pool-types.js +256 -0
- package/dist/cjs/transaction-control.d.ts +51 -0
- package/dist/cjs/transaction-control.js +316 -0
- package/dist/cjs/transaction-state.d.ts +342 -0
- package/dist/cjs/transaction-state.js +707 -0
- package/dist/cjs/typed-sql.d.ts +37 -3
- package/dist/cjs/typed-sql.js +102 -8
- package/dist/cli/code-first-tags.d.ts +62 -0
- package/dist/cli/code-first-tags.js +120 -0
- package/dist/cli/compile-query.js +9 -0
- package/dist/cli/config.d.ts +35 -6
- package/dist/cli/config.js +16 -1
- package/dist/cli/destructive.d.ts +7 -4
- package/dist/cli/destructive.js +224 -20
- package/dist/cli/error-catalog.js +36 -0
- package/dist/cli/error-text.d.ts +15 -0
- package/dist/cli/error-text.js +37 -0
- package/dist/cli/index.d.ts +62 -4
- package/dist/cli/index.js +569 -112
- package/dist/cli/local-server-guard.d.ts +53 -0
- package/dist/cli/local-server-guard.js +113 -0
- package/dist/cli/local-server-output.d.ts +41 -0
- package/dist/cli/local-server-output.js +98 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +121 -34
- package/dist/cli/migrate.d.ts +113 -5
- package/dist/cli/migrate.js +261 -21
- package/dist/cli/observe.d.ts +6 -1
- package/dist/cli/observe.js +84 -54
- package/dist/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cli/pii-predicate-guard.js +100 -35
- package/dist/cli/prisma-resolve.js +15 -11
- package/dist/cli/prisma-schema.js +12 -4
- package/dist/cli/studio-ui.generated.js +1 -1
- package/dist/cli/studio.d.ts +14 -2
- package/dist/cli/studio.js +246 -71
- package/dist/cli/ui.d.ts +1 -1
- package/dist/client.d.ts +558 -85
- package/dist/client.js +1275 -400
- package/dist/connection-guard.d.ts +13 -0
- package/dist/connection-guard.js +27 -0
- package/dist/connection-url.d.ts +51 -16
- package/dist/connection-url.js +63 -34
- package/dist/diagnostics.d.ts +81 -0
- package/dist/diagnostics.js +144 -0
- package/dist/dialect.d.ts +449 -20
- package/dist/dialect.js +115 -43
- package/dist/engine-config.d.ts +7 -6
- package/dist/errors.d.ts +126 -6
- package/dist/errors.js +252 -12
- package/dist/generate.d.ts +57 -7
- package/dist/generate.js +635 -281
- package/dist/global-filters-config.d.ts +59 -0
- package/dist/global-filters-config.js +361 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.js +4 -2
- package/dist/introspect.d.ts +31 -6
- package/dist/introspect.js +106 -50
- package/dist/log-codes.d.ts +12 -0
- package/dist/log-codes.js +74 -0
- package/dist/logger.d.ts +87 -0
- package/dist/logger.js +93 -0
- package/dist/mssql.d.ts +8 -5
- package/dist/mssql.js +354 -67
- package/dist/mysql.d.ts +3 -5
- package/dist/mysql.js +423 -73
- package/dist/nested-write.d.ts +3 -0
- package/dist/nested-write.js +177 -112
- package/dist/pipeline-submittable.d.ts +12 -0
- package/dist/pipeline-submittable.js +117 -44
- package/dist/pipeline.js +21 -26
- package/dist/powdb-introspect.d.ts +5 -2
- package/dist/powdb-introspect.js +21 -16
- package/dist/powdb-shared.d.ts +36 -5
- package/dist/powdb-shared.js +65 -8
- package/dist/powdb.d.ts +4 -0
- package/dist/powdb.js +183 -51
- package/dist/powql.d.ts +394 -51
- package/dist/powql.js +1836 -291
- package/dist/prisma-compat.d.ts +23 -15
- package/dist/prisma-compat.js +508 -373
- package/dist/query/aggregates.d.ts +17 -1
- package/dist/query/aggregates.js +263 -32
- package/dist/query/batched-loader.d.ts +25 -6
- package/dist/query/batched-loader.js +101 -21
- package/dist/query/builder.d.ts +325 -184
- package/dist/query/builder.js +1458 -495
- package/dist/query/column-ref.d.ts +61 -0
- package/dist/query/column-ref.js +66 -0
- package/dist/query/compound-unique.d.ts +21 -0
- package/dist/query/compound-unique.js +97 -19
- package/dist/query/deferred.d.ts +53 -16
- package/dist/query/expr.d.ts +217 -0
- package/dist/query/expr.js +848 -0
- package/dist/query/filters.d.ts +155 -53
- package/dist/query/filters.js +597 -72
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +4 -0
- package/dist/query/json-value.d.ts +43 -0
- package/dist/query/json-value.js +54 -0
- package/dist/query/normalize-args.d.ts +87 -0
- package/dist/query/normalize-args.js +517 -0
- package/dist/query/option-surface.d.ts +16 -4
- package/dist/query/option-surface.js +56 -13
- package/dist/query/relation-names.d.ts +14 -0
- package/dist/query/relation-names.js +77 -19
- package/dist/query/relations.d.ts +30 -3
- package/dist/query/relations.js +220 -67
- package/dist/query/row-lock.d.ts +49 -0
- package/dist/query/row-lock.js +131 -0
- package/dist/query/sql-comment.d.ts +161 -0
- package/dist/query/sql-comment.js +374 -0
- package/dist/query/stream-idle.d.ts +132 -0
- package/dist/query/stream-idle.js +203 -0
- package/dist/query/table-client.d.ts +101 -0
- package/dist/query/table-client.js +70 -0
- package/dist/query/types.d.ts +677 -298
- package/dist/query/utils.d.ts +105 -6
- package/dist/query/utils.js +414 -18
- package/dist/query/warn-registry.d.ts +18 -0
- package/dist/query/warn-registry.js +18 -0
- package/dist/query/where-compile.d.ts +138 -14
- package/dist/query/where-compile.js +508 -31
- package/dist/query/where.d.ts +159 -59
- package/dist/query/where.js +711 -248
- package/dist/query/writes.d.ts +112 -50
- package/dist/query/writes.js +1496 -202
- package/dist/query-events.d.ts +4 -2
- package/dist/query-events.js +3 -1
- package/dist/realtime.d.ts +7 -3
- package/dist/realtime.js +13 -2
- package/dist/schema-builder.d.ts +55 -4
- package/dist/schema-builder.js +381 -18
- package/dist/schema-metadata.d.ts +21 -1
- package/dist/schema-metadata.js +28 -7
- package/dist/schema-sql.d.ts +75 -5
- package/dist/schema-sql.js +494 -44
- package/dist/schema.d.ts +26 -5
- package/dist/schema.js +109 -13
- package/dist/sql-placeholders.d.ts +56 -0
- package/dist/sql-placeholders.js +200 -0
- package/dist/sqlite.d.ts +75 -20
- package/dist/sqlite.js +597 -99
- package/dist/supplied-pool-types.d.ts +48 -0
- package/dist/supplied-pool-types.js +247 -0
- package/dist/transaction-control.d.ts +51 -0
- package/dist/transaction-control.js +311 -0
- package/dist/transaction-state.d.ts +342 -0
- package/dist/transaction-state.js +696 -0
- package/dist/typed-sql.d.ts +37 -3
- package/dist/typed-sql.js +100 -8
- package/package.json +7 -4
- package/skills/turbine-orm/SKILL.md +56 -6
package/dist/cjs/query/utils.js
CHANGED
|
@@ -8,7 +8,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
8
8
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
9
|
};
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.JSON_WIRE_COERCION_OIDS = exports.OPERATOR_KEYS = exports.LRUCache = exports.INTERNAL_COMBINATOR = void 0;
|
|
11
|
+
exports.JSON_WIRE_COERCION_OIDS = exports.OPERATOR_KEYS = exports.PREPARED_STATEMENT_BUDGET = exports.LRUCache = exports.INTERNAL_COMBINATOR = void 0;
|
|
12
12
|
exports.quoteIdent = quoteIdent;
|
|
13
13
|
exports.ownLookup = ownLookup;
|
|
14
14
|
exports.resolveColumnName = resolveColumnName;
|
|
@@ -22,12 +22,23 @@ exports.escSingleQuote = escSingleQuote;
|
|
|
22
22
|
exports.escapeLike = escapeLike;
|
|
23
23
|
exports.fnv1a64Hex = fnv1a64Hex;
|
|
24
24
|
exports.sqlToPreparedName = sqlToPreparedName;
|
|
25
|
+
exports.boundedPreparedName = boundedPreparedName;
|
|
26
|
+
exports.claimPreparedName = claimPreparedName;
|
|
27
|
+
exports.resetPreparedNameBudget = resetPreparedNameBudget;
|
|
28
|
+
exports.readOnlyMiddlewareParams = readOnlyMiddlewareParams;
|
|
29
|
+
exports.assertMiddlewareArgsKept = assertMiddlewareArgsKept;
|
|
30
|
+
exports.isNodePostgresPool = isNodePostgresPool;
|
|
31
|
+
exports.canCancelBackend = canCancelBackend;
|
|
32
|
+
exports.sendCancelRequest = sendCancelRequest;
|
|
25
33
|
exports.buildCorrelation = buildCorrelation;
|
|
26
34
|
exports.toTimeOfDayLiteral = toTimeOfDayLiteral;
|
|
27
35
|
exports.toLocalDateTimeLiteral = toLocalDateTimeLiteral;
|
|
28
36
|
exports.temporalBindKind = temporalBindKind;
|
|
29
37
|
exports.coerceTemporalValue = coerceTemporalValue;
|
|
30
38
|
exports.parseDbDate = parseDbDate;
|
|
39
|
+
exports.readJsonFloat = readJsonFloat;
|
|
40
|
+
exports.readJsonFloatArray = readJsonFloatArray;
|
|
41
|
+
exports.readTextArray = readTextArray;
|
|
31
42
|
exports.isTemporalInfinity = isTemporalInfinity;
|
|
32
43
|
exports.createUtcDateParser = createUtcDateParser;
|
|
33
44
|
exports.createUtcDateParserGeneral = createUtcDateParserGeneral;
|
|
@@ -53,6 +64,7 @@ exports.selectOmitExclusiveMessage = selectOmitExclusiveMessage;
|
|
|
53
64
|
exports.normalizePagination = normalizePagination;
|
|
54
65
|
const _pg_1 = __importDefault(require("pg"));
|
|
55
66
|
const errors_js_1 = require("../errors.js");
|
|
67
|
+
const logger_js_1 = require("../logger.js");
|
|
56
68
|
const schema_js_1 = require("../schema.js");
|
|
57
69
|
const warn_registry_js_1 = require("./warn-registry.js");
|
|
58
70
|
// ---------------------------------------------------------------------------
|
|
@@ -307,9 +319,15 @@ function canonicalWriteEntries(meta, entries) {
|
|
|
307
319
|
* where walker enumerates) never sees it and no emitted SQL can change.
|
|
308
320
|
*/
|
|
309
321
|
exports.INTERNAL_COMBINATOR = Symbol.for('turbine.internalCombinator');
|
|
322
|
+
/** Shared by every brand: a frozen descriptor saves an allocation per branded where. */
|
|
323
|
+
const INTERNAL_COMBINATOR_DESCRIPTOR = Object.freeze({
|
|
324
|
+
value: true,
|
|
325
|
+
enumerable: false,
|
|
326
|
+
configurable: true,
|
|
327
|
+
});
|
|
310
328
|
/** Tag `where` as carrying a Turbine-synthesized combinator, and return it. */
|
|
311
329
|
function markInternalCombinator(where) {
|
|
312
|
-
Object.defineProperty(where, exports.INTERNAL_COMBINATOR,
|
|
330
|
+
Object.defineProperty(where, exports.INTERNAL_COMBINATOR, INTERNAL_COMBINATOR_DESCRIPTOR);
|
|
313
331
|
return where;
|
|
314
332
|
}
|
|
315
333
|
/** Was this WHERE object's combinator synthesized by Turbine? */
|
|
@@ -323,12 +341,17 @@ function isInternalCombinator(where) {
|
|
|
323
341
|
function escSingleQuote(s) {
|
|
324
342
|
return s.replace(/'/g, "''");
|
|
325
343
|
}
|
|
344
|
+
const LIKE_META = /[\\%_]/;
|
|
345
|
+
const LIKE_META_G = /[\\%_]/g;
|
|
326
346
|
/**
|
|
327
347
|
* Escape LIKE pattern metacharacters: %, _, and \.
|
|
328
348
|
* Must be used with `ESCAPE '\'` in the LIKE clause.
|
|
329
349
|
*/
|
|
330
350
|
function escapeLike(value) {
|
|
331
|
-
|
|
351
|
+
// One pass, and none at all for the common operand with no metacharacter.
|
|
352
|
+
// Identical output to escaping `\` then `%` then `_` in turn: the backslashes
|
|
353
|
+
// the first step adds are never `%` or `_`, so the steps never interact.
|
|
354
|
+
return LIKE_META.test(value) ? value.replace(LIKE_META_G, '\\$&') : value;
|
|
332
355
|
}
|
|
333
356
|
// ---------------------------------------------------------------------------
|
|
334
357
|
// LRU cache, bounded SQL template cache to prevent memory leaks
|
|
@@ -415,6 +438,307 @@ function fnv1a64Hex(s) {
|
|
|
415
438
|
function sqlToPreparedName(sql) {
|
|
416
439
|
return `t_${fnv1a64Hex(sql)}`;
|
|
417
440
|
}
|
|
441
|
+
/**
|
|
442
|
+
* How many distinct statement names one process hands out. Every connection
|
|
443
|
+
* keeps each named statement it has prepared, at 9 to 45 KB of server memory
|
|
444
|
+
* apiece, until the connection closes, so the number of names is what bounds
|
|
445
|
+
* that memory. A statement past the budget is sent unnamed: parsed on every
|
|
446
|
+
* execution and never kept, which costs a few microseconds on a cheap query.
|
|
447
|
+
*/
|
|
448
|
+
exports.PREPARED_STATEMENT_BUDGET = 200;
|
|
449
|
+
/** `Symbol.for` so the ESM and CJS copies of this module share one budget. */
|
|
450
|
+
const PREPARED_NAMES = Symbol.for('turbine.preparedStatementNames');
|
|
451
|
+
function preparedNames() {
|
|
452
|
+
const holder = globalThis;
|
|
453
|
+
let names = holder[PREPARED_NAMES];
|
|
454
|
+
if (!names) {
|
|
455
|
+
names = new Set();
|
|
456
|
+
holder[PREPARED_NAMES] = names;
|
|
457
|
+
}
|
|
458
|
+
return names;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* The prepared-statement name for `sql`, or `''` (send it unnamed) once the
|
|
462
|
+
* process has named {@link PREPARED_STATEMENT_BUDGET} other statements.
|
|
463
|
+
*
|
|
464
|
+
* The first shapes a process runs keep their names for its lifetime, which in
|
|
465
|
+
* practice are its hot shapes. A server-side `DEALLOCATE` cannot replace this:
|
|
466
|
+
* a pooled query does not know which connection it will run on, and a
|
|
467
|
+
* connection keeps every name it ever prepared.
|
|
468
|
+
*/
|
|
469
|
+
function boundedPreparedName(sql) {
|
|
470
|
+
return claimPreparedName(sqlToPreparedName(sql));
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Claim an already derived statement name from the same budget as
|
|
474
|
+
* {@link boundedPreparedName}: `name` itself, or `''` (send it unnamed) once
|
|
475
|
+
* the budget is spent. `sqlComment`'s `c_` names (query/sql-comment.ts) are
|
|
476
|
+
* claimed here, so a commented statement costs one slot like any other.
|
|
477
|
+
*/
|
|
478
|
+
function claimPreparedName(name) {
|
|
479
|
+
const names = preparedNames();
|
|
480
|
+
if (names.has(name))
|
|
481
|
+
return name;
|
|
482
|
+
if (names.size >= exports.PREPARED_STATEMENT_BUDGET)
|
|
483
|
+
return '';
|
|
484
|
+
names.add(name);
|
|
485
|
+
return name;
|
|
486
|
+
}
|
|
487
|
+
/** @internal Tests only: forget every name handed out. */
|
|
488
|
+
function resetPreparedNameBudget() {
|
|
489
|
+
preparedNames().clear();
|
|
490
|
+
}
|
|
491
|
+
function argsRewriteError(model, action, path) {
|
|
492
|
+
return new TypeError(`[turbine] middleware cannot change \`params.${path}\` on ${model}.${action}: the query is compiled from the ` +
|
|
493
|
+
'arguments the caller passed, so a change made in middleware would not reliably reach it. Put the ' +
|
|
494
|
+
'condition in the query itself, or use `globalFilters` for a filter that applies to every query.');
|
|
495
|
+
}
|
|
496
|
+
/** Plain objects and arrays are copied; a Date, Buffer, class instance or other value is shared as it is. */
|
|
497
|
+
function isPlainContainer(value) {
|
|
498
|
+
if (value === null || typeof value !== 'object')
|
|
499
|
+
return false;
|
|
500
|
+
if (Array.isArray(value))
|
|
501
|
+
return true;
|
|
502
|
+
const proto = Object.getPrototypeOf(value);
|
|
503
|
+
return proto === Object.prototype || proto === null;
|
|
504
|
+
}
|
|
505
|
+
/** Nesting past this is shared, not copied, so a cyclic object cannot recurse without end. */
|
|
506
|
+
const MIDDLEWARE_ARGS_MAX_DEPTH = 100;
|
|
507
|
+
/**
|
|
508
|
+
* A copy of `value` that middleware may read, spread, serialize or
|
|
509
|
+
* `structuredClone`: plain objects and arrays are copied at every depth, and
|
|
510
|
+
* everything else (Date, Buffer, bigint, symbol, class instance) is shared.
|
|
511
|
+
* Symbol-keyed properties are copied by descriptor, so the markers the
|
|
512
|
+
* pipeline reads (the internal-combinator brand, the inclusive-cursor flag,
|
|
513
|
+
* column and expression brands) are on the copy exactly as on the original,
|
|
514
|
+
* non-enumerable ones included.
|
|
515
|
+
*/
|
|
516
|
+
function copyArgs(value, depth) {
|
|
517
|
+
if (depth > MIDDLEWARE_ARGS_MAX_DEPTH || !isPlainContainer(value))
|
|
518
|
+
return value;
|
|
519
|
+
let out;
|
|
520
|
+
if (Array.isArray(value)) {
|
|
521
|
+
const items = new Array(value.length);
|
|
522
|
+
// A long list of ids is the common big argument; keep its scalars off the call path.
|
|
523
|
+
for (let i = 0; i < value.length; i++) {
|
|
524
|
+
const item = value[i];
|
|
525
|
+
items[i] = item !== null && typeof item === 'object' ? copyArgs(item, depth + 1) : item;
|
|
526
|
+
}
|
|
527
|
+
out = items;
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
out = Object.getPrototypeOf(value) === null ? Object.create(null) : {};
|
|
531
|
+
for (const key of Object.keys(value)) {
|
|
532
|
+
const item = value[key];
|
|
533
|
+
const copied = item !== null && typeof item === 'object' ? copyArgs(item, depth + 1) : item;
|
|
534
|
+
// `__proto__` from JSON.parse is an own key; assigning it would set the prototype.
|
|
535
|
+
if (key === '__proto__')
|
|
536
|
+
Object.defineProperty(out, key, { value: copied, enumerable: true, writable: true, configurable: true });
|
|
537
|
+
else
|
|
538
|
+
out[key] = copied;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
for (const sym of Object.getOwnPropertySymbols(value)) {
|
|
542
|
+
Object.defineProperty(out, sym, Object.getOwnPropertyDescriptor(value, sym));
|
|
543
|
+
}
|
|
544
|
+
return out;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Where `b` first differs from `a`, as a path suffix (`.where.id`, or `''` for
|
|
548
|
+
* the values themselves), or undefined when they are structurally equal. The
|
|
549
|
+
* suffix is built on the way back out, so an equal pair costs no string work.
|
|
550
|
+
*/
|
|
551
|
+
function argsDifference(a, b, depth) {
|
|
552
|
+
if (Object.is(a, b))
|
|
553
|
+
return undefined;
|
|
554
|
+
if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object')
|
|
555
|
+
return '';
|
|
556
|
+
if (a instanceof Date || b instanceof Date) {
|
|
557
|
+
return a instanceof Date && b instanceof Date && Object.is(a.getTime(), b.getTime()) ? undefined : '';
|
|
558
|
+
}
|
|
559
|
+
if (ArrayBuffer.isView(a) || ArrayBuffer.isView(b)) {
|
|
560
|
+
if (!(ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) || a.byteLength !== b.byteLength)
|
|
561
|
+
return '';
|
|
562
|
+
const x = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
|
|
563
|
+
const y = new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
|
|
564
|
+
for (let i = 0; i < x.length; i++)
|
|
565
|
+
if (x[i] !== y[i])
|
|
566
|
+
return '';
|
|
567
|
+
return undefined;
|
|
568
|
+
}
|
|
569
|
+
if (a instanceof RegExp || b instanceof RegExp)
|
|
570
|
+
return String(a) === String(b) ? undefined : '';
|
|
571
|
+
if (a instanceof Map || a instanceof Set || b instanceof Map || b instanceof Set)
|
|
572
|
+
return '';
|
|
573
|
+
if (Array.isArray(a) !== Array.isArray(b) || depth > MIDDLEWARE_ARGS_MAX_DEPTH)
|
|
574
|
+
return '';
|
|
575
|
+
if (Array.isArray(a)) {
|
|
576
|
+
const other = b;
|
|
577
|
+
const shared = Math.min(a.length, other.length);
|
|
578
|
+
for (let i = 0; i < shared; i++) {
|
|
579
|
+
if (Object.is(a[i], other[i]))
|
|
580
|
+
continue;
|
|
581
|
+
const inner = argsDifference(a[i], other[i], depth + 1);
|
|
582
|
+
if (inner !== undefined)
|
|
583
|
+
return `.${i}${inner}`;
|
|
584
|
+
}
|
|
585
|
+
return a.length === other.length ? undefined : `.${shared}`;
|
|
586
|
+
}
|
|
587
|
+
const left = a;
|
|
588
|
+
const right = b;
|
|
589
|
+
for (const key of Object.keys(left)) {
|
|
590
|
+
if (!Object.hasOwn(right, key))
|
|
591
|
+
return `.${key}`;
|
|
592
|
+
const inner = argsDifference(left[key], right[key], depth + 1);
|
|
593
|
+
if (inner !== undefined)
|
|
594
|
+
return `.${key}${inner}`;
|
|
595
|
+
}
|
|
596
|
+
for (const key of Object.keys(right))
|
|
597
|
+
if (!Object.hasOwn(left, key))
|
|
598
|
+
return `.${key}`;
|
|
599
|
+
return undefined;
|
|
600
|
+
}
|
|
601
|
+
const MIDDLEWARE_ARGS = new WeakMap();
|
|
602
|
+
/** The key Node's `util.inspect` looks for, from the global registry so no `node:` import is needed. */
|
|
603
|
+
const NODE_INSPECT = Symbol.for('nodejs.util.inspect.custom');
|
|
604
|
+
/** Makes `console.log(params)` show the values rather than an accessor. Not own, so a spread of `params` never carries it. */
|
|
605
|
+
const MIDDLEWARE_PARAMS_PROTOTYPE = Object.defineProperty({}, NODE_INSPECT, {
|
|
606
|
+
value(_depth, options, inspect) {
|
|
607
|
+
return inspect({ model: this.model, action: this.action, args: this.args }, options);
|
|
608
|
+
},
|
|
609
|
+
});
|
|
610
|
+
/**
|
|
611
|
+
* The `params` a middleware receives. `params.args` is a plain copy of the
|
|
612
|
+
* caller's args, made when it is first read, so middleware can read it, spread
|
|
613
|
+
* it, serialize it and `structuredClone` it, and one that never reads it pays
|
|
614
|
+
* nothing.
|
|
615
|
+
*
|
|
616
|
+
* It is a copy because the query is compiled from the caller's args, not from
|
|
617
|
+
* what middleware sees. A change to the copy would never reach the query, so
|
|
618
|
+
* {@link assertMiddlewareArgsKept} refuses it, naming the path, when the
|
|
619
|
+
* middleware calls `next`. That check compares contents, which is why the copy
|
|
620
|
+
* is not frozen: a frozen object ignores a write silently in a script that is
|
|
621
|
+
* not in strict mode, and a filter added there would be dropped without a word.
|
|
622
|
+
* Assigning to `params.args` itself throws at once.
|
|
623
|
+
*/
|
|
624
|
+
function readOnlyMiddlewareParams(model, action, args) {
|
|
625
|
+
const state = { model, action, original: args, copy: undefined };
|
|
626
|
+
const params = {
|
|
627
|
+
__proto__: MIDDLEWARE_PARAMS_PROTOTYPE,
|
|
628
|
+
model,
|
|
629
|
+
action,
|
|
630
|
+
get args() {
|
|
631
|
+
if (state.copy === undefined)
|
|
632
|
+
state.copy = copyArgs(args, 0);
|
|
633
|
+
return state.copy;
|
|
634
|
+
},
|
|
635
|
+
set args(_replacement) {
|
|
636
|
+
throw argsRewriteError(model, action, 'args');
|
|
637
|
+
},
|
|
638
|
+
};
|
|
639
|
+
MIDDLEWARE_ARGS.set(params, state);
|
|
640
|
+
return params;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Refuse a `next(p)` whose `p.args` is not the caller's args: one that
|
|
644
|
+
* middleware changed in place, or replaced with an object that differs from
|
|
645
|
+
* them. A copy that is structurally equal passes (`structuredClone(params.args)`,
|
|
646
|
+
* `{ ...params.args }`), because nothing it would change is lost. Throws a
|
|
647
|
+
* TypeError naming the first path that differs.
|
|
648
|
+
*/
|
|
649
|
+
function assertMiddlewareArgsKept(handedOut, passed) {
|
|
650
|
+
const state = MIDDLEWARE_ARGS.get(handedOut);
|
|
651
|
+
if (passed === handedOut) {
|
|
652
|
+
if (handedOut.model !== state.model)
|
|
653
|
+
throw argsRewriteError(state.model, state.action, 'model');
|
|
654
|
+
if (handedOut.action !== state.action)
|
|
655
|
+
throw argsRewriteError(state.model, state.action, 'action');
|
|
656
|
+
// Nothing has read the args, so nothing could have changed them.
|
|
657
|
+
if (state.copy === undefined)
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
const given = passed?.args;
|
|
661
|
+
if (given === state.original)
|
|
662
|
+
return;
|
|
663
|
+
const changed = argsDifference(state.original, given, 0);
|
|
664
|
+
if (changed !== undefined)
|
|
665
|
+
throw argsRewriteError(state.model, state.action, `args${changed}`);
|
|
666
|
+
}
|
|
667
|
+
/** Whether `pool` is a node-postgres `Pool`, whose checkouts are real backend connections. */
|
|
668
|
+
function isNodePostgresPool(pool) {
|
|
669
|
+
const Pool = _pg_1.default.Pool;
|
|
670
|
+
return typeof Pool === 'function' && pool instanceof Pool;
|
|
671
|
+
}
|
|
672
|
+
/** Whether `client` is a node-postgres connection a cancel request can reach. */
|
|
673
|
+
function canCancelBackend(client) {
|
|
674
|
+
const c = client;
|
|
675
|
+
return (typeof _pg_1.default.Connection === 'function' &&
|
|
676
|
+
!!c &&
|
|
677
|
+
typeof c.processID === 'number' &&
|
|
678
|
+
typeof c.secretKey === 'number' &&
|
|
679
|
+
(typeof c.port === 'number' || typeof c.port === 'string'));
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Ask the server to cancel whatever `client`'s backend is running, with the
|
|
683
|
+
* protocol's CancelRequest: a separate short connection carrying the backend's
|
|
684
|
+
* process id and secret key. No login, no session state, and a pooler forwards
|
|
685
|
+
* it to the right server backend, which `pg_cancel_backend(pid)` through a
|
|
686
|
+
* pooler would not.
|
|
687
|
+
*
|
|
688
|
+
* Resolves `true` once the server has closed the cancel connection, i.e. has
|
|
689
|
+
* signalled the backend; `false` when the request could not be delivered
|
|
690
|
+
* within `waitMs`. A cancel that arrives after the statement finished is
|
|
691
|
+
* ignored by the server.
|
|
692
|
+
*/
|
|
693
|
+
function sendCancelRequest(client, waitMs) {
|
|
694
|
+
if (!canCancelBackend(client))
|
|
695
|
+
return Promise.resolve(false);
|
|
696
|
+
const target = client;
|
|
697
|
+
const Connection = _pg_1.default.Connection;
|
|
698
|
+
return new Promise((resolve) => {
|
|
699
|
+
let con;
|
|
700
|
+
let sent = false;
|
|
701
|
+
let done = false;
|
|
702
|
+
const finish = (delivered) => {
|
|
703
|
+
if (done)
|
|
704
|
+
return;
|
|
705
|
+
done = true;
|
|
706
|
+
clearTimeout(timer);
|
|
707
|
+
try {
|
|
708
|
+
con?.stream?.destroy?.();
|
|
709
|
+
}
|
|
710
|
+
catch {
|
|
711
|
+
// already closed
|
|
712
|
+
}
|
|
713
|
+
resolve(delivered);
|
|
714
|
+
};
|
|
715
|
+
const timer = setTimeout(() => finish(false), waitMs);
|
|
716
|
+
try {
|
|
717
|
+
con = new Connection({ ssl: target.ssl, sslNegotiation: target.sslNegotiation });
|
|
718
|
+
const send = () => {
|
|
719
|
+
sent = true;
|
|
720
|
+
con?.cancel(target.processID, target.secretKey);
|
|
721
|
+
};
|
|
722
|
+
con.on('error', () => finish(false));
|
|
723
|
+
con.on('end', () => finish(sent));
|
|
724
|
+
con.on('connect', () => {
|
|
725
|
+
if (!target.ssl)
|
|
726
|
+
send();
|
|
727
|
+
else if (target.sslNegotiation !== 'direct')
|
|
728
|
+
con?.requestSsl();
|
|
729
|
+
});
|
|
730
|
+
con.on('sslconnect', send);
|
|
731
|
+
const host = typeof target.host === 'string' ? target.host : undefined;
|
|
732
|
+
if (host?.startsWith('/'))
|
|
733
|
+
con.connect(`${host}/.s.PGSQL.${String(target.port)}`);
|
|
734
|
+
else
|
|
735
|
+
con.connect(target.port, host);
|
|
736
|
+
}
|
|
737
|
+
catch {
|
|
738
|
+
finish(false);
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
}
|
|
418
742
|
/** Known operator keys, used to detect operator objects vs plain values */
|
|
419
743
|
exports.OPERATOR_KEYS = new Set([
|
|
420
744
|
'equals',
|
|
@@ -576,6 +900,12 @@ const TZ_SUFFIX_RE = /(?:Z|[+-]\d{2}(?::?\d{2})?)$/;
|
|
|
576
900
|
* as-is.
|
|
577
901
|
*/
|
|
578
902
|
function parseDbDate(value) {
|
|
903
|
+
const date = parseDbDateCommon(value);
|
|
904
|
+
// The shapes JS cannot parse (a BC year, an offset with seconds, a year past
|
|
905
|
+
// 9999) come out invalid; only those pay for the general parse.
|
|
906
|
+
return Number.isNaN(date.getTime()) ? (parseDbDateGeneral(value) ?? date) : date;
|
|
907
|
+
}
|
|
908
|
+
function parseDbDateCommon(value) {
|
|
579
909
|
// Date-only values (`2026-07-07`, from `date` columns in json_agg output)
|
|
580
910
|
// have no time to zone-pin, and their `-07` tail must not be read as an
|
|
581
911
|
// offset. JS parses bare ISO dates as UTC midnight already.
|
|
@@ -590,6 +920,79 @@ function parseDbDate(value) {
|
|
|
590
920
|
// normalize `YYYY-MM-DD HH:MM:SS` (driver form) to ISO before pinning UTC
|
|
591
921
|
return new Date(`${value.replace(' ', 'T')}Z`);
|
|
592
922
|
}
|
|
923
|
+
const DB_DATE_GENERAL_RE = /^(\d{4,})-(\d\d)-(\d\d)(?:[T ](\d\d):(\d\d):(\d\d)(\.\d+)?)?(?:(Z)|([+-])(\d\d)(?::?(\d\d))?(?::?(\d\d))?)?( BC)?$/;
|
|
924
|
+
/**
|
|
925
|
+
* The Postgres renderings JS `Date` cannot parse: a ` BC` suffix, a
|
|
926
|
+
* local-mean-time offset with seconds (`-04:56:02`, any zone before about
|
|
927
|
+
* 1900), and years of five or more digits. Offset-less text is read as UTC,
|
|
928
|
+
* as in {@link parseDbDate}. `undefined` when the text is none of these.
|
|
929
|
+
*/
|
|
930
|
+
function parseDbDateGeneral(value) {
|
|
931
|
+
const m = DB_DATE_GENERAL_RE.exec(value);
|
|
932
|
+
if (!m)
|
|
933
|
+
return undefined;
|
|
934
|
+
let year = Number(m[1]);
|
|
935
|
+
if (m[13])
|
|
936
|
+
year = 1 - year;
|
|
937
|
+
const month = Number(m[2]) - 1;
|
|
938
|
+
const ms = m[7] ? Math.trunc(1000 * Number(`0${m[7]}`)) : 0;
|
|
939
|
+
const date = new Date(Date.UTC(2000, month, Number(m[3]), Number(m[4] ?? 0), Number(m[5] ?? 0), Number(m[6] ?? 0), ms));
|
|
940
|
+
// setUTCFullYear, not Date.UTC: Date.UTC reads years 0-99 as 1900-1999.
|
|
941
|
+
date.setUTCFullYear(year, month, Number(m[3]));
|
|
942
|
+
if (m[9]) {
|
|
943
|
+
const offset = Number(m[10]) * 3600 + Number(m[11] ?? 0) * 60 + Number(m[12] ?? 0);
|
|
944
|
+
return new Date(date.getTime() - (m[9] === '-' ? -offset : offset) * 1000);
|
|
945
|
+
}
|
|
946
|
+
return date;
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* A float column's value as the driver reads it. JSON has no NaN or infinity,
|
|
950
|
+
* so `json_build_object` renders them as the strings "NaN", "Infinity" and
|
|
951
|
+
* "-Infinity"; every other value passes through.
|
|
952
|
+
*/
|
|
953
|
+
function readJsonFloat(value) {
|
|
954
|
+
if (typeof value !== 'string')
|
|
955
|
+
return value;
|
|
956
|
+
if (value === 'NaN')
|
|
957
|
+
return Number.NaN;
|
|
958
|
+
if (value === 'Infinity')
|
|
959
|
+
return Number.POSITIVE_INFINITY;
|
|
960
|
+
if (value === '-Infinity')
|
|
961
|
+
return Number.NEGATIVE_INFINITY;
|
|
962
|
+
return value;
|
|
963
|
+
}
|
|
964
|
+
/** {@link readJsonFloat} over a float array (at any depth); the input when nothing changes. */
|
|
965
|
+
function readJsonFloatArray(value) {
|
|
966
|
+
if (!Array.isArray(value))
|
|
967
|
+
return value;
|
|
968
|
+
let out;
|
|
969
|
+
for (let i = 0; i < value.length; i++) {
|
|
970
|
+
const el = value[i];
|
|
971
|
+
const read = Array.isArray(el) ? readJsonFloatArray(el) : readJsonFloat(el);
|
|
972
|
+
if (read !== el) {
|
|
973
|
+
out ??= value.slice();
|
|
974
|
+
out[i] = read;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
return out ?? value;
|
|
978
|
+
}
|
|
979
|
+
let textArrayParser;
|
|
980
|
+
/**
|
|
981
|
+
* An array column the driver has no parser for (an enum array) arrives as
|
|
982
|
+
* Postgres array text, `{ok,sad}`; read it into an array of strings, as the
|
|
983
|
+
* same column reads through a relation. The input when it cannot be parsed.
|
|
984
|
+
*/
|
|
985
|
+
function readTextArray(value) {
|
|
986
|
+
if (typeof value !== 'string' || value.charCodeAt(0) !== 123)
|
|
987
|
+
return value;
|
|
988
|
+
try {
|
|
989
|
+
textArrayParser ??= createPgArrayParser((text) => text);
|
|
990
|
+
return textArrayParser(value) ?? value;
|
|
991
|
+
}
|
|
992
|
+
catch {
|
|
993
|
+
return value;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
593
996
|
/**
|
|
594
997
|
* Is `value` one of the two representations a Postgres temporal `infinity` /
|
|
595
998
|
* `-infinity` reaches the ORM row parser in?
|
|
@@ -1128,7 +1531,7 @@ function isDefaultTextParser(oid, parser) {
|
|
|
1128
1531
|
* construction, and only when somebody else's non-default parser is actually
|
|
1129
1532
|
* being replaced.
|
|
1130
1533
|
*/
|
|
1131
|
-
function warnParserOverwrite(oid, typeName) {
|
|
1534
|
+
function warnParserOverwrite(oid, typeName, logger = logger_js_1.consoleLogger) {
|
|
1132
1535
|
const getParser = _pg_1.default.types.getTypeParser;
|
|
1133
1536
|
const current = getParser(oid, 'text');
|
|
1134
1537
|
// Turbine's own earlier registration is not a third party's expectation.
|
|
@@ -1147,13 +1550,13 @@ function warnParserOverwrite(oid, typeName) {
|
|
|
1147
1550
|
const remedy = TEMPORAL_PARSER_OIDS.has(oid)
|
|
1148
1551
|
? ' `utcTimestamps: false` leaves the six temporal OIDs (1114, 1082, 1115, 1182, 1184, 1185) alone entirely.'
|
|
1149
1552
|
: ' There is no opt-out for this OID: Turbine registers it so bigint values come back as numbers.';
|
|
1150
|
-
|
|
1553
|
+
(0, logger_js_1.logTo)(logger, 'warn', `pg type parser for OID ${oid} (${typeName}) was already customized by something else in this ` +
|
|
1151
1554
|
'process, and Turbine is replacing it. `pg.types.setTypeParser` is process-global and takes effect ' +
|
|
1152
1555
|
'immediately for EVERY pg.Pool in the process, including pools that already exist and are already ' +
|
|
1153
1556
|
'querying, so whatever set that parser will now read this column differently. If yours should win, ' +
|
|
1154
1557
|
`register it AFTER constructing the client.${remedy} This warning fires under \`NODE_ENV=production\` ` +
|
|
1155
1558
|
'too: which parser wins depends on module evaluation order, so a process can be clean in dev and wrong ' +
|
|
1156
|
-
'in production from import order alone.');
|
|
1559
|
+
'in production from import order alone.', { code: 'parser-overwrite', oid, type: typeName });
|
|
1157
1560
|
}
|
|
1158
1561
|
/**
|
|
1159
1562
|
* Register Turbine's temporal text parsers on the pg module. SIX OIDs, doing
|
|
@@ -1189,16 +1592,16 @@ function warnParserOverwrite(oid, typeName) {
|
|
|
1189
1592
|
* per row at decode time, not captured per pool). If any of the four OIDs is
|
|
1190
1593
|
* already on a NON-default parser, {@link warnParserOverwrite} says so once.
|
|
1191
1594
|
*/
|
|
1192
|
-
function registerUtcTemporalParsers() {
|
|
1595
|
+
function registerUtcTemporalParsers(logger) {
|
|
1193
1596
|
// pg-types declares get/setTypeParser over its own OID enum, which lists the
|
|
1194
1597
|
// scalar types only. The array OIDs are just as real, so both calls are
|
|
1195
1598
|
// retyped over a plain number rather than the incomplete enum.
|
|
1196
1599
|
const getParser = _pg_1.default.types.getTypeParser;
|
|
1197
1600
|
const setParser = _pg_1.default.types.setTypeParser;
|
|
1198
|
-
warnParserOverwrite(1114, 'timestamp');
|
|
1199
|
-
warnParserOverwrite(1082, 'date');
|
|
1200
|
-
warnParserOverwrite(1115, 'timestamp[]');
|
|
1201
|
-
warnParserOverwrite(1182, 'date[]');
|
|
1601
|
+
warnParserOverwrite(1114, 'timestamp', logger);
|
|
1602
|
+
warnParserOverwrite(1082, 'date', logger);
|
|
1603
|
+
warnParserOverwrite(1115, 'timestamp[]', logger);
|
|
1604
|
+
warnParserOverwrite(1182, 'date[]', logger);
|
|
1202
1605
|
const parseDate = createUtcDateParser(getParser(1082, 'text'));
|
|
1203
1606
|
const parseTimestamp = createUtcTimestampParser(getParser(1114, 'text'));
|
|
1204
1607
|
setParser(1114, markTurbineParser(parseTimestamp));
|
|
@@ -1367,8 +1770,11 @@ function nameCloseness(input, candidate) {
|
|
|
1367
1770
|
const b = candidate.toLowerCase();
|
|
1368
1771
|
if (a === b)
|
|
1369
1772
|
return 1000;
|
|
1370
|
-
|
|
1773
|
+
// Containment only between names of 3+ characters: `id` sits inside almost
|
|
1774
|
+
// any name, so `tenentId` must reach `tenantId` by edit distance instead.
|
|
1775
|
+
if (Math.min(a.length, b.length) >= 3 && (a.includes(b) || b.includes(a))) {
|
|
1371
1776
|
return 500 + Math.min(a.length, b.length);
|
|
1777
|
+
}
|
|
1372
1778
|
// Levenshtein, bounded: only near-misses are worth suggesting.
|
|
1373
1779
|
const rows = a.length + 1;
|
|
1374
1780
|
const cols = b.length + 1;
|
|
@@ -1508,7 +1914,7 @@ function relationInProjectionMessage(table, field, clause) {
|
|
|
1508
1914
|
' out of the result.';
|
|
1509
1915
|
}
|
|
1510
1916
|
/**
|
|
1511
|
-
*
|
|
1917
|
+
* Advice (`diagnostics.advice`) for a sort/grouping term Turbine dropped as redundant
|
|
1512
1918
|
* (`filters.ts` `dedupeOrderEntries` / `dedupeColumnList`).
|
|
1513
1919
|
*
|
|
1514
1920
|
* Deliberately a WARNING and not an error, and deliberately not silent either.
|
|
@@ -1517,15 +1923,16 @@ function relationInProjectionMessage(table, field, clause) {
|
|
|
1517
1923
|
* plus an unconditional primary-key tiebreak, which collide exactly when the
|
|
1518
1924
|
* caller sorts by the primary key). But a caller who wrote the duplicate by
|
|
1519
1925
|
* hand, or who believes a second key is doing something, should hear about it
|
|
1520
|
-
* once.
|
|
1926
|
+
* once. Advice for the usual reason: it describes the QUERY the application
|
|
1521
1927
|
* sends, which does not vary with the environment, so a production process
|
|
1522
|
-
* learns nothing from repeating it.
|
|
1928
|
+
* learns nothing from repeating it. The caller passes its advice logger, or
|
|
1929
|
+
* `undefined` when advice is off.
|
|
1523
1930
|
*
|
|
1524
1931
|
* Keyed per dropped key, so a sort assembled per request from the same UI says
|
|
1525
1932
|
* it once rather than once per request.
|
|
1526
1933
|
*/
|
|
1527
|
-
function warnRedundantSortTerm(table, clause, dropped) {
|
|
1528
|
-
if (
|
|
1934
|
+
function warnRedundantSortTerm(advice, table, clause, dropped) {
|
|
1935
|
+
if (!advice)
|
|
1529
1936
|
return;
|
|
1530
1937
|
for (const d of dropped) {
|
|
1531
1938
|
if (!(0, warn_registry_js_1.shouldWarnOnce)(warn_registry_js_1.WARN_NS.redundantSortTerm, `${table}|${clause}|${d.key}`))
|
|
@@ -1533,9 +1940,9 @@ function warnRedundantSortTerm(table, clause, dropped) {
|
|
|
1533
1940
|
const how = d.first === d.key
|
|
1534
1941
|
? `"${d.key}" is named twice`
|
|
1535
1942
|
: `"${d.key}" and the earlier "${d.first}" both target ${d.resolved}`;
|
|
1536
|
-
|
|
1943
|
+
(0, logger_js_1.logTo)(advice, 'warn', `${clause} on table "${table}": ${how}, so the later one was dropped. It could not have ` +
|
|
1537
1944
|
'changed the result (the earlier term already orders those rows), and dropping it keeps the query on ' +
|
|
1538
|
-
'a shared prepared statement. Remove it to silence this.');
|
|
1945
|
+
'a shared prepared statement. Remove it to silence this.', { code: 'redundant-sort-term', table, clause, key: d.key });
|
|
1539
1946
|
}
|
|
1540
1947
|
}
|
|
1541
1948
|
/**
|
|
@@ -127,6 +127,17 @@ export declare const WARN_NS: {
|
|
|
127
127
|
* Keyed on the requested mode.
|
|
128
128
|
*/
|
|
129
129
|
readonly planCacheModeIgnored: "planCacheModeIgnored";
|
|
130
|
+
/**
|
|
131
|
+
* `statementTimeoutMs` or `maxLifetimeSeconds` was set on a client given an
|
|
132
|
+
* EXTERNAL pool, whose connections Turbine never opens (client.ts
|
|
133
|
+
* `warnExternalPoolOptions`). Keyed on the option name.
|
|
134
|
+
*/
|
|
135
|
+
readonly connectionOptionIgnored: "connectionOptionIgnored";
|
|
136
|
+
/**
|
|
137
|
+
* `preparedStatements: true` on a connection string that names a connection
|
|
138
|
+
* pooler (client.ts `warnPreparedOnPooler`). Keyed on `host:port`.
|
|
139
|
+
*/
|
|
140
|
+
readonly preparedStatementsOnPooler: "preparedStatementsOnPooler";
|
|
130
141
|
/**
|
|
131
142
|
* A relation's JSON payload could not be parsed in `parseNestedRow`
|
|
132
143
|
* (relations.ts). Keyed on `table.relation`, so a page of 10,000 rows whose
|
|
@@ -134,4 +145,11 @@ export declare const WARN_NS: {
|
|
|
134
145
|
* warn sits in the per-relation loop, which runs once per row per relation.
|
|
135
146
|
*/
|
|
136
147
|
readonly relationParseFailure: "relationParseFailure";
|
|
148
|
+
/**
|
|
149
|
+
* `findMany` with no row limit (builder.ts `maybeWarnUnlimited`, powql.ts).
|
|
150
|
+
* Keyed on the table and process-wide: every `$transaction` builds its own
|
|
151
|
+
* query interfaces, so a dedupe held on the interface said it again in
|
|
152
|
+
* every transaction.
|
|
153
|
+
*/
|
|
154
|
+
readonly unlimitedFindMany: "unlimitedFindMany";
|
|
137
155
|
};
|
|
@@ -168,6 +168,17 @@ exports.WARN_NS = {
|
|
|
168
168
|
* Keyed on the requested mode.
|
|
169
169
|
*/
|
|
170
170
|
planCacheModeIgnored: 'planCacheModeIgnored',
|
|
171
|
+
/**
|
|
172
|
+
* `statementTimeoutMs` or `maxLifetimeSeconds` was set on a client given an
|
|
173
|
+
* EXTERNAL pool, whose connections Turbine never opens (client.ts
|
|
174
|
+
* `warnExternalPoolOptions`). Keyed on the option name.
|
|
175
|
+
*/
|
|
176
|
+
connectionOptionIgnored: 'connectionOptionIgnored',
|
|
177
|
+
/**
|
|
178
|
+
* `preparedStatements: true` on a connection string that names a connection
|
|
179
|
+
* pooler (client.ts `warnPreparedOnPooler`). Keyed on `host:port`.
|
|
180
|
+
*/
|
|
181
|
+
preparedStatementsOnPooler: 'preparedStatementsOnPooler',
|
|
171
182
|
/**
|
|
172
183
|
* A relation's JSON payload could not be parsed in `parseNestedRow`
|
|
173
184
|
* (relations.ts). Keyed on `table.relation`, so a page of 10,000 rows whose
|
|
@@ -175,4 +186,11 @@ exports.WARN_NS = {
|
|
|
175
186
|
* warn sits in the per-relation loop, which runs once per row per relation.
|
|
176
187
|
*/
|
|
177
188
|
relationParseFailure: 'relationParseFailure',
|
|
189
|
+
/**
|
|
190
|
+
* `findMany` with no row limit (builder.ts `maybeWarnUnlimited`, powql.ts).
|
|
191
|
+
* Keyed on the table and process-wide: every `$transaction` builds its own
|
|
192
|
+
* query interfaces, so a dedupe held on the interface said it again in
|
|
193
|
+
* every transaction.
|
|
194
|
+
*/
|
|
195
|
+
unlimitedFindMany: 'unlimitedFindMany',
|
|
178
196
|
};
|