@prisma-next/sql-orm-lane 0.0.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/README.md +84 -0
- package/dist/chunk-JOTSRS66.js +1707 -0
- package/dist/chunk-JOTSRS66.js.map +1 -0
- package/dist/exports/orm.d.ts +5 -0
- package/dist/exports/orm.js +7 -0
- package/dist/exports/orm.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/orm-C_3ipYf3.d.ts +150 -0
- package/package.json +43 -0
|
@@ -0,0 +1,1707 @@
|
|
|
1
|
+
// src/orm/builder.ts
|
|
2
|
+
import { planInvalid as planInvalid5 } from "@prisma-next/plan";
|
|
3
|
+
import { schema as schema4 } from "@prisma-next/sql-relational-core/schema";
|
|
4
|
+
|
|
5
|
+
// src/utils/ast.ts
|
|
6
|
+
import {
|
|
7
|
+
createBinaryExpr,
|
|
8
|
+
createColumnRef,
|
|
9
|
+
createDeleteAst,
|
|
10
|
+
createInsertAst,
|
|
11
|
+
createJoinOnExpr,
|
|
12
|
+
createOrderByItem,
|
|
13
|
+
createParamRef,
|
|
14
|
+
createSelectAst,
|
|
15
|
+
createTableRef,
|
|
16
|
+
createUpdateAst
|
|
17
|
+
} from "@prisma-next/sql-relational-core/ast";
|
|
18
|
+
|
|
19
|
+
// src/utils/errors.ts
|
|
20
|
+
import { planInvalid } from "@prisma-next/plan";
|
|
21
|
+
function errorModelNotFound(modelName) {
|
|
22
|
+
throw planInvalid(`Model ${modelName} not found in mappings`);
|
|
23
|
+
}
|
|
24
|
+
function errorTableNotFound(tableName) {
|
|
25
|
+
throw planInvalid(`Table ${tableName} not found in schema`);
|
|
26
|
+
}
|
|
27
|
+
function errorUnknownTable(tableName) {
|
|
28
|
+
throw planInvalid(`Unknown table ${tableName}`);
|
|
29
|
+
}
|
|
30
|
+
function errorUnknownColumn(columnName, tableName) {
|
|
31
|
+
throw planInvalid(`Unknown column ${columnName} in table ${tableName}`);
|
|
32
|
+
}
|
|
33
|
+
function errorMissingParameter(paramName) {
|
|
34
|
+
throw planInvalid(`Missing value for parameter ${paramName}`);
|
|
35
|
+
}
|
|
36
|
+
function errorAliasPathEmpty() {
|
|
37
|
+
throw planInvalid("Alias path cannot be empty");
|
|
38
|
+
}
|
|
39
|
+
function errorAliasCollision(path, alias, existingPath) {
|
|
40
|
+
throw planInvalid(
|
|
41
|
+
`Alias collision: path ${path.join(".")} would generate alias "${alias}" which conflicts with path ${existingPath?.join(".") ?? "unknown"}`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function errorInvalidProjectionValue(path) {
|
|
45
|
+
throw planInvalid(
|
|
46
|
+
`Invalid projection value at path ${path.join(".")}: expected ColumnBuilder or nested object`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
function errorIncludeAliasNotFound(alias) {
|
|
50
|
+
throw planInvalid(
|
|
51
|
+
`Include alias "${alias}" not found. Did you call includeMany() with alias "${alias}"?`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
function errorInvalidProjectionKey(key) {
|
|
55
|
+
throw planInvalid(
|
|
56
|
+
`Invalid projection value at key "${key}": expected ColumnBuilder, boolean true (for includes), or nested object`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
function errorProjectionEmpty() {
|
|
60
|
+
throw planInvalid("select() requires at least one column or include");
|
|
61
|
+
}
|
|
62
|
+
function errorCreateRequiresFields() {
|
|
63
|
+
throw planInvalid("create() requires at least one field");
|
|
64
|
+
}
|
|
65
|
+
function errorUpdateRequiresFields() {
|
|
66
|
+
throw planInvalid("update() requires at least one field");
|
|
67
|
+
}
|
|
68
|
+
function errorIncludeRequiresCapabilities() {
|
|
69
|
+
throw planInvalid("includeMany requires lateral and jsonAgg capabilities");
|
|
70
|
+
}
|
|
71
|
+
function errorIncludeCapabilitiesNotTrue() {
|
|
72
|
+
throw planInvalid("includeMany requires lateral and jsonAgg capabilities to be true");
|
|
73
|
+
}
|
|
74
|
+
function errorMultiColumnJoinsNotSupported() {
|
|
75
|
+
throw planInvalid("Multi-column joins in includes are not yet supported");
|
|
76
|
+
}
|
|
77
|
+
function errorJoinColumnsMustBeDefined() {
|
|
78
|
+
throw planInvalid("Join columns must be defined");
|
|
79
|
+
}
|
|
80
|
+
function errorColumnNotFound(columnName, tableName) {
|
|
81
|
+
throw planInvalid(`Column ${columnName} not found in table ${tableName}`);
|
|
82
|
+
}
|
|
83
|
+
function errorChildProjectionMustBeSpecified() {
|
|
84
|
+
throw planInvalid("Child projection must be specified");
|
|
85
|
+
}
|
|
86
|
+
function errorChildProjectionEmpty() {
|
|
87
|
+
throw planInvalid("Child projection must not be empty after filtering boolean values");
|
|
88
|
+
}
|
|
89
|
+
function errorMissingAlias(index) {
|
|
90
|
+
throw planInvalid(`Missing alias at index ${index}`);
|
|
91
|
+
}
|
|
92
|
+
function errorMissingColumn(alias, index) {
|
|
93
|
+
throw planInvalid(`Missing column for alias ${alias} at index ${index}`);
|
|
94
|
+
}
|
|
95
|
+
function errorInvalidColumn(alias, index) {
|
|
96
|
+
throw planInvalid(`Invalid column for alias ${alias} at index ${index}`);
|
|
97
|
+
}
|
|
98
|
+
function errorFailedToBuildWhereClause() {
|
|
99
|
+
throw planInvalid("Failed to build WHERE clause");
|
|
100
|
+
}
|
|
101
|
+
function assertColumnExists(columnMeta, columnName, tableName) {
|
|
102
|
+
if (!columnMeta) {
|
|
103
|
+
errorUnknownColumn(columnName, tableName);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function assertParameterExists(paramsMap, paramName) {
|
|
107
|
+
if (!Object.hasOwn(paramsMap, paramName)) {
|
|
108
|
+
errorMissingParameter(paramName);
|
|
109
|
+
}
|
|
110
|
+
return paramsMap[paramName];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/selection/predicates.ts
|
|
114
|
+
function buildWhereExpr(where, contract, paramsMap, descriptors, values) {
|
|
115
|
+
const placeholder = where.right;
|
|
116
|
+
const paramName = placeholder.name;
|
|
117
|
+
if (!Object.hasOwn(paramsMap, paramName)) {
|
|
118
|
+
errorMissingParameter(paramName);
|
|
119
|
+
}
|
|
120
|
+
const value = paramsMap[paramName];
|
|
121
|
+
const index = values.push(value);
|
|
122
|
+
let leftExpr;
|
|
123
|
+
let codecId;
|
|
124
|
+
const operationExpr = where.left._operationExpr;
|
|
125
|
+
if (operationExpr) {
|
|
126
|
+
leftExpr = operationExpr;
|
|
127
|
+
} else {
|
|
128
|
+
const colBuilder = where.left;
|
|
129
|
+
const meta = colBuilder.columnMeta ?? {};
|
|
130
|
+
descriptors.push({
|
|
131
|
+
name: paramName,
|
|
132
|
+
source: "dsl",
|
|
133
|
+
refs: { table: colBuilder.table, column: colBuilder.column },
|
|
134
|
+
...typeof meta.type === "string" ? { type: meta.type } : {},
|
|
135
|
+
...typeof meta.nullable === "boolean" ? { nullable: meta.nullable } : {}
|
|
136
|
+
});
|
|
137
|
+
const contractTable = contract.storage.tables[colBuilder.table];
|
|
138
|
+
const columnMeta = contractTable?.columns[colBuilder.column];
|
|
139
|
+
codecId = columnMeta?.type;
|
|
140
|
+
leftExpr = createColumnRef(colBuilder.table, colBuilder.column);
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
expr: createBinaryExpr("eq", leftExpr, createParamRef(index, paramName)),
|
|
144
|
+
...codecId ? { codecId } : {},
|
|
145
|
+
paramName
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/mutations/delete-builder.ts
|
|
150
|
+
function buildDeletePlan(context, modelName, where, getModelAccessor, options) {
|
|
151
|
+
const modelAccessor = getModelAccessor();
|
|
152
|
+
const wherePredicate = where(modelAccessor);
|
|
153
|
+
const tableName = context.contract.mappings.modelToTable?.[modelName];
|
|
154
|
+
if (!tableName) {
|
|
155
|
+
errorModelNotFound(modelName);
|
|
156
|
+
}
|
|
157
|
+
const table = createTableRef(tableName);
|
|
158
|
+
const paramsMap = options?.params ?? {};
|
|
159
|
+
const paramDescriptors = [];
|
|
160
|
+
const paramValues = [];
|
|
161
|
+
const paramCodecs = {};
|
|
162
|
+
const whereResult = buildWhereExpr(
|
|
163
|
+
wherePredicate,
|
|
164
|
+
context.contract,
|
|
165
|
+
paramsMap,
|
|
166
|
+
paramDescriptors,
|
|
167
|
+
paramValues
|
|
168
|
+
);
|
|
169
|
+
const whereExpr = whereResult.expr;
|
|
170
|
+
if (!whereExpr) {
|
|
171
|
+
errorFailedToBuildWhereClause();
|
|
172
|
+
}
|
|
173
|
+
if (whereResult?.codecId && whereResult.paramName) {
|
|
174
|
+
paramCodecs[whereResult.paramName] = whereResult.codecId;
|
|
175
|
+
}
|
|
176
|
+
const ast = createDeleteAst({
|
|
177
|
+
table,
|
|
178
|
+
where: whereExpr
|
|
179
|
+
});
|
|
180
|
+
return Object.freeze({
|
|
181
|
+
ast,
|
|
182
|
+
params: paramValues,
|
|
183
|
+
meta: {
|
|
184
|
+
target: context.contract.target,
|
|
185
|
+
targetFamily: context.contract.targetFamily,
|
|
186
|
+
coreHash: context.contract.coreHash,
|
|
187
|
+
lane: "orm",
|
|
188
|
+
refs: {
|
|
189
|
+
tables: [tableName],
|
|
190
|
+
columns: []
|
|
191
|
+
},
|
|
192
|
+
projection: {},
|
|
193
|
+
paramDescriptors,
|
|
194
|
+
...Object.keys(paramCodecs).length > 0 ? {
|
|
195
|
+
annotations: {
|
|
196
|
+
codecs: paramCodecs,
|
|
197
|
+
intent: "write",
|
|
198
|
+
isMutation: true
|
|
199
|
+
}
|
|
200
|
+
} : {
|
|
201
|
+
annotations: {
|
|
202
|
+
intent: "write",
|
|
203
|
+
isMutation: true
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/mutations/insert-builder.ts
|
|
211
|
+
import { param } from "@prisma-next/sql-relational-core/param";
|
|
212
|
+
|
|
213
|
+
// src/utils/param-descriptor.ts
|
|
214
|
+
function createParamDescriptor(args) {
|
|
215
|
+
return {
|
|
216
|
+
name: args.name,
|
|
217
|
+
source: "dsl",
|
|
218
|
+
refs: { table: args.table, column: args.column },
|
|
219
|
+
...args.type ? { type: args.type } : {},
|
|
220
|
+
nullable: args.nullable
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/mutations/insert-builder.ts
|
|
225
|
+
function convertModelFieldsToColumns(contract, modelName, fields) {
|
|
226
|
+
const model = contract.models[modelName];
|
|
227
|
+
if (!model || typeof model !== "object" || !("fields" in model)) {
|
|
228
|
+
throw new Error(`Model ${modelName} does not have fields`);
|
|
229
|
+
}
|
|
230
|
+
const modelFields = model.fields;
|
|
231
|
+
const result = {};
|
|
232
|
+
for (const fieldName in fields) {
|
|
233
|
+
if (!Object.hasOwn(fields, fieldName)) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (!Object.hasOwn(modelFields, fieldName)) {
|
|
237
|
+
throw new Error(`Field ${fieldName} does not exist on model ${modelName}`);
|
|
238
|
+
}
|
|
239
|
+
const field = modelFields[fieldName];
|
|
240
|
+
if (!field) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
const columnName = contract.mappings.fieldToColumn?.[modelName]?.[fieldName] ?? field.column ?? fieldName;
|
|
244
|
+
result[columnName] = param(fieldName);
|
|
245
|
+
}
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
function buildInsertPlan(context, modelName, data, options) {
|
|
249
|
+
if (!data || Object.keys(data).length === 0) {
|
|
250
|
+
errorCreateRequiresFields();
|
|
251
|
+
}
|
|
252
|
+
const values = convertModelFieldsToColumns(context.contract, modelName, data);
|
|
253
|
+
const tableName = context.contract.mappings.modelToTable?.[modelName];
|
|
254
|
+
if (!tableName) {
|
|
255
|
+
errorModelNotFound(modelName);
|
|
256
|
+
}
|
|
257
|
+
const table = createTableRef(tableName);
|
|
258
|
+
const paramsMap = {
|
|
259
|
+
...options?.params ?? {},
|
|
260
|
+
...data
|
|
261
|
+
};
|
|
262
|
+
const paramDescriptors = [];
|
|
263
|
+
const paramValues = [];
|
|
264
|
+
const paramCodecs = {};
|
|
265
|
+
const contractTable = context.contract.storage.tables[tableName];
|
|
266
|
+
if (!contractTable) {
|
|
267
|
+
errorUnknownTable(tableName);
|
|
268
|
+
}
|
|
269
|
+
const insertValues = {};
|
|
270
|
+
for (const [columnName, placeholder] of Object.entries(values)) {
|
|
271
|
+
const columnMeta = contractTable.columns[columnName];
|
|
272
|
+
assertColumnExists(columnMeta, columnName, tableName);
|
|
273
|
+
const paramName = placeholder.name;
|
|
274
|
+
const value = assertParameterExists(paramsMap, paramName);
|
|
275
|
+
const index = paramValues.push(value);
|
|
276
|
+
const codecId = columnMeta.type;
|
|
277
|
+
if (codecId && paramName) {
|
|
278
|
+
paramCodecs[paramName] = codecId;
|
|
279
|
+
}
|
|
280
|
+
paramDescriptors.push(
|
|
281
|
+
createParamDescriptor({
|
|
282
|
+
name: paramName,
|
|
283
|
+
table: tableName,
|
|
284
|
+
column: columnName,
|
|
285
|
+
type: codecId,
|
|
286
|
+
nullable: columnMeta.nullable
|
|
287
|
+
})
|
|
288
|
+
);
|
|
289
|
+
insertValues[columnName] = createParamRef(index, paramName);
|
|
290
|
+
}
|
|
291
|
+
const ast = createInsertAst({
|
|
292
|
+
table,
|
|
293
|
+
values: insertValues
|
|
294
|
+
});
|
|
295
|
+
return Object.freeze({
|
|
296
|
+
ast,
|
|
297
|
+
params: paramValues,
|
|
298
|
+
meta: {
|
|
299
|
+
target: context.contract.target,
|
|
300
|
+
targetFamily: context.contract.targetFamily,
|
|
301
|
+
coreHash: context.contract.coreHash,
|
|
302
|
+
lane: "orm",
|
|
303
|
+
refs: {
|
|
304
|
+
tables: [tableName],
|
|
305
|
+
columns: []
|
|
306
|
+
},
|
|
307
|
+
projection: {},
|
|
308
|
+
paramDescriptors,
|
|
309
|
+
...Object.keys(paramCodecs).length > 0 ? {
|
|
310
|
+
annotations: {
|
|
311
|
+
codecs: paramCodecs,
|
|
312
|
+
intent: "write",
|
|
313
|
+
isMutation: true
|
|
314
|
+
}
|
|
315
|
+
} : {
|
|
316
|
+
annotations: {
|
|
317
|
+
intent: "write",
|
|
318
|
+
isMutation: true
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// src/mutations/update-builder.ts
|
|
326
|
+
function buildUpdatePlan(context, modelName, where, getModelAccessor, data, options) {
|
|
327
|
+
if (!data || Object.keys(data).length === 0) {
|
|
328
|
+
errorUpdateRequiresFields();
|
|
329
|
+
}
|
|
330
|
+
const set = convertModelFieldsToColumns(context.contract, modelName, data);
|
|
331
|
+
const modelAccessor = getModelAccessor();
|
|
332
|
+
const wherePredicate = where(modelAccessor);
|
|
333
|
+
const tableName = context.contract.mappings.modelToTable?.[modelName];
|
|
334
|
+
if (!tableName) {
|
|
335
|
+
errorModelNotFound(modelName);
|
|
336
|
+
}
|
|
337
|
+
const table = createTableRef(tableName);
|
|
338
|
+
const paramsMap = {
|
|
339
|
+
...options?.params ?? {},
|
|
340
|
+
...data
|
|
341
|
+
};
|
|
342
|
+
const paramDescriptors = [];
|
|
343
|
+
const paramValues = [];
|
|
344
|
+
const paramCodecs = {};
|
|
345
|
+
const contractTable = context.contract.storage.tables[tableName];
|
|
346
|
+
if (!contractTable) {
|
|
347
|
+
errorUnknownTable(tableName);
|
|
348
|
+
}
|
|
349
|
+
const updateSet = {};
|
|
350
|
+
for (const [columnName, placeholder] of Object.entries(set)) {
|
|
351
|
+
const columnMeta = contractTable.columns[columnName];
|
|
352
|
+
assertColumnExists(columnMeta, columnName, tableName);
|
|
353
|
+
const paramName = placeholder.name;
|
|
354
|
+
const value = assertParameterExists(paramsMap, paramName);
|
|
355
|
+
const index = paramValues.push(value);
|
|
356
|
+
const codecId = columnMeta.type;
|
|
357
|
+
if (codecId && paramName) {
|
|
358
|
+
paramCodecs[paramName] = codecId;
|
|
359
|
+
}
|
|
360
|
+
paramDescriptors.push(
|
|
361
|
+
createParamDescriptor({
|
|
362
|
+
name: paramName,
|
|
363
|
+
table: tableName,
|
|
364
|
+
column: columnName,
|
|
365
|
+
type: codecId,
|
|
366
|
+
nullable: columnMeta.nullable
|
|
367
|
+
})
|
|
368
|
+
);
|
|
369
|
+
updateSet[columnName] = createParamRef(index, paramName);
|
|
370
|
+
}
|
|
371
|
+
const whereResult = buildWhereExpr(
|
|
372
|
+
wherePredicate,
|
|
373
|
+
context.contract,
|
|
374
|
+
paramsMap,
|
|
375
|
+
paramDescriptors,
|
|
376
|
+
paramValues
|
|
377
|
+
);
|
|
378
|
+
const whereExpr = whereResult.expr;
|
|
379
|
+
if (!whereExpr) {
|
|
380
|
+
errorFailedToBuildWhereClause();
|
|
381
|
+
}
|
|
382
|
+
if (whereResult?.codecId && whereResult.paramName) {
|
|
383
|
+
paramCodecs[whereResult.paramName] = whereResult.codecId;
|
|
384
|
+
}
|
|
385
|
+
const ast = createUpdateAst({
|
|
386
|
+
table,
|
|
387
|
+
set: updateSet,
|
|
388
|
+
where: whereExpr
|
|
389
|
+
});
|
|
390
|
+
return Object.freeze({
|
|
391
|
+
ast,
|
|
392
|
+
params: paramValues,
|
|
393
|
+
meta: {
|
|
394
|
+
target: context.contract.target,
|
|
395
|
+
targetFamily: context.contract.targetFamily,
|
|
396
|
+
coreHash: context.contract.coreHash,
|
|
397
|
+
lane: "orm",
|
|
398
|
+
refs: {
|
|
399
|
+
tables: [tableName],
|
|
400
|
+
columns: []
|
|
401
|
+
},
|
|
402
|
+
projection: {},
|
|
403
|
+
paramDescriptors,
|
|
404
|
+
...Object.keys(paramCodecs).length > 0 ? {
|
|
405
|
+
annotations: {
|
|
406
|
+
codecs: paramCodecs,
|
|
407
|
+
intent: "write",
|
|
408
|
+
isMutation: true
|
|
409
|
+
}
|
|
410
|
+
} : {
|
|
411
|
+
annotations: {
|
|
412
|
+
intent: "write",
|
|
413
|
+
isMutation: true
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// src/orm-include-child.ts
|
|
421
|
+
import { planInvalid as planInvalid2 } from "@prisma-next/plan";
|
|
422
|
+
import { schema } from "@prisma-next/sql-relational-core/schema";
|
|
423
|
+
var OrmIncludeChildBuilderImpl = class _OrmIncludeChildBuilderImpl {
|
|
424
|
+
context;
|
|
425
|
+
contract;
|
|
426
|
+
childModelName;
|
|
427
|
+
childWhere;
|
|
428
|
+
childOrderBy;
|
|
429
|
+
childLimit;
|
|
430
|
+
childProjection = void 0;
|
|
431
|
+
constructor(options, childModelName) {
|
|
432
|
+
this.context = options.context;
|
|
433
|
+
this.contract = options.context.contract;
|
|
434
|
+
this.childModelName = childModelName;
|
|
435
|
+
}
|
|
436
|
+
where(fn) {
|
|
437
|
+
const builder = new _OrmIncludeChildBuilderImpl(
|
|
438
|
+
{ context: this.context },
|
|
439
|
+
this.childModelName
|
|
440
|
+
);
|
|
441
|
+
builder.childWhere = fn(this._getModelAccessor());
|
|
442
|
+
builder.childOrderBy = this.childOrderBy;
|
|
443
|
+
builder.childLimit = this.childLimit;
|
|
444
|
+
builder.childProjection = this.childProjection;
|
|
445
|
+
return builder;
|
|
446
|
+
}
|
|
447
|
+
orderBy(fn) {
|
|
448
|
+
const builder = new _OrmIncludeChildBuilderImpl(
|
|
449
|
+
{ context: this.context },
|
|
450
|
+
this.childModelName
|
|
451
|
+
);
|
|
452
|
+
builder.childWhere = this.childWhere;
|
|
453
|
+
builder.childOrderBy = fn(this._getModelAccessor());
|
|
454
|
+
builder.childLimit = this.childLimit;
|
|
455
|
+
builder.childProjection = this.childProjection;
|
|
456
|
+
return builder;
|
|
457
|
+
}
|
|
458
|
+
take(n) {
|
|
459
|
+
const builder = new _OrmIncludeChildBuilderImpl(
|
|
460
|
+
{ context: this.context },
|
|
461
|
+
this.childModelName
|
|
462
|
+
);
|
|
463
|
+
builder.childWhere = this.childWhere;
|
|
464
|
+
builder.childOrderBy = this.childOrderBy;
|
|
465
|
+
builder.childLimit = n;
|
|
466
|
+
builder.childProjection = this.childProjection;
|
|
467
|
+
return builder;
|
|
468
|
+
}
|
|
469
|
+
select(fn) {
|
|
470
|
+
const builder = new _OrmIncludeChildBuilderImpl({ context: this.context }, this.childModelName);
|
|
471
|
+
builder.childWhere = this.childWhere;
|
|
472
|
+
builder.childOrderBy = this.childOrderBy;
|
|
473
|
+
builder.childLimit = this.childLimit;
|
|
474
|
+
builder.childProjection = fn(this._getModelAccessor());
|
|
475
|
+
return builder;
|
|
476
|
+
}
|
|
477
|
+
getState() {
|
|
478
|
+
return {
|
|
479
|
+
...this.childWhere !== void 0 ? { childWhere: this.childWhere } : {},
|
|
480
|
+
...this.childOrderBy !== void 0 ? { childOrderBy: this.childOrderBy } : {},
|
|
481
|
+
...this.childLimit !== void 0 ? { childLimit: this.childLimit } : {},
|
|
482
|
+
...this.childProjection !== void 0 ? { childProjection: this.childProjection } : {}
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
_getModelAccessor() {
|
|
486
|
+
const tableName = this.contract.mappings.modelToTable?.[this.childModelName];
|
|
487
|
+
if (!tableName) {
|
|
488
|
+
throw planInvalid2(`Model ${this.childModelName} not found in mappings`);
|
|
489
|
+
}
|
|
490
|
+
const schemaHandle = schema(this.context);
|
|
491
|
+
const table = schemaHandle.tables[tableName];
|
|
492
|
+
if (!table) {
|
|
493
|
+
throw planInvalid2(`Table ${tableName} not found in schema`);
|
|
494
|
+
}
|
|
495
|
+
const accessor = {};
|
|
496
|
+
const model = this.contract.models[this.childModelName];
|
|
497
|
+
if (!model || typeof model !== "object" || !("fields" in model)) {
|
|
498
|
+
throw planInvalid2(`Model ${this.childModelName} does not have fields`);
|
|
499
|
+
}
|
|
500
|
+
const modelFields = model.fields;
|
|
501
|
+
for (const fieldName in modelFields) {
|
|
502
|
+
const field = modelFields[fieldName];
|
|
503
|
+
if (!field) continue;
|
|
504
|
+
const columnName = this.contract.mappings.fieldToColumn?.[this.childModelName]?.[fieldName] ?? field.column ?? fieldName;
|
|
505
|
+
const column = table.columns[columnName];
|
|
506
|
+
if (column) {
|
|
507
|
+
accessor[fieldName] = column;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return accessor;
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
// src/orm-relation-filter.ts
|
|
515
|
+
import { planInvalid as planInvalid3 } from "@prisma-next/plan";
|
|
516
|
+
import { schema as schema2 } from "@prisma-next/sql-relational-core/schema";
|
|
517
|
+
var OrmRelationFilterBuilderImpl = class _OrmRelationFilterBuilderImpl {
|
|
518
|
+
context;
|
|
519
|
+
contract;
|
|
520
|
+
childModelName;
|
|
521
|
+
wherePredicate = void 0;
|
|
522
|
+
modelAccessor = void 0;
|
|
523
|
+
constructor(options, childModelName) {
|
|
524
|
+
this.context = options.context;
|
|
525
|
+
this.contract = options.context.contract;
|
|
526
|
+
this.childModelName = childModelName;
|
|
527
|
+
this.modelAccessor = this._getModelAccessor();
|
|
528
|
+
}
|
|
529
|
+
where(fn) {
|
|
530
|
+
const builder = new _OrmRelationFilterBuilderImpl(
|
|
531
|
+
{ context: this.context },
|
|
532
|
+
this.childModelName
|
|
533
|
+
);
|
|
534
|
+
builder.modelAccessor = this.modelAccessor;
|
|
535
|
+
if (this.modelAccessor) {
|
|
536
|
+
builder.wherePredicate = fn(this.modelAccessor);
|
|
537
|
+
}
|
|
538
|
+
return builder;
|
|
539
|
+
}
|
|
540
|
+
getWherePredicate() {
|
|
541
|
+
return this.wherePredicate;
|
|
542
|
+
}
|
|
543
|
+
getChildModelName() {
|
|
544
|
+
return this.childModelName;
|
|
545
|
+
}
|
|
546
|
+
getModelAccessor() {
|
|
547
|
+
if (!this.modelAccessor) {
|
|
548
|
+
this.modelAccessor = this._getModelAccessor();
|
|
549
|
+
}
|
|
550
|
+
if (!this.modelAccessor) {
|
|
551
|
+
throw planInvalid3(`Failed to get model accessor for ${this.childModelName}`);
|
|
552
|
+
}
|
|
553
|
+
return this.modelAccessor;
|
|
554
|
+
}
|
|
555
|
+
_getModelAccessor() {
|
|
556
|
+
const tableName = this.contract.mappings.modelToTable?.[this.childModelName];
|
|
557
|
+
if (!tableName) {
|
|
558
|
+
throw planInvalid3(`Model ${this.childModelName} not found in mappings`);
|
|
559
|
+
}
|
|
560
|
+
const schemaHandle = schema2(this.context);
|
|
561
|
+
const table = schemaHandle.tables[tableName];
|
|
562
|
+
if (!table) {
|
|
563
|
+
throw planInvalid3(`Table ${tableName} not found in schema`);
|
|
564
|
+
}
|
|
565
|
+
const accessor = {};
|
|
566
|
+
const model = this.contract.models[this.childModelName];
|
|
567
|
+
if (!model || typeof model !== "object" || !("fields" in model)) {
|
|
568
|
+
throw planInvalid3(`Model ${this.childModelName} does not have fields`);
|
|
569
|
+
}
|
|
570
|
+
const modelFields = model.fields;
|
|
571
|
+
for (const fieldName in modelFields) {
|
|
572
|
+
const field = modelFields[fieldName];
|
|
573
|
+
if (!field) continue;
|
|
574
|
+
const columnName = this.contract.mappings.fieldToColumn?.[this.childModelName]?.[fieldName] ?? field.column ?? fieldName;
|
|
575
|
+
const column = table.columns[columnName];
|
|
576
|
+
if (column) {
|
|
577
|
+
accessor[fieldName] = column;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return accessor;
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
// src/plan/plan-assembly.ts
|
|
585
|
+
import { planInvalid as planInvalid4 } from "@prisma-next/plan";
|
|
586
|
+
import { compact } from "@prisma-next/sql-relational-core/ast";
|
|
587
|
+
|
|
588
|
+
// src/utils/guards.ts
|
|
589
|
+
function extractBaseColumnRef(expr) {
|
|
590
|
+
if (expr.kind === "col") {
|
|
591
|
+
return expr;
|
|
592
|
+
}
|
|
593
|
+
return extractBaseColumnRef(expr.self);
|
|
594
|
+
}
|
|
595
|
+
function collectColumnRefs(expr) {
|
|
596
|
+
if (expr.kind === "col") {
|
|
597
|
+
return [expr];
|
|
598
|
+
}
|
|
599
|
+
if (expr.kind === "operation") {
|
|
600
|
+
const refs = collectColumnRefs(expr.self);
|
|
601
|
+
for (const arg of expr.args) {
|
|
602
|
+
refs.push(...collectColumnRefs(arg));
|
|
603
|
+
}
|
|
604
|
+
return refs;
|
|
605
|
+
}
|
|
606
|
+
return [];
|
|
607
|
+
}
|
|
608
|
+
function isOperationExpr(expr) {
|
|
609
|
+
return typeof expr === "object" && expr !== null && "kind" in expr && expr.kind === "operation";
|
|
610
|
+
}
|
|
611
|
+
function getColumnInfo(expr) {
|
|
612
|
+
if (isOperationExpr(expr)) {
|
|
613
|
+
const baseCol = extractBaseColumnRef(expr);
|
|
614
|
+
return { table: baseCol.table, column: baseCol.column };
|
|
615
|
+
}
|
|
616
|
+
const colBuilder = expr;
|
|
617
|
+
return { table: colBuilder.table, column: colBuilder.column };
|
|
618
|
+
}
|
|
619
|
+
function isColumnBuilder(value) {
|
|
620
|
+
return typeof value === "object" && value !== null && "kind" in value && value.kind === "column";
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// src/plan/plan-assembly.ts
|
|
624
|
+
function buildMeta(args) {
|
|
625
|
+
const refsColumns = /* @__PURE__ */ new Map();
|
|
626
|
+
const refsTables = /* @__PURE__ */ new Set([args.table.name]);
|
|
627
|
+
for (const column of args.projection.columns) {
|
|
628
|
+
const operationExpr = column._operationExpr;
|
|
629
|
+
if (operationExpr) {
|
|
630
|
+
const allRefs = collectColumnRefs(operationExpr);
|
|
631
|
+
for (const ref of allRefs) {
|
|
632
|
+
refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
633
|
+
table: ref.table,
|
|
634
|
+
column: ref.column
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
} else {
|
|
638
|
+
const col = column;
|
|
639
|
+
if (col.table && col.column) {
|
|
640
|
+
refsColumns.set(`${col.table}.${col.column}`, {
|
|
641
|
+
table: col.table,
|
|
642
|
+
column: col.column
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
if (args.includes) {
|
|
648
|
+
for (const include of args.includes) {
|
|
649
|
+
refsTables.add(include.table.name);
|
|
650
|
+
const onLeft = include.on.left;
|
|
651
|
+
const onRight = include.on.right;
|
|
652
|
+
if (onLeft.table && onLeft.column && onRight.table && onRight.column) {
|
|
653
|
+
refsColumns.set(`${onLeft.table}.${onLeft.column}`, {
|
|
654
|
+
table: onLeft.table,
|
|
655
|
+
column: onLeft.column
|
|
656
|
+
});
|
|
657
|
+
refsColumns.set(`${onRight.table}.${onRight.column}`, {
|
|
658
|
+
table: onRight.table,
|
|
659
|
+
column: onRight.column
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
for (const column of include.childProjection.columns) {
|
|
663
|
+
const col = column;
|
|
664
|
+
if (col.table && col.column) {
|
|
665
|
+
refsColumns.set(`${col.table}.${col.column}`, {
|
|
666
|
+
table: col.table,
|
|
667
|
+
column: col.column
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
if (include.childWhere) {
|
|
672
|
+
const colInfo = getColumnInfo(include.childWhere.left);
|
|
673
|
+
refsColumns.set(`${colInfo.table}.${colInfo.column}`, {
|
|
674
|
+
table: colInfo.table,
|
|
675
|
+
column: colInfo.column
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
if (include.childOrderBy) {
|
|
679
|
+
const orderBy = include.childOrderBy;
|
|
680
|
+
if (orderBy.expr) {
|
|
681
|
+
const colInfo = getColumnInfo(orderBy.expr);
|
|
682
|
+
refsColumns.set(`${colInfo.table}.${colInfo.column}`, {
|
|
683
|
+
table: colInfo.table,
|
|
684
|
+
column: colInfo.column
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
if (args.where) {
|
|
691
|
+
const whereLeft = args.where.left;
|
|
692
|
+
const operationExpr = whereLeft._operationExpr;
|
|
693
|
+
if (operationExpr) {
|
|
694
|
+
const allRefs = collectColumnRefs(operationExpr);
|
|
695
|
+
for (const ref of allRefs) {
|
|
696
|
+
refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
697
|
+
table: ref.table,
|
|
698
|
+
column: ref.column
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
} else {
|
|
702
|
+
const colBuilder = whereLeft;
|
|
703
|
+
if (colBuilder.table && colBuilder.column) {
|
|
704
|
+
refsColumns.set(`${colBuilder.table}.${colBuilder.column}`, {
|
|
705
|
+
table: colBuilder.table,
|
|
706
|
+
column: colBuilder.column
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (args.orderBy) {
|
|
712
|
+
const orderBy = args.orderBy;
|
|
713
|
+
const orderByExpr = orderBy.expr;
|
|
714
|
+
if (orderByExpr) {
|
|
715
|
+
if (isOperationExpr(orderByExpr)) {
|
|
716
|
+
const allRefs = collectColumnRefs(orderByExpr);
|
|
717
|
+
for (const ref of allRefs) {
|
|
718
|
+
refsColumns.set(`${ref.table}.${ref.column}`, {
|
|
719
|
+
table: ref.table,
|
|
720
|
+
column: ref.column
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
} else {
|
|
724
|
+
const colBuilder = orderByExpr;
|
|
725
|
+
if (colBuilder.table && colBuilder.column) {
|
|
726
|
+
refsColumns.set(`${colBuilder.table}.${colBuilder.column}`, {
|
|
727
|
+
table: colBuilder.table,
|
|
728
|
+
column: colBuilder.column
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
const includeAliases = new Set(args.includes?.map((inc) => inc.alias) ?? []);
|
|
735
|
+
const projectionMap = Object.fromEntries(
|
|
736
|
+
args.projection.aliases.map((alias, index) => {
|
|
737
|
+
if (includeAliases.has(alias)) {
|
|
738
|
+
return [alias, `include:${alias}`];
|
|
739
|
+
}
|
|
740
|
+
const column = args.projection.columns[index];
|
|
741
|
+
if (!column) {
|
|
742
|
+
throw planInvalid4(`Missing column for alias ${alias} at index ${index}`);
|
|
743
|
+
}
|
|
744
|
+
const col = column;
|
|
745
|
+
if (!col.table || !col.column) {
|
|
746
|
+
return [alias, `include:${alias}`];
|
|
747
|
+
}
|
|
748
|
+
const operationExpr = col._operationExpr;
|
|
749
|
+
if (operationExpr) {
|
|
750
|
+
return [alias, `operation:${operationExpr.method}`];
|
|
751
|
+
}
|
|
752
|
+
return [alias, `${col.table}.${col.column}`];
|
|
753
|
+
})
|
|
754
|
+
);
|
|
755
|
+
const projectionTypes = {};
|
|
756
|
+
for (let i = 0; i < args.projection.aliases.length; i++) {
|
|
757
|
+
const alias = args.projection.aliases[i];
|
|
758
|
+
if (!alias || includeAliases.has(alias)) {
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
const col = args.projection.columns[i];
|
|
762
|
+
if (!col) {
|
|
763
|
+
continue;
|
|
764
|
+
}
|
|
765
|
+
const operationExpr = col._operationExpr;
|
|
766
|
+
if (operationExpr) {
|
|
767
|
+
if (operationExpr.returns.kind === "typeId") {
|
|
768
|
+
projectionTypes[alias] = operationExpr.returns.type;
|
|
769
|
+
} else if (operationExpr.returns.kind === "builtin") {
|
|
770
|
+
projectionTypes[alias] = operationExpr.returns.type;
|
|
771
|
+
}
|
|
772
|
+
} else {
|
|
773
|
+
const colMeta = col;
|
|
774
|
+
const columnMeta = colMeta.columnMeta;
|
|
775
|
+
if (columnMeta?.type) {
|
|
776
|
+
projectionTypes[alias] = columnMeta.type;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
const projectionCodecs = {};
|
|
781
|
+
for (let i = 0; i < args.projection.aliases.length; i++) {
|
|
782
|
+
const alias = args.projection.aliases[i];
|
|
783
|
+
if (!alias || includeAliases.has(alias)) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
const column = args.projection.columns[i];
|
|
787
|
+
if (!column) {
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
const operationExpr = column._operationExpr;
|
|
791
|
+
if (operationExpr) {
|
|
792
|
+
if (operationExpr.returns.kind === "typeId") {
|
|
793
|
+
projectionCodecs[alias] = operationExpr.returns.type;
|
|
794
|
+
}
|
|
795
|
+
} else {
|
|
796
|
+
const col = column;
|
|
797
|
+
const columnMeta = col.columnMeta;
|
|
798
|
+
if (columnMeta?.type) {
|
|
799
|
+
projectionCodecs[alias] = columnMeta.type;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const allCodecs = {
|
|
804
|
+
...projectionCodecs,
|
|
805
|
+
...args.paramCodecs ? args.paramCodecs : {}
|
|
806
|
+
};
|
|
807
|
+
return Object.freeze(
|
|
808
|
+
compact({
|
|
809
|
+
target: args.contract.target,
|
|
810
|
+
targetFamily: args.contract.targetFamily,
|
|
811
|
+
coreHash: args.contract.coreHash,
|
|
812
|
+
lane: "dsl",
|
|
813
|
+
refs: {
|
|
814
|
+
tables: Array.from(refsTables),
|
|
815
|
+
columns: Array.from(refsColumns.values())
|
|
816
|
+
},
|
|
817
|
+
projection: projectionMap,
|
|
818
|
+
projectionTypes: Object.keys(projectionTypes).length > 0 ? projectionTypes : void 0,
|
|
819
|
+
annotations: Object.keys(allCodecs).length > 0 ? Object.freeze({ codecs: Object.freeze(allCodecs) }) : void 0,
|
|
820
|
+
paramDescriptors: args.paramDescriptors,
|
|
821
|
+
profileHash: args.contract.profileHash
|
|
822
|
+
})
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// src/relations/include-plan.ts
|
|
827
|
+
import { compact as compact2 } from "@prisma-next/sql-relational-core/ast";
|
|
828
|
+
import { schema as schema3 } from "@prisma-next/sql-relational-core/schema";
|
|
829
|
+
|
|
830
|
+
// src/orm/capabilities.ts
|
|
831
|
+
function checkIncludeCapabilities(contract) {
|
|
832
|
+
const target = contract.target;
|
|
833
|
+
const capabilities = contract.capabilities;
|
|
834
|
+
if (!capabilities || !capabilities[target]) {
|
|
835
|
+
errorIncludeRequiresCapabilities();
|
|
836
|
+
}
|
|
837
|
+
const targetCapabilities = capabilities[target];
|
|
838
|
+
if (capabilities[target]["lateral"] !== true || targetCapabilities["jsonAgg"] !== true) {
|
|
839
|
+
errorIncludeCapabilitiesNotTrue();
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// src/selection/join.ts
|
|
844
|
+
function buildJoinOnExpr(parentTableName, parentColName, childTableName, childColName) {
|
|
845
|
+
const leftCol = createColumnRef(parentTableName, parentColName);
|
|
846
|
+
const rightCol = createColumnRef(childTableName, childColName);
|
|
847
|
+
return createJoinOnExpr(leftCol, rightCol);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// src/selection/ordering.ts
|
|
851
|
+
function buildOrderByClause(orderBy) {
|
|
852
|
+
if (!orderBy) {
|
|
853
|
+
return void 0;
|
|
854
|
+
}
|
|
855
|
+
const orderByBuilder = orderBy;
|
|
856
|
+
const orderExpr = orderByBuilder.expr;
|
|
857
|
+
const expr = isOperationExpr(orderExpr) ? orderExpr : (() => {
|
|
858
|
+
const colBuilder = orderExpr;
|
|
859
|
+
return createColumnRef(colBuilder.table, colBuilder.column);
|
|
860
|
+
})();
|
|
861
|
+
return [createOrderByItem(expr, orderByBuilder.dir)];
|
|
862
|
+
}
|
|
863
|
+
function buildChildOrderByClause(orderBy) {
|
|
864
|
+
if (!orderBy) {
|
|
865
|
+
return void 0;
|
|
866
|
+
}
|
|
867
|
+
const orderByBuilder = orderBy;
|
|
868
|
+
const orderExpr = orderByBuilder.expr;
|
|
869
|
+
const expr = (() => {
|
|
870
|
+
if (isOperationExpr(orderExpr)) {
|
|
871
|
+
const baseCol = extractBaseColumnRef(orderExpr);
|
|
872
|
+
return createColumnRef(baseCol.table, baseCol.column);
|
|
873
|
+
}
|
|
874
|
+
const colBuilder = orderExpr;
|
|
875
|
+
return createColumnRef(colBuilder.table, colBuilder.column);
|
|
876
|
+
})();
|
|
877
|
+
return [createOrderByItem(expr, orderByBuilder.dir)];
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// src/selection/projection.ts
|
|
881
|
+
function generateAlias(path) {
|
|
882
|
+
if (path.length === 0) {
|
|
883
|
+
errorAliasPathEmpty();
|
|
884
|
+
}
|
|
885
|
+
return path.join("_");
|
|
886
|
+
}
|
|
887
|
+
var AliasTracker = class {
|
|
888
|
+
aliases = /* @__PURE__ */ new Set();
|
|
889
|
+
aliasToPath = /* @__PURE__ */ new Map();
|
|
890
|
+
register(path) {
|
|
891
|
+
const alias = generateAlias(path);
|
|
892
|
+
if (this.aliases.has(alias)) {
|
|
893
|
+
const existingPath = this.aliasToPath.get(alias);
|
|
894
|
+
errorAliasCollision(path, alias, existingPath);
|
|
895
|
+
}
|
|
896
|
+
this.aliases.add(alias);
|
|
897
|
+
this.aliasToPath.set(alias, path);
|
|
898
|
+
return alias;
|
|
899
|
+
}
|
|
900
|
+
getPath(alias) {
|
|
901
|
+
return this.aliasToPath.get(alias);
|
|
902
|
+
}
|
|
903
|
+
has(alias) {
|
|
904
|
+
return this.aliases.has(alias);
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
function flattenProjection(projection, tracker, currentPath = []) {
|
|
908
|
+
const aliases = [];
|
|
909
|
+
const columns = [];
|
|
910
|
+
for (const [key, value] of Object.entries(projection)) {
|
|
911
|
+
const path = [...currentPath, key];
|
|
912
|
+
if (isColumnBuilder(value)) {
|
|
913
|
+
const alias = tracker.register(path);
|
|
914
|
+
aliases.push(alias);
|
|
915
|
+
columns.push(value);
|
|
916
|
+
} else if (typeof value === "object" && value !== null) {
|
|
917
|
+
const nested = flattenProjection(value, tracker, path);
|
|
918
|
+
aliases.push(...nested.aliases);
|
|
919
|
+
columns.push(...nested.columns);
|
|
920
|
+
} else {
|
|
921
|
+
errorInvalidProjectionValue(path);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
return { aliases, columns };
|
|
925
|
+
}
|
|
926
|
+
function buildProjectionState(_table, projection, includes) {
|
|
927
|
+
const tracker = new AliasTracker();
|
|
928
|
+
const aliases = [];
|
|
929
|
+
const columns = [];
|
|
930
|
+
for (const [key, value] of Object.entries(projection)) {
|
|
931
|
+
if (value === true) {
|
|
932
|
+
const matchingInclude = includes?.find((inc) => inc.alias === key);
|
|
933
|
+
if (!matchingInclude) {
|
|
934
|
+
errorIncludeAliasNotFound(key);
|
|
935
|
+
}
|
|
936
|
+
aliases.push(key);
|
|
937
|
+
columns.push({
|
|
938
|
+
kind: "column",
|
|
939
|
+
table: matchingInclude.table.name,
|
|
940
|
+
column: "",
|
|
941
|
+
columnMeta: { type: "core/json@1", nullable: true }
|
|
942
|
+
});
|
|
943
|
+
} else if (isColumnBuilder(value)) {
|
|
944
|
+
const alias = tracker.register([key]);
|
|
945
|
+
aliases.push(alias);
|
|
946
|
+
columns.push(value);
|
|
947
|
+
} else if (typeof value === "object" && value !== null) {
|
|
948
|
+
const nested = flattenProjection(value, tracker, [key]);
|
|
949
|
+
aliases.push(...nested.aliases);
|
|
950
|
+
columns.push(...nested.columns);
|
|
951
|
+
} else {
|
|
952
|
+
errorInvalidProjectionKey(key);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
if (aliases.length === 0) {
|
|
956
|
+
errorProjectionEmpty();
|
|
957
|
+
}
|
|
958
|
+
return { aliases, columns };
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// src/relations/include-plan.ts
|
|
962
|
+
function buildIncludeAsts(includes, contract, context, modelName, paramsMap, paramDescriptors, paramValues, paramCodecs) {
|
|
963
|
+
const includesAst = [];
|
|
964
|
+
const includesForMeta = [];
|
|
965
|
+
for (const includeState of includes) {
|
|
966
|
+
checkIncludeCapabilities(contract);
|
|
967
|
+
const parentTableName = contract.mappings.modelToTable?.[modelName];
|
|
968
|
+
if (!parentTableName) {
|
|
969
|
+
errorModelNotFound(modelName);
|
|
970
|
+
}
|
|
971
|
+
const parentSchemaHandle = schema3(context);
|
|
972
|
+
const parentSchemaTable = parentSchemaHandle.tables[parentTableName];
|
|
973
|
+
if (!parentSchemaTable) {
|
|
974
|
+
errorTableNotFound(parentTableName);
|
|
975
|
+
}
|
|
976
|
+
const childSchemaHandle = schema3(context);
|
|
977
|
+
const childSchemaTable = childSchemaHandle.tables[includeState.childTable.name];
|
|
978
|
+
if (!childSchemaTable) {
|
|
979
|
+
errorTableNotFound(includeState.childTable.name);
|
|
980
|
+
}
|
|
981
|
+
if (includeState.relation.on.parentCols.length !== 1 || includeState.relation.on.childCols.length !== 1) {
|
|
982
|
+
errorMultiColumnJoinsNotSupported();
|
|
983
|
+
}
|
|
984
|
+
const parentColName = includeState.relation.on.parentCols[0];
|
|
985
|
+
const childColName = includeState.relation.on.childCols[0];
|
|
986
|
+
if (!parentColName || !childColName) {
|
|
987
|
+
errorJoinColumnsMustBeDefined();
|
|
988
|
+
}
|
|
989
|
+
const parentCol = parentSchemaTable.columns[parentColName];
|
|
990
|
+
const childCol = childSchemaTable.columns[childColName];
|
|
991
|
+
if (!parentCol) {
|
|
992
|
+
errorColumnNotFound(parentColName, parentTableName);
|
|
993
|
+
}
|
|
994
|
+
if (!childCol) {
|
|
995
|
+
errorColumnNotFound(childColName, includeState.childTable.name);
|
|
996
|
+
}
|
|
997
|
+
const onExpr = buildJoinOnExpr(
|
|
998
|
+
parentTableName,
|
|
999
|
+
parentColName,
|
|
1000
|
+
includeState.childTable.name,
|
|
1001
|
+
childColName
|
|
1002
|
+
);
|
|
1003
|
+
if (!includeState.childProjection) {
|
|
1004
|
+
errorChildProjectionMustBeSpecified();
|
|
1005
|
+
}
|
|
1006
|
+
const filteredProjection = {};
|
|
1007
|
+
for (const [key, value] of Object.entries(includeState.childProjection)) {
|
|
1008
|
+
if (value !== true && value !== false) {
|
|
1009
|
+
filteredProjection[key] = value;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
if (Object.keys(filteredProjection).length === 0) {
|
|
1013
|
+
errorChildProjectionEmpty();
|
|
1014
|
+
}
|
|
1015
|
+
const childProjectionState = buildProjectionState(
|
|
1016
|
+
includeState.childTable,
|
|
1017
|
+
filteredProjection
|
|
1018
|
+
);
|
|
1019
|
+
let childWhere;
|
|
1020
|
+
if (includeState.childWhere) {
|
|
1021
|
+
const whereResult = buildWhereExpr(
|
|
1022
|
+
includeState.childWhere,
|
|
1023
|
+
contract,
|
|
1024
|
+
paramsMap,
|
|
1025
|
+
paramDescriptors,
|
|
1026
|
+
paramValues
|
|
1027
|
+
);
|
|
1028
|
+
childWhere = whereResult.expr;
|
|
1029
|
+
if (whereResult.codecId && whereResult.paramName) {
|
|
1030
|
+
paramCodecs[whereResult.paramName] = whereResult.codecId;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
const childOrderBy = buildChildOrderByClause(includeState.childOrderBy);
|
|
1034
|
+
const childProjectionItems = [];
|
|
1035
|
+
for (let i = 0; i < childProjectionState.aliases.length; i++) {
|
|
1036
|
+
const alias = childProjectionState.aliases[i];
|
|
1037
|
+
if (!alias) {
|
|
1038
|
+
errorMissingAlias(i);
|
|
1039
|
+
}
|
|
1040
|
+
const column = childProjectionState.columns[i];
|
|
1041
|
+
if (!column) {
|
|
1042
|
+
errorMissingColumn(alias, i);
|
|
1043
|
+
}
|
|
1044
|
+
const operationExpr = column._operationExpr;
|
|
1045
|
+
if (operationExpr) {
|
|
1046
|
+
childProjectionItems.push({ alias, expr: operationExpr });
|
|
1047
|
+
} else {
|
|
1048
|
+
const col = column;
|
|
1049
|
+
childProjectionItems.push({ alias, expr: createColumnRef(col.table, col.column) });
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
const includeAst = compact2({
|
|
1053
|
+
kind: "includeMany",
|
|
1054
|
+
alias: includeState.alias,
|
|
1055
|
+
child: compact2({
|
|
1056
|
+
table: includeState.childTable,
|
|
1057
|
+
on: onExpr,
|
|
1058
|
+
project: childProjectionItems,
|
|
1059
|
+
where: childWhere,
|
|
1060
|
+
orderBy: childOrderBy,
|
|
1061
|
+
limit: includeState.childLimit
|
|
1062
|
+
})
|
|
1063
|
+
});
|
|
1064
|
+
includesAst.push(includeAst);
|
|
1065
|
+
const includeForMeta = compact2({
|
|
1066
|
+
alias: includeState.alias,
|
|
1067
|
+
table: includeState.childTable,
|
|
1068
|
+
on: {
|
|
1069
|
+
kind: "join-on",
|
|
1070
|
+
left: parentCol,
|
|
1071
|
+
right: childCol
|
|
1072
|
+
},
|
|
1073
|
+
childProjection: childProjectionState,
|
|
1074
|
+
childWhere: includeState.childWhere,
|
|
1075
|
+
childOrderBy: includeState.childOrderBy,
|
|
1076
|
+
childLimit: includeState.childLimit
|
|
1077
|
+
});
|
|
1078
|
+
includesForMeta.push(includeForMeta);
|
|
1079
|
+
}
|
|
1080
|
+
return { includesAst, includesForMeta };
|
|
1081
|
+
}
|
|
1082
|
+
function buildExistsSubqueries(relationFilters, contract, modelName, options) {
|
|
1083
|
+
const existsExprs = [];
|
|
1084
|
+
for (const filter of relationFilters) {
|
|
1085
|
+
const childTableName = contract.mappings.modelToTable?.[filter.childModelName];
|
|
1086
|
+
if (!childTableName) {
|
|
1087
|
+
errorModelNotFound(filter.childModelName);
|
|
1088
|
+
}
|
|
1089
|
+
const childTable = { kind: "table", name: childTableName };
|
|
1090
|
+
const parentTableName = contract.mappings.modelToTable?.[modelName];
|
|
1091
|
+
if (!parentTableName) {
|
|
1092
|
+
errorModelNotFound(modelName);
|
|
1093
|
+
}
|
|
1094
|
+
const joinConditions = [];
|
|
1095
|
+
for (let i = 0; i < filter.relation.on.parentCols.length; i++) {
|
|
1096
|
+
const parentCol = filter.relation.on.parentCols[i];
|
|
1097
|
+
const childCol = filter.relation.on.childCols[i];
|
|
1098
|
+
if (!parentCol || !childCol) {
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
joinConditions.push({
|
|
1102
|
+
left: { kind: "col", table: parentTableName, column: parentCol },
|
|
1103
|
+
right: { kind: "col", table: childTableName, column: childCol }
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
let childWhere;
|
|
1107
|
+
if (filter.childWhere) {
|
|
1108
|
+
const paramsMap = options?.params ?? {};
|
|
1109
|
+
const paramDescriptors = [];
|
|
1110
|
+
const paramValues = [];
|
|
1111
|
+
const whereResult = buildWhereExpr(
|
|
1112
|
+
filter.childWhere,
|
|
1113
|
+
contract,
|
|
1114
|
+
paramsMap,
|
|
1115
|
+
paramDescriptors,
|
|
1116
|
+
paramValues
|
|
1117
|
+
);
|
|
1118
|
+
childWhere = whereResult.expr;
|
|
1119
|
+
}
|
|
1120
|
+
let subqueryWhere = childWhere;
|
|
1121
|
+
if (joinConditions.length > 0) {
|
|
1122
|
+
const firstJoinCondition = joinConditions[0];
|
|
1123
|
+
if (firstJoinCondition) {
|
|
1124
|
+
const joinWhere = {
|
|
1125
|
+
kind: "bin",
|
|
1126
|
+
op: "eq",
|
|
1127
|
+
left: firstJoinCondition.left,
|
|
1128
|
+
right: firstJoinCondition.right
|
|
1129
|
+
};
|
|
1130
|
+
if (childWhere) {
|
|
1131
|
+
subqueryWhere = joinWhere;
|
|
1132
|
+
} else {
|
|
1133
|
+
subqueryWhere = joinWhere;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
const projectionColumn = joinConditions[0]?.right ?? createColumnRef(childTableName, "id");
|
|
1138
|
+
const subquery = createSelectAst({
|
|
1139
|
+
from: childTable,
|
|
1140
|
+
project: [{ alias: "_exists", expr: projectionColumn }],
|
|
1141
|
+
where: subqueryWhere
|
|
1142
|
+
});
|
|
1143
|
+
const notExists = filter.filterType === "none" || filter.filterType === "every";
|
|
1144
|
+
const existsExpr = {
|
|
1145
|
+
kind: "exists",
|
|
1146
|
+
subquery,
|
|
1147
|
+
not: notExists
|
|
1148
|
+
};
|
|
1149
|
+
existsExprs.push(existsExpr);
|
|
1150
|
+
}
|
|
1151
|
+
return existsExprs;
|
|
1152
|
+
}
|
|
1153
|
+
function combineWhereClauses(mainWhere, existsExprs) {
|
|
1154
|
+
if (existsExprs.length === 1) {
|
|
1155
|
+
return existsExprs[0];
|
|
1156
|
+
}
|
|
1157
|
+
if (mainWhere) {
|
|
1158
|
+
return mainWhere;
|
|
1159
|
+
}
|
|
1160
|
+
if (existsExprs.length > 0) {
|
|
1161
|
+
return existsExprs[0];
|
|
1162
|
+
}
|
|
1163
|
+
return void 0;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// src/selection/select-builder.ts
|
|
1167
|
+
function buildProjectionItems(projectionState, includesForMeta) {
|
|
1168
|
+
const projectEntries = [];
|
|
1169
|
+
for (let i = 0; i < projectionState.aliases.length; i++) {
|
|
1170
|
+
const alias = projectionState.aliases[i];
|
|
1171
|
+
if (!alias) {
|
|
1172
|
+
errorMissingAlias(i);
|
|
1173
|
+
}
|
|
1174
|
+
const column = projectionState.columns[i];
|
|
1175
|
+
if (!column) {
|
|
1176
|
+
errorMissingColumn(alias, i);
|
|
1177
|
+
}
|
|
1178
|
+
const matchingInclude = includesForMeta.find((inc) => inc.alias === alias);
|
|
1179
|
+
if (matchingInclude) {
|
|
1180
|
+
projectEntries.push({
|
|
1181
|
+
alias,
|
|
1182
|
+
expr: { kind: "includeRef", alias }
|
|
1183
|
+
});
|
|
1184
|
+
} else {
|
|
1185
|
+
const operationExpr = column._operationExpr;
|
|
1186
|
+
if (operationExpr) {
|
|
1187
|
+
projectEntries.push({
|
|
1188
|
+
alias,
|
|
1189
|
+
expr: operationExpr
|
|
1190
|
+
});
|
|
1191
|
+
} else {
|
|
1192
|
+
const col = column;
|
|
1193
|
+
const tableName = col.table;
|
|
1194
|
+
const columnName = col.column;
|
|
1195
|
+
if (!tableName || !columnName) {
|
|
1196
|
+
errorInvalidColumn(alias, i);
|
|
1197
|
+
}
|
|
1198
|
+
projectEntries.push({
|
|
1199
|
+
alias,
|
|
1200
|
+
expr: createColumnRef(tableName, columnName)
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
return projectEntries;
|
|
1206
|
+
}
|
|
1207
|
+
function buildSelectAst(table, projectEntries, includesAst, whereExpr, orderByClause, limit) {
|
|
1208
|
+
return createSelectAst({
|
|
1209
|
+
from: createTableRef(table.name),
|
|
1210
|
+
project: projectEntries,
|
|
1211
|
+
includes: includesAst,
|
|
1212
|
+
where: whereExpr,
|
|
1213
|
+
orderBy: orderByClause,
|
|
1214
|
+
limit
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// src/orm/context.ts
|
|
1219
|
+
function createOrmContext(context) {
|
|
1220
|
+
return context;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// src/orm/builder.ts
|
|
1224
|
+
var OrmModelBuilderImpl = class _OrmModelBuilderImpl {
|
|
1225
|
+
context;
|
|
1226
|
+
contract;
|
|
1227
|
+
modelName;
|
|
1228
|
+
table;
|
|
1229
|
+
wherePredicate = void 0;
|
|
1230
|
+
relationFilters = [];
|
|
1231
|
+
includes = [];
|
|
1232
|
+
orderByExpr = void 0;
|
|
1233
|
+
limitValue = void 0;
|
|
1234
|
+
offsetValue = void 0;
|
|
1235
|
+
projection = void 0;
|
|
1236
|
+
constructor(options, modelName) {
|
|
1237
|
+
this.context = options.context;
|
|
1238
|
+
this.contract = options.context.contract;
|
|
1239
|
+
this.modelName = modelName;
|
|
1240
|
+
const tableName = this.contract.mappings.modelToTable?.[modelName];
|
|
1241
|
+
if (!tableName) {
|
|
1242
|
+
errorModelNotFound(modelName);
|
|
1243
|
+
}
|
|
1244
|
+
const schemaHandle = schema4(options.context);
|
|
1245
|
+
const table = schemaHandle.tables[tableName];
|
|
1246
|
+
if (!table) {
|
|
1247
|
+
errorTableNotFound(tableName);
|
|
1248
|
+
}
|
|
1249
|
+
this.table = table;
|
|
1250
|
+
}
|
|
1251
|
+
get where() {
|
|
1252
|
+
const whereFn = (fn) => {
|
|
1253
|
+
const builder = new _OrmModelBuilderImpl(
|
|
1254
|
+
{ context: this.context },
|
|
1255
|
+
this.modelName
|
|
1256
|
+
);
|
|
1257
|
+
builder["table"] = this.table;
|
|
1258
|
+
builder.wherePredicate = fn(this._getModelAccessor());
|
|
1259
|
+
builder.relationFilters = this.relationFilters;
|
|
1260
|
+
builder.includes = this.includes;
|
|
1261
|
+
builder.orderByExpr = this.orderByExpr;
|
|
1262
|
+
builder.limitValue = this.limitValue;
|
|
1263
|
+
builder.offsetValue = this.offsetValue;
|
|
1264
|
+
builder.projection = this.projection;
|
|
1265
|
+
return builder;
|
|
1266
|
+
};
|
|
1267
|
+
const related = this._createRelatedProxy();
|
|
1268
|
+
return Object.assign(whereFn, { related });
|
|
1269
|
+
}
|
|
1270
|
+
get include() {
|
|
1271
|
+
return this._createIncludeProxy();
|
|
1272
|
+
}
|
|
1273
|
+
_createIncludeProxy() {
|
|
1274
|
+
const self = this;
|
|
1275
|
+
const tableName = this.contract.mappings.modelToTable?.[this.modelName];
|
|
1276
|
+
if (!tableName) {
|
|
1277
|
+
return {};
|
|
1278
|
+
}
|
|
1279
|
+
const modelRelations = this.contract.relations?.[tableName];
|
|
1280
|
+
if (!modelRelations || typeof modelRelations !== "object") {
|
|
1281
|
+
return {};
|
|
1282
|
+
}
|
|
1283
|
+
return new Proxy({}, {
|
|
1284
|
+
get(_target, prop) {
|
|
1285
|
+
if (typeof prop !== "string") {
|
|
1286
|
+
return void 0;
|
|
1287
|
+
}
|
|
1288
|
+
const relation = modelRelations[prop];
|
|
1289
|
+
if (!relation || typeof relation !== "object" || !("to" in relation)) {
|
|
1290
|
+
throw planInvalid5(`Relation ${prop} not found on model ${self.modelName}`);
|
|
1291
|
+
}
|
|
1292
|
+
const childModelName = relation.to;
|
|
1293
|
+
const relationDef = relation;
|
|
1294
|
+
const relationName = prop;
|
|
1295
|
+
const includeFn = ((child) => {
|
|
1296
|
+
return self._applyInclude(
|
|
1297
|
+
relationName,
|
|
1298
|
+
childModelName,
|
|
1299
|
+
child,
|
|
1300
|
+
relationDef
|
|
1301
|
+
);
|
|
1302
|
+
});
|
|
1303
|
+
return includeFn;
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
_applyInclude(relationName, childModelName, childBuilderFn, relationDef) {
|
|
1308
|
+
const childTableName = this.contract.mappings.modelToTable?.[childModelName];
|
|
1309
|
+
if (!childTableName) {
|
|
1310
|
+
errorModelNotFound(childModelName);
|
|
1311
|
+
}
|
|
1312
|
+
const childTable = { kind: "table", name: childTableName };
|
|
1313
|
+
const childBuilder = new OrmIncludeChildBuilderImpl(
|
|
1314
|
+
{ context: this.context },
|
|
1315
|
+
childModelName
|
|
1316
|
+
);
|
|
1317
|
+
const builtChild = childBuilderFn(
|
|
1318
|
+
childBuilder
|
|
1319
|
+
);
|
|
1320
|
+
const childState = builtChild.getState();
|
|
1321
|
+
const includeState = {
|
|
1322
|
+
relationName,
|
|
1323
|
+
childModelName,
|
|
1324
|
+
childTable,
|
|
1325
|
+
childWhere: childState.childWhere,
|
|
1326
|
+
childOrderBy: childState.childOrderBy,
|
|
1327
|
+
childLimit: childState.childLimit,
|
|
1328
|
+
childProjection: childState.childProjection,
|
|
1329
|
+
alias: relationName,
|
|
1330
|
+
relation: relationDef
|
|
1331
|
+
};
|
|
1332
|
+
const builder = new _OrmModelBuilderImpl({ context: this.context }, this.modelName);
|
|
1333
|
+
builder["table"] = this.table;
|
|
1334
|
+
builder.wherePredicate = this.wherePredicate;
|
|
1335
|
+
builder.relationFilters = this.relationFilters;
|
|
1336
|
+
builder.includes = [...this.includes, includeState];
|
|
1337
|
+
builder.orderByExpr = this.orderByExpr;
|
|
1338
|
+
builder.limitValue = this.limitValue;
|
|
1339
|
+
builder.offsetValue = this.offsetValue;
|
|
1340
|
+
builder.projection = this.projection;
|
|
1341
|
+
return builder;
|
|
1342
|
+
}
|
|
1343
|
+
_createRelatedProxy() {
|
|
1344
|
+
const self = this;
|
|
1345
|
+
const tableName = this.contract.mappings.modelToTable?.[this.modelName];
|
|
1346
|
+
if (!tableName) {
|
|
1347
|
+
return {};
|
|
1348
|
+
}
|
|
1349
|
+
const modelRelations = this.contract.relations?.[tableName];
|
|
1350
|
+
if (!modelRelations || typeof modelRelations !== "object") {
|
|
1351
|
+
return {};
|
|
1352
|
+
}
|
|
1353
|
+
return new Proxy(
|
|
1354
|
+
{},
|
|
1355
|
+
{
|
|
1356
|
+
get(_target, prop) {
|
|
1357
|
+
if (typeof prop !== "string") {
|
|
1358
|
+
return void 0;
|
|
1359
|
+
}
|
|
1360
|
+
const relation = modelRelations[prop];
|
|
1361
|
+
if (!relation || typeof relation !== "object" || !("to" in relation)) {
|
|
1362
|
+
throw planInvalid5(`Relation ${prop} not found on model ${self.modelName}`);
|
|
1363
|
+
}
|
|
1364
|
+
const childModelName = relation.to;
|
|
1365
|
+
const relationDef = relation;
|
|
1366
|
+
const filterBuilder = new OrmRelationFilterBuilderImpl({ context: self.context }, childModelName);
|
|
1367
|
+
const modelAccessor = filterBuilder.getModelAccessor();
|
|
1368
|
+
const builderWithAccessor = Object.assign(
|
|
1369
|
+
filterBuilder,
|
|
1370
|
+
modelAccessor
|
|
1371
|
+
);
|
|
1372
|
+
return {
|
|
1373
|
+
some: (fn) => {
|
|
1374
|
+
const result = fn(builderWithAccessor);
|
|
1375
|
+
if (result && "kind" in result && result.kind === "binary") {
|
|
1376
|
+
const wrappedBuilder = new OrmRelationFilterBuilderImpl({ context: self.context }, childModelName);
|
|
1377
|
+
wrappedBuilder["wherePredicate"] = result;
|
|
1378
|
+
return self._applyRelationFilter(
|
|
1379
|
+
prop,
|
|
1380
|
+
childModelName,
|
|
1381
|
+
"some",
|
|
1382
|
+
() => wrappedBuilder,
|
|
1383
|
+
relationDef
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
return self._applyRelationFilter(
|
|
1387
|
+
prop,
|
|
1388
|
+
childModelName,
|
|
1389
|
+
"some",
|
|
1390
|
+
() => result,
|
|
1391
|
+
relationDef
|
|
1392
|
+
);
|
|
1393
|
+
},
|
|
1394
|
+
none: (fn) => {
|
|
1395
|
+
const result = fn(builderWithAccessor);
|
|
1396
|
+
if (result && "kind" in result && result.kind === "binary") {
|
|
1397
|
+
const wrappedBuilder = new OrmRelationFilterBuilderImpl({ context: self.context }, childModelName);
|
|
1398
|
+
wrappedBuilder["wherePredicate"] = result;
|
|
1399
|
+
return self._applyRelationFilter(
|
|
1400
|
+
prop,
|
|
1401
|
+
childModelName,
|
|
1402
|
+
"none",
|
|
1403
|
+
() => wrappedBuilder,
|
|
1404
|
+
relationDef
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
return self._applyRelationFilter(
|
|
1408
|
+
prop,
|
|
1409
|
+
childModelName,
|
|
1410
|
+
"none",
|
|
1411
|
+
() => result,
|
|
1412
|
+
relationDef
|
|
1413
|
+
);
|
|
1414
|
+
},
|
|
1415
|
+
every: (fn) => {
|
|
1416
|
+
const result = fn(builderWithAccessor);
|
|
1417
|
+
if (result && "kind" in result && result.kind === "binary") {
|
|
1418
|
+
const wrappedBuilder = new OrmRelationFilterBuilderImpl({ context: self.context }, childModelName);
|
|
1419
|
+
wrappedBuilder["wherePredicate"] = result;
|
|
1420
|
+
return self._applyRelationFilter(
|
|
1421
|
+
prop,
|
|
1422
|
+
childModelName,
|
|
1423
|
+
"every",
|
|
1424
|
+
() => wrappedBuilder,
|
|
1425
|
+
relationDef
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
return self._applyRelationFilter(
|
|
1429
|
+
prop,
|
|
1430
|
+
childModelName,
|
|
1431
|
+
"every",
|
|
1432
|
+
() => result,
|
|
1433
|
+
relationDef
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
_applyRelationFilter(relationName, childModelName, filterType, fn, relationDef) {
|
|
1442
|
+
const filterBuilder = new OrmRelationFilterBuilderImpl(
|
|
1443
|
+
{ context: this.context },
|
|
1444
|
+
childModelName
|
|
1445
|
+
);
|
|
1446
|
+
const appliedFilter = fn(
|
|
1447
|
+
filterBuilder
|
|
1448
|
+
);
|
|
1449
|
+
const childWhere = appliedFilter.getWherePredicate();
|
|
1450
|
+
const relationFilter = {
|
|
1451
|
+
relationName,
|
|
1452
|
+
childModelName,
|
|
1453
|
+
filterType,
|
|
1454
|
+
childWhere,
|
|
1455
|
+
relation: relationDef
|
|
1456
|
+
};
|
|
1457
|
+
const builder = new _OrmModelBuilderImpl(
|
|
1458
|
+
{ context: this.context },
|
|
1459
|
+
this.modelName
|
|
1460
|
+
);
|
|
1461
|
+
builder["table"] = this.table;
|
|
1462
|
+
builder.wherePredicate = this.wherePredicate;
|
|
1463
|
+
builder.relationFilters = [...this.relationFilters, relationFilter];
|
|
1464
|
+
builder.includes = this.includes;
|
|
1465
|
+
builder.orderByExpr = this.orderByExpr;
|
|
1466
|
+
builder.limitValue = this.limitValue;
|
|
1467
|
+
builder.offsetValue = this.offsetValue;
|
|
1468
|
+
builder.projection = this.projection;
|
|
1469
|
+
return builder;
|
|
1470
|
+
}
|
|
1471
|
+
orderBy(fn) {
|
|
1472
|
+
const builder = new _OrmModelBuilderImpl(
|
|
1473
|
+
{ context: this.context },
|
|
1474
|
+
this.modelName
|
|
1475
|
+
);
|
|
1476
|
+
builder["table"] = this.table;
|
|
1477
|
+
builder.wherePredicate = this.wherePredicate;
|
|
1478
|
+
builder.relationFilters = this.relationFilters;
|
|
1479
|
+
builder.includes = this.includes;
|
|
1480
|
+
builder.orderByExpr = fn(this._getModelAccessor());
|
|
1481
|
+
builder.limitValue = this.limitValue;
|
|
1482
|
+
builder.offsetValue = this.offsetValue;
|
|
1483
|
+
builder.projection = this.projection;
|
|
1484
|
+
return builder;
|
|
1485
|
+
}
|
|
1486
|
+
take(n) {
|
|
1487
|
+
const builder = new _OrmModelBuilderImpl(
|
|
1488
|
+
{ context: this.context },
|
|
1489
|
+
this.modelName
|
|
1490
|
+
);
|
|
1491
|
+
builder["table"] = this.table;
|
|
1492
|
+
builder.wherePredicate = this.wherePredicate;
|
|
1493
|
+
builder.relationFilters = this.relationFilters;
|
|
1494
|
+
builder.includes = this.includes;
|
|
1495
|
+
builder.orderByExpr = this.orderByExpr;
|
|
1496
|
+
builder.limitValue = n;
|
|
1497
|
+
builder.offsetValue = this.offsetValue;
|
|
1498
|
+
builder.projection = this.projection;
|
|
1499
|
+
return builder;
|
|
1500
|
+
}
|
|
1501
|
+
skip(n) {
|
|
1502
|
+
const builder = new _OrmModelBuilderImpl(
|
|
1503
|
+
{ context: this.context },
|
|
1504
|
+
this.modelName
|
|
1505
|
+
);
|
|
1506
|
+
builder["table"] = this.table;
|
|
1507
|
+
builder.wherePredicate = this.wherePredicate;
|
|
1508
|
+
builder.relationFilters = this.relationFilters;
|
|
1509
|
+
builder.includes = this.includes;
|
|
1510
|
+
builder.orderByExpr = this.orderByExpr;
|
|
1511
|
+
builder.limitValue = this.limitValue;
|
|
1512
|
+
builder.offsetValue = n;
|
|
1513
|
+
builder.projection = this.projection;
|
|
1514
|
+
return builder;
|
|
1515
|
+
}
|
|
1516
|
+
select(fn) {
|
|
1517
|
+
const builder = new _OrmModelBuilderImpl({ context: this.context }, this.modelName);
|
|
1518
|
+
builder["table"] = this.table;
|
|
1519
|
+
builder.wherePredicate = this.wherePredicate;
|
|
1520
|
+
builder.relationFilters = this.relationFilters;
|
|
1521
|
+
builder.includes = this.includes;
|
|
1522
|
+
builder.orderByExpr = this.orderByExpr;
|
|
1523
|
+
builder.limitValue = this.limitValue;
|
|
1524
|
+
builder.offsetValue = this.offsetValue;
|
|
1525
|
+
builder.projection = fn(this._getModelAccessor());
|
|
1526
|
+
return builder;
|
|
1527
|
+
}
|
|
1528
|
+
findMany(options) {
|
|
1529
|
+
const paramsMap = options?.params ?? {};
|
|
1530
|
+
const contractTable = this.contract.storage.tables[this.table.name];
|
|
1531
|
+
if (!contractTable) {
|
|
1532
|
+
errorUnknownTable(this.table.name);
|
|
1533
|
+
}
|
|
1534
|
+
const paramDescriptors = [];
|
|
1535
|
+
const paramValues = [];
|
|
1536
|
+
const paramCodecs = {};
|
|
1537
|
+
const projectionInput = this.projection ?? (() => {
|
|
1538
|
+
const modelAccessor = this._getModelAccessor();
|
|
1539
|
+
const defaultProjection = {};
|
|
1540
|
+
for (const fieldName in modelAccessor) {
|
|
1541
|
+
defaultProjection[fieldName] = modelAccessor[fieldName];
|
|
1542
|
+
}
|
|
1543
|
+
return defaultProjection;
|
|
1544
|
+
})();
|
|
1545
|
+
const { includesAst, includesForMeta } = buildIncludeAsts(
|
|
1546
|
+
this.includes,
|
|
1547
|
+
this.contract,
|
|
1548
|
+
this.context,
|
|
1549
|
+
this.modelName,
|
|
1550
|
+
paramsMap,
|
|
1551
|
+
paramDescriptors,
|
|
1552
|
+
paramValues,
|
|
1553
|
+
paramCodecs
|
|
1554
|
+
);
|
|
1555
|
+
const projectionState = buildProjectionState(
|
|
1556
|
+
this.table,
|
|
1557
|
+
projectionInput,
|
|
1558
|
+
includesForMeta.length > 0 ? includesForMeta : void 0
|
|
1559
|
+
);
|
|
1560
|
+
const whereResult = this.wherePredicate ? buildWhereExpr(this.wherePredicate, this.contract, paramsMap, paramDescriptors, paramValues) : void 0;
|
|
1561
|
+
const whereExpr = whereResult?.expr;
|
|
1562
|
+
if (whereResult?.codecId && whereResult.paramName) {
|
|
1563
|
+
paramCodecs[whereResult.paramName] = whereResult.codecId;
|
|
1564
|
+
}
|
|
1565
|
+
const orderByClause = buildOrderByClause(this.orderByExpr);
|
|
1566
|
+
const projectEntries = buildProjectionItems(projectionState, includesForMeta);
|
|
1567
|
+
const ast = buildSelectAst(
|
|
1568
|
+
this.table,
|
|
1569
|
+
projectEntries,
|
|
1570
|
+
includesAst.length > 0 ? includesAst : void 0,
|
|
1571
|
+
whereExpr,
|
|
1572
|
+
orderByClause,
|
|
1573
|
+
this.limitValue
|
|
1574
|
+
);
|
|
1575
|
+
const planMeta = buildMeta({
|
|
1576
|
+
contract: this.contract,
|
|
1577
|
+
table: createTableRef(this.table.name),
|
|
1578
|
+
projection: projectionState,
|
|
1579
|
+
includes: includesForMeta.length > 0 ? includesForMeta : void 0,
|
|
1580
|
+
paramDescriptors,
|
|
1581
|
+
paramCodecs: Object.keys(paramCodecs).length > 0 ? paramCodecs : void 0,
|
|
1582
|
+
where: this.wherePredicate,
|
|
1583
|
+
orderBy: this.orderByExpr
|
|
1584
|
+
});
|
|
1585
|
+
if (this.relationFilters.length > 0) {
|
|
1586
|
+
const existsExprs = buildExistsSubqueries(
|
|
1587
|
+
this.relationFilters,
|
|
1588
|
+
this.contract,
|
|
1589
|
+
this.modelName,
|
|
1590
|
+
options
|
|
1591
|
+
);
|
|
1592
|
+
if (existsExprs.length > 0) {
|
|
1593
|
+
const combinedWhere = combineWhereClauses(ast.where, existsExprs);
|
|
1594
|
+
const modifiedAst = {
|
|
1595
|
+
...ast,
|
|
1596
|
+
...combinedWhere !== void 0 ? { where: combinedWhere } : {}
|
|
1597
|
+
};
|
|
1598
|
+
return Object.freeze({
|
|
1599
|
+
ast: modifiedAst,
|
|
1600
|
+
params: paramValues,
|
|
1601
|
+
meta: {
|
|
1602
|
+
...planMeta,
|
|
1603
|
+
lane: "orm"
|
|
1604
|
+
}
|
|
1605
|
+
});
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
return Object.freeze({
|
|
1609
|
+
ast,
|
|
1610
|
+
params: paramValues,
|
|
1611
|
+
meta: {
|
|
1612
|
+
...planMeta,
|
|
1613
|
+
lane: "orm"
|
|
1614
|
+
}
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
findFirst(options) {
|
|
1618
|
+
const queryPlan = this.take(1).findMany(options);
|
|
1619
|
+
return queryPlan;
|
|
1620
|
+
}
|
|
1621
|
+
findUnique(where, options) {
|
|
1622
|
+
return this.where(where).take(1).findMany(options);
|
|
1623
|
+
}
|
|
1624
|
+
create(data, options) {
|
|
1625
|
+
const context = createOrmContext(this.context);
|
|
1626
|
+
return buildInsertPlan(context, this.modelName, data, options);
|
|
1627
|
+
}
|
|
1628
|
+
update(where, data, options) {
|
|
1629
|
+
const context = createOrmContext(this.context);
|
|
1630
|
+
return buildUpdatePlan(
|
|
1631
|
+
context,
|
|
1632
|
+
this.modelName,
|
|
1633
|
+
where,
|
|
1634
|
+
() => this._getModelAccessor(),
|
|
1635
|
+
data,
|
|
1636
|
+
options
|
|
1637
|
+
);
|
|
1638
|
+
}
|
|
1639
|
+
delete(where, options) {
|
|
1640
|
+
const context = createOrmContext(this.context);
|
|
1641
|
+
return buildDeletePlan(
|
|
1642
|
+
context,
|
|
1643
|
+
this.modelName,
|
|
1644
|
+
where,
|
|
1645
|
+
() => this._getModelAccessor(),
|
|
1646
|
+
options
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1649
|
+
_getModelAccessor() {
|
|
1650
|
+
const tableName = this.contract.mappings.modelToTable?.[this.modelName];
|
|
1651
|
+
if (!tableName) {
|
|
1652
|
+
errorModelNotFound(this.modelName);
|
|
1653
|
+
}
|
|
1654
|
+
const schemaHandle = schema4(this.context);
|
|
1655
|
+
const table = schemaHandle.tables[tableName];
|
|
1656
|
+
if (!table) {
|
|
1657
|
+
errorTableNotFound(tableName);
|
|
1658
|
+
}
|
|
1659
|
+
const accessor = {};
|
|
1660
|
+
const model = this.contract.models[this.modelName];
|
|
1661
|
+
if (!model || typeof model !== "object" || !("fields" in model)) {
|
|
1662
|
+
throw planInvalid5(`Model ${this.modelName} does not have fields`);
|
|
1663
|
+
}
|
|
1664
|
+
const modelFields = model.fields;
|
|
1665
|
+
for (const fieldName in modelFields) {
|
|
1666
|
+
const field = modelFields[fieldName];
|
|
1667
|
+
if (!field) continue;
|
|
1668
|
+
const columnName = this.contract.mappings.fieldToColumn?.[this.modelName]?.[fieldName] ?? field.column ?? fieldName;
|
|
1669
|
+
const column = table.columns[columnName];
|
|
1670
|
+
if (column) {
|
|
1671
|
+
accessor[fieldName] = column;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
return accessor;
|
|
1675
|
+
}
|
|
1676
|
+
};
|
|
1677
|
+
|
|
1678
|
+
// src/orm.ts
|
|
1679
|
+
import { planInvalid as planInvalid6 } from "@prisma-next/plan";
|
|
1680
|
+
function orm(options) {
|
|
1681
|
+
const contract = options.context.contract;
|
|
1682
|
+
return new Proxy({}, {
|
|
1683
|
+
get(_target, prop) {
|
|
1684
|
+
if (typeof prop !== "string") {
|
|
1685
|
+
return void 0;
|
|
1686
|
+
}
|
|
1687
|
+
const modelName = prop.charAt(0).toUpperCase() + prop.slice(1);
|
|
1688
|
+
if (!contract.models || typeof contract.models !== "object" || !(modelName in contract.models)) {
|
|
1689
|
+
throw planInvalid6(`Model ${prop} (resolved to ${modelName}) not found in contract`);
|
|
1690
|
+
}
|
|
1691
|
+
return () => new OrmModelBuilderImpl(options, modelName);
|
|
1692
|
+
},
|
|
1693
|
+
has(_target, prop) {
|
|
1694
|
+
if (typeof prop !== "string") {
|
|
1695
|
+
return false;
|
|
1696
|
+
}
|
|
1697
|
+
const modelName = prop.charAt(0).toUpperCase() + prop.slice(1);
|
|
1698
|
+
return contract.models && typeof contract.models === "object" && modelName in contract.models;
|
|
1699
|
+
}
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
export {
|
|
1704
|
+
OrmModelBuilderImpl,
|
|
1705
|
+
orm
|
|
1706
|
+
};
|
|
1707
|
+
//# sourceMappingURL=chunk-JOTSRS66.js.map
|