turbine-orm 0.56.0 → 0.57.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 +16 -1
- package/dist/cjs/cli/index.js +254 -37
- package/dist/cjs/client.js +3 -39
- package/dist/cjs/plan-divergence.d.ts +305 -38
- package/dist/cjs/plan-divergence.js +413 -67
- package/dist/cjs/prisma-compat.d.ts +32 -1
- package/dist/cjs/prisma-compat.js +297 -41
- package/dist/cjs/query/index.d.ts +2 -0
- package/dist/cjs/query/index.js +18 -1
- package/dist/cjs/query/option-surface.d.ts +100 -0
- package/dist/cjs/query/option-surface.js +214 -0
- package/dist/cjs/query/utils.d.ts +16 -0
- package/dist/cjs/query/utils.js +50 -0
- package/dist/cjs/query/warn-registry.d.ts +8 -0
- package/dist/cjs/query/warn-registry.js +8 -0
- package/dist/cli/index.js +255 -38
- package/dist/client.js +4 -40
- package/dist/plan-divergence.d.ts +305 -38
- package/dist/plan-divergence.js +412 -67
- package/dist/prisma-compat.d.ts +32 -1
- package/dist/prisma-compat.js +297 -41
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +1 -0
- package/dist/query/option-surface.d.ts +100 -0
- package/dist/query/option-surface.js +209 -0
- package/dist/query/utils.d.ts +16 -0
- package/dist/query/utils.js +49 -0
- package/dist/query/warn-registry.d.ts +8 -0
- package/dist/query/warn-registry.js +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm, the query-argument OPTION SURFACE as runtime data.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this file exists
|
|
5
|
+
*
|
|
6
|
+
* TypeScript erases interfaces, so `FindManyArgs` does not exist at runtime and
|
|
7
|
+
* any layer that has to decide, key by key, what to do with an args object has
|
|
8
|
+
* to keep its own hand-written list. `turbine-orm/prisma-compat` is exactly
|
|
9
|
+
* such a layer: it builds a FRESH turbine args object out of Prisma-shaped
|
|
10
|
+
* input and copies over the keys it recognizes. Every time core gained a
|
|
11
|
+
* query-level option, that ad-hoc allowlist silently failed to gain it, and the
|
|
12
|
+
* option was accepted by the caller's type-checker and then dropped on the
|
|
13
|
+
* floor. There was no feedback of any kind: no error, no warning, no test.
|
|
14
|
+
*
|
|
15
|
+
* These tables are the fix. Each one is a `Record<keyof SomeArgs<Row>,
|
|
16
|
+
* OptionKind>`, the same mechanism `TURBINE_CONFIG_KEYS` (client.ts) uses for
|
|
17
|
+
* the client-config surface, and it binds the compiler in BOTH directions:
|
|
18
|
+
*
|
|
19
|
+
* - add an option to an arg interface and this file stops compiling until a
|
|
20
|
+
* human classifies it ("Property 'fooMode' is missing in type ..."), so an
|
|
21
|
+
* option can no longer be stranded BY OMISSION;
|
|
22
|
+
* - list a key here that is not on the interface and it fails as an excess
|
|
23
|
+
* property, so a table can never drift into describing an option that does
|
|
24
|
+
* not exist.
|
|
25
|
+
*
|
|
26
|
+
* It deliberately does NOT make "add the option in one place" sufficient: it
|
|
27
|
+
* makes the second edit a BUILD FAILURE rather than a silent drop. That trade is
|
|
28
|
+
* intentional. A passthrough-by-default translator would satisfy the shorter
|
|
29
|
+
* wording and be actively wrong, because two of the options below carry FIELD
|
|
30
|
+
* NAMES in their values (`optimisticLock.field`, `distinctOn.columns`), which a
|
|
31
|
+
* compat layer must rename before core ever sees them. Copying those blind
|
|
32
|
+
* works on a schema whose names happen to coincide and breaks on one that
|
|
33
|
+
* renames a column, i.e. it makes the failure mode depend on the schema.
|
|
34
|
+
*
|
|
35
|
+
* ## THE ONE RULE for classifying a new option
|
|
36
|
+
*
|
|
37
|
+
* Classify a key `'native'` ONLY when its value contains no field, relation,
|
|
38
|
+
* column, or model NAME. If the value names anything in the schema, it is
|
|
39
|
+
* `'prisma'`: a name-translating consumer has to walk it by hand.
|
|
40
|
+
*
|
|
41
|
+
* @module
|
|
42
|
+
*/
|
|
43
|
+
import type { AggregateArgs, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GroupByArgs, UpdateArgs, UpdateManyArgs, UpsertArgs } from './types.js';
|
|
44
|
+
/**
|
|
45
|
+
* How a name-translating consumer (today: `turbine-orm/prisma-compat`) must
|
|
46
|
+
* handle one key of a turbine query-arg interface.
|
|
47
|
+
*
|
|
48
|
+
* - `'prisma'`, the key is a Prisma concept too, or its VALUE carries names
|
|
49
|
+
* that live in the caller's naming space. Translated by hand; NEVER copied
|
|
50
|
+
* verbatim.
|
|
51
|
+
* - `'native'`, turbine-only and its value is opaque to naming (a boolean, a
|
|
52
|
+
* number, a list of table names). Copied through untouched.
|
|
53
|
+
* - `'nativeAlias'`, the turbine SPELLING of a concept the caller's surface
|
|
54
|
+
* already has under another name (`with`/`limit`/`offset` vs
|
|
55
|
+
* `include`/`take`/`skip`). Refused, because forwarding it would collide with
|
|
56
|
+
* the translated key and would carry turbine relation names into a call
|
|
57
|
+
* written in the caller's names. The diagnostic names the right key instead.
|
|
58
|
+
* - `'internal'`, not reachable through the compat surface at all
|
|
59
|
+
* (`batchSize` belongs to a streaming method compat does not expose), so it
|
|
60
|
+
* is not part of any known set and passing it is reported as unknown.
|
|
61
|
+
*/
|
|
62
|
+
export type OptionKind = 'prisma' | 'native' | 'nativeAlias' | 'internal';
|
|
63
|
+
/**
|
|
64
|
+
* The generic parameter the tables are instantiated at. `keyof FindManyArgs<T>`
|
|
65
|
+
* is the literal union of the DECLARED key names regardless of `T`, so a
|
|
66
|
+
* neutral row type keeps the tables stable and free of entity coupling.
|
|
67
|
+
*/
|
|
68
|
+
type Row = Record<string, unknown>;
|
|
69
|
+
/** One option table: every declared key of one arg interface, classified. */
|
|
70
|
+
export type OptionTable<A> = Readonly<Record<keyof A, OptionKind>>;
|
|
71
|
+
export declare const FIND_UNIQUE_OPTIONS: OptionTable<FindUniqueArgs<Row>>;
|
|
72
|
+
export declare const FIND_MANY_OPTIONS: OptionTable<FindManyArgs<Row>>;
|
|
73
|
+
export declare const FIND_MANY_STREAM_OPTIONS: OptionTable<FindManyStreamArgs<Row>>;
|
|
74
|
+
export declare const CREATE_OPTIONS: OptionTable<CreateArgs<Row>>;
|
|
75
|
+
export declare const CREATE_MANY_OPTIONS: OptionTable<CreateManyArgs<Row>>;
|
|
76
|
+
export declare const UPDATE_OPTIONS: OptionTable<UpdateArgs<Row>>;
|
|
77
|
+
export declare const UPDATE_MANY_OPTIONS: OptionTable<UpdateManyArgs<Row>>;
|
|
78
|
+
export declare const DELETE_OPTIONS: OptionTable<DeleteArgs<Row>>;
|
|
79
|
+
export declare const DELETE_MANY_OPTIONS: OptionTable<DeleteManyArgs<Row>>;
|
|
80
|
+
export declare const UPSERT_OPTIONS: OptionTable<UpsertArgs<Row>>;
|
|
81
|
+
export declare const COUNT_OPTIONS: OptionTable<CountArgs<Row>>;
|
|
82
|
+
export declare const AGGREGATE_OPTIONS: OptionTable<AggregateArgs<Row>>;
|
|
83
|
+
export declare const GROUP_BY_OPTIONS: OptionTable<GroupByArgs<Row>>;
|
|
84
|
+
/**
|
|
85
|
+
* Every table, so a test can assert the set is complete and well-formed without
|
|
86
|
+
* naming each one (a table stubbed out during a refactor shows up here).
|
|
87
|
+
*/
|
|
88
|
+
export declare const ALL_OPTION_TABLES: Readonly<Record<string, Readonly<Record<string, OptionKind>>>>;
|
|
89
|
+
/**
|
|
90
|
+
* Copy every `'native'` key present on `src` onto `dst`.
|
|
91
|
+
*
|
|
92
|
+
* Iterates `src` (a small caller-supplied object) rather than the table, so the
|
|
93
|
+
* cost is proportional to what was actually passed. `undefined` values are
|
|
94
|
+
* skipped: `{ ...maybeOpts }` routinely materializes keys with no value, and
|
|
95
|
+
* writing `undefined` through would be indistinguishable from passing it.
|
|
96
|
+
*/
|
|
97
|
+
export declare function applyNativeOptions(table: Readonly<Record<string, OptionKind>>, src: Record<string, unknown>, dst: Record<string, unknown>): void;
|
|
98
|
+
/** The keys of `table` with the given kind, as a set. */
|
|
99
|
+
export declare function optionKeysOfKind(table: Readonly<Record<string, OptionKind>>, ...kinds: OptionKind[]): string[];
|
|
100
|
+
export {};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* turbine-orm, the query-argument OPTION SURFACE as runtime data.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this file exists
|
|
6
|
+
*
|
|
7
|
+
* TypeScript erases interfaces, so `FindManyArgs` does not exist at runtime and
|
|
8
|
+
* any layer that has to decide, key by key, what to do with an args object has
|
|
9
|
+
* to keep its own hand-written list. `turbine-orm/prisma-compat` is exactly
|
|
10
|
+
* such a layer: it builds a FRESH turbine args object out of Prisma-shaped
|
|
11
|
+
* input and copies over the keys it recognizes. Every time core gained a
|
|
12
|
+
* query-level option, that ad-hoc allowlist silently failed to gain it, and the
|
|
13
|
+
* option was accepted by the caller's type-checker and then dropped on the
|
|
14
|
+
* floor. There was no feedback of any kind: no error, no warning, no test.
|
|
15
|
+
*
|
|
16
|
+
* These tables are the fix. Each one is a `Record<keyof SomeArgs<Row>,
|
|
17
|
+
* OptionKind>`, the same mechanism `TURBINE_CONFIG_KEYS` (client.ts) uses for
|
|
18
|
+
* the client-config surface, and it binds the compiler in BOTH directions:
|
|
19
|
+
*
|
|
20
|
+
* - add an option to an arg interface and this file stops compiling until a
|
|
21
|
+
* human classifies it ("Property 'fooMode' is missing in type ..."), so an
|
|
22
|
+
* option can no longer be stranded BY OMISSION;
|
|
23
|
+
* - list a key here that is not on the interface and it fails as an excess
|
|
24
|
+
* property, so a table can never drift into describing an option that does
|
|
25
|
+
* not exist.
|
|
26
|
+
*
|
|
27
|
+
* It deliberately does NOT make "add the option in one place" sufficient: it
|
|
28
|
+
* makes the second edit a BUILD FAILURE rather than a silent drop. That trade is
|
|
29
|
+
* intentional. A passthrough-by-default translator would satisfy the shorter
|
|
30
|
+
* wording and be actively wrong, because two of the options below carry FIELD
|
|
31
|
+
* NAMES in their values (`optimisticLock.field`, `distinctOn.columns`), which a
|
|
32
|
+
* compat layer must rename before core ever sees them. Copying those blind
|
|
33
|
+
* works on a schema whose names happen to coincide and breaks on one that
|
|
34
|
+
* renames a column, i.e. it makes the failure mode depend on the schema.
|
|
35
|
+
*
|
|
36
|
+
* ## THE ONE RULE for classifying a new option
|
|
37
|
+
*
|
|
38
|
+
* Classify a key `'native'` ONLY when its value contains no field, relation,
|
|
39
|
+
* column, or model NAME. If the value names anything in the schema, it is
|
|
40
|
+
* `'prisma'`: a name-translating consumer has to walk it by hand.
|
|
41
|
+
*
|
|
42
|
+
* @module
|
|
43
|
+
*/
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.ALL_OPTION_TABLES = exports.GROUP_BY_OPTIONS = exports.AGGREGATE_OPTIONS = exports.COUNT_OPTIONS = exports.UPSERT_OPTIONS = exports.DELETE_MANY_OPTIONS = exports.DELETE_OPTIONS = exports.UPDATE_MANY_OPTIONS = exports.UPDATE_OPTIONS = exports.CREATE_MANY_OPTIONS = exports.CREATE_OPTIONS = exports.FIND_MANY_STREAM_OPTIONS = exports.FIND_MANY_OPTIONS = exports.FIND_UNIQUE_OPTIONS = void 0;
|
|
46
|
+
exports.applyNativeOptions = applyNativeOptions;
|
|
47
|
+
exports.optionKeysOfKind = optionKeysOfKind;
|
|
48
|
+
exports.FIND_UNIQUE_OPTIONS = {
|
|
49
|
+
where: 'prisma',
|
|
50
|
+
select: 'prisma',
|
|
51
|
+
omit: 'prisma',
|
|
52
|
+
// Prisma spells this `include`; forwarding `with` would collide with the
|
|
53
|
+
// translated projection and carry turbine relation names into a Prisma call.
|
|
54
|
+
with: 'nativeAlias',
|
|
55
|
+
// Same key on both surfaces, DIFFERENT value domains ('query' | 'join' vs
|
|
56
|
+
// 'join' | 'batched' | 'auto' | 'flatten'), so the value needs mapping.
|
|
57
|
+
relationLoadStrategy: 'prisma',
|
|
58
|
+
timeout: 'native',
|
|
59
|
+
stableRelationOrder: 'native',
|
|
60
|
+
skipGlobalFilters: 'native',
|
|
61
|
+
includePii: 'native',
|
|
62
|
+
forceCustomPlan: 'native',
|
|
63
|
+
};
|
|
64
|
+
exports.FIND_MANY_OPTIONS = {
|
|
65
|
+
where: 'prisma',
|
|
66
|
+
select: 'prisma',
|
|
67
|
+
omit: 'prisma',
|
|
68
|
+
orderBy: 'prisma',
|
|
69
|
+
cursor: 'prisma',
|
|
70
|
+
take: 'prisma',
|
|
71
|
+
distinct: 'prisma',
|
|
72
|
+
relationLoadStrategy: 'prisma',
|
|
73
|
+
with: 'nativeAlias',
|
|
74
|
+
limit: 'nativeAlias',
|
|
75
|
+
offset: 'nativeAlias',
|
|
76
|
+
timeout: 'native',
|
|
77
|
+
stableRelationOrder: 'native',
|
|
78
|
+
skipGlobalFilters: 'native',
|
|
79
|
+
warnOnUnlimited: 'native',
|
|
80
|
+
includePii: 'native',
|
|
81
|
+
forceCustomPlan: 'native',
|
|
82
|
+
};
|
|
83
|
+
exports.FIND_MANY_STREAM_OPTIONS = {
|
|
84
|
+
...exports.FIND_MANY_OPTIONS,
|
|
85
|
+
// No streaming delegate exists on the compat surface, so this is not a known
|
|
86
|
+
// key there and passing it is reported rather than quietly ignored.
|
|
87
|
+
batchSize: 'internal',
|
|
88
|
+
};
|
|
89
|
+
exports.CREATE_OPTIONS = {
|
|
90
|
+
data: 'prisma',
|
|
91
|
+
timeout: 'native',
|
|
92
|
+
};
|
|
93
|
+
exports.CREATE_MANY_OPTIONS = {
|
|
94
|
+
data: 'prisma',
|
|
95
|
+
skipDuplicates: 'prisma',
|
|
96
|
+
timeout: 'native',
|
|
97
|
+
};
|
|
98
|
+
exports.UPDATE_OPTIONS = {
|
|
99
|
+
where: 'prisma',
|
|
100
|
+
data: 'prisma',
|
|
101
|
+
// `{ field, expected }`, and `field` is a FIELD NAME, so it has to be renamed
|
|
102
|
+
// into turbine's naming space rather than copied. See THE ONE RULE above.
|
|
103
|
+
optimisticLock: 'prisma',
|
|
104
|
+
timeout: 'native',
|
|
105
|
+
allowFullTableScan: 'native',
|
|
106
|
+
skipGlobalFilters: 'native',
|
|
107
|
+
};
|
|
108
|
+
exports.UPDATE_MANY_OPTIONS = {
|
|
109
|
+
where: 'prisma',
|
|
110
|
+
data: 'prisma',
|
|
111
|
+
timeout: 'native',
|
|
112
|
+
allowFullTableScan: 'native',
|
|
113
|
+
skipGlobalFilters: 'native',
|
|
114
|
+
};
|
|
115
|
+
exports.DELETE_OPTIONS = {
|
|
116
|
+
where: 'prisma',
|
|
117
|
+
timeout: 'native',
|
|
118
|
+
allowFullTableScan: 'native',
|
|
119
|
+
skipGlobalFilters: 'native',
|
|
120
|
+
};
|
|
121
|
+
exports.DELETE_MANY_OPTIONS = {
|
|
122
|
+
where: 'prisma',
|
|
123
|
+
timeout: 'native',
|
|
124
|
+
allowFullTableScan: 'native',
|
|
125
|
+
skipGlobalFilters: 'native',
|
|
126
|
+
};
|
|
127
|
+
exports.UPSERT_OPTIONS = {
|
|
128
|
+
where: 'prisma',
|
|
129
|
+
create: 'prisma',
|
|
130
|
+
update: 'prisma',
|
|
131
|
+
timeout: 'native',
|
|
132
|
+
skipGlobalFilters: 'native',
|
|
133
|
+
};
|
|
134
|
+
exports.COUNT_OPTIONS = {
|
|
135
|
+
where: 'prisma',
|
|
136
|
+
timeout: 'native',
|
|
137
|
+
skipGlobalFilters: 'native',
|
|
138
|
+
forceCustomPlan: 'native',
|
|
139
|
+
};
|
|
140
|
+
exports.AGGREGATE_OPTIONS = {
|
|
141
|
+
where: 'prisma',
|
|
142
|
+
_count: 'prisma',
|
|
143
|
+
_sum: 'prisma',
|
|
144
|
+
_avg: 'prisma',
|
|
145
|
+
_min: 'prisma',
|
|
146
|
+
_max: 'prisma',
|
|
147
|
+
timeout: 'native',
|
|
148
|
+
skipGlobalFilters: 'native',
|
|
149
|
+
includePii: 'native',
|
|
150
|
+
forceCustomPlan: 'native',
|
|
151
|
+
};
|
|
152
|
+
exports.GROUP_BY_OPTIONS = {
|
|
153
|
+
by: 'prisma',
|
|
154
|
+
where: 'prisma',
|
|
155
|
+
having: 'prisma',
|
|
156
|
+
orderBy: 'prisma',
|
|
157
|
+
_count: 'prisma',
|
|
158
|
+
_sum: 'prisma',
|
|
159
|
+
_avg: 'prisma',
|
|
160
|
+
_min: 'prisma',
|
|
161
|
+
_max: 'prisma',
|
|
162
|
+
// `{ columns, orderBy }`, both in FIELD-NAME space. See THE ONE RULE.
|
|
163
|
+
distinctOn: 'prisma',
|
|
164
|
+
limit: 'nativeAlias',
|
|
165
|
+
offset: 'nativeAlias',
|
|
166
|
+
timeout: 'native',
|
|
167
|
+
skipGlobalFilters: 'native',
|
|
168
|
+
includePii: 'native',
|
|
169
|
+
forceCustomPlan: 'native',
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Every table, so a test can assert the set is complete and well-formed without
|
|
173
|
+
* naming each one (a table stubbed out during a refactor shows up here).
|
|
174
|
+
*/
|
|
175
|
+
exports.ALL_OPTION_TABLES = {
|
|
176
|
+
findUnique: exports.FIND_UNIQUE_OPTIONS,
|
|
177
|
+
findMany: exports.FIND_MANY_OPTIONS,
|
|
178
|
+
findManyStream: exports.FIND_MANY_STREAM_OPTIONS,
|
|
179
|
+
create: exports.CREATE_OPTIONS,
|
|
180
|
+
createMany: exports.CREATE_MANY_OPTIONS,
|
|
181
|
+
update: exports.UPDATE_OPTIONS,
|
|
182
|
+
updateMany: exports.UPDATE_MANY_OPTIONS,
|
|
183
|
+
delete: exports.DELETE_OPTIONS,
|
|
184
|
+
deleteMany: exports.DELETE_MANY_OPTIONS,
|
|
185
|
+
upsert: exports.UPSERT_OPTIONS,
|
|
186
|
+
count: exports.COUNT_OPTIONS,
|
|
187
|
+
aggregate: exports.AGGREGATE_OPTIONS,
|
|
188
|
+
groupBy: exports.GROUP_BY_OPTIONS,
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Copy every `'native'` key present on `src` onto `dst`.
|
|
192
|
+
*
|
|
193
|
+
* Iterates `src` (a small caller-supplied object) rather than the table, so the
|
|
194
|
+
* cost is proportional to what was actually passed. `undefined` values are
|
|
195
|
+
* skipped: `{ ...maybeOpts }` routinely materializes keys with no value, and
|
|
196
|
+
* writing `undefined` through would be indistinguishable from passing it.
|
|
197
|
+
*/
|
|
198
|
+
function applyNativeOptions(table, src, dst) {
|
|
199
|
+
// Total on any input: a delegate whose args are optional can be called with
|
|
200
|
+
// none, and a diagnostic-adjacent helper must not be the thing that throws.
|
|
201
|
+
if (src === null || typeof src !== 'object')
|
|
202
|
+
return;
|
|
203
|
+
for (const key of Object.keys(src)) {
|
|
204
|
+
if (table[key] !== 'native')
|
|
205
|
+
continue;
|
|
206
|
+
const value = src[key];
|
|
207
|
+
if (value !== undefined)
|
|
208
|
+
dst[key] = value;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/** The keys of `table` with the given kind, as a set. */
|
|
212
|
+
function optionKeysOfKind(table, ...kinds) {
|
|
213
|
+
return Object.keys(table).filter((k) => kinds.includes(table[k]));
|
|
214
|
+
}
|
|
@@ -420,6 +420,22 @@ export declare function jsonWireCoercionOid(pgType: string | undefined): number
|
|
|
420
420
|
export declare function coerceJsonWireValue(oid: number, value: unknown): unknown;
|
|
421
421
|
/** The closest name in `candidates` to `input`, or null when none is close. */
|
|
422
422
|
export declare function closestName(input: string, candidates: Iterable<string>): string | null;
|
|
423
|
+
/**
|
|
424
|
+
* The real option key `key` most likely meant, or null when nothing is close.
|
|
425
|
+
*
|
|
426
|
+
* Shared by every "unknown option" diagnostic (the client-config warner in
|
|
427
|
+
* client.ts and the prisma-compat query-option warner), so a reader who has
|
|
428
|
+
* seen one recognizes the ranking in the other.
|
|
429
|
+
*
|
|
430
|
+
* {@link closestName} decides first, which is bounded by edit distance and
|
|
431
|
+
* covers typos. It does not cover the miss these warnings exist for: a guessed
|
|
432
|
+
* name that omits a whole WORD. `logParams` is five edits from `logQueryParams`,
|
|
433
|
+
* past the bound, yet it names the same words in the same order; likewise
|
|
434
|
+
* `customPlan` for `forceCustomPlan`. So a second pass accepts a candidate whose
|
|
435
|
+
* camelCase words CONTAIN the guess's words in order, preferring the one that
|
|
436
|
+
* adds fewest words.
|
|
437
|
+
*/
|
|
438
|
+
export declare function suggestKey(key: string, candidates: Iterable<string>): string | null;
|
|
423
439
|
/**
|
|
424
440
|
* The "unknown field" error text, listing RELATIONS as well as columns.
|
|
425
441
|
*
|
package/dist/cjs/query/utils.js
CHANGED
|
@@ -34,6 +34,7 @@ exports.registerUtcTemporalParsers = registerUtcTemporalParsers;
|
|
|
34
34
|
exports.jsonWireCoercionOid = jsonWireCoercionOid;
|
|
35
35
|
exports.coerceJsonWireValue = coerceJsonWireValue;
|
|
36
36
|
exports.closestName = closestName;
|
|
37
|
+
exports.suggestKey = suggestKey;
|
|
37
38
|
exports.unknownFieldMessage = unknownFieldMessage;
|
|
38
39
|
const pg_1 = __importDefault(require("pg"));
|
|
39
40
|
const schema_js_1 = require("../schema.js");
|
|
@@ -814,6 +815,55 @@ function closestName(input, candidates) {
|
|
|
814
815
|
}
|
|
815
816
|
return best;
|
|
816
817
|
}
|
|
818
|
+
/** camelCase name → its lowercased words (`logQueryParams` → log, query, params). */
|
|
819
|
+
function camelWords(name) {
|
|
820
|
+
return name
|
|
821
|
+
.split(/(?=[A-Z])/)
|
|
822
|
+
.map((w) => w.toLowerCase())
|
|
823
|
+
.filter(Boolean);
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* The real option key `key` most likely meant, or null when nothing is close.
|
|
827
|
+
*
|
|
828
|
+
* Shared by every "unknown option" diagnostic (the client-config warner in
|
|
829
|
+
* client.ts and the prisma-compat query-option warner), so a reader who has
|
|
830
|
+
* seen one recognizes the ranking in the other.
|
|
831
|
+
*
|
|
832
|
+
* {@link closestName} decides first, which is bounded by edit distance and
|
|
833
|
+
* covers typos. It does not cover the miss these warnings exist for: a guessed
|
|
834
|
+
* name that omits a whole WORD. `logParams` is five edits from `logQueryParams`,
|
|
835
|
+
* past the bound, yet it names the same words in the same order; likewise
|
|
836
|
+
* `customPlan` for `forceCustomPlan`. So a second pass accepts a candidate whose
|
|
837
|
+
* camelCase words CONTAIN the guess's words in order, preferring the one that
|
|
838
|
+
* adds fewest words.
|
|
839
|
+
*/
|
|
840
|
+
function suggestKey(key, candidates) {
|
|
841
|
+
const direct = closestName(key, candidates);
|
|
842
|
+
if (direct)
|
|
843
|
+
return direct;
|
|
844
|
+
const wanted = camelWords(key);
|
|
845
|
+
if (wanted.length < 2)
|
|
846
|
+
return null;
|
|
847
|
+
let best = null;
|
|
848
|
+
let bestExtra = Number.POSITIVE_INFINITY;
|
|
849
|
+
for (const candidate of candidates) {
|
|
850
|
+
const words = camelWords(candidate);
|
|
851
|
+
if (words.length <= wanted.length)
|
|
852
|
+
continue;
|
|
853
|
+
let i = 0;
|
|
854
|
+
for (const w of words)
|
|
855
|
+
if (w === wanted[i])
|
|
856
|
+
i++;
|
|
857
|
+
if (i !== wanted.length)
|
|
858
|
+
continue;
|
|
859
|
+
const extra = words.length - wanted.length;
|
|
860
|
+
if (extra < bestExtra) {
|
|
861
|
+
bestExtra = extra;
|
|
862
|
+
best = candidate;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
return best;
|
|
866
|
+
}
|
|
817
867
|
/**
|
|
818
868
|
* The "unknown field" error text, listing RELATIONS as well as columns.
|
|
819
869
|
*
|
|
@@ -96,6 +96,14 @@ export declare const WARN_NS: {
|
|
|
96
96
|
* `warnParserOverwrite`). Keyed on the OID.
|
|
97
97
|
*/
|
|
98
98
|
readonly parserOverwrite: "parserOverwrite";
|
|
99
|
+
/**
|
|
100
|
+
* A key on the args object passed to a `turbine-orm/prisma-compat` delegate
|
|
101
|
+
* call that is neither a Prisma arg for that operation nor a turbine-native
|
|
102
|
+
* query option (prisma-compat.ts `warnUnknownQueryOptions`). Keyed on
|
|
103
|
+
* `model.operation.key`, so the same typo on two models is two reports, and
|
|
104
|
+
* a million executions of one call site is one.
|
|
105
|
+
*/
|
|
106
|
+
readonly unknownQueryOption: "unknownQueryOption";
|
|
99
107
|
/**
|
|
100
108
|
* `planCacheMode` was set on a client given an EXTERNAL pool, where Turbine
|
|
101
109
|
* runs no connection setup, so the option is a no-op (client.ts constructor).
|
|
@@ -137,6 +137,14 @@ exports.WARN_NS = {
|
|
|
137
137
|
* `warnParserOverwrite`). Keyed on the OID.
|
|
138
138
|
*/
|
|
139
139
|
parserOverwrite: 'parserOverwrite',
|
|
140
|
+
/**
|
|
141
|
+
* A key on the args object passed to a `turbine-orm/prisma-compat` delegate
|
|
142
|
+
* call that is neither a Prisma arg for that operation nor a turbine-native
|
|
143
|
+
* query option (prisma-compat.ts `warnUnknownQueryOptions`). Keyed on
|
|
144
|
+
* `model.operation.key`, so the same typo on two models is two reports, and
|
|
145
|
+
* a million executions of one call site is one.
|
|
146
|
+
*/
|
|
147
|
+
unknownQueryOption: 'unknownQueryOption',
|
|
140
148
|
/**
|
|
141
149
|
* `planCacheMode` was set on a client given an EXTERNAL pool, where Turbine
|
|
142
150
|
* runs no connection setup, so the option is a no-op (client.ts constructor).
|