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
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `undefined` means absent, decided ONCE at the args seam.
|
|
3
|
+
*
|
|
4
|
+
* Every public operation (and its `build*` twin) runs its args through
|
|
5
|
+
* {@link pruneUndefinedArgs} before anything else reads them: the empty-`where`
|
|
6
|
+
* guards, the SQL-cache fingerprint, the SQL build and the param collect. A key
|
|
7
|
+
* whose value is `undefined` is removed, and so is an object (or combinator
|
|
8
|
+
* array) that BECOMES empty because of it, recursively, so
|
|
9
|
+
* `{ user: { email: undefined } }` is exactly `{}`. One pass up front, because
|
|
10
|
+
* consumers that each decide what `undefined` means end up disagreeing: a cache
|
|
11
|
+
* key that counted `{ gte: undefined }` while the builder skipped it served a
|
|
12
|
+
* `<=` template to a `>=` call.
|
|
13
|
+
*
|
|
14
|
+
* Pruned positions: `where` (combinators, relation filters, column operator
|
|
15
|
+
* objects including a nested `not`), `having`, `cursor`, `orderBy`, and every
|
|
16
|
+
* `with` relation's `where` / `orderBy`. Never `data` / `create` / `update`
|
|
17
|
+
* (a json column may legitimately receive `{}`), never an operand value (an
|
|
18
|
+
* `in` list, a JSON document, a vector), and never an object written empty
|
|
19
|
+
* (`{}`, `{ OR: [] }`), which keeps its own meaning. A column operator object
|
|
20
|
+
* left holding only modifiers (`mode`, `path`, `config`) is removed too:
|
|
21
|
+
* `{ contains: q, mode: 'insensitive' }` with `q` undefined is no filter.
|
|
22
|
+
*
|
|
23
|
+
* PowDB runs the same function from `PowqlInterface.normalizeArgs`, so the
|
|
24
|
+
* two engines cannot disagree about what `undefined` means.
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
import { ValidationError } from '../errors.js';
|
|
29
|
+
import { isPlainRecord, RELATION_FILTER_WRAPPER_SET } from './filters.js';
|
|
30
|
+
import { resolveColumnName, resolveRelation } from './utils.js';
|
|
31
|
+
import { MAX_WHERE_DEPTH } from './where-compile.js';
|
|
32
|
+
/** Sentinel for "remove this key / element". Never escapes this module. */
|
|
33
|
+
const REMOVE = Symbol('turbine.prune.remove');
|
|
34
|
+
/** Keys that qualify an operator rather than state one. */
|
|
35
|
+
const MODIFIER_KEYS = new Set(['mode', 'path', 'config']);
|
|
36
|
+
/**
|
|
37
|
+
* Past this depth the pass stops descending and returns the node as written.
|
|
38
|
+
* The where walkers refuse anything deeper than {@link MAX_WHERE_DEPTH} with a
|
|
39
|
+
* typed error, so stopping here only hands that refusal the original shape;
|
|
40
|
+
* it never lets an unbounded walk through.
|
|
41
|
+
*/
|
|
42
|
+
const PRUNE_DEPTH_LIMIT = MAX_WHERE_DEPTH + 2;
|
|
43
|
+
function hasNoKeys(obj) {
|
|
44
|
+
for (const _ in obj)
|
|
45
|
+
return false;
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Copy-on-write key replacement. Spread rather than a fresh literal so any
|
|
50
|
+
* symbol-keyed brand on the object survives the copy.
|
|
51
|
+
*/
|
|
52
|
+
function withKey(current, original, key, next) {
|
|
53
|
+
const out = current ?? { ...original };
|
|
54
|
+
if (next === REMOVE)
|
|
55
|
+
delete out[key];
|
|
56
|
+
else
|
|
57
|
+
out[key] = next;
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
function isJsonColumn(meta, column) {
|
|
61
|
+
if (!meta || !column)
|
|
62
|
+
return false;
|
|
63
|
+
const type = (meta.pgTypes?.[column] ?? '').toLowerCase();
|
|
64
|
+
return type === 'json' || type === 'jsonb';
|
|
65
|
+
}
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// where
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
/**
|
|
70
|
+
* Prune one where object scoped to `meta`'s table. Returns the input when
|
|
71
|
+
* nothing changed. The result may be `{}`; the CALLER decides whether an
|
|
72
|
+
* emptied object is removed (nested positions) or kept (the top level).
|
|
73
|
+
*/
|
|
74
|
+
function pruneWhere(schema, meta, where, depth) {
|
|
75
|
+
if (depth > PRUNE_DEPTH_LIMIT)
|
|
76
|
+
return where;
|
|
77
|
+
let out;
|
|
78
|
+
for (const key of Object.keys(where)) {
|
|
79
|
+
const value = where[key];
|
|
80
|
+
let next = value;
|
|
81
|
+
if (value === undefined) {
|
|
82
|
+
next = REMOVE;
|
|
83
|
+
}
|
|
84
|
+
else if (key === 'AND' || key === 'OR' || key === 'NOT') {
|
|
85
|
+
next = pruneCombinator(schema, meta, value, depth + 1);
|
|
86
|
+
}
|
|
87
|
+
else if (isPlainRecord(value)) {
|
|
88
|
+
next = pruneField(schema, meta, key, value, depth + 1);
|
|
89
|
+
}
|
|
90
|
+
if (next !== value)
|
|
91
|
+
out = withKey(out, where, key, next);
|
|
92
|
+
}
|
|
93
|
+
return out ?? where;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* `AND` / `OR` / `NOT`: an object, or an array of objects. An `undefined`
|
|
97
|
+
* member is removed like an emptied one; any other non-object member is left
|
|
98
|
+
* for the where walk, which refuses it by name (`combinatorBranches`).
|
|
99
|
+
*/
|
|
100
|
+
function pruneCombinator(schema, meta, value, depth) {
|
|
101
|
+
if (Array.isArray(value)) {
|
|
102
|
+
let out;
|
|
103
|
+
for (let i = 0; i < value.length; i++) {
|
|
104
|
+
const element = value[i];
|
|
105
|
+
let next = element;
|
|
106
|
+
if (element === undefined) {
|
|
107
|
+
next = REMOVE;
|
|
108
|
+
}
|
|
109
|
+
else if (isPlainRecord(element)) {
|
|
110
|
+
const pruned = pruneWhere(schema, meta, element, depth);
|
|
111
|
+
next = pruned !== element && hasNoKeys(pruned) ? REMOVE : pruned;
|
|
112
|
+
}
|
|
113
|
+
if (next !== element && !out)
|
|
114
|
+
out = value.slice(0, i);
|
|
115
|
+
if (out && next !== REMOVE)
|
|
116
|
+
out.push(next);
|
|
117
|
+
}
|
|
118
|
+
if (!out)
|
|
119
|
+
return value;
|
|
120
|
+
// Every element was removed: the combinator itself said nothing.
|
|
121
|
+
return out.length === 0 ? REMOVE : out;
|
|
122
|
+
}
|
|
123
|
+
if (isPlainRecord(value)) {
|
|
124
|
+
const next = pruneWhere(schema, meta, value, depth);
|
|
125
|
+
return next !== value && hasNoKeys(next) ? REMOVE : next;
|
|
126
|
+
}
|
|
127
|
+
return value;
|
|
128
|
+
}
|
|
129
|
+
/** One where key whose value is a plain object: a relation filter or a column filter. */
|
|
130
|
+
function pruneField(schema, meta, key, value, depth) {
|
|
131
|
+
// Relation first, matching the where walker's branch order.
|
|
132
|
+
const relation = meta ? resolveRelation(meta.relations, key) : undefined;
|
|
133
|
+
if (relation)
|
|
134
|
+
return pruneRelationFilter(schema, relation.def, value, depth);
|
|
135
|
+
const column = meta ? resolveColumnName(meta, key) : undefined;
|
|
136
|
+
// An unknown key is left for the builder, which names it in its error.
|
|
137
|
+
if (meta && column === undefined)
|
|
138
|
+
return value;
|
|
139
|
+
return pruneOperatorObject(value, !isJsonColumn(meta, column));
|
|
140
|
+
}
|
|
141
|
+
function pruneRelationFilter(schema, def, value, depth) {
|
|
142
|
+
const target = schema.tables[def.to];
|
|
143
|
+
let hasCardinalityKey = false;
|
|
144
|
+
for (const k of Object.keys(value)) {
|
|
145
|
+
if (RELATION_FILTER_WRAPPER_SET.has(k)) {
|
|
146
|
+
hasCardinalityKey = true;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (!hasCardinalityKey) {
|
|
151
|
+
// A bare object on a to-one relation is an implicit `is`.
|
|
152
|
+
const next = pruneWhere(schema, target, value, depth);
|
|
153
|
+
return next !== value && hasNoKeys(next) ? REMOVE : next;
|
|
154
|
+
}
|
|
155
|
+
let out;
|
|
156
|
+
for (const k of Object.keys(value)) {
|
|
157
|
+
const v = value[k];
|
|
158
|
+
let next = v;
|
|
159
|
+
if (v === undefined) {
|
|
160
|
+
next = REMOVE;
|
|
161
|
+
}
|
|
162
|
+
else if (RELATION_FILTER_WRAPPER_SET.has(k) && isPlainRecord(v)) {
|
|
163
|
+
const pruned = pruneWhere(schema, target, v, depth);
|
|
164
|
+
next = pruned !== v && hasNoKeys(pruned) ? REMOVE : pruned;
|
|
165
|
+
}
|
|
166
|
+
if (next !== v)
|
|
167
|
+
out = withKey(out, value, k, next);
|
|
168
|
+
}
|
|
169
|
+
if (!out)
|
|
170
|
+
return value;
|
|
171
|
+
return hasNoKeys(out) ? REMOVE : out;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* A column's operator / JSON / array / text-search / vector filter object. Only
|
|
175
|
+
* its own keys are stripped; operands are values and are never walked, except
|
|
176
|
+
* a nested operator object under `not` (on a non-JSON column) and a vector
|
|
177
|
+
* filter's `distance` block, whose keys are operators too.
|
|
178
|
+
*/
|
|
179
|
+
function pruneOperatorObject(value, walkNot) {
|
|
180
|
+
let out;
|
|
181
|
+
for (const k of Object.keys(value)) {
|
|
182
|
+
const v = value[k];
|
|
183
|
+
let next = v;
|
|
184
|
+
if (v === undefined) {
|
|
185
|
+
next = REMOVE;
|
|
186
|
+
}
|
|
187
|
+
else if ((k === 'not' && walkNot) || k === 'distance') {
|
|
188
|
+
if (isPlainRecord(v))
|
|
189
|
+
next = pruneOperatorObject(v, walkNot);
|
|
190
|
+
}
|
|
191
|
+
if (next !== v)
|
|
192
|
+
out = withKey(out, value, k, next);
|
|
193
|
+
}
|
|
194
|
+
if (!out)
|
|
195
|
+
return value;
|
|
196
|
+
// Nothing but modifiers (or nothing at all) survived.
|
|
197
|
+
return onlyModifiers(out) ? REMOVE : out;
|
|
198
|
+
}
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// having, orderBy, cursor, with
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
/**
|
|
203
|
+
* Structural prune for positions whose values carry no JSON operands (`having`
|
|
204
|
+
* filters, orderBy entries): strip `undefined` at every plain-object level,
|
|
205
|
+
* drop emptied objects and emptied (or `undefined`) array elements. Arrays of
|
|
206
|
+
* scalars (a vector, a JSON path) are values and are left alone.
|
|
207
|
+
*
|
|
208
|
+
* `having` also drops an object stripped down to modifiers alone, the same
|
|
209
|
+
* rule `where` applies to a column operator object. orderBy does not: a
|
|
210
|
+
* JSON-path ordering is `{ path }` plus an optional direction.
|
|
211
|
+
*/
|
|
212
|
+
function pruneStructural(value, depth, dropModifierOnly) {
|
|
213
|
+
if (depth > PRUNE_DEPTH_LIMIT)
|
|
214
|
+
return value;
|
|
215
|
+
if (Array.isArray(value)) {
|
|
216
|
+
let out;
|
|
217
|
+
for (let i = 0; i < value.length; i++) {
|
|
218
|
+
const element = value[i];
|
|
219
|
+
const next = element === undefined
|
|
220
|
+
? REMOVE
|
|
221
|
+
: isPlainRecord(element)
|
|
222
|
+
? pruneStructural(element, depth + 1, dropModifierOnly)
|
|
223
|
+
: element;
|
|
224
|
+
if (next !== element && !out)
|
|
225
|
+
out = value.slice(0, i);
|
|
226
|
+
if (out && next !== REMOVE)
|
|
227
|
+
out.push(next);
|
|
228
|
+
}
|
|
229
|
+
if (!out)
|
|
230
|
+
return value;
|
|
231
|
+
return out.length === 0 ? REMOVE : out;
|
|
232
|
+
}
|
|
233
|
+
if (!isPlainRecord(value))
|
|
234
|
+
return value;
|
|
235
|
+
let out;
|
|
236
|
+
for (const k of Object.keys(value)) {
|
|
237
|
+
const v = value[k];
|
|
238
|
+
const next = v === undefined ? REMOVE : pruneStructural(v, depth + 1, dropModifierOnly);
|
|
239
|
+
if (next !== v)
|
|
240
|
+
out = withKey(out, value, k, next);
|
|
241
|
+
}
|
|
242
|
+
if (!out)
|
|
243
|
+
return value;
|
|
244
|
+
if (hasNoKeys(out) || (dropModifierOnly && onlyModifiers(out)))
|
|
245
|
+
return REMOVE;
|
|
246
|
+
return out;
|
|
247
|
+
}
|
|
248
|
+
/** True when every key left is a modifier. */
|
|
249
|
+
function onlyModifiers(obj) {
|
|
250
|
+
for (const k of Object.keys(obj)) {
|
|
251
|
+
if (!MODIFIER_KEYS.has(k))
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
/** A cursor's values are scalars: only its own keys are stripped. */
|
|
257
|
+
function pruneCursor(cursor) {
|
|
258
|
+
let out;
|
|
259
|
+
for (const k of Object.keys(cursor)) {
|
|
260
|
+
if (cursor[k] === undefined)
|
|
261
|
+
out = withKey(out, cursor, k, REMOVE);
|
|
262
|
+
}
|
|
263
|
+
if (!out)
|
|
264
|
+
return cursor;
|
|
265
|
+
return hasNoKeys(out) ? REMOVE : out;
|
|
266
|
+
}
|
|
267
|
+
function pruneWith(schema, meta, withClause, depth) {
|
|
268
|
+
if (depth > PRUNE_DEPTH_LIMIT)
|
|
269
|
+
return withClause;
|
|
270
|
+
let out;
|
|
271
|
+
for (const key of Object.keys(withClause)) {
|
|
272
|
+
const spec = withClause[key];
|
|
273
|
+
let next = spec;
|
|
274
|
+
if (spec === undefined) {
|
|
275
|
+
next = REMOVE;
|
|
276
|
+
}
|
|
277
|
+
else if (key !== '_count' && isPlainRecord(spec)) {
|
|
278
|
+
const relation = meta ? resolveRelation(meta.relations, key) : undefined;
|
|
279
|
+
next = pruneWithOptions(schema, relation ? schema.tables[relation.def.to] : undefined, spec, depth + 1);
|
|
280
|
+
}
|
|
281
|
+
if (next !== spec)
|
|
282
|
+
out = withKey(out, withClause, key, next);
|
|
283
|
+
}
|
|
284
|
+
if (!out)
|
|
285
|
+
return withClause;
|
|
286
|
+
return hasNoKeys(out) ? REMOVE : out;
|
|
287
|
+
}
|
|
288
|
+
function pruneWithOptions(schema, target, spec, depth) {
|
|
289
|
+
let out;
|
|
290
|
+
for (const k of Object.keys(spec)) {
|
|
291
|
+
const v = spec[k];
|
|
292
|
+
let next = v;
|
|
293
|
+
if (v === undefined) {
|
|
294
|
+
next = REMOVE;
|
|
295
|
+
}
|
|
296
|
+
else if (k === 'where' && isPlainRecord(v)) {
|
|
297
|
+
const pruned = pruneWhere(schema, target, v, depth);
|
|
298
|
+
next = pruned !== v && hasNoKeys(pruned) ? REMOVE : pruned;
|
|
299
|
+
}
|
|
300
|
+
else if (k === 'orderBy') {
|
|
301
|
+
next = pruneStructural(v, depth, false);
|
|
302
|
+
}
|
|
303
|
+
else if (k === 'with' && isPlainRecord(v)) {
|
|
304
|
+
next = pruneWith(schema, target, v, depth);
|
|
305
|
+
}
|
|
306
|
+
if (next !== v)
|
|
307
|
+
out = withKey(out, spec, k, next);
|
|
308
|
+
}
|
|
309
|
+
// An emptied relation spec stays an (empty) options object: `{ posts: {} }`
|
|
310
|
+
// still loads the relation, which is what `{ posts: { where: undefined } }`
|
|
311
|
+
// asked for.
|
|
312
|
+
return out ?? spec;
|
|
313
|
+
}
|
|
314
|
+
// ---------------------------------------------------------------------------
|
|
315
|
+
// Pre-scan
|
|
316
|
+
// ---------------------------------------------------------------------------
|
|
317
|
+
/**
|
|
318
|
+
* Operand keys whose ARRAY value is a list of values (an `in` list, a JSON
|
|
319
|
+
* path, a vector). The prune never edits one, and they can be long, so the
|
|
320
|
+
* pre-scan does not read them. An object under one of these names is still
|
|
321
|
+
* scanned: it is a column called `to` or `path`, not an operand.
|
|
322
|
+
*/
|
|
323
|
+
const OPERAND_LIST_KEYS = new Set(['in', 'notIn', 'has', 'hasSome', 'hasEvery', 'path', 'to']);
|
|
324
|
+
/** Past this the pre-scan answers yes and lets the prune, which has its own bound, decide. */
|
|
325
|
+
const SCAN_DEPTH_LIMIT = 4 * MAX_WHERE_DEPTH;
|
|
326
|
+
/**
|
|
327
|
+
* Whether `value` holds an `undefined` the prune might remove. Read-only and
|
|
328
|
+
* schema-blind, so a call with nothing undefined (nearly every call) costs one
|
|
329
|
+
* pass and no allocation before {@link pruneUndefinedArgs} returns its input.
|
|
330
|
+
* It may answer yes for an `undefined` the prune leaves in place (inside a JSON
|
|
331
|
+
* document); that only costs the prune's own walk.
|
|
332
|
+
*/
|
|
333
|
+
function holdsUndefined(value, depth) {
|
|
334
|
+
if (depth > SCAN_DEPTH_LIMIT)
|
|
335
|
+
return true;
|
|
336
|
+
if (Array.isArray(value)) {
|
|
337
|
+
for (let i = 0; i < value.length; i++) {
|
|
338
|
+
const element = value[i];
|
|
339
|
+
if (element === undefined)
|
|
340
|
+
return true;
|
|
341
|
+
if (typeof element === 'object' && element !== null && holdsUndefined(element, depth + 1))
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
// A class instance is a bound value, never walked (the isPlainRecord rule).
|
|
347
|
+
const proto = Object.getPrototypeOf(value);
|
|
348
|
+
if (proto !== Object.prototype && proto !== null)
|
|
349
|
+
return false;
|
|
350
|
+
const record = value;
|
|
351
|
+
for (const key in record) {
|
|
352
|
+
const v = record[key];
|
|
353
|
+
if (v === undefined)
|
|
354
|
+
return true;
|
|
355
|
+
if (typeof v !== 'object' || v === null)
|
|
356
|
+
continue;
|
|
357
|
+
if (Array.isArray(v) && OPERAND_LIST_KEYS.has(key))
|
|
358
|
+
continue;
|
|
359
|
+
if (holdsUndefined(v, depth + 1))
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
/** {@link holdsUndefined} for one top-level argument, which may be absent or a scalar. */
|
|
365
|
+
function argHoldsUndefined(value) {
|
|
366
|
+
return typeof value === 'object' && value !== null && holdsUndefined(value, 0);
|
|
367
|
+
}
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
// Public surface
|
|
370
|
+
// ---------------------------------------------------------------------------
|
|
371
|
+
/**
|
|
372
|
+
* Remove every `undefined` from the pruned positions of one operation's args
|
|
373
|
+
* (see the module comment). Returns `args` by reference when nothing changed.
|
|
374
|
+
*
|
|
375
|
+
* `table` is the operation's table; relation filters and `with` levels are
|
|
376
|
+
* resolved against `schema` so each sub-where is pruned against its own target.
|
|
377
|
+
*/
|
|
378
|
+
export function pruneUndefinedArgs(schema, table, args) {
|
|
379
|
+
if (!isPlainRecord(args))
|
|
380
|
+
return args;
|
|
381
|
+
const src = args;
|
|
382
|
+
if (!argHoldsUndefined(src.where) &&
|
|
383
|
+
!argHoldsUndefined(src.having) &&
|
|
384
|
+
!argHoldsUndefined(src.cursor) &&
|
|
385
|
+
!argHoldsUndefined(src.orderBy) &&
|
|
386
|
+
!argHoldsUndefined(src.with)) {
|
|
387
|
+
return args;
|
|
388
|
+
}
|
|
389
|
+
const meta = schema.tables[table];
|
|
390
|
+
let out;
|
|
391
|
+
const where = src.where;
|
|
392
|
+
if (isPlainRecord(where)) {
|
|
393
|
+
const next = pruneWhere(schema, meta, where, 0);
|
|
394
|
+
if (next !== where)
|
|
395
|
+
out = withKey(out, src, 'where', next);
|
|
396
|
+
}
|
|
397
|
+
const having = src.having;
|
|
398
|
+
if (isPlainRecord(having)) {
|
|
399
|
+
const next = pruneStructural(having, 0, true);
|
|
400
|
+
if (next !== having)
|
|
401
|
+
out = withKey(out, src, 'having', next === REMOVE ? {} : next);
|
|
402
|
+
}
|
|
403
|
+
const cursor = src.cursor;
|
|
404
|
+
if (isPlainRecord(cursor)) {
|
|
405
|
+
const next = pruneCursor(cursor);
|
|
406
|
+
if (next !== cursor)
|
|
407
|
+
out = withKey(out, src, 'cursor', next);
|
|
408
|
+
}
|
|
409
|
+
const orderBy = src.orderBy;
|
|
410
|
+
if (orderBy !== undefined && (isPlainRecord(orderBy) || Array.isArray(orderBy))) {
|
|
411
|
+
const next = pruneStructural(orderBy, 0, false);
|
|
412
|
+
if (next !== orderBy)
|
|
413
|
+
out = withKey(out, src, 'orderBy', next);
|
|
414
|
+
}
|
|
415
|
+
const withClause = src.with;
|
|
416
|
+
if (isPlainRecord(withClause)) {
|
|
417
|
+
const next = pruneWith(schema, meta, withClause, 0);
|
|
418
|
+
if (next !== withClause)
|
|
419
|
+
out = withKey(out, src, 'with', next);
|
|
420
|
+
}
|
|
421
|
+
return (out ?? args);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Whether pruning turned a `where` that HAD keys into one with none: every key
|
|
425
|
+
* the caller wrote was `undefined`. A `where: {}` written as `{}` is not
|
|
426
|
+
* emptied; it was empty already.
|
|
427
|
+
*/
|
|
428
|
+
export function whereEmptiedByPruning(original, pruned) {
|
|
429
|
+
if (original === pruned)
|
|
430
|
+
return false;
|
|
431
|
+
const before = isPlainRecord(original) ? original.where : undefined;
|
|
432
|
+
const after = isPlainRecord(pruned) ? pruned.where : undefined;
|
|
433
|
+
if (!isPlainRecord(before) || hasNoKeys(before))
|
|
434
|
+
return false;
|
|
435
|
+
return before !== after && (!isPlainRecord(after) || hasNoKeys(after));
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Refuse a single-row read whose `where` was emptied by pruning. `findFirst`
|
|
439
|
+
* with every filter value `undefined` would otherwise return an arbitrary row,
|
|
440
|
+
* which on a lookup by a secret (a reset token, an invite code) is another
|
|
441
|
+
* user's row. `findMany` and `count` keep "undefined means absent".
|
|
442
|
+
*/
|
|
443
|
+
export function assertWhereNotEmptiedByPruning(table, operation, original, pruned) {
|
|
444
|
+
if (!whereEmptiedByPruning(original, pruned))
|
|
445
|
+
return;
|
|
446
|
+
throw new ValidationError(`${operation} on "${table}" refused: every key in \`where\` was undefined, so this would return an ` +
|
|
447
|
+
'arbitrary row rather than one matching your filter. Check that the values you filter on are defined. ' +
|
|
448
|
+
'To ask for any row on purpose, omit `where` or pass `where: {}`.');
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* THE "has a cursor" test: a plain object holding at least one defined value.
|
|
452
|
+
* The page-order completion and the cursor planner both ask it (on PowDB too),
|
|
453
|
+
* so a page cannot be a cursor page to one and not to the other. A `cursor`
|
|
454
|
+
* written in a shape that names no row never reaches it as "no cursor": see
|
|
455
|
+
* {@link assertCursorWritten} and {@link assertCursorNotEmptied}.
|
|
456
|
+
*/
|
|
457
|
+
export function hasCursor(cursor) {
|
|
458
|
+
if (!isPlainRecord(cursor))
|
|
459
|
+
return false;
|
|
460
|
+
for (const key of Object.keys(cursor)) {
|
|
461
|
+
if (cursor[key] !== undefined)
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Refuse a `cursor` that is written but names no row: `null`, a value that is
|
|
468
|
+
* not an object, or `{}`. Read as "no cursor", such a page skipped both the
|
|
469
|
+
* cursor and the page tiebreaker, so a pager written as
|
|
470
|
+
* `cursor: last ? { id: last.id } : {}` cut its first page from a different
|
|
471
|
+
* order than every later page and skipped rows.
|
|
472
|
+
*/
|
|
473
|
+
export function assertCursorWritten(table, operation, cursor) {
|
|
474
|
+
if (cursor === undefined)
|
|
475
|
+
return;
|
|
476
|
+
if (!isPlainRecord(cursor)) {
|
|
477
|
+
throw new ValidationError(`${operation} on "${table}" refused: \`cursor\` takes an object naming the row to page after ` +
|
|
478
|
+
`(for example \`cursor: { id: lastRow.id }\`), received ${cursor === null ? 'null' : Array.isArray(cursor) ? 'an array' : `a ${typeof cursor}`}. ` +
|
|
479
|
+
'Leave `cursor` out for the first page.');
|
|
480
|
+
}
|
|
481
|
+
if (hasNoKeys(cursor)) {
|
|
482
|
+
throw new ValidationError(`${operation} on "${table}" refused: \`cursor: {}\` names no row. Leave \`cursor\` out for the first page, ` +
|
|
483
|
+
"or pass the last row's values (for example `cursor: { id: lastRow.id }`).");
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Refuse a `cursor` whose every field was `undefined`. Read as absent it would
|
|
488
|
+
* restart the walk at the first page, so a pager whose last-row value went
|
|
489
|
+
* missing would re-read page one forever. Same rule and message on every engine.
|
|
490
|
+
* `operation` names the call in the message when the caller knows it; without
|
|
491
|
+
* it the message names no operation rather than a wrong one.
|
|
492
|
+
*/
|
|
493
|
+
export function assertCursorNotEmptied(table, original, pruned, operation) {
|
|
494
|
+
const before = isPlainRecord(original) ? original.cursor : undefined;
|
|
495
|
+
if (!isPlainRecord(before) || hasNoKeys(before))
|
|
496
|
+
return;
|
|
497
|
+
if (hasCursor(isPlainRecord(pruned) ? pruned.cursor : undefined))
|
|
498
|
+
return;
|
|
499
|
+
throw new ValidationError(`${operation ? `${operation} on` : 'Query on'} "${table}" refused: every field of \`cursor\` was undefined, so ` +
|
|
500
|
+
"the page would restart at the first row. Pass the last row's values, or leave `cursor` out for the first page.");
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Internal findMany flag: the page STARTS AT the cursor row instead of after
|
|
504
|
+
* it. Prisma's cursor is inclusive (its `skip: 1` idiom drops the cursor row),
|
|
505
|
+
* so `turbine-orm/prisma-compat` sets this; core's own `cursor` stays
|
|
506
|
+
* exclusive. A symbol key, so a request body spread into findMany args cannot
|
|
507
|
+
* set it (JSON.parse never produces a symbol) and the unknown-option check,
|
|
508
|
+
* which reads `Object.keys`, never sees it. `Symbol.for` so ESM and CJS copies
|
|
509
|
+
* of the package agree on it.
|
|
510
|
+
*
|
|
511
|
+
* @internal
|
|
512
|
+
*/
|
|
513
|
+
export const CURSOR_INCLUSIVE = Symbol.for('turbine-orm.cursorInclusive');
|
|
514
|
+
/** Whether `args` carries {@link CURSOR_INCLUSIVE}. @internal */
|
|
515
|
+
export function isCursorInclusive(args) {
|
|
516
|
+
return typeof args === 'object' && args !== null && args[CURSOR_INCLUSIVE] === true;
|
|
517
|
+
}
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
*
|
|
52
52
|
* @module
|
|
53
53
|
*/
|
|
54
|
+
import { type TurbineLogger } from '../logger.js';
|
|
54
55
|
import type { AggregateArgs, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GroupByArgs, UpdateArgs, UpdateManyArgs, UpsertArgs } from './types.js';
|
|
55
56
|
/**
|
|
56
57
|
* How a name-translating consumer (today: `turbine-orm/prisma-compat`) must
|
|
@@ -109,7 +110,15 @@ export declare function applyNativeOptions(table: Readonly<Record<string, Option
|
|
|
109
110
|
/** The keys of `table` with the given kind, as a set. */
|
|
110
111
|
export declare function optionKeysOfKind(table: Readonly<Record<string, OptionKind>>, ...kinds: OptionKind[]): string[];
|
|
111
112
|
/**
|
|
112
|
-
*
|
|
113
|
+
* Keys an operation does not declare but REFUSES by name with its own error
|
|
114
|
+
* (E003 naming the key and the alternative), rather than ignoring. Warning
|
|
115
|
+
* "it is ignored" about one of these would contradict the error that follows,
|
|
116
|
+
* so the warning skips them. Every entry must have a refusal behind it;
|
|
117
|
+
* `src/test/fix-where-option-warnings.test.ts` checks that each one throws.
|
|
118
|
+
*/
|
|
119
|
+
export declare const REFUSED_OPTION_KEYS: Readonly<Record<string, ReadonlySet<string>>>;
|
|
120
|
+
/**
|
|
121
|
+
* Advice for a key that is not part of the operation's option
|
|
113
122
|
* surface, and is therefore doing nothing.
|
|
114
123
|
*
|
|
115
124
|
* The motivating case is `include`. It is Prisma's word for `with`, it is what
|
|
@@ -126,8 +135,11 @@ export declare function optionKeysOfKind(table: Readonly<Record<string, OptionKi
|
|
|
126
135
|
* working query start throwing. A warning costs a correct program nothing and
|
|
127
136
|
* tells an incorrect one exactly what happened.
|
|
128
137
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
138
|
+
* Advice: emitted only when the client's `diagnostics.advice` is on. The
|
|
139
|
+
* caller passes its advice logger, or `null` when advice is off, so this
|
|
140
|
+
* module never reads the environment. Once per `table.operation.key` per
|
|
141
|
+
* process, and total: the whole body is wrapped, because a diagnostic must
|
|
142
|
+
* never be the reason a query fails.
|
|
131
143
|
*/
|
|
132
|
-
export declare function warnUnknownQueryOptions(table: string, operation: string, args: unknown): void;
|
|
144
|
+
export declare function warnUnknownQueryOptions(table: string, operation: string, args: unknown, advice: TurbineLogger | null): void;
|
|
133
145
|
export {};
|