@prisma-next/sql-orm-client 0.5.0-dev.9 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +50 -38
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +309 -213
- package/dist/index.mjs.map +1 -1
- package/package.json +24 -25
- package/src/collection-contract.ts +19 -0
- package/src/collection.ts +103 -8
- package/src/filters.ts +1 -1
- package/src/include-strategy.ts +36 -14
- package/src/model-accessor.ts +69 -63
- package/src/mutation-executor.ts +9 -1
- package/src/query-plan-aggregate.ts +32 -13
- package/src/query-plan-meta.ts +6 -66
- package/src/query-plan-mutations.ts +31 -23
- package/src/query-plan-select.ts +16 -6
- package/src/types.ts +86 -93
- package/src/where-binding.ts +10 -2
package/src/types.ts
CHANGED
|
@@ -16,14 +16,12 @@ import {
|
|
|
16
16
|
OrderByItem,
|
|
17
17
|
ParamRef,
|
|
18
18
|
} from '@prisma-next/sql-relational-core/ast';
|
|
19
|
+
import type { Expression } from '@prisma-next/sql-relational-core/expression';
|
|
19
20
|
import type { ExecutionContext } from '@prisma-next/sql-relational-core/query-lane-context';
|
|
20
21
|
import type { ComputeColumnJsType, RuntimeScope } from '@prisma-next/sql-relational-core/types';
|
|
22
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
21
23
|
import type { RowSelection } from './collection-internal-types';
|
|
22
24
|
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
// Comparison / Filter / Order / Include
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
|
|
27
25
|
export type AggregateFn = 'count' | 'sum' | 'avg' | 'min' | 'max';
|
|
28
26
|
|
|
29
27
|
export interface IncludeScalar<Result> extends RowSelection<Result> {
|
|
@@ -63,10 +61,6 @@ export interface IncludeExpr {
|
|
|
63
61
|
readonly combine: Readonly<Record<string, IncludeCombineBranch>> | undefined;
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
// CollectionState — plain data, no query builder types
|
|
68
|
-
// ---------------------------------------------------------------------------
|
|
69
|
-
|
|
70
64
|
export interface CollectionState {
|
|
71
65
|
readonly filters: readonly AnyExpression[];
|
|
72
66
|
readonly includes: readonly IncludeExpr[];
|
|
@@ -111,10 +105,6 @@ export type DefaultCollectionTypeState = {
|
|
|
111
105
|
readonly variantName: undefined;
|
|
112
106
|
};
|
|
113
107
|
|
|
114
|
-
// ---------------------------------------------------------------------------
|
|
115
|
-
// CollectionContext — bundles lane context + runtime
|
|
116
|
-
// ---------------------------------------------------------------------------
|
|
117
|
-
|
|
118
108
|
export interface RuntimeConnection extends RuntimeScope {
|
|
119
109
|
release?(): Promise<void>;
|
|
120
110
|
transaction?(): Promise<RuntimeTransaction>;
|
|
@@ -135,10 +125,6 @@ export interface CollectionContext<TContract extends Contract<SqlStorage>> {
|
|
|
135
125
|
readonly context: ExecutionContext<TContract>;
|
|
136
126
|
}
|
|
137
127
|
|
|
138
|
-
// ---------------------------------------------------------------------------
|
|
139
|
-
// ModelAccessor — type-safe proxy for where() callbacks
|
|
140
|
-
// ---------------------------------------------------------------------------
|
|
141
|
-
|
|
142
128
|
export type ComparisonMethodFns<T> = {
|
|
143
129
|
eq(value: T): AnyExpression;
|
|
144
130
|
neq(value: T): AnyExpression;
|
|
@@ -156,8 +142,7 @@ export type ComparisonMethodFns<T> = {
|
|
|
156
142
|
};
|
|
157
143
|
|
|
158
144
|
/**
|
|
159
|
-
* Trait-gated comparison methods. Only methods whose required traits are
|
|
160
|
-
* all present in `Traits` are included.
|
|
145
|
+
* Trait-gated comparison methods. Only methods whose required traits are all present in `Traits` are included.
|
|
161
146
|
*
|
|
162
147
|
* - `traits: []` → always available (isNull, isNotNull)
|
|
163
148
|
*/
|
|
@@ -167,10 +152,6 @@ export type ComparisonMethods<T, Traits> = {
|
|
|
167
152
|
: never]: ComparisonMethodFns<T>[K];
|
|
168
153
|
};
|
|
169
154
|
|
|
170
|
-
// ---------------------------------------------------------------------------
|
|
171
|
-
// Extension operation result — returned by calling an extension method
|
|
172
|
-
// ---------------------------------------------------------------------------
|
|
173
|
-
|
|
174
155
|
type QueryOperationReturnTraits<
|
|
175
156
|
Returns,
|
|
176
157
|
TCodecTypes extends Record<string, unknown>,
|
|
@@ -195,26 +176,6 @@ type QueryOperationReturnJsType<
|
|
|
195
176
|
: unknown
|
|
196
177
|
: unknown;
|
|
197
178
|
|
|
198
|
-
type CodecArgJsType<Arg, TCodecTypes extends Record<string, unknown>> = Arg extends {
|
|
199
|
-
readonly codecId: infer CId extends string;
|
|
200
|
-
readonly nullable: infer N;
|
|
201
|
-
}
|
|
202
|
-
? CId extends keyof TCodecTypes
|
|
203
|
-
? TCodecTypes[CId] extends { readonly output: infer O }
|
|
204
|
-
? N extends true
|
|
205
|
-
? O | null
|
|
206
|
-
: O
|
|
207
|
-
: unknown
|
|
208
|
-
: unknown
|
|
209
|
-
: unknown;
|
|
210
|
-
|
|
211
|
-
type MapArgsToJsTypes<
|
|
212
|
-
Args extends readonly unknown[],
|
|
213
|
-
TCodecTypes extends Record<string, unknown>,
|
|
214
|
-
> = Args extends readonly [infer Head, ...infer Tail]
|
|
215
|
-
? [CodecArgJsType<Head, TCodecTypes>, ...MapArgsToJsTypes<Tail, TCodecTypes>]
|
|
216
|
-
: [];
|
|
217
|
-
|
|
218
179
|
type IsBooleanReturn<Returns, TCodecTypes extends Record<string, unknown>> = Returns extends {
|
|
219
180
|
readonly codecId: infer Id extends string;
|
|
220
181
|
}
|
|
@@ -227,22 +188,41 @@ type IsBooleanReturn<Returns, TCodecTypes extends Record<string, unknown>> = Ret
|
|
|
227
188
|
: false
|
|
228
189
|
: false;
|
|
229
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Extract the `{codecId, nullable}` spec carried inside an `Expression<T>`. Used to recover the op's return spec from its impl signature so the pre-existing `QueryOperationReturn*` helpers can consume it unchanged.
|
|
193
|
+
*/
|
|
194
|
+
type SpecOf<E> = E extends Expression<infer T> ? T : never;
|
|
195
|
+
|
|
196
|
+
type ImplReturnSpec<Impl> = Impl extends (...args: never[]) => infer Ret ? SpecOf<Ret> : never;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Builds the ORM column-method signature for an operation.
|
|
200
|
+
*
|
|
201
|
+
* - User args: drops the impl's first parameter (the column is bound at access time) and forwards the rest unchanged. Each remaining arg keeps its authored `CodecExpression` / `TraitExpression` shape — so callers can pass a raw JS value, another column handle (which itself implements `Expression`), or `null` when nullable.
|
|
202
|
+
* - Return: predicate ops (boolean-traited return) yield `AnyExpression`; non-predicate ops yield `ComparisonMethods<JsType, Traits>` of the return codec.
|
|
203
|
+
*/
|
|
230
204
|
type QueryOperationMethod<Op, TCodecTypes extends Record<string, unknown>> = Op extends {
|
|
231
|
-
readonly args:
|
|
232
|
-
readonly returns: infer Returns;
|
|
205
|
+
readonly impl: (...args: never[]) => unknown;
|
|
233
206
|
}
|
|
234
|
-
?
|
|
235
|
-
?
|
|
236
|
-
|
|
237
|
-
...args:
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
207
|
+
? Op['impl'] extends (first: never, ...rest: infer UserArgs extends readonly unknown[]) => unknown
|
|
208
|
+
? ImplReturnSpec<Op['impl']> extends infer Returns
|
|
209
|
+
? IsBooleanReturn<Returns, TCodecTypes> extends true
|
|
210
|
+
? (...args: UserArgs) => AnyExpression
|
|
211
|
+
: (
|
|
212
|
+
...args: UserArgs
|
|
213
|
+
) => ComparisonMethods<
|
|
214
|
+
QueryOperationReturnJsType<Returns, TCodecTypes>,
|
|
215
|
+
QueryOperationReturnTraits<Returns, TCodecTypes>
|
|
216
|
+
>
|
|
217
|
+
: never
|
|
218
|
+
: never
|
|
242
219
|
: never;
|
|
243
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Tests whether an operation's `self` dispatch hint reaches a field with the given codec identity. Codec hints match by identity; trait hints match when every required trait is present in the field codec's trait set.
|
|
223
|
+
*/
|
|
244
224
|
type OpMatchesField<Op, CodecId extends string, CT extends Record<string, unknown>> = Op extends {
|
|
245
|
-
readonly
|
|
225
|
+
readonly self: infer Self;
|
|
246
226
|
}
|
|
247
227
|
? Self extends { readonly codecId: CodecId }
|
|
248
228
|
? true
|
|
@@ -275,21 +255,43 @@ type FieldOperations<
|
|
|
275
255
|
: unknown
|
|
276
256
|
: unknown;
|
|
277
257
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Resolve the unique column ref carried by `left` so its surrounding `ParamRef` can dispatch through `forColumn`. The previous implementation only matched bare `column-ref` expressions, which lost refs the moment the expression got wrapped (`upper(f.id)`, `BinaryExpr`, function-call expressions, etc.) — and column-aware dispatch (AC-5) silently degraded for any predicate that touched a computed column.
|
|
260
|
+
*
|
|
261
|
+
* Walking via `collectColumnRefs()` and accepting only a single unambiguous ref gives `eq(upper(f.id), value)` and friends correct dispatch without inventing refs for ambiguous shapes (e.g. `eq(concat(f.firstName, f.lastName), value)` returns `undefined` and falls through to the codec-id path, which is correct for non-parameterized comparisons).
|
|
262
|
+
*/
|
|
263
|
+
function refsFromLeft(left: AnyExpression): { table: string; column: string } | undefined {
|
|
264
|
+
if (left.kind === 'column-ref') {
|
|
265
|
+
return { table: left.table, column: left.column };
|
|
266
|
+
}
|
|
267
|
+
const columnRefs = left.collectColumnRefs();
|
|
268
|
+
if (columnRefs.length !== 1) return undefined;
|
|
269
|
+
const single = columnRefs[0];
|
|
270
|
+
if (!single) return undefined;
|
|
271
|
+
return { table: single.table, column: single.column };
|
|
272
|
+
}
|
|
281
273
|
|
|
282
|
-
function param(
|
|
283
|
-
|
|
274
|
+
function param(
|
|
275
|
+
codecId: string | undefined,
|
|
276
|
+
value: unknown,
|
|
277
|
+
refs: { table: string; column: string } | undefined,
|
|
278
|
+
): ParamRef {
|
|
279
|
+
if (codecId === undefined && refs === undefined) return ParamRef.of(value);
|
|
280
|
+
return ParamRef.of(value, {
|
|
281
|
+
...ifDefined('codecId', codecId),
|
|
282
|
+
...ifDefined('refs', refs),
|
|
283
|
+
});
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
-
function paramList(
|
|
287
|
-
|
|
286
|
+
function paramList(
|
|
287
|
+
codecId: string | undefined,
|
|
288
|
+
values: readonly unknown[],
|
|
289
|
+
refs: { table: string; column: string } | undefined,
|
|
290
|
+
): ListExpression {
|
|
291
|
+
return ListExpression.of(values.map((value) => param(codecId, value, refs)));
|
|
288
292
|
}
|
|
289
293
|
|
|
290
|
-
// never[] is intentional: factories have heterogeneous signatures (value: unknown,
|
|
291
|
-
// values: readonly unknown[], pattern: string, etc.) but are only called through
|
|
292
|
-
// the typed ComparisonMethodFns interface, never through this type directly.
|
|
294
|
+
// never[] is intentional: factories have heterogeneous signatures (value: unknown, values: readonly unknown[], pattern: string, etc.) but are only called through the typed ComparisonMethodFns interface, never through this type directly.
|
|
293
295
|
type MethodFactory = (
|
|
294
296
|
left: AnyExpression,
|
|
295
297
|
codecId: string | undefined,
|
|
@@ -302,12 +304,16 @@ type ComparisonMethodMeta = {
|
|
|
302
304
|
|
|
303
305
|
function scalarComparisonMethod(op: BinaryOp) {
|
|
304
306
|
return ((left, codecId) => (value: unknown) =>
|
|
305
|
-
new BinaryExpr(op, left, param(codecId, value))) satisfies MethodFactory;
|
|
307
|
+
new BinaryExpr(op, left, param(codecId, value, refsFromLeft(left)))) satisfies MethodFactory;
|
|
306
308
|
}
|
|
307
309
|
|
|
308
310
|
function listComparisonMethod(op: BinaryOp) {
|
|
309
311
|
return ((left, codecId) => (values: readonly unknown[]) =>
|
|
310
|
-
new BinaryExpr(
|
|
312
|
+
new BinaryExpr(
|
|
313
|
+
op,
|
|
314
|
+
left,
|
|
315
|
+
paramList(codecId, values, refsFromLeft(left)),
|
|
316
|
+
)) satisfies MethodFactory;
|
|
311
317
|
}
|
|
312
318
|
|
|
313
319
|
/**
|
|
@@ -392,10 +398,11 @@ export type RelationFilterAccessor<
|
|
|
392
398
|
};
|
|
393
399
|
|
|
394
400
|
type ScalarModelAccessor<TContract extends Contract<SqlStorage>, ModelName extends string> = {
|
|
395
|
-
[K in keyof FieldsOf<TContract, ModelName> & string]:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
> &
|
|
401
|
+
[K in keyof FieldsOf<TContract, ModelName> & string]: Expression<{
|
|
402
|
+
codecId: FieldCodecId<TContract, ModelName, K>;
|
|
403
|
+
nullable: FieldNullable<TContract, ModelName, K>;
|
|
404
|
+
}> &
|
|
405
|
+
ComparisonMethods<FieldJsType<TContract, ModelName, K>, FieldTraits<TContract, ModelName, K>> &
|
|
399
406
|
FieldOperations<TContract, ModelName, K>;
|
|
400
407
|
};
|
|
401
408
|
|
|
@@ -411,18 +418,10 @@ export type ModelAccessor<
|
|
|
411
418
|
ModelName extends string,
|
|
412
419
|
> = ScalarModelAccessor<TContract, ModelName> & RelationModelAccessor<TContract, ModelName>;
|
|
413
420
|
|
|
414
|
-
// ---------------------------------------------------------------------------
|
|
415
|
-
// DefaultModelRow — all scalar fields with JS types
|
|
416
|
-
// ---------------------------------------------------------------------------
|
|
417
|
-
|
|
418
421
|
export type DefaultModelRow<TContract extends Contract<SqlStorage>, ModelName extends string> = {
|
|
419
422
|
[K in keyof FieldsOf<TContract, ModelName> & string]: FieldJsType<TContract, ModelName, K>;
|
|
420
423
|
};
|
|
421
424
|
|
|
422
|
-
// ---------------------------------------------------------------------------
|
|
423
|
-
// InferRootRow — discriminated union for polymorphic base models
|
|
424
|
-
// ---------------------------------------------------------------------------
|
|
425
|
-
|
|
426
425
|
type Simplify<T> = { [K in keyof T]: T[K] } & {};
|
|
427
426
|
|
|
428
427
|
type VariantRow<TContract extends Contract<SqlStorage>, ModelName extends string> = ModelDef<
|
|
@@ -543,10 +542,6 @@ export type ShorthandWhereFilter<
|
|
|
543
542
|
| undefined;
|
|
544
543
|
}>;
|
|
545
544
|
|
|
546
|
-
// ---------------------------------------------------------------------------
|
|
547
|
-
// Helpers for extracting fields / types from the contract
|
|
548
|
-
// ---------------------------------------------------------------------------
|
|
549
|
-
|
|
550
545
|
type ModelsOf<TContract extends Contract<SqlStorage>> =
|
|
551
546
|
TContract['models'] extends Record<string, unknown> ? TContract['models'] : Record<string, never>;
|
|
552
547
|
|
|
@@ -660,10 +655,6 @@ type FieldStorageColumn<
|
|
|
660
655
|
FieldName extends string,
|
|
661
656
|
> = ResolvedStorageColumn<TContract, ModelName, FieldName>;
|
|
662
657
|
|
|
663
|
-
// ---------------------------------------------------------------------------
|
|
664
|
-
// Field trait resolution from contract CodecTypes
|
|
665
|
-
// ---------------------------------------------------------------------------
|
|
666
|
-
|
|
667
658
|
type FieldCodecId<
|
|
668
659
|
TContract extends Contract<SqlStorage>,
|
|
669
660
|
ModelName extends string,
|
|
@@ -674,6 +665,16 @@ type FieldCodecId<
|
|
|
674
665
|
? Id
|
|
675
666
|
: never;
|
|
676
667
|
|
|
668
|
+
type FieldNullable<
|
|
669
|
+
TContract extends Contract<SqlStorage>,
|
|
670
|
+
ModelName extends string,
|
|
671
|
+
FieldName extends string,
|
|
672
|
+
> = FieldStorageColumn<TContract, ModelName, FieldName> extends {
|
|
673
|
+
readonly nullable: infer N extends boolean;
|
|
674
|
+
}
|
|
675
|
+
? N
|
|
676
|
+
: false;
|
|
677
|
+
|
|
677
678
|
type FieldTraits<
|
|
678
679
|
TContract extends Contract<SqlStorage>,
|
|
679
680
|
ModelName extends string,
|
|
@@ -774,10 +775,6 @@ export type CreateInput<TContract extends Contract<SqlStorage>, ModelName extend
|
|
|
774
775
|
> &
|
|
775
776
|
RelationMutationFields<TContract, ModelName>;
|
|
776
777
|
|
|
777
|
-
// ---------------------------------------------------------------------------
|
|
778
|
-
// Polymorphic write gating
|
|
779
|
-
// ---------------------------------------------------------------------------
|
|
780
|
-
|
|
781
778
|
type IsPolymorphicBase<TContract extends Contract<SqlStorage>, ModelName extends string> = ModelDef<
|
|
782
779
|
TContract,
|
|
783
780
|
ModelName
|
|
@@ -1049,10 +1046,6 @@ export type MutationUpdateInput<
|
|
|
1049
1046
|
ModelName extends string,
|
|
1050
1047
|
> = Partial<DefaultModelRow<TContract, ModelName>> & RelationMutationFields<TContract, ModelName>;
|
|
1051
1048
|
|
|
1052
|
-
// ---------------------------------------------------------------------------
|
|
1053
|
-
// Relation helpers
|
|
1054
|
-
// ---------------------------------------------------------------------------
|
|
1055
|
-
|
|
1056
1049
|
type ModelRelations<TContract extends Contract<SqlStorage>, ModelName extends string> = ModelDef<
|
|
1057
1050
|
TContract,
|
|
1058
1051
|
ModelName
|
package/src/where-binding.ts
CHANGED
|
@@ -122,7 +122,10 @@ function createParamRef(
|
|
|
122
122
|
if (!codecId) {
|
|
123
123
|
throw new Error(`Unknown column "${columnRef.column}" in table "${columnRef.table}"`);
|
|
124
124
|
}
|
|
125
|
-
return ParamRef.of(value, {
|
|
125
|
+
return ParamRef.of(value, {
|
|
126
|
+
codecId,
|
|
127
|
+
refs: { table: columnRef.table, column: columnRef.column },
|
|
128
|
+
});
|
|
126
129
|
}
|
|
127
130
|
|
|
128
131
|
function createExpressionBinder(contract: Contract<SqlStorage>): ExpressionRewriter {
|
|
@@ -170,7 +173,12 @@ function bindSelectAst(contract: Contract<SqlStorage>, ast: SelectAst): SelectAs
|
|
|
170
173
|
joins: ast.joins?.map((join) => bindJoin(contract, join)),
|
|
171
174
|
projection: ast.projection.map(
|
|
172
175
|
(projection) =>
|
|
173
|
-
new ProjectionItem(
|
|
176
|
+
new ProjectionItem(
|
|
177
|
+
projection.alias,
|
|
178
|
+
bindProjectionExpr(contract, projection.expr),
|
|
179
|
+
projection.codecId,
|
|
180
|
+
projection.refs,
|
|
181
|
+
),
|
|
174
182
|
),
|
|
175
183
|
where: ast.where ? bindWhereExprNode(contract, ast.where) : undefined,
|
|
176
184
|
orderBy: ast.orderBy?.map((orderItem) => bindOrderByItem(contract, orderItem)),
|