@prisma/orm-family-sql 8.0.0-rc.17-dev.10 → 8.0.0-rc.17-dev.12
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/{authoring-type-constructors-0Iv2zdwS-DX59Qw3z.mjs → authoring-type-constructors-0Iv2zdwS-CnynTqjm.mjs} +2 -2
- package/dist/{authoring-type-constructors-0Iv2zdwS-DX59Qw3z.mjs.map → authoring-type-constructors-0Iv2zdwS-CnynTqjm.mjs.map} +1 -1
- package/dist/{config-types-HwU-FfRj.mjs → config-types-DggwpWr3.mjs} +2 -2
- package/dist/{config-types-HwU-FfRj.mjs.map → config-types-DggwpWr3.mjs.map} +1 -1
- package/dist/{contract-builder-Tmmlb0mv.mjs → contract-builder-J9D4EprQ.mjs} +3 -3
- package/dist/{contract-builder-Tmmlb0mv.mjs.map → contract-builder-J9D4EprQ.mjs.map} +1 -1
- package/dist/contract-prisma7__provider.mjs +4 -4
- package/dist/contract-psl.mjs +1 -1
- package/dist/contract-psl__attribute-specs.mjs +1 -1
- package/dist/contract-psl__provider.mjs +2 -2
- package/dist/contract-ts.mjs +3 -3
- package/dist/contract-ts__config-types.mjs +1 -1
- package/dist/contract-ts__contract-builder.mjs +2 -2
- package/dist/contract.d.mts +2 -2
- package/dist/contract.mjs +2 -2
- package/dist/contract__validators.d.mts +2 -2
- package/dist/contract__validators.mjs +2 -2
- package/dist/{control-COI98aRs.mjs → control-Bce-z7el.mjs} +5 -5
- package/dist/{control-COI98aRs.mjs.map → control-Bce-z7el.mjs.map} +1 -1
- package/dist/{control-BQpDsD3I.d.mts → control-DdyeUFkv.d.mts} +2 -2
- package/dist/{control-BQpDsD3I.d.mts.map → control-DdyeUFkv.d.mts.map} +1 -1
- package/dist/{derived-checks-RB_lNgFJ-CHamqgFW.mjs → derived-checks-CEK-Ls_a-plK5KxX3.mjs} +45 -7
- package/dist/derived-checks-CEK-Ls_a-plK5KxX3.mjs.map +1 -0
- package/dist/family.d.mts +2 -2
- package/dist/family.mjs +3 -3
- package/dist/family__control.d.mts +2 -2
- package/dist/family__control.mjs +2 -2
- package/dist/family__ir.mjs +1 -1
- package/dist/family__pack.mjs +2 -2
- package/dist/{interpreter-BTM9k0wn-Bu5eCC-Z.mjs → interpreter-BTM9k0wn-Cya0qReB.mjs} +3 -3
- package/dist/{interpreter-BTM9k0wn-Bu5eCC-Z.mjs.map → interpreter-BTM9k0wn-Cya0qReB.mjs.map} +1 -1
- package/dist/orm-client.mjs +421 -252
- package/dist/orm-client.mjs.map +1 -1
- package/dist/{psl-field-resolution-CAJsUfST-DWY_oqor.mjs → psl-field-resolution-CAJsUfST-C4QwwiqV.mjs} +3 -3
- package/dist/{psl-field-resolution-CAJsUfST-DWY_oqor.mjs.map → psl-field-resolution-CAJsUfST-C4QwwiqV.mjs.map} +1 -1
- package/dist/{sql-contract-serializer-DDaAVCQr-CGG0I8ur.mjs → sql-contract-serializer-DDaAVCQr-CK2KUyq0.mjs} +2 -2
- package/dist/{sql-contract-serializer-DDaAVCQr-CGG0I8ur.mjs.map → sql-contract-serializer-DDaAVCQr-CK2KUyq0.mjs.map} +1 -1
- package/dist/{validators-CIfn8ezs.mjs → validators-B9prRmOP.mjs} +63 -6
- package/dist/validators-B9prRmOP.mjs.map +1 -0
- package/dist/{validators-COcD3_iw.d.mts → validators-CudqzmkF.d.mts} +11 -6
- package/dist/{validators-COcD3_iw.d.mts.map → validators-CudqzmkF.d.mts.map} +1 -1
- package/package.json +18 -18
- package/dist/derived-checks-RB_lNgFJ-CHamqgFW.mjs.map +0 -1
- package/dist/validators-CIfn8ezs.mjs.map +0 -1
package/dist/orm-client.mjs
CHANGED
|
@@ -33,6 +33,20 @@ function aggregateOperationNames(registry) {
|
|
|
33
33
|
operationNamesByRegistry.set(registry, names);
|
|
34
34
|
return names;
|
|
35
35
|
}
|
|
36
|
+
const contractCache = /* @__PURE__ */ new WeakMap();
|
|
37
|
+
/** Builds a value derived from `contract` once per contract and key. Every key starts with a name that only one function uses, and that function stores its own result type under it. */
|
|
38
|
+
function cachedFor(contract, key, build) {
|
|
39
|
+
let perContract = contractCache.get(contract);
|
|
40
|
+
if (!perContract) {
|
|
41
|
+
perContract = /* @__PURE__ */ new Map();
|
|
42
|
+
contractCache.set(contract, perContract);
|
|
43
|
+
}
|
|
44
|
+
const cacheKey = JSON.stringify(key);
|
|
45
|
+
if (perContract.has(cacheKey)) return blindCast(perContract.get(cacheKey));
|
|
46
|
+
const built = build();
|
|
47
|
+
perContract.set(cacheKey, built);
|
|
48
|
+
return built;
|
|
49
|
+
}
|
|
36
50
|
function ormError(code, message, options) {
|
|
37
51
|
return structuredError(code, message, options);
|
|
38
52
|
}
|
|
@@ -76,8 +90,6 @@ function modelOf(contract, namespaceId, name) {
|
|
|
76
90
|
const model = contract.domain.namespaces[namespaceId]?.models[name];
|
|
77
91
|
return model === void 0 ? void 0 : blindCast(model);
|
|
78
92
|
}
|
|
79
|
-
const fieldToColumnCache = /* @__PURE__ */ new WeakMap();
|
|
80
|
-
const columnToFieldCache = /* @__PURE__ */ new WeakMap();
|
|
81
93
|
const polymorphismCache = /* @__PURE__ */ new WeakMap();
|
|
82
94
|
function resolvePolymorphismInfo(contract, namespaceId, modelName) {
|
|
83
95
|
let perContract = polymorphismCache.get(contract);
|
|
@@ -99,7 +111,7 @@ function resolvePolymorphismInfo(contract, namespaceId, modelName) {
|
|
|
99
111
|
return;
|
|
100
112
|
}
|
|
101
113
|
const discriminatorField = model.discriminator.field;
|
|
102
|
-
const discriminatorColumn =
|
|
114
|
+
const discriminatorColumn = columnOfContractField(contract, namespaceId, modelName, discriminatorField);
|
|
103
115
|
const variants = /* @__PURE__ */ new Map();
|
|
104
116
|
const variantsByValue = /* @__PURE__ */ new Map();
|
|
105
117
|
const mtiVariants = [];
|
|
@@ -129,81 +141,235 @@ function resolvePolymorphismInfo(contract, namespaceId, modelName) {
|
|
|
129
141
|
perContract.set(cacheKey, result);
|
|
130
142
|
return result;
|
|
131
143
|
}
|
|
132
|
-
|
|
133
|
-
|
|
144
|
+
/** The column each of the model's own fields maps, keyed by field name. */
|
|
145
|
+
function getOwnFieldColumns(contract, namespaceId, modelName) {
|
|
146
|
+
return cachedFor(contract, [
|
|
147
|
+
"ownFieldColumns",
|
|
148
|
+
namespaceId,
|
|
149
|
+
modelName
|
|
150
|
+
], () => {
|
|
151
|
+
const storageFields = modelsOf(contract, namespaceId)[modelName]?.storage?.fields ?? {};
|
|
152
|
+
const columns = {};
|
|
153
|
+
for (const [field, storage] of Object.entries(storageFields)) if (storage?.column) columns[field] = storage.column;
|
|
154
|
+
return columns;
|
|
155
|
+
});
|
|
134
156
|
}
|
|
135
157
|
/**
|
|
136
|
-
*
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
158
|
+
* A model's fields, keyed by field name, with the table and column each maps: its own fields on its own table, and the fields it inherits from its base model on the base model's table. This is the one list of a model's fields; a column no field maps has no entry.
|
|
159
|
+
*/
|
|
160
|
+
function getModelFields(contract, namespaceId, modelName) {
|
|
161
|
+
return cachedFor(contract, [
|
|
162
|
+
"modelFields",
|
|
163
|
+
namespaceId,
|
|
164
|
+
modelName
|
|
165
|
+
], () => {
|
|
166
|
+
const model = modelOf(contract, namespaceId, modelName);
|
|
167
|
+
const table = model?.storage?.table;
|
|
168
|
+
const own = table === void 0 ? {} : Object.fromEntries(Object.entries(getOwnFieldColumns(contract, namespaceId, modelName)).map(([field, column]) => [field, {
|
|
169
|
+
table,
|
|
170
|
+
column
|
|
171
|
+
}]));
|
|
172
|
+
const base = model?.base;
|
|
173
|
+
return {
|
|
174
|
+
...base === void 0 ? {} : getModelFields(contract, base.namespace, base.model),
|
|
175
|
+
...own
|
|
176
|
+
};
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/** The column each of a model's own and inherited fields maps, keyed by field name. */
|
|
180
|
+
function getModelFieldColumns(contract, namespaceId, modelName) {
|
|
181
|
+
return cachedFor(contract, [
|
|
182
|
+
"modelFieldColumns",
|
|
183
|
+
namespaceId,
|
|
184
|
+
modelName
|
|
185
|
+
], () => Object.fromEntries(Object.entries(getModelFields(contract, namespaceId, modelName)).map(([field, { column }]) => [field, column])));
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* The column each field of the model and of the variant `variantName` maps, keyed by field name. Without a variant, the model's fields alone.
|
|
142
189
|
*
|
|
143
|
-
*
|
|
144
|
-
|
|
145
|
-
|
|
190
|
+
* A surface accepts a variant's field only when it can place that field's column on the variant's table. A collection narrowed to a variant reads that variant's table, so `select`, the `where` and `orderBy` accessor and a variant create accept the narrowed variant's fields. A collection that is not narrowed reads the base table only, so only `select`, whose polymorphic projection joins each variant's table, accepts variant fields there (`getModelAndEveryVariantFieldColumns`).
|
|
191
|
+
*/
|
|
192
|
+
function getModelAndVariantFieldColumns(contract, namespaceId, modelName, variantName) {
|
|
193
|
+
return cachedFor(contract, [
|
|
194
|
+
"modelAndVariantFieldColumns",
|
|
195
|
+
namespaceId,
|
|
196
|
+
modelName,
|
|
197
|
+
variantName ?? null
|
|
198
|
+
], () => ({
|
|
199
|
+
...variantName === void 0 ? {} : getOwnFieldColumns(contract, namespaceId, variantName),
|
|
200
|
+
...getModelFieldColumns(contract, namespaceId, modelName)
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Every column each field of the model and of every one of its variants maps, keyed by field name. Two variants may map one field name to different columns, so a name can map several columns.
|
|
205
|
+
*/
|
|
206
|
+
function getModelAndEveryVariantFieldColumns(contract, namespaceId, modelName) {
|
|
207
|
+
return cachedFor(contract, [
|
|
208
|
+
"modelAndEveryVariantFieldColumns",
|
|
209
|
+
namespaceId,
|
|
210
|
+
modelName
|
|
211
|
+
], () => {
|
|
212
|
+
const columns = {};
|
|
213
|
+
const add = (fieldColumns) => {
|
|
214
|
+
for (const [field, column] of Object.entries(fieldColumns)) {
|
|
215
|
+
const existing = columns[field] ?? [];
|
|
216
|
+
if (!existing.includes(column)) existing.push(column);
|
|
217
|
+
columns[field] = existing;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
add(getModelFieldColumns(contract, namespaceId, modelName));
|
|
221
|
+
const modelFields = new Set(Object.keys(columns));
|
|
222
|
+
for (const variant of resolvePolymorphismInfo(contract, namespaceId, modelName)?.variants.keys() ?? []) add(Object.fromEntries(Object.entries(getOwnFieldColumns(contract, namespaceId, variant)).filter(([field]) => !modelFields.has(field))));
|
|
223
|
+
return columns;
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
/** The field each column of the model's own fields maps, keyed by column. */
|
|
227
|
+
function getOwnColumnFields(contract, namespaceId, modelName) {
|
|
228
|
+
return cachedFor(contract, [
|
|
229
|
+
"ownColumnFields",
|
|
230
|
+
namespaceId,
|
|
231
|
+
modelName
|
|
232
|
+
], () => invert(getOwnFieldColumns(contract, namespaceId, modelName)));
|
|
233
|
+
}
|
|
234
|
+
/** The field each column of the model's own and inherited fields maps, keyed by column. */
|
|
235
|
+
function getModelColumnFields(contract, namespaceId, modelName) {
|
|
236
|
+
return cachedFor(contract, [
|
|
237
|
+
"modelColumnFields",
|
|
238
|
+
namespaceId,
|
|
239
|
+
modelName
|
|
240
|
+
], () => invert(getModelFieldColumns(contract, namespaceId, modelName)));
|
|
241
|
+
}
|
|
242
|
+
function invert(map) {
|
|
243
|
+
return Object.fromEntries(Object.entries(map).map(([key, value]) => [value, key]));
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* The column a name a caller passed maps in `fieldColumns`. A name that is not a field is refused with `ORM.FIELD_UNKNOWN`, so no caller reaches a column by its column name, including a column no field maps.
|
|
247
|
+
*/
|
|
248
|
+
function columnOfCallerField(contract, namespaceId, fieldColumns, modelName, fieldName) {
|
|
249
|
+
const column = Object.hasOwn(fieldColumns, fieldName) ? fieldColumns[fieldName] : void 0;
|
|
250
|
+
if (column === void 0) throw callerFieldUnknown(contract, namespaceId, fieldColumns, modelName, fieldName);
|
|
251
|
+
return column;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* The refusal of a name a caller passed that is not a field of the model it addressed. When the name is the column of one of the fields in `fieldColumns`, or a column that no field maps on a table of the model's hierarchy, the message says so and names the table.
|
|
255
|
+
*/
|
|
256
|
+
function callerFieldUnknown(contract, namespaceId, fieldColumns, modelName, fieldName) {
|
|
257
|
+
const unknown = `Model "${modelName}" has no field "${fieldName}"`;
|
|
258
|
+
const fieldForColumn = Object.entries(fieldColumns).find(([, columns]) => typeof columns === "string" ? columns === fieldName : columns.includes(fieldName))?.[0];
|
|
259
|
+
if (fieldForColumn !== void 0) return ormError("ORM.FIELD_UNKNOWN", `${unknown}. "${fieldName}" is the column of field "${fieldForColumn}"; pass the field name.`, { meta: {
|
|
260
|
+
model: modelName,
|
|
261
|
+
field: fieldName,
|
|
262
|
+
fieldForColumn
|
|
263
|
+
} });
|
|
264
|
+
const unmapped = getUnmappedColumns(contract, namespaceId, modelName).find(({ column }) => column === fieldName);
|
|
265
|
+
return ormError("ORM.FIELD_UNKNOWN", `${unknown}${unmapped === void 0 ? "" : `. Table "${unmapped.table}" has a column "${fieldName}" that no field maps, so the ORM cannot read or write it.`}`, { meta: {
|
|
266
|
+
model: modelName,
|
|
267
|
+
field: fieldName
|
|
268
|
+
} });
|
|
269
|
+
}
|
|
270
|
+
/** The columns of the tables of a model's hierarchy that no field of the hierarchy maps. */
|
|
271
|
+
function getUnmappedColumns(contract, namespaceId, modelName) {
|
|
272
|
+
return cachedFor(contract, [
|
|
273
|
+
"unmappedColumns",
|
|
274
|
+
namespaceId,
|
|
275
|
+
modelName
|
|
276
|
+
], () => {
|
|
277
|
+
const root = hierarchyRootName(contract, namespaceId, modelName);
|
|
278
|
+
const rootTable = domainModelTableInNamespace(contract, namespaceId, root);
|
|
279
|
+
if (rootTable === void 0) return [];
|
|
280
|
+
const variants = resolvePolymorphismInfo(contract, namespaceId, root)?.variants.values();
|
|
281
|
+
return [.../* @__PURE__ */ new Set([rootTable, ...[...variants ?? []].map((variant) => variant.table)])].flatMap((table) => {
|
|
282
|
+
const read = new Set(getColumnsReadOnTable(contract, namespaceId, root, table));
|
|
283
|
+
return getAllTableColumns(contract, namespaceId, table).filter((column) => !read.has(column)).map((column) => ({
|
|
284
|
+
table,
|
|
285
|
+
column
|
|
286
|
+
}));
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
function hierarchyRootName(contract, namespaceId, modelName) {
|
|
291
|
+
const base = modelOf(contract, namespaceId, modelName)?.base;
|
|
292
|
+
return base === void 0 || base.namespace !== namespaceId ? modelName : hierarchyRootName(contract, namespaceId, base.model);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The column a field name the contract itself gives maps among the model's own and inherited fields, such as a relation's join field or a discriminator. The contract was validated, so a name that is not a field is an internal error.
|
|
296
|
+
*/
|
|
297
|
+
function columnOfContractField(contract, namespaceId, modelName, fieldName) {
|
|
298
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
299
|
+
const column = Object.hasOwn(fieldColumns, fieldName) ? fieldColumns[fieldName] : void 0;
|
|
300
|
+
if (column === void 0) throw new InternalError(`Model "${modelName}" has no field "${fieldName}" the contract names`);
|
|
301
|
+
return column;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* The field that maps `column` in `columnFields`. The ORM only asks this for a column it chose itself, such as a key column or a column it projected, so a column no field maps is an internal error.
|
|
305
|
+
*/
|
|
306
|
+
function fieldOfColumn(columnFields, modelName, column) {
|
|
307
|
+
const field = Object.hasOwn(columnFields, column) ? columnFields[column] : void 0;
|
|
308
|
+
if (field === void 0) throw new InternalError(`Column "${column}" of model "${modelName}" is mapped by no field`);
|
|
309
|
+
return field;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* The columns a relation's target fields name. A relation through a junction table names the junction's columns there, not fields of the target model.
|
|
313
|
+
*/
|
|
314
|
+
function resolveRelationTargetColumns(contract, relation) {
|
|
315
|
+
if (relation.through !== void 0) return [...relation.on.targetFields];
|
|
316
|
+
return relation.on.targetFields.map((field) => columnOfContractField(contract, relation.toNamespace, relation.to, field));
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* The fields a multi-table variant declares, with the table and column each maps, which is the variant's own table the read path joins. A single-table variant's columns are on the base table, and inherited fields are on the base model's table, so neither appears here.
|
|
146
320
|
*/
|
|
147
321
|
function resolveVariantFieldColumns(contract, namespaceId, baseModelName, variantName) {
|
|
148
322
|
const variant = resolvePolymorphismInfo(contract, namespaceId, baseModelName)?.variants.get(variantName);
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const variantFieldToColumn = getFieldToColumnMap(contract, namespaceId, variant.modelName);
|
|
152
|
-
for (const [field, column] of Object.entries(variantFieldToColumn)) result[field] = {
|
|
153
|
-
table: variant.table,
|
|
154
|
-
column
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
return result;
|
|
323
|
+
if (variant?.strategy !== "mti") return {};
|
|
324
|
+
return Object.fromEntries(Object.entries(getModelFields(contract, namespaceId, variant.modelName)).filter(([, field]) => field.table === variant.table));
|
|
158
325
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
cached = {};
|
|
170
|
-
for (const [f, s] of Object.entries(storageFields)) if (s?.column) cached[f] = s.column;
|
|
171
|
-
perContract.set(cacheKey, cached);
|
|
172
|
-
return cached;
|
|
173
|
-
}
|
|
174
|
-
function getColumnToFieldMap(contract, namespaceId, modelName) {
|
|
175
|
-
let perContract = columnToFieldCache.get(contract);
|
|
176
|
-
if (!perContract) {
|
|
177
|
-
perContract = /* @__PURE__ */ new Map();
|
|
178
|
-
columnToFieldCache.set(contract, perContract);
|
|
326
|
+
/** Every column of a table, in table order. */
|
|
327
|
+
function getAllTableColumns(contract, namespaceId, tableName) {
|
|
328
|
+
try {
|
|
329
|
+
return Object.keys(storageTableForContract(contract, namespaceId, tableName).columns);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
if (error instanceof Error && error.message.includes("ambiguous")) throw error;
|
|
332
|
+
throw ormError("ORM.TABLE_UNKNOWN", `Unknown table "${tableName}" in SQL ORM query planner`, { meta: {
|
|
333
|
+
namespaceId,
|
|
334
|
+
tableName
|
|
335
|
+
} });
|
|
179
336
|
}
|
|
180
|
-
const cacheKey = metadataCacheKey(namespaceId, modelName);
|
|
181
|
-
let cached = perContract.get(cacheKey);
|
|
182
|
-
if (cached) return cached;
|
|
183
|
-
const storageFields = modelsOf(contract, namespaceId)[modelName]?.storage?.fields ?? {};
|
|
184
|
-
cached = {};
|
|
185
|
-
for (const [f, s] of Object.entries(storageFields)) if (s?.column) cached[s.column] = f;
|
|
186
|
-
perContract.set(cacheKey, cached);
|
|
187
|
-
return cached;
|
|
188
337
|
}
|
|
189
|
-
|
|
338
|
+
function isMultiTableVariantTable(contract, namespaceId, modelName, tableName) {
|
|
339
|
+
const base = modelOf(contract, namespaceId, modelName)?.base;
|
|
340
|
+
return base !== void 0 && domainModelTableInNamespace(contract, namespaceId, modelName) === tableName && domainModelTableInNamespace(contract, base.namespace, base.model) !== tableName;
|
|
341
|
+
}
|
|
190
342
|
/**
|
|
191
|
-
*
|
|
343
|
+
* The columns of `tableName` a query on `modelName` reads, in table order: the columns on that table of the model's own and inherited fields and of its variants' fields, and, on a multi-table variant's table, the key the variant inherits. Any other column of the table is storage the model does not map, and the ORM never reads it into a row.
|
|
192
344
|
*/
|
|
193
|
-
function
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
345
|
+
function getColumnsReadOnTable(contract, namespaceId, modelName, tableName) {
|
|
346
|
+
return cachedFor(contract, [
|
|
347
|
+
"columnsReadOnTable",
|
|
348
|
+
namespaceId,
|
|
349
|
+
modelName,
|
|
350
|
+
tableName
|
|
351
|
+
], () => {
|
|
352
|
+
const read = /* @__PURE__ */ new Set();
|
|
353
|
+
const addFieldsOnTable = (name) => {
|
|
354
|
+
for (const field of Object.values(getModelFields(contract, namespaceId, name))) if (field.table === tableName) read.add(field.column);
|
|
355
|
+
};
|
|
356
|
+
const addInheritedKey = () => {
|
|
357
|
+
for (const column of resolvePrimaryKeyColumns(contract, namespaceId, tableName)) read.add(column);
|
|
358
|
+
};
|
|
359
|
+
addFieldsOnTable(modelName);
|
|
360
|
+
if (isMultiTableVariantTable(contract, namespaceId, modelName, tableName)) addInheritedKey();
|
|
361
|
+
const variants = resolvePolymorphismInfo(contract, namespaceId, modelName)?.variants.values();
|
|
362
|
+
for (const variant of variants ?? []) {
|
|
363
|
+
if (variant.table !== tableName) continue;
|
|
364
|
+
addFieldsOnTable(variant.modelName);
|
|
365
|
+
if (variant.strategy === "mti") addInheritedKey();
|
|
366
|
+
}
|
|
367
|
+
return getAllTableColumns(contract, namespaceId, tableName).filter((column) => read.has(column));
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
/** The model a query or write addresses: the variant it is narrowed to, otherwise the collection's model. */
|
|
371
|
+
function addressedModelName(modelName, variantName) {
|
|
372
|
+
return variantName ?? modelName;
|
|
207
373
|
}
|
|
208
374
|
function resolveIncludeRelation(contract, namespaceId, baseModelName, relationName, variantName) {
|
|
209
375
|
const polymorphism = resolvePolymorphismInfo(contract, namespaceId, baseModelName);
|
|
@@ -212,22 +378,24 @@ function resolveIncludeRelation(contract, namespaceId, baseModelName, relationNa
|
|
|
212
378
|
let localTableName = resolveModelTableName(contract, namespaceId, baseModelName);
|
|
213
379
|
let relation;
|
|
214
380
|
if (variant !== void 0) {
|
|
215
|
-
const
|
|
381
|
+
const variantRelations = resolveModelRelations(contract, namespaceId, variant.modelName);
|
|
382
|
+
const candidate = Object.hasOwn(variantRelations, relationName) ? variantRelations[relationName] : void 0;
|
|
216
383
|
if (candidate !== void 0) {
|
|
217
384
|
relation = candidate;
|
|
218
385
|
declaringModelName = variant.modelName;
|
|
219
386
|
localTableName = variant.table;
|
|
220
387
|
}
|
|
221
388
|
}
|
|
222
|
-
|
|
389
|
+
const baseRelations = resolveModelRelations(contract, namespaceId, baseModelName);
|
|
390
|
+
relation ??= Object.hasOwn(baseRelations, relationName) ? baseRelations[relationName] : void 0;
|
|
223
391
|
if (!relation) throw ormError("ORM.RELATION_UNKNOWN", `Relation '${relationName}' not found on model '${baseModelName}'`, { meta: {
|
|
224
392
|
model: baseModelName,
|
|
225
393
|
relation: relationName
|
|
226
394
|
} });
|
|
227
395
|
const { localFields, targetFields } = relation.on;
|
|
228
396
|
if (localFields.length === 0 || localFields.length !== targetFields.length) throw new InternalError(`Relation '${relationName}' on model '${declaringModelName}' has incomplete join metadata: ${localFields.length} local field(s), ${targetFields.length} target field(s)`);
|
|
229
|
-
const localColumns = localFields.map((field) =>
|
|
230
|
-
const targetColumns =
|
|
397
|
+
const localColumns = localFields.map((field) => columnOfContractField(contract, namespaceId, declaringModelName, field));
|
|
398
|
+
const targetColumns = resolveRelationTargetColumns(contract, relation);
|
|
231
399
|
const relatedTableName = resolveModelTableName(contract, relation.toNamespace, relation.to);
|
|
232
400
|
let through;
|
|
233
401
|
if (relation.through !== void 0) through = {
|
|
@@ -307,7 +475,8 @@ function parseRelationCardinality(value) {
|
|
|
307
475
|
}
|
|
308
476
|
function resolveUpsertConflictColumns(contract, namespaceId, modelName, conflictOn) {
|
|
309
477
|
if (conflictOn && typeof conflictOn === "object") {
|
|
310
|
-
const
|
|
478
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
479
|
+
const columns = Object.keys(conflictOn).map((fieldName) => columnOfCallerField(contract, namespaceId, fieldColumns, modelName, fieldName));
|
|
311
480
|
if (columns.length > 0) return columns;
|
|
312
481
|
}
|
|
313
482
|
return [...storageTableForContract(contract, namespaceId, resolveModelTableName(contract, namespaceId, modelName)).primaryKey?.columns ?? []];
|
|
@@ -352,17 +521,9 @@ function requireCapability(contract, action, capability) {
|
|
|
352
521
|
action
|
|
353
522
|
} });
|
|
354
523
|
}
|
|
355
|
-
function resolveInsertConflictColumns(contract, namespaceId, modelName, conflictOn
|
|
356
|
-
const
|
|
357
|
-
return conflictOn.map((fieldName) =>
|
|
358
|
-
const column = fieldToColumn[fieldName];
|
|
359
|
-
if (column === void 0) throw ormError("ORM.ARGUMENT_INVALID", `${action} conflictOn field "${fieldName}" is not a scalar field of model "${modelName}"`, { meta: {
|
|
360
|
-
action,
|
|
361
|
-
model: modelName,
|
|
362
|
-
field: fieldName
|
|
363
|
-
} });
|
|
364
|
-
return column;
|
|
365
|
-
});
|
|
524
|
+
function resolveInsertConflictColumns(contract, namespaceId, modelName, conflictOn) {
|
|
525
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
526
|
+
return conflictOn.map((fieldName) => columnOfCallerField(contract, namespaceId, fieldColumns, modelName, fieldName));
|
|
366
527
|
}
|
|
367
528
|
function assertDistinctOnCapability(contract, methodName) {
|
|
368
529
|
if (contract.capabilities["postgres"]?.["distinctOn"] === true) return;
|
|
@@ -405,10 +566,10 @@ function isToOneCardinality(cardinality) {
|
|
|
405
566
|
* to the same registry.
|
|
406
567
|
*/
|
|
407
568
|
function createAggregateBuilder(contract, aggregates, namespaceId, modelName) {
|
|
408
|
-
const
|
|
569
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
409
570
|
const builder = {};
|
|
410
571
|
for (const operation of aggregateOperationNames(aggregates)) builder[operation] = (field) => {
|
|
411
|
-
const column = field === void 0 ? void 0 :
|
|
572
|
+
const column = field === void 0 ? void 0 : columnOfCallerField(contract, namespaceId, fieldColumns, modelName, field);
|
|
412
573
|
return {
|
|
413
574
|
kind: "aggregate",
|
|
414
575
|
fn: operation,
|
|
@@ -486,41 +647,48 @@ function inputCodecRef(query) {
|
|
|
486
647
|
function emptyAggregateResult(result, codec) {
|
|
487
648
|
return result.nullable ? null : codec.decodeJson(result.emptyResultJson);
|
|
488
649
|
}
|
|
650
|
+
/** The columns of a model's own and inherited fields, for operations that apply each column to the model's table: `groupBy`, `distinct` and `distinctOn`. */
|
|
489
651
|
function mapFieldsToColumns(contract, namespaceId, modelName, fieldNames) {
|
|
490
|
-
const
|
|
491
|
-
return fieldNames.map((fieldName) =>
|
|
652
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
653
|
+
return fieldNames.map((fieldName) => columnOfCallerField(contract, namespaceId, fieldColumns, modelName, fieldName));
|
|
654
|
+
}
|
|
655
|
+
/** The columns a `select` names: the narrowed variant's fields too, or, when the collection is not narrowed, every variant's fields, each name reading every column a variant maps it to. See `getModelAndVariantFieldColumns` for why `select` accepts more than other surfaces. */
|
|
656
|
+
function mapSelectedFieldsToColumns(contract, namespaceId, modelName, variantName, fieldNames) {
|
|
657
|
+
const addressed = addressedModelName(modelName, variantName);
|
|
658
|
+
if (variantName !== void 0) {
|
|
659
|
+
const fieldColumns = getModelAndVariantFieldColumns(contract, namespaceId, modelName, variantName);
|
|
660
|
+
return fieldNames.map((fieldName) => columnOfCallerField(contract, namespaceId, fieldColumns, addressed, fieldName));
|
|
661
|
+
}
|
|
662
|
+
const fieldColumns = getModelAndEveryVariantFieldColumns(contract, namespaceId, modelName);
|
|
663
|
+
return fieldNames.flatMap((fieldName) => {
|
|
664
|
+
const columns = Object.hasOwn(fieldColumns, fieldName) ? fieldColumns[fieldName] : void 0;
|
|
665
|
+
if (columns === void 0) throw callerFieldUnknown(contract, namespaceId, fieldColumns, addressed, fieldName);
|
|
666
|
+
return [...columns];
|
|
667
|
+
});
|
|
492
668
|
}
|
|
493
669
|
function mapCursorValuesToColumns(contract, namespaceId, modelName, cursorValues) {
|
|
494
|
-
const
|
|
670
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
495
671
|
const mappedCursor = {};
|
|
496
672
|
for (const [fieldName, value] of Object.entries(cursorValues)) {
|
|
497
673
|
if (value === void 0) continue;
|
|
498
|
-
|
|
499
|
-
mappedCursor[columnName] = value;
|
|
674
|
+
mappedCursor[columnOfCallerField(contract, namespaceId, fieldColumns, modelName, fieldName)] = value;
|
|
500
675
|
}
|
|
501
676
|
return mappedCursor;
|
|
502
677
|
}
|
|
503
678
|
function stripHiddenMappedFields(contract, namespaceId, modelName, mapped, hiddenColumns) {
|
|
504
679
|
if (hiddenColumns.length === 0) return;
|
|
505
|
-
const columnToField =
|
|
680
|
+
const columnToField = getModelColumnFields(contract, namespaceId, modelName);
|
|
506
681
|
for (const hiddenColumn of hiddenColumns) {
|
|
507
|
-
const fieldName = columnToField[hiddenColumn]
|
|
508
|
-
delete mapped[fieldName];
|
|
682
|
+
const fieldName = Object.hasOwn(columnToField, hiddenColumn) ? columnToField[hiddenColumn] : void 0;
|
|
683
|
+
if (fieldName !== void 0) delete mapped[fieldName];
|
|
509
684
|
}
|
|
510
685
|
}
|
|
511
686
|
function mapStorageRowToModelFields(contract, namespaceId, modelName, row) {
|
|
512
|
-
|
|
513
|
-
if (Object.keys(columnToField).length === 0) return { ...row };
|
|
514
|
-
return mapColumnNames(row, columnToField);
|
|
687
|
+
return mapKnownColumnNames(row, getModelColumnFields(contract, namespaceId, modelName));
|
|
515
688
|
}
|
|
516
689
|
function createStorageRowMapper(contract, namespaceId, modelName) {
|
|
517
|
-
const columnToField =
|
|
518
|
-
return
|
|
519
|
-
}
|
|
520
|
-
function mapColumnNames(row, columnToField) {
|
|
521
|
-
const mapped = {};
|
|
522
|
-
for (const [columnName, value] of Object.entries(row)) mapped[columnToField[columnName] ?? columnName] = value;
|
|
523
|
-
return mapped;
|
|
690
|
+
const columnToField = getModelColumnFields(contract, namespaceId, modelName);
|
|
691
|
+
return (row) => mapKnownColumnNames(row, columnToField);
|
|
524
692
|
}
|
|
525
693
|
const mergedColumnToFieldCache = /* @__PURE__ */ new WeakMap();
|
|
526
694
|
function getMergedColumnToFieldMap(contract, namespaceId, baseModelName, variantModelName, variantTable) {
|
|
@@ -532,8 +700,8 @@ function getMergedColumnToFieldMap(contract, namespaceId, baseModelName, variant
|
|
|
532
700
|
}
|
|
533
701
|
const cached = perContract.get(cacheKey);
|
|
534
702
|
if (cached) return cached;
|
|
535
|
-
const baseMap =
|
|
536
|
-
const variantMap =
|
|
703
|
+
const baseMap = getModelColumnFields(contract, namespaceId, baseModelName);
|
|
704
|
+
const variantMap = getOwnColumnFields(contract, namespaceId, variantModelName);
|
|
537
705
|
const merged = { ...baseMap };
|
|
538
706
|
for (const [col, field] of Object.entries(variantMap)) if (variantTable) merged[`${variantTable}__${col}`] = field;
|
|
539
707
|
else merged[col] = field;
|
|
@@ -543,12 +711,12 @@ function getMergedColumnToFieldMap(contract, namespaceId, baseModelName, variant
|
|
|
543
711
|
function mapPolymorphicRow(contract, namespaceId, baseModelName, polyInfo, row, variantName) {
|
|
544
712
|
const discriminatorValue = row[polyInfo.discriminatorColumn] ?? row["__prisma_polymorphic_discriminator"];
|
|
545
713
|
const variant = variantName ? polyInfo.variants.get(variantName) : typeof discriminatorValue === "string" ? polyInfo.variantsByValue.get(discriminatorValue) : void 0;
|
|
546
|
-
if (!variant) return mapKnownColumnNames(row,
|
|
714
|
+
if (!variant) return mapKnownColumnNames(row, getModelColumnFields(contract, namespaceId, baseModelName));
|
|
547
715
|
const mtiTable = variant.strategy === "mti" ? variant.table : void 0;
|
|
548
716
|
return mapKnownColumnNames(row, getMergedColumnToFieldMap(contract, namespaceId, baseModelName, variant.modelName, mtiTable));
|
|
549
717
|
}
|
|
550
718
|
function createPolymorphicRowMapper(contract, namespaceId, baseModelName, polyInfo, variantName) {
|
|
551
|
-
const baseMapper = captureColumnMapper(() =>
|
|
719
|
+
const baseMapper = captureColumnMapper(() => getModelColumnFields(contract, namespaceId, baseModelName));
|
|
552
720
|
const mappersByValue = /* @__PURE__ */ new Map();
|
|
553
721
|
let pinnedMapper = baseMapper;
|
|
554
722
|
for (const [name, variant] of polyInfo.variants) {
|
|
@@ -573,21 +741,26 @@ function captureColumnMapper(resolve) {
|
|
|
573
741
|
};
|
|
574
742
|
}
|
|
575
743
|
}
|
|
744
|
+
/** Maps a row from columns to fields. A column no field maps is dropped. */
|
|
576
745
|
function mapKnownColumnNames(row, columns) {
|
|
577
746
|
const mapped = {};
|
|
578
747
|
for (const [col, val] of Object.entries(row)) {
|
|
579
|
-
const field = columns[col];
|
|
748
|
+
const field = Object.hasOwn(columns, col) ? columns[col] : void 0;
|
|
580
749
|
if (field !== void 0) mapped[field] = val;
|
|
581
750
|
}
|
|
582
751
|
return mapped;
|
|
583
752
|
}
|
|
753
|
+
/** Refuses any name in `data` with a value that is not a field of the model, as `mapModelDataToStorageRow` would, before anything reads or writes a row. */
|
|
754
|
+
function assertModelFieldNames(contract, namespaceId, modelName, data) {
|
|
755
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
756
|
+
for (const [fieldName, value] of Object.entries(data)) if (value !== void 0) columnOfCallerField(contract, namespaceId, fieldColumns, modelName, fieldName);
|
|
757
|
+
}
|
|
584
758
|
function mapModelDataToStorageRow(contract, namespaceId, modelName, row) {
|
|
585
|
-
const
|
|
759
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
586
760
|
const mapped = {};
|
|
587
761
|
for (const [fieldName, value] of Object.entries(row)) {
|
|
588
762
|
if (value === void 0) continue;
|
|
589
|
-
|
|
590
|
-
mapped[columnName] = value;
|
|
763
|
+
mapped[columnOfCallerField(contract, namespaceId, fieldColumns, modelName, fieldName)] = value;
|
|
591
764
|
}
|
|
592
765
|
return mapped;
|
|
593
766
|
}
|
|
@@ -647,17 +820,6 @@ function checkedOrderByItem(dir, expr, options) {
|
|
|
647
820
|
function deriveParamsFromAst(ast) {
|
|
648
821
|
return { params: collectOrderedParamRefs(ast).map((p) => p.kind === "param-ref" ? p.value : void 0) };
|
|
649
822
|
}
|
|
650
|
-
function resolveTableColumns(contract, namespaceId, tableName) {
|
|
651
|
-
try {
|
|
652
|
-
return Object.keys(storageTableForContract(contract, namespaceId, tableName).columns);
|
|
653
|
-
} catch (error) {
|
|
654
|
-
if (error instanceof Error && error.message.includes("ambiguous")) throw error;
|
|
655
|
-
throw ormError("ORM.TABLE_UNKNOWN", `Unknown table "${tableName}" in SQL ORM query planner`, { meta: {
|
|
656
|
-
namespaceId,
|
|
657
|
-
tableName
|
|
658
|
-
} });
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
823
|
function buildOrmPlanMeta(contract, annotations) {
|
|
662
824
|
const annotationRecord = annotations !== void 0 && annotations.size > 0 ? Object.freeze(Object.fromEntries(annotations)) : void 0;
|
|
663
825
|
return {
|
|
@@ -973,7 +1135,7 @@ function buildMtiJoins(contract, namespaceId, polyInfo, variantName, selectedCol
|
|
|
973
1135
|
const joinOn = buildPrimaryKeyJoinOn(polyInfo.baseTable, variant.table, pkColumns);
|
|
974
1136
|
const join = joinType === "inner" ? JoinAst.inner(tableSourceForContract(contract, namespaceId, variant.table), joinOn) : JoinAst.left(tableSourceForContract(contract, namespaceId, variant.table), joinOn);
|
|
975
1137
|
joins.push(join);
|
|
976
|
-
const variantColumns =
|
|
1138
|
+
const variantColumns = getColumnsReadOnTable(contract, namespaceId, variant.modelName, variant.table);
|
|
977
1139
|
const selectedVariantColumns = selectedColumnsByTable?.get(variant.table);
|
|
978
1140
|
for (const col of variantColumns) {
|
|
979
1141
|
if (pkColumns.includes(col)) continue;
|
|
@@ -1303,8 +1465,8 @@ function compileGroupedAggregate(contract, aggregates, namespaceId, tableName, p
|
|
|
1303
1465
|
const { params } = deriveParamsFromAst(ast);
|
|
1304
1466
|
return buildOrmQueryPlan(contract, ast, params);
|
|
1305
1467
|
}
|
|
1306
|
-
function buildReturningColumns(contract, namespaceId, tableName, returningColumns) {
|
|
1307
|
-
return (returningColumns && returningColumns.length > 0 ? [...returningColumns] :
|
|
1468
|
+
function buildReturningColumns(contract, namespaceId, modelName, tableName, returningColumns) {
|
|
1469
|
+
return (returningColumns && returningColumns.length > 0 ? [...returningColumns] : getColumnsReadOnTable(contract, namespaceId, modelName, tableName)).map((column) => ProjectionItem.of(column, ColumnRef.of(tableName, column), codecRefForStorageColumn(contract.storage, namespaceId, tableName, column)));
|
|
1308
1470
|
}
|
|
1309
1471
|
function toParamAssignments(contract, namespaceId, tableName, values) {
|
|
1310
1472
|
const assignments = {};
|
|
@@ -1360,9 +1522,9 @@ function conflictSkipClause(tableName, conflictSkip) {
|
|
|
1360
1522
|
if (conflictSkip.columns.length === 0) return InsertOnConflict.doNothing();
|
|
1361
1523
|
return InsertOnConflict.on(conflictSkip.columns.map((column) => ColumnRef.of(tableName, column))).doNothing();
|
|
1362
1524
|
}
|
|
1363
|
-
function compileInsertReturning(contract, namespaceId, tableName, rows, returningColumns, conflictSkip) {
|
|
1525
|
+
function compileInsertReturning(contract, namespaceId, modelName, tableName, rows, returningColumns, conflictSkip) {
|
|
1364
1526
|
const { rows: normalizedRows } = normalizeInsertRows(contract, namespaceId, tableName, rows);
|
|
1365
|
-
const ast = InsertAst.into(tableSourceForContract(contract, namespaceId, tableName)).withRows(normalizedRows).withOnConflict(conflictSkipClause(tableName, conflictSkip)).withReturning(buildReturningColumns(contract, namespaceId, tableName, returningColumns));
|
|
1527
|
+
const ast = InsertAst.into(tableSourceForContract(contract, namespaceId, tableName)).withRows(normalizedRows).withOnConflict(conflictSkipClause(tableName, conflictSkip)).withReturning(buildReturningColumns(contract, namespaceId, modelName, tableName, returningColumns));
|
|
1366
1528
|
const { params } = deriveParamsFromAst(ast);
|
|
1367
1529
|
return buildOrmQueryPlan(contract, ast, params);
|
|
1368
1530
|
}
|
|
@@ -1419,13 +1581,13 @@ function groupRowsByColumnSignature(rows) {
|
|
|
1419
1581
|
if (currentGroup.length > 0) groups.push(currentGroup);
|
|
1420
1582
|
return groups;
|
|
1421
1583
|
}
|
|
1422
|
-
function compileInsertReturningSplit(contract, namespaceId, tableName, rows, returningColumns, conflictSkip) {
|
|
1584
|
+
function compileInsertReturningSplit(contract, namespaceId, modelName, tableName, rows, returningColumns, conflictSkip) {
|
|
1423
1585
|
if (rows.length === 0) throw ormError("ORM.MUTATION_DATA_MISSING", "create() requires at least one row", { meta: {
|
|
1424
1586
|
method: "create",
|
|
1425
1587
|
namespaceId,
|
|
1426
1588
|
tableName
|
|
1427
1589
|
} });
|
|
1428
|
-
return groupRowsByColumnSignature(rows).map((group) => compileInsertReturning(contract, namespaceId, tableName, group, returningColumns, conflictSkip));
|
|
1590
|
+
return groupRowsByColumnSignature(rows).map((group) => compileInsertReturning(contract, namespaceId, modelName, tableName, group, returningColumns, conflictSkip));
|
|
1429
1591
|
}
|
|
1430
1592
|
function compileInsertCountSplit(contract, namespaceId, tableName, rows, conflictSkip) {
|
|
1431
1593
|
if (rows.length === 0) throw ormError("ORM.MUTATION_DATA_MISSING", "createAndCount() requires at least one row", { meta: {
|
|
@@ -1435,18 +1597,18 @@ function compileInsertCountSplit(contract, namespaceId, tableName, rows, conflic
|
|
|
1435
1597
|
} });
|
|
1436
1598
|
return groupRowsByColumnSignature(rows).map((group) => compileInsertCount(contract, namespaceId, tableName, group, conflictSkip));
|
|
1437
1599
|
}
|
|
1438
|
-
function compileUpsertReturning(contract, namespaceId, tableName, createValues, updateValues, conflictColumns, returningColumns) {
|
|
1600
|
+
function compileUpsertReturning(contract, namespaceId, modelName, tableName, createValues, updateValues, conflictColumns, returningColumns) {
|
|
1439
1601
|
const createAssignments = toParamAssignments(contract, namespaceId, tableName, createValues);
|
|
1440
1602
|
const updateAssignments = Object.keys(updateValues).length > 0 ? toParamAssignments(contract, namespaceId, tableName, updateValues) : void 0;
|
|
1441
1603
|
const onConflict = updateAssignments ? InsertOnConflict.on(conflictColumns.map((column) => ColumnRef.of(tableName, column))).doUpdateSet(updateAssignments.assignments) : InsertOnConflict.on(conflictColumns.map((column) => ColumnRef.of(tableName, column))).doNothing();
|
|
1442
|
-
const ast = InsertAst.into(tableSourceForContract(contract, namespaceId, tableName)).withRows([createAssignments.assignments]).withOnConflict(onConflict).withReturning(buildReturningColumns(contract, namespaceId, tableName, returningColumns));
|
|
1604
|
+
const ast = InsertAst.into(tableSourceForContract(contract, namespaceId, tableName)).withRows([createAssignments.assignments]).withOnConflict(onConflict).withReturning(buildReturningColumns(contract, namespaceId, modelName, tableName, returningColumns));
|
|
1443
1605
|
const { params } = deriveParamsFromAst(ast);
|
|
1444
1606
|
return buildOrmQueryPlan(contract, ast, params);
|
|
1445
1607
|
}
|
|
1446
|
-
function compileUpdateReturning(contract, namespaceId, tableName, setValues, filters, returningColumns) {
|
|
1608
|
+
function compileUpdateReturning(contract, namespaceId, modelName, tableName, setValues, filters, returningColumns) {
|
|
1447
1609
|
const where = combineWhereExprs(filters);
|
|
1448
1610
|
const { assignments } = toParamAssignments(contract, namespaceId, tableName, setValues);
|
|
1449
|
-
let ast = UpdateAst.table(tableSourceForContract(contract, namespaceId, tableName)).withSet(assignments).withReturning(buildReturningColumns(contract, namespaceId, tableName, returningColumns));
|
|
1611
|
+
let ast = UpdateAst.table(tableSourceForContract(contract, namespaceId, tableName)).withSet(assignments).withReturning(buildReturningColumns(contract, namespaceId, modelName, tableName, returningColumns));
|
|
1450
1612
|
if (where) ast = ast.withWhere(where);
|
|
1451
1613
|
const { params } = deriveParamsFromAst(ast);
|
|
1452
1614
|
return buildOrmQueryPlan(contract, ast, params);
|
|
@@ -1459,9 +1621,9 @@ function compileUpdateCount(contract, namespaceId, tableName, setValues, filters
|
|
|
1459
1621
|
const { params } = deriveParamsFromAst(ast);
|
|
1460
1622
|
return buildOrmQueryPlan(contract, ast, params);
|
|
1461
1623
|
}
|
|
1462
|
-
function compileDeleteReturning(contract, namespaceId, tableName, filters, returningColumns) {
|
|
1624
|
+
function compileDeleteReturning(contract, namespaceId, modelName, tableName, filters, returningColumns) {
|
|
1463
1625
|
const where = combineWhereExprs(filters);
|
|
1464
|
-
let ast = DeleteAst.from(tableSourceForContract(contract, namespaceId, tableName)).withReturning(buildReturningColumns(contract, namespaceId, tableName, returningColumns));
|
|
1626
|
+
let ast = DeleteAst.from(tableSourceForContract(contract, namespaceId, tableName)).withReturning(buildReturningColumns(contract, namespaceId, modelName, tableName, returningColumns));
|
|
1465
1627
|
if (where) ast = ast.withWhere(where);
|
|
1466
1628
|
const { params } = deriveParamsFromAst(ast);
|
|
1467
1629
|
return buildOrmQueryPlan(contract, ast, params);
|
|
@@ -1542,8 +1704,8 @@ function jsonEntryProjection(value, identity) {
|
|
|
1542
1704
|
if (identity.document === true) return new JsonDocumentProjection(value);
|
|
1543
1705
|
return new NativeJsonValueProjection(value);
|
|
1544
1706
|
}
|
|
1545
|
-
function buildProjection(contract, namespaceId, tableName, selectedFields, tableRef = tableName) {
|
|
1546
|
-
return (selectedFields !== void 0 ? [...selectedFields] :
|
|
1707
|
+
function buildProjection(contract, namespaceId, modelName, tableName, selectedFields, tableRef = tableName) {
|
|
1708
|
+
return (selectedFields !== void 0 ? [...selectedFields] : getColumnsReadOnTable(contract, namespaceId, modelName, tableName)).map((column) => ProjectionItem.of(column, ColumnRef.of(tableRef, column), codecRefForStorageColumn(contract.storage, namespaceId, tableName, column)));
|
|
1547
1709
|
}
|
|
1548
1710
|
function appendUnique(values, value) {
|
|
1549
1711
|
if (!values.includes(value)) values.push(value);
|
|
@@ -1554,22 +1716,21 @@ function resolvePolymorphicProjectionSelection(contract, namespaceId, modelName,
|
|
|
1554
1716
|
selectedMtiColumnsByTable: void 0,
|
|
1555
1717
|
needsHiddenDiscriminator: false
|
|
1556
1718
|
};
|
|
1557
|
-
const
|
|
1558
|
-
const
|
|
1559
|
-
const variantFieldMaps = Array.from(polyInfo.variants.values(), (variant) => ({
|
|
1719
|
+
const baseColumnToField = getModelColumnFields(contract, namespaceId, modelName);
|
|
1720
|
+
const variantColumnMaps = Array.from(polyInfo.variants.values(), (variant) => ({
|
|
1560
1721
|
variant,
|
|
1561
|
-
columnToField:
|
|
1722
|
+
columnToField: getOwnColumnFields(contract, namespaceId, variant.modelName)
|
|
1562
1723
|
}));
|
|
1563
1724
|
const baseSelectedFields = [];
|
|
1564
1725
|
const selectedMtiColumnsByTable = /* @__PURE__ */ new Map();
|
|
1565
1726
|
let hasVariantOwnedSelection = false;
|
|
1566
|
-
for (const
|
|
1567
|
-
const
|
|
1568
|
-
if (
|
|
1569
|
-
let
|
|
1570
|
-
for (const { variant, columnToField } of
|
|
1571
|
-
if (
|
|
1572
|
-
|
|
1727
|
+
for (const column of state.selectedFields) {
|
|
1728
|
+
const isBaseColumn = Object.hasOwn(baseColumnToField, column);
|
|
1729
|
+
if (isBaseColumn) appendUnique(baseSelectedFields, column);
|
|
1730
|
+
let isVariantColumn = false;
|
|
1731
|
+
for (const { variant, columnToField } of variantColumnMaps) {
|
|
1732
|
+
if (!Object.hasOwn(columnToField, column)) continue;
|
|
1733
|
+
isVariantColumn = true;
|
|
1573
1734
|
hasVariantOwnedSelection = true;
|
|
1574
1735
|
if (variant.strategy === "sti") {
|
|
1575
1736
|
appendUnique(baseSelectedFields, column);
|
|
@@ -1582,7 +1743,7 @@ function resolvePolymorphicProjectionSelection(contract, namespaceId, modelName,
|
|
|
1582
1743
|
}
|
|
1583
1744
|
selectedColumns.add(column);
|
|
1584
1745
|
}
|
|
1585
|
-
if (
|
|
1746
|
+
if (!isBaseColumn && !isVariantColumn) throw new InternalError(`Selected column "${column}" is mapped by no field of model "${modelName}" or its variants; select() resolves field names before they reach the projection`);
|
|
1586
1747
|
}
|
|
1587
1748
|
return {
|
|
1588
1749
|
baseSelectedFields,
|
|
@@ -1792,7 +1953,7 @@ function buildIncludeChildRowsSelect(contract, aggregates, parentSource, include
|
|
|
1792
1953
|
junctionJoins
|
|
1793
1954
|
});
|
|
1794
1955
|
const polyJoinsAndProjection = buildChildPolymorphismJoinsAndProjection(contract, include, childTableAlias, childTableRef);
|
|
1795
|
-
const scalarProjection = buildProjection(contract, include.relatedNamespaceId, include.relatedTableName, polyJoinsAndProjection.baseSelectedFields, childTableRef);
|
|
1956
|
+
const scalarProjection = buildProjection(contract, include.relatedNamespaceId, addressedModelName(include.relatedModelName, include.nested.variantName), include.relatedTableName, polyJoinsAndProjection.baseSelectedFields, childTableRef);
|
|
1796
1957
|
const nestedProjections = buildNestedIncludeProjections(contract, aggregates, {
|
|
1797
1958
|
baseTableName: include.relatedTableName,
|
|
1798
1959
|
tableRef: childTableRef,
|
|
@@ -1843,7 +2004,7 @@ function buildDistinctNonLeafChildRowsSelect(options) {
|
|
|
1843
2004
|
selectedFields: selectedForQuery
|
|
1844
2005
|
}
|
|
1845
2006
|
}, childTableAlias, childTableRef);
|
|
1846
|
-
const innerScalarProjection = buildProjection(contract, include.relatedNamespaceId, include.relatedTableName, queryPolyProjection.baseSelectedFields, childTableRef);
|
|
2007
|
+
const innerScalarProjection = buildProjection(contract, include.relatedNamespaceId, addressedModelName(include.relatedModelName, include.nested.variantName), include.relatedTableName, queryPolyProjection.baseSelectedFields, childTableRef);
|
|
1847
2008
|
const innerMtiProjection = mergeProjectionByAlias(queryPolyProjection.projection, buildRequiredMtiJoinKeyProjection(contract, include));
|
|
1848
2009
|
let baseInner = SelectAst.from(tableSourceForContract(contract, include.relatedNamespaceId, include.relatedTableName, childTableAlias)).withProjection([
|
|
1849
2010
|
...innerScalarProjection,
|
|
@@ -1866,7 +2027,7 @@ function buildDistinctNonLeafChildRowsSelect(options) {
|
|
|
1866
2027
|
if (childState.limit !== void 0) innerSelect = innerSelect.withLimit(childState.limit);
|
|
1867
2028
|
if (childState.offset !== void 0) innerSelect = innerSelect.withOffset(childState.offset);
|
|
1868
2029
|
const distinctAlias = `${include.relationName}__distinct`;
|
|
1869
|
-
const outerScalarProjection = buildProjection(contract, include.relatedNamespaceId, include.relatedTableName, visiblePolyProjection.baseSelectedFields, distinctAlias);
|
|
2030
|
+
const outerScalarProjection = buildProjection(contract, include.relatedNamespaceId, addressedModelName(include.relatedModelName, include.nested.variantName), include.relatedTableName, visiblePolyProjection.baseSelectedFields, distinctAlias);
|
|
1870
2031
|
const outerNestedProjections = buildNestedIncludeProjections(contract, aggregates, {
|
|
1871
2032
|
baseTableName: include.relatedTableName,
|
|
1872
2033
|
tableRef: distinctAlias,
|
|
@@ -2063,14 +2224,15 @@ function buildCorrelatedIncludeProjection(contract, aggregates, parentSource, in
|
|
|
2063
2224
|
const aggregateQuery = buildIncludeChildRowsAggregateSelect(contract, aggregates, parentSource, include);
|
|
2064
2225
|
return { projection: ProjectionItem.of(include.relationName, SubqueryExpr.of(aggregateQuery)) };
|
|
2065
2226
|
}
|
|
2066
|
-
function buildSelectAst(contract, tableName, state, options) {
|
|
2227
|
+
function buildSelectAst(contract, modelName, tableName, state, options) {
|
|
2067
2228
|
const namespaceId = options.namespaceId;
|
|
2068
2229
|
if (state.distinctOn !== void 0 && state.distinctOn.length > 0) {
|
|
2069
2230
|
assertDistinctOnCapability(contract, "distinctOn");
|
|
2070
2231
|
assertDistinctOnCompatibleOrder(state.orderBy, state.distinctOn.length);
|
|
2071
2232
|
}
|
|
2072
|
-
const
|
|
2073
|
-
const
|
|
2233
|
+
const addressed = addressedModelName(modelName, state.variantName);
|
|
2234
|
+
const projection = [...buildProjection(contract, namespaceId, addressed, tableName, state.selectedFields, tableName), ...options.includeProjection ?? []];
|
|
2235
|
+
const { source: fromSource, where: effectiveWhere } = buildDedupedTableSource(contract, namespaceId, tableName, state, options.where ?? buildStateWhere(contract, tableName, state, { namespaceId }), getColumnsReadOnTable(contract, namespaceId, addressed, tableName).map((column) => ProjectionItem.of(column, ColumnRef.of(tableName, column))));
|
|
2074
2236
|
let ast = SelectAst.from(fromSource).withProjection(projection);
|
|
2075
2237
|
if (effectiveWhere) ast = ast.withWhere(effectiveWhere);
|
|
2076
2238
|
if (state.orderBy) ast = ast.withOrderBy(state.orderBy);
|
|
@@ -2082,18 +2244,18 @@ function buildSelectAst(contract, tableName, state, options) {
|
|
|
2082
2244
|
if (state.locking !== void 0) ast = ast.withLocking(state.locking);
|
|
2083
2245
|
return ast;
|
|
2084
2246
|
}
|
|
2085
|
-
function compileSelect(contract, namespaceId, tableName, state
|
|
2247
|
+
function compileSelect(contract, namespaceId, modelName, tableName, state) {
|
|
2086
2248
|
assertLockCompatible(state);
|
|
2087
2249
|
if (state.distinctOn !== void 0 && state.distinctOn.length > 0) assertDistinctOnCapability(contract, "distinctOn");
|
|
2088
|
-
const polyInfo =
|
|
2089
|
-
const selection = polyInfo
|
|
2250
|
+
const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
|
|
2251
|
+
const selection = polyInfo ? resolvePolymorphicProjectionSelection(contract, namespaceId, modelName, polyInfo, state) : void 0;
|
|
2090
2252
|
const projectionState = selection ? {
|
|
2091
2253
|
...state,
|
|
2092
2254
|
selectedFields: selection.baseSelectedFields
|
|
2093
2255
|
} : state;
|
|
2094
2256
|
const mtiArtifacts = polyInfo && polyInfo.mtiVariants.length > 0 ? buildMtiJoins(contract, namespaceId, polyInfo, state.variantName, selection?.selectedMtiColumnsByTable) : void 0;
|
|
2095
2257
|
const hiddenProjection = polyInfo && selection ? buildHiddenDiscriminatorProjection(contract, namespaceId, polyInfo, tableName, selection.needsHiddenDiscriminator) : [];
|
|
2096
|
-
const ast = buildSelectAst(contract, tableName, {
|
|
2258
|
+
const ast = buildSelectAst(contract, modelName, tableName, {
|
|
2097
2259
|
...projectionState,
|
|
2098
2260
|
includes: []
|
|
2099
2261
|
}, {
|
|
@@ -2104,13 +2266,13 @@ function compileSelect(contract, namespaceId, tableName, state, modelName) {
|
|
|
2104
2266
|
const { params } = deriveParamsFromAst(ast);
|
|
2105
2267
|
return buildOrmQueryPlan(contract, ast, params, state.annotations);
|
|
2106
2268
|
}
|
|
2107
|
-
function compileSelectWithIncludes(contract, aggregates, namespaceId, tableName, state
|
|
2269
|
+
function compileSelectWithIncludes(contract, aggregates, namespaceId, modelName, tableName, state) {
|
|
2108
2270
|
assertLockCompatible(state);
|
|
2109
2271
|
const includeJoins = [];
|
|
2110
2272
|
const includeProjection = [];
|
|
2111
2273
|
const topLevelWhere = buildStateWhere(contract, tableName, state, { namespaceId });
|
|
2112
|
-
const polyInfo =
|
|
2113
|
-
const selection = polyInfo
|
|
2274
|
+
const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
|
|
2275
|
+
const selection = polyInfo ? resolvePolymorphicProjectionSelection(contract, namespaceId, modelName, polyInfo, state) : void 0;
|
|
2114
2276
|
const projectionState = selection ? {
|
|
2115
2277
|
...state,
|
|
2116
2278
|
selectedFields: selection.baseSelectedFields
|
|
@@ -2132,7 +2294,7 @@ function compileSelectWithIncludes(contract, aggregates, namespaceId, tableName,
|
|
|
2132
2294
|
const artifact = buildCorrelatedIncludeProjection(contract, aggregates, parentSource, include);
|
|
2133
2295
|
includeProjection.push(artifact.projection);
|
|
2134
2296
|
}
|
|
2135
|
-
const ast = buildSelectAst(contract, tableName, {
|
|
2297
|
+
const ast = buildSelectAst(contract, modelName, tableName, {
|
|
2136
2298
|
...projectionState,
|
|
2137
2299
|
includes: []
|
|
2138
2300
|
}, {
|
|
@@ -2158,7 +2320,7 @@ function describeExecutionRows(options) {
|
|
|
2158
2320
|
const { contract } = context;
|
|
2159
2321
|
const polyInfo = resolvePolymorphismInfo(contract, namespaceId, modelName);
|
|
2160
2322
|
if (state.includes.length === 0) {
|
|
2161
|
-
const compiled = compileSelect(contract, namespaceId, tableName, state
|
|
2323
|
+
const compiled = compileSelect(contract, namespaceId, modelName, tableName, state);
|
|
2162
2324
|
const mapper = polyInfo ? (rawRow) => blindCast(mapPolymorphicRow(contract, namespaceId, modelName, polyInfo, rawRow, state.variantName)) : (rawRow) => blindCast(mapStorageRowToModelFields(contract, namespaceId, modelName, rawRow));
|
|
2163
2325
|
return {
|
|
2164
2326
|
plan: compiled,
|
|
@@ -2166,7 +2328,7 @@ function describeExecutionRows(options) {
|
|
|
2166
2328
|
};
|
|
2167
2329
|
}
|
|
2168
2330
|
return {
|
|
2169
|
-
plan: compileSelectWithIncludes(contract, context.aggregateDescriptors, namespaceId, tableName, state
|
|
2331
|
+
plan: compileSelectWithIncludes(contract, context.aggregateDescriptors, namespaceId, modelName, tableName, state),
|
|
2170
2332
|
consume: (rows) => consumeIncludeRows(context, state, namespaceId, modelName, rows)
|
|
2171
2333
|
};
|
|
2172
2334
|
}
|
|
@@ -2231,10 +2393,10 @@ function createPreparedIncludeConsumer(context, include) {
|
|
|
2231
2393
|
}
|
|
2232
2394
|
const mapRow = createPreparedMapper(contract, include.relatedNamespaceId, include.relatedModelName, include.nested.variantName);
|
|
2233
2395
|
const bindings = deferResolution(() => {
|
|
2234
|
-
const
|
|
2235
|
-
const keys = new Set(
|
|
2236
|
-
const polyInfo = resolvePolymorphismInfo(contract,
|
|
2237
|
-
for (const variant of polyInfo?.mtiVariants ?? []) for (const column of
|
|
2396
|
+
const namespace = include.relatedNamespaceId;
|
|
2397
|
+
const keys = new Set(getColumnsReadOnTable(contract, namespace, addressedModelName(include.relatedModelName, include.nested.variantName), include.relatedTableName));
|
|
2398
|
+
const polyInfo = resolvePolymorphismInfo(contract, namespace, include.relatedModelName);
|
|
2399
|
+
for (const variant of polyInfo?.mtiVariants ?? []) for (const column of getColumnsReadOnTable(contract, namespace, variant.modelName, variant.table)) keys.add(`${variant.table}__${column}`);
|
|
2238
2400
|
return new Map([...keys].map((key) => [key, deferResolution(() => resolveIncludedColumnBinding(contract, context, include, key))]));
|
|
2239
2401
|
});
|
|
2240
2402
|
const bindingFor = (key) => bindings().get(key)?.() ?? null;
|
|
@@ -2261,19 +2423,19 @@ function createPreparedIncludedRowDecoder(contract, include, bindingFor) {
|
|
|
2261
2423
|
const namespace = include.relatedNamespaceId;
|
|
2262
2424
|
const model = include.relatedModelName;
|
|
2263
2425
|
if (resolvePolymorphismInfo(contract, namespace, model)) return void 0;
|
|
2264
|
-
const
|
|
2265
|
-
const
|
|
2266
|
-
const columns = (include.nested.selectedFields ?? Object.keys(fieldToColumn)).map((field) => Object.hasOwn(fieldToColumn, field) ? fieldToColumn[field] ?? field : field);
|
|
2426
|
+
const columnToField = getModelColumnFields(contract, namespace, model);
|
|
2427
|
+
const columns = include.nested.selectedFields ?? getColumnsReadOnTable(contract, namespace, model, include.relatedTableName);
|
|
2267
2428
|
const aliases = include.nested.includes.map((child) => child.relationName);
|
|
2268
2429
|
const table = contract.storage.namespaces[namespace]?.entries.table?.[include.relatedTableName];
|
|
2269
2430
|
if (aliases.some((alias) => table?.columns[alias] !== void 0)) return void 0;
|
|
2270
2431
|
const keys = [...columns, ...aliases];
|
|
2271
2432
|
if (keys.includes("__proto__") || new Set(keys).size !== keys.length) return void 0;
|
|
2433
|
+
const fieldOf = (key) => aliases.includes(key) ? key : fieldOfColumn(columnToField, model, key);
|
|
2272
2434
|
const operations = keys.map((key) => {
|
|
2273
2435
|
const binding = deferResolution(() => bindingFor(key));
|
|
2274
2436
|
return {
|
|
2275
2437
|
key,
|
|
2276
|
-
field:
|
|
2438
|
+
field: fieldOf(key),
|
|
2277
2439
|
decode(value) {
|
|
2278
2440
|
if (value === null || value === void 0) return value;
|
|
2279
2441
|
const resolved = binding();
|
|
@@ -2766,12 +2928,11 @@ function all() {
|
|
|
2766
2928
|
function shorthandToWhereExpr(context, namespaceId, modelName, filters) {
|
|
2767
2929
|
const contract = context.contract;
|
|
2768
2930
|
const tableName = resolveModelTableName(contract, namespaceId, modelName);
|
|
2769
|
-
const
|
|
2931
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
2770
2932
|
const exprs = [];
|
|
2771
2933
|
for (const [fieldName, value] of Object.entries(filters)) {
|
|
2772
2934
|
if (value === void 0) continue;
|
|
2773
|
-
const
|
|
2774
|
-
const left = ColumnRef.of(tableName, columnName);
|
|
2935
|
+
const left = ColumnRef.of(tableName, columnOfCallerField(contract, namespaceId, fieldColumns, modelName, fieldName));
|
|
2775
2936
|
if (value === null) {
|
|
2776
2937
|
exprs.push(NullCheckExpr.isNull(left));
|
|
2777
2938
|
continue;
|
|
@@ -2931,7 +3092,7 @@ function assertDeclaredFieldsFragmentFields(collection, fields) {
|
|
|
2931
3092
|
const { contract } = collection.ctx.context;
|
|
2932
3093
|
const { modelName, namespaceId } = collection;
|
|
2933
3094
|
const label = modelLabel(collection);
|
|
2934
|
-
const
|
|
3095
|
+
const modelFields = getModelFields(contract, namespaceId, modelName);
|
|
2935
3096
|
for (const [name, spec] of fields) {
|
|
2936
3097
|
const declared = `The fragment was declared for models that have a ${spec.many === false ? "field" : "list field"} ${name} ${describeField(spec)}.`;
|
|
2937
3098
|
const meta = {
|
|
@@ -2942,14 +3103,14 @@ function assertDeclaredFieldsFragmentFields(collection, fields) {
|
|
|
2942
3103
|
nullable: spec.nullable,
|
|
2943
3104
|
many: spec.many
|
|
2944
3105
|
};
|
|
2945
|
-
const
|
|
2946
|
-
if (
|
|
3106
|
+
const fieldColumn = Object.hasOwn(modelFields, name) ? modelFields[name] : void 0;
|
|
3107
|
+
if (fieldColumn === void 0) throw ormError("ORM.FIELD_UNKNOWN", `Cannot apply a fragment to ${label}: it has no field ${name}`, {
|
|
2947
3108
|
why: declared,
|
|
2948
3109
|
fix: `Apply the fragment to a model that has a field ${name}, or remove ${name} from the declaration in the fragment.`,
|
|
2949
3110
|
meta
|
|
2950
3111
|
});
|
|
2951
|
-
const fieldMany = multiplicity(
|
|
2952
|
-
const column = resolveColumn(contract, namespaceId,
|
|
3112
|
+
const fieldMany = multiplicity(domainFieldOf(contract, namespaceId, modelName, name)?.many);
|
|
3113
|
+
const column = resolveColumn(contract, namespaceId, fieldColumn.table, fieldColumn.column);
|
|
2953
3114
|
const actual = column === void 0 ? `${label}.${name} has no column.` : fieldMany === false ? `${label}.${name} has codec ${column.codecId} and ${nullability(column.nullable)}.` : `${label}.${name} is a list ${describeField({
|
|
2954
3115
|
codecId: column.codecId,
|
|
2955
3116
|
nullable: column.nullable,
|
|
@@ -2998,23 +3159,35 @@ function cutNote(subject, value) {
|
|
|
2998
3159
|
}
|
|
2999
3160
|
function fieldCodecId(collection, field) {
|
|
3000
3161
|
const { contract } = collection.ctx.context;
|
|
3001
|
-
const
|
|
3002
|
-
|
|
3162
|
+
const modelFields = getModelFields(contract, collection.namespaceId, collection.modelName);
|
|
3163
|
+
const fieldColumn = Object.hasOwn(modelFields, field) ? modelFields[field] : void 0;
|
|
3164
|
+
if (fieldColumn === void 0) return void 0;
|
|
3165
|
+
return resolveColumn(contract, collection.namespaceId, fieldColumn.table, fieldColumn.column)?.codecId;
|
|
3166
|
+
}
|
|
3167
|
+
/** The domain declaration of a model's own or inherited field. */
|
|
3168
|
+
function domainFieldOf(contract, namespaceId, modelName, name) {
|
|
3169
|
+
let model = modelOf(contract, namespaceId, modelName);
|
|
3170
|
+
while (model !== void 0) {
|
|
3171
|
+
const fields = model.fields ?? {};
|
|
3172
|
+
if (Object.hasOwn(fields, name)) return fields[name];
|
|
3173
|
+
const base = model.base;
|
|
3174
|
+
model = base === void 0 ? void 0 : modelOf(contract, base.namespace, base.model);
|
|
3175
|
+
}
|
|
3003
3176
|
}
|
|
3004
3177
|
function canOrder(collection, field) {
|
|
3005
3178
|
const codecId = fieldCodecId(collection, field);
|
|
3006
3179
|
return codecId !== void 0 && hasTrait(collection.ctx.context, codecId, "order");
|
|
3007
3180
|
}
|
|
3008
3181
|
function orderableFieldNames(collection) {
|
|
3009
|
-
const
|
|
3010
|
-
return Object.keys(
|
|
3182
|
+
const modelFields = getModelFields(collection.ctx.context.contract, collection.namespaceId, collection.modelName);
|
|
3183
|
+
return Object.keys(modelFields).filter((field) => canOrder(collection, field));
|
|
3011
3184
|
}
|
|
3012
3185
|
function whyNotOrderable(collection, name) {
|
|
3013
3186
|
const { modelName } = collection;
|
|
3014
3187
|
const model = modelOf(collection.ctx.context.contract, collection.namespaceId, modelName);
|
|
3015
3188
|
const quoted = shown(name).text;
|
|
3016
3189
|
if (Object.hasOwn(model?.relations ?? {}, name)) return `${quoted} is a relation of ${modelName}, not a field.`;
|
|
3017
|
-
if (!Object.hasOwn(
|
|
3190
|
+
if (!Object.hasOwn(getModelFields(collection.ctx.context.contract, collection.namespaceId, modelName), name)) return `${modelName} has no field ${quoted}.`;
|
|
3018
3191
|
return canOrder(collection, name) ? `${quoted} is not one of the fields allowed for ordering.` : `The codec ${fieldCodecId(collection, name)} of ${modelName}.${name} cannot be ordered.`;
|
|
3019
3192
|
}
|
|
3020
3193
|
/**
|
|
@@ -3177,7 +3350,7 @@ function createModelAccessor(context, namespaceId, modelName, variantName) {
|
|
|
3177
3350
|
}
|
|
3178
3351
|
function createModelAccessorInScope(context, namespaceId, modelName, variantName, scope) {
|
|
3179
3352
|
const contract = context.contract;
|
|
3180
|
-
const
|
|
3353
|
+
const fieldColumns = getModelAndVariantFieldColumns(contract, namespaceId, modelName, variantName);
|
|
3181
3354
|
const tableName = resolveModelTableName(contract, namespaceId, modelName);
|
|
3182
3355
|
const modelRelations = resolveModelRelations(contract, namespaceId, modelName);
|
|
3183
3356
|
const variantFieldColumns = variantName ? resolveVariantFieldColumns(contract, namespaceId, modelName, variantName) : {};
|
|
@@ -3205,20 +3378,23 @@ function createModelAccessorInScope(context, namespaceId, modelName, variantName
|
|
|
3205
3378
|
if (self.traits.every((t) => descriptorTraits.includes(t))) registerOp(descriptor.codecId, op);
|
|
3206
3379
|
}
|
|
3207
3380
|
}
|
|
3208
|
-
return blindCast(new Proxy({}, { get(
|
|
3381
|
+
return blindCast(new Proxy({}, { get(target, prop) {
|
|
3209
3382
|
if (typeof prop !== "string") return;
|
|
3210
|
-
if (variantCoordinates) {
|
|
3383
|
+
if (variantCoordinates && Object.hasOwn(variantCoordinates.relations, prop)) {
|
|
3211
3384
|
const variantRelation = variantCoordinates.relations[prop];
|
|
3212
3385
|
if (variantRelation) return createRelationFilterAccessor(context, namespaceId, variantCoordinates.name, scope.forJoinedSource(namespaceId, variantCoordinates.tableName), variantRelation);
|
|
3213
3386
|
}
|
|
3214
|
-
const relation = modelRelations[prop];
|
|
3387
|
+
const relation = Object.hasOwn(modelRelations, prop) ? modelRelations[prop] : void 0;
|
|
3215
3388
|
if (relation) return createRelationFilterAccessor(context, namespaceId, modelName, scope, relation);
|
|
3216
|
-
const variantField = variantFieldColumns[prop];
|
|
3389
|
+
const variantField = Object.hasOwn(variantFieldColumns, prop) ? variantFieldColumns[prop] : void 0;
|
|
3390
|
+
if (variantField === void 0 && !Object.hasOwn(fieldColumns, prop)) {
|
|
3391
|
+
if (isProbedByRuntime(prop)) return probedValue(target, prop);
|
|
3392
|
+
}
|
|
3217
3393
|
const resolvedTable = variantField?.table ?? tableName;
|
|
3218
3394
|
const fieldBinding = scope.forJoinedSource(namespaceId, resolvedTable).current;
|
|
3219
|
-
const columnName = variantField?.column ??
|
|
3395
|
+
const columnName = variantField?.column ?? columnOfCallerField(contract, namespaceId, fieldColumns, addressedModelName(modelName, variantName), prop);
|
|
3220
3396
|
const column = resolveColumn(contract, namespaceId, resolvedTable, columnName);
|
|
3221
|
-
if (!column)
|
|
3397
|
+
if (!column) throw new InternalError(`Field "${modelName}.${prop}" maps column "${columnName}", which table "${resolvedTable}" does not have`);
|
|
3222
3398
|
const traits = codecTraits(context, column.codecId);
|
|
3223
3399
|
const operations = opsByCodecId.get(column.codecId) ?? [];
|
|
3224
3400
|
const codec = codecRefForStorageColumn(contract.storage, namespaceId, resolvedTable, columnName);
|
|
@@ -3278,6 +3454,7 @@ function createRelationFilterAccessor(context, parentNamespaceId, parentModelNam
|
|
|
3278
3454
|
if (typeof prop !== "string") return void 0;
|
|
3279
3455
|
if (Object.hasOwn(target, prop)) return Reflect.get(target, prop);
|
|
3280
3456
|
if (RELATION_ACCESSOR_METHOD_NAMES.has(prop)) return void 0;
|
|
3457
|
+
if (isProbedByRuntime(prop) && !Object.hasOwn(getModelFieldColumns(context.contract, relation.toNamespace, relation.to), prop)) return probedValue(target, prop);
|
|
3281
3458
|
return relatedOrderableField(context, relation, relatedTableName, correlate, prop);
|
|
3282
3459
|
} });
|
|
3283
3460
|
return {
|
|
@@ -3285,6 +3462,15 @@ function createRelationFilterAccessor(context, parentNamespaceId, parentModelNam
|
|
|
3285
3462
|
count: (predicate) => createOrderable(() => buildRelationCountExpr(context, relation, correlate(), predicate))
|
|
3286
3463
|
};
|
|
3287
3464
|
}
|
|
3465
|
+
/**
|
|
3466
|
+
* Whether the JavaScript runtime or a common library reads `prop` from an object it is handed: `then` when a value is awaited or resolved as a promise, `toJSON` when it is stringified, and the `Object.prototype` members such as `toString`. An accessor answers these like a plain object, so a name that is not a field is refused only when the caller asks for it.
|
|
3467
|
+
*/
|
|
3468
|
+
function isProbedByRuntime(prop) {
|
|
3469
|
+
return prop === "then" || prop === "toJSON" || prop in Object.prototype;
|
|
3470
|
+
}
|
|
3471
|
+
function probedValue(target, prop) {
|
|
3472
|
+
return prop === "then" || prop === "toJSON" ? void 0 : Reflect.get(target, prop);
|
|
3473
|
+
}
|
|
3288
3474
|
function createOrderable(buildExpr) {
|
|
3289
3475
|
return {
|
|
3290
3476
|
asc: (options) => checkedOrderByItem("asc", buildExpr(), options),
|
|
@@ -3292,10 +3478,7 @@ function createOrderable(buildExpr) {
|
|
|
3292
3478
|
};
|
|
3293
3479
|
}
|
|
3294
3480
|
function relatedOrderableField(context, relation, relatedTableName, correlate, fieldName) {
|
|
3295
|
-
const
|
|
3296
|
-
if (!Object.hasOwn(fieldToColumn, fieldName)) return void 0;
|
|
3297
|
-
const columnName = fieldToColumn[fieldName];
|
|
3298
|
-
if (columnName === void 0) return void 0;
|
|
3481
|
+
const columnName = columnOfCallerField(context.contract, relation.toNamespace, getModelFieldColumns(context.contract, relation.toNamespace, relation.to), relation.to, fieldName);
|
|
3299
3482
|
const column = resolveColumn(context.contract, relation.toNamespace, relatedTableName, columnName);
|
|
3300
3483
|
if (!column || !hasTrait(context, column.codecId, "order")) return void 0;
|
|
3301
3484
|
return createOrderable(() => {
|
|
@@ -3312,7 +3495,7 @@ function correlateRelatedRows(context, parentNamespaceId, parentModelName, paren
|
|
|
3312
3495
|
const { through } = relation;
|
|
3313
3496
|
const { childScope, junctionBinding } = parentScope.forManyToManyRelation(relation.toNamespace, relatedTableName, through.namespaceId, through.table);
|
|
3314
3497
|
const junctionJoinOn = buildPairedColumnExprs(junctionBinding, through.childColumns, childScope.current, through.targetColumns);
|
|
3315
|
-
const parentLocalColumns = relation.on.localFields.map((field) =>
|
|
3498
|
+
const parentLocalColumns = relation.on.localFields.map((field) => columnOfContractField(context.contract, parentNamespaceId, parentModelName, field));
|
|
3316
3499
|
return {
|
|
3317
3500
|
childScope,
|
|
3318
3501
|
source: SelectAst.from(childScope.current.tableSource(context.contract)).withJoins([JoinAst.inner(junctionBinding.tableSource(context.contract), junctionJoinOn)]),
|
|
@@ -3325,7 +3508,7 @@ function correlateRelatedRows(context, parentNamespaceId, parentModelName, paren
|
|
|
3325
3508
|
childScope,
|
|
3326
3509
|
source: SelectAst.from(childScope.current.tableSource(context.contract)),
|
|
3327
3510
|
correlation: buildJoinWhere(context.contract, parentNamespaceId, parentModelName, parentScope.current, childScope.current, relation),
|
|
3328
|
-
keyColumn:
|
|
3511
|
+
keyColumn: firstJoinColumn(resolveRelationTargetColumns(context.contract, relation), "targetFields")
|
|
3329
3512
|
};
|
|
3330
3513
|
}
|
|
3331
3514
|
function buildExistsExpr(context, relation, rows, mode, predicate) {
|
|
@@ -3377,14 +3560,12 @@ function toRelationWhereExpr(context, relatedNamespaceId, relatedModelName, pred
|
|
|
3377
3560
|
if (!predicate) return;
|
|
3378
3561
|
const accessor = createModelAccessorInScope(context, relatedNamespaceId, relatedModelName, void 0, scope);
|
|
3379
3562
|
if (typeof predicate === "function") return predicate(accessor);
|
|
3563
|
+
assertModelFieldNames(context.contract, relatedNamespaceId, relatedModelName, predicate);
|
|
3380
3564
|
const exprs = [];
|
|
3381
3565
|
for (const [fieldName, value] of Object.entries(predicate)) {
|
|
3382
3566
|
if (value === void 0) continue;
|
|
3383
3567
|
const fieldAccessor = blindCast(accessor)[fieldName];
|
|
3384
|
-
if (!fieldAccessor) throw
|
|
3385
|
-
model: relatedModelName,
|
|
3386
|
-
field: fieldName
|
|
3387
|
-
} });
|
|
3568
|
+
if (!fieldAccessor) throw new InternalError(`Shorthand filter on "${relatedModelName}.${fieldName}": the field's column is missing from its table`);
|
|
3388
3569
|
if (value === null) {
|
|
3389
3570
|
if (!fieldAccessor.isNull) throw new InternalError(`Shorthand filter on "${relatedModelName}.${fieldName}": isNull is unexpectedly missing — this is a bug in trait gating`);
|
|
3390
3571
|
exprs.push(fieldAccessor.isNull());
|
|
@@ -3409,8 +3590,8 @@ function buildJoinWhere(contract, parentNamespaceId, parentModelName, parentTabl
|
|
|
3409
3590
|
const localField = localFields[i];
|
|
3410
3591
|
const targetField = targetFields[i];
|
|
3411
3592
|
if (!localField || !targetField) continue;
|
|
3412
|
-
const localColumn =
|
|
3413
|
-
const targetColumn =
|
|
3593
|
+
const localColumn = columnOfContractField(contract, parentNamespaceId, parentModelName, localField);
|
|
3594
|
+
const targetColumn = columnOfContractField(contract, relation.toNamespace, relation.to, targetField);
|
|
3414
3595
|
joinExprs.push(BinaryExpr.eq(relatedTable.column(targetColumn), parentTable.column(localColumn)));
|
|
3415
3596
|
}
|
|
3416
3597
|
if (joinExprs.length === 0) throw new InternalError("Relation metadata is missing join columns");
|
|
@@ -3418,11 +3599,6 @@ function buildJoinWhere(contract, parentNamespaceId, parentModelName, parentTabl
|
|
|
3418
3599
|
if (joinExprs.length === 1 && firstExpr !== void 0) return firstExpr;
|
|
3419
3600
|
return and(...joinExprs);
|
|
3420
3601
|
}
|
|
3421
|
-
function firstTargetColumn(contract, relation) {
|
|
3422
|
-
const firstField = (relation.on?.targetFields)?.[0];
|
|
3423
|
-
if (!firstField) return;
|
|
3424
|
-
return resolveFieldToColumn(contract, relation.toNamespace, relation.to, firstField);
|
|
3425
|
-
}
|
|
3426
3602
|
var GroupedCollection = class GroupedCollection {
|
|
3427
3603
|
ctx;
|
|
3428
3604
|
contract;
|
|
@@ -3560,7 +3736,7 @@ var GroupedCollection = class GroupedCollection {
|
|
|
3560
3736
|
* dynamic invocation.
|
|
3561
3737
|
*/
|
|
3562
3738
|
function createHavingBuilder(contract, aggregates, namespaceId, modelName, tableName) {
|
|
3563
|
-
const
|
|
3739
|
+
const fieldColumns = getModelFieldColumns(contract, namespaceId, modelName);
|
|
3564
3740
|
const builder = {};
|
|
3565
3741
|
for (const operation of aggregateOperationNames(aggregates)) builder[operation] = (field) => {
|
|
3566
3742
|
if (!isAggregateFn(operation)) throw ormError("ORM.AGGREGATE_PROJECTION_ONLY", `Aggregate operation '${operation}' is projection-only: it has no plain SQL form for HAVING, ORDER BY, or comparison positions.`, {
|
|
@@ -3568,13 +3744,14 @@ function createHavingBuilder(contract, aggregates, namespaceId, modelName, table
|
|
|
3568
3744
|
fix: `Project '${operation}' in a select and filter or order on the projected value, or use an operation from the SQL aggregate alphabet.`,
|
|
3569
3745
|
meta: { operation }
|
|
3570
3746
|
});
|
|
3571
|
-
|
|
3747
|
+
const column = field === void 0 ? void 0 : columnOfCallerField(contract, namespaceId, fieldColumns, modelName, field);
|
|
3748
|
+
return createHavingComparisonMethods(new AggregateExpr(operation, column === void 0 ? void 0 : ColumnRef.of(tableName, column)), () => resolveAggregate({
|
|
3572
3749
|
aggregates,
|
|
3573
3750
|
contract,
|
|
3574
3751
|
namespaceId,
|
|
3575
3752
|
tableName,
|
|
3576
3753
|
fn: operation,
|
|
3577
|
-
column
|
|
3754
|
+
column
|
|
3578
3755
|
}).codec.codecId);
|
|
3579
3756
|
};
|
|
3580
3757
|
return blindCast(builder);
|
|
@@ -3781,7 +3958,7 @@ async function updateFirstGraph(scope, context, namespaceId, modelName, filters,
|
|
|
3781
3958
|
for (const def of appliedUpdateDefaults) mappedUpdateData[def.field] = def.value;
|
|
3782
3959
|
const identityWhere = shorthandToWhereExpr(context, namespaceId, modelName, castAs(buildRowIdentityFilterFromRow(contract, namespaceId, modelName, existingRow)));
|
|
3783
3960
|
if (!identityWhere) throw new InternalError(`Failed to build row identity filter for model "${modelName}"`);
|
|
3784
|
-
const updatedRaw = (await queryPlanRows(scope, compileUpdateReturning(contract, namespaceId, tableName, mappedUpdateData, [identityWhere], void 0)).toArray())[0];
|
|
3961
|
+
const updatedRaw = (await queryPlanRows(scope, compileUpdateReturning(contract, namespaceId, modelName, tableName, mappedUpdateData, [identityWhere], void 0)).toArray())[0];
|
|
3785
3962
|
if (updatedRaw) parentRow = mapStorageRowToModelFields(contract, namespaceId, modelName, updatedRaw);
|
|
3786
3963
|
}
|
|
3787
3964
|
for (const relationMutation of childOwned) await applyChildOwnedMutation(scope, context, namespaceId, modelName, parentRow, relationMutation.relation, relationMutation.mutation);
|
|
@@ -4104,7 +4281,7 @@ async function insertSingleRow(scope, context, namespaceId, modelName, data) {
|
|
|
4104
4281
|
values: mappedData
|
|
4105
4282
|
});
|
|
4106
4283
|
for (const def of applied) mappedData[def.field] = def.value;
|
|
4107
|
-
const firstRow = (await queryPlanRows(scope, compileInsertReturning(contract, namespaceId, tableName, [mappedData], void 0)).toArray())[0];
|
|
4284
|
+
const firstRow = (await queryPlanRows(scope, compileInsertReturning(contract, namespaceId, modelName, tableName, [mappedData], void 0)).toArray())[0];
|
|
4108
4285
|
if (!firstRow) throw ormError("ORM.MUTATION_ROW_MISSING", `Nested create for model "${modelName}" did not return a row`, { meta: {
|
|
4109
4286
|
operation: "create",
|
|
4110
4287
|
model: modelName,
|
|
@@ -4120,7 +4297,7 @@ async function findRowByCriterion(scope, context, namespaceId, modelName, criter
|
|
|
4120
4297
|
model: modelName,
|
|
4121
4298
|
problem: "empty-criterion"
|
|
4122
4299
|
} });
|
|
4123
|
-
const firstRow = (await queryPlanRows(scope, compileSelect(contract, namespaceId, resolveModelTableName(contract, namespaceId, modelName), {
|
|
4300
|
+
const firstRow = (await queryPlanRows(scope, compileSelect(contract, namespaceId, modelName, resolveModelTableName(contract, namespaceId, modelName), {
|
|
4124
4301
|
...emptyState(),
|
|
4125
4302
|
filters: [whereExpr],
|
|
4126
4303
|
limit: 1
|
|
@@ -4129,7 +4306,7 @@ async function findRowByCriterion(scope, context, namespaceId, modelName, criter
|
|
|
4129
4306
|
return mapStorageRowToModelFields(contract, namespaceId, modelName, firstRow);
|
|
4130
4307
|
}
|
|
4131
4308
|
async function findFirstByFilters(scope, contract, namespaceId, modelName, filters) {
|
|
4132
|
-
const firstRow = (await queryPlanRows(scope, compileSelect(contract, namespaceId, resolveModelTableName(contract, namespaceId, modelName), {
|
|
4309
|
+
const firstRow = (await queryPlanRows(scope, compileSelect(contract, namespaceId, modelName, resolveModelTableName(contract, namespaceId, modelName), {
|
|
4133
4310
|
...emptyState(),
|
|
4134
4311
|
filters,
|
|
4135
4312
|
limit: 1
|
|
@@ -4158,8 +4335,8 @@ function getRelationDefinitions(contract, namespaceId, modelName) {
|
|
|
4158
4335
|
relatedNamespaceId: relation.toNamespace,
|
|
4159
4336
|
relatedTableName: resolveModelTableName(contract, relation.toNamespace, relation.to),
|
|
4160
4337
|
cardinality: relation.cardinality,
|
|
4161
|
-
localColumns: relation.on.localFields.map((f) =>
|
|
4162
|
-
targetColumns:
|
|
4338
|
+
localColumns: relation.on.localFields.map((f) => columnOfContractField(contract, namespaceId, modelName, f)),
|
|
4339
|
+
targetColumns: resolveRelationTargetColumns(contract, relation),
|
|
4163
4340
|
through: relation.through ? {
|
|
4164
4341
|
table: relation.through.table,
|
|
4165
4342
|
namespaceId: relation.through.namespaceId,
|
|
@@ -4173,7 +4350,7 @@ function getRelationDefinitions(contract, namespaceId, modelName) {
|
|
|
4173
4350
|
return definitions;
|
|
4174
4351
|
}
|
|
4175
4352
|
function toFieldName(contract, namespaceId, modelName, columnName) {
|
|
4176
|
-
return
|
|
4353
|
+
return fieldOfColumn(getModelColumnFields(contract, namespaceId, modelName), modelName, columnName);
|
|
4177
4354
|
}
|
|
4178
4355
|
function normalizeWhereArg(arg, options) {
|
|
4179
4356
|
if (arg === void 0) return;
|
|
@@ -4385,7 +4562,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4385
4562
|
*/
|
|
4386
4563
|
#includeScalarReducer(operation, field) {
|
|
4387
4564
|
this.#assertIncludeRefinementMode(`${operation}()`);
|
|
4388
|
-
const column = field === void 0 ? void 0 :
|
|
4565
|
+
const column = field === void 0 ? void 0 : columnOfCallerField(this.contract, this.namespaceId, getModelFieldColumns(this.contract, this.namespaceId, this.modelName), this.modelName, field);
|
|
4389
4566
|
return createIncludeScalar(operation, this.state, column);
|
|
4390
4567
|
}
|
|
4391
4568
|
where(input) {
|
|
@@ -4494,7 +4671,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4494
4671
|
return this.#cloneWithRow({ includes: [...this.state.includes, includeExpr] });
|
|
4495
4672
|
}
|
|
4496
4673
|
select(...fields) {
|
|
4497
|
-
const selectedFields =
|
|
4674
|
+
const selectedFields = mapSelectedFieldsToColumns(this.contract, this.namespaceId, this.modelName, this.state.variantName, fields);
|
|
4498
4675
|
return this.#cloneWithRow({ selectedFields });
|
|
4499
4676
|
}
|
|
4500
4677
|
orderBy(selection) {
|
|
@@ -4782,7 +4959,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4782
4959
|
applyCreateDefaults(this.ctx, this.namespaceId, this.tableName, mappedRows);
|
|
4783
4960
|
const { selectedForQuery: selectedForInsert, hiddenColumns } = this.#augmentMutationSelection();
|
|
4784
4961
|
if (this.contract.capabilities?.["sql"]?.["defaultInInsert"] !== true) {
|
|
4785
|
-
const plans = compileInsertReturningSplit(this.contract, this.namespaceId, this.tableName, mappedRows, selectedForInsert, conflictSkip).map((plan) => mergeAnnotations(plan, annotationsMap));
|
|
4962
|
+
const plans = compileInsertReturningSplit(this.contract, this.namespaceId, this.modelName, this.tableName, mappedRows, selectedForInsert, conflictSkip).map((plan) => mergeAnnotations(plan, annotationsMap));
|
|
4786
4963
|
return dispatchSplitMutationRows({
|
|
4787
4964
|
context: this.ctx.context,
|
|
4788
4965
|
runtime: this.ctx.runtime,
|
|
@@ -4797,7 +4974,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4797
4974
|
mapRow: (mapped) => blindCast(mapped)
|
|
4798
4975
|
});
|
|
4799
4976
|
}
|
|
4800
|
-
const compiled = mergeAnnotations(compileInsertReturning(this.contract, this.namespaceId, this.tableName, mappedRows, selectedForInsert, conflictSkip), annotationsMap);
|
|
4977
|
+
const compiled = mergeAnnotations(compileInsertReturning(this.contract, this.namespaceId, this.modelName, this.tableName, mappedRows, selectedForInsert, conflictSkip), annotationsMap);
|
|
4801
4978
|
return dispatchMutationRows({
|
|
4802
4979
|
context: this.ctx.context,
|
|
4803
4980
|
runtime: this.ctx.runtime,
|
|
@@ -4822,7 +4999,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4822
4999
|
else this.#assertNotMtiVariant(method);
|
|
4823
5000
|
const conflictOn = options.conflictOn ?? [];
|
|
4824
5001
|
assertInsertConflictSkipCapability(this.contract, method, conflictOn.length > 0);
|
|
4825
|
-
return { columns: resolveInsertConflictColumns(this.contract, this.namespaceId, this.modelName, conflictOn
|
|
5002
|
+
return { columns: resolveInsertConflictColumns(this.contract, this.namespaceId, this.modelName, conflictOn) };
|
|
4826
5003
|
}
|
|
4827
5004
|
#assertNotMtiVariant(method) {
|
|
4828
5005
|
this.#refuseOnMtiVariant(method, `${method} is not supported for MTI variant "${this.state.variantName}" on model "${this.modelName}". Use createAll() instead.`);
|
|
@@ -4846,16 +5023,20 @@ var CollectionBase = class CollectionBase {
|
|
|
4846
5023
|
if (!polyInfo) return null;
|
|
4847
5024
|
const variant = polyInfo.variants.get(variantName);
|
|
4848
5025
|
if (!isMtiVariantInfo(variant)) return null;
|
|
5026
|
+
const baseFieldToColumn = getModelFieldColumns(this.contract, this.namespaceId, this.modelName);
|
|
5027
|
+
const variantFieldToColumn = getOwnFieldColumns(this.contract, this.namespaceId, variant.modelName);
|
|
5028
|
+
const pkColumns = resolvePrimaryKeyColumns(this.contract, this.namespaceId, this.tableName);
|
|
4849
5029
|
return {
|
|
4850
5030
|
polyInfo,
|
|
4851
5031
|
variant,
|
|
4852
|
-
baseFieldToColumn
|
|
4853
|
-
variantFieldToColumn
|
|
4854
|
-
|
|
5032
|
+
baseFieldToColumn,
|
|
5033
|
+
variantFieldToColumn,
|
|
5034
|
+
mergedFieldToColumn: getModelAndVariantFieldColumns(this.contract, this.namespaceId, this.modelName, variant.modelName),
|
|
5035
|
+
pkColumns
|
|
4855
5036
|
};
|
|
4856
5037
|
}
|
|
4857
5038
|
#executeMtiCreate(data, mtiCtx) {
|
|
4858
|
-
const { polyInfo, variant, baseFieldToColumn, variantFieldToColumn, pkColumns } = mtiCtx;
|
|
5039
|
+
const { polyInfo, variant, baseFieldToColumn, variantFieldToColumn, mergedFieldToColumn, pkColumns } = mtiCtx;
|
|
4859
5040
|
const contract = this.contract;
|
|
4860
5041
|
const collectionCtx = this.ctx;
|
|
4861
5042
|
const runtime = collectionCtx.runtime;
|
|
@@ -4864,18 +5045,13 @@ var CollectionBase = class CollectionBase {
|
|
|
4864
5045
|
const namespaceId = this.namespaceId;
|
|
4865
5046
|
const baseFieldColumns = new Set(Object.values(baseFieldToColumn));
|
|
4866
5047
|
const variantFieldColumns = new Set(Object.values(variantFieldToColumn));
|
|
4867
|
-
const mergedFieldToColumn = {
|
|
4868
|
-
...baseFieldToColumn,
|
|
4869
|
-
...variantFieldToColumn
|
|
4870
|
-
};
|
|
4871
5048
|
const generator = async function* () {
|
|
4872
5049
|
const defaultValueCache = /* @__PURE__ */ new Map();
|
|
4873
5050
|
for (const row of data) {
|
|
4874
5051
|
const allMapped = {};
|
|
4875
5052
|
for (const [fieldName, value] of Object.entries(row)) {
|
|
4876
5053
|
if (value === void 0) continue;
|
|
4877
|
-
|
|
4878
|
-
allMapped[columnName] = value;
|
|
5054
|
+
allMapped[columnOfCallerField(contract, namespaceId, mergedFieldToColumn, variant.modelName, fieldName)] = value;
|
|
4879
5055
|
}
|
|
4880
5056
|
allMapped[polyInfo.discriminatorColumn] = variant.value;
|
|
4881
5057
|
const baseRow = {};
|
|
@@ -4886,7 +5062,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4886
5062
|
}
|
|
4887
5063
|
yield blindCast(await withMutationScope(runtime, async (scope) => {
|
|
4888
5064
|
applyCreateDefaults(collectionCtx, namespaceId, tableName, [baseRow], defaultValueCache);
|
|
4889
|
-
const baseCreated = (await queryPlanRows(scope, compileInsertReturning(contract, namespaceId, tableName, [baseRow], void 0)).toArray())[0];
|
|
5065
|
+
const baseCreated = (await queryPlanRows(scope, compileInsertReturning(contract, namespaceId, modelName, tableName, [baseRow], void 0)).toArray())[0];
|
|
4890
5066
|
if (!baseCreated) throw ormError("ORM.MUTATION_ROW_MISSING", `MTI base INSERT for model "${modelName}" did not return a row`, { meta: {
|
|
4891
5067
|
operation: "create",
|
|
4892
5068
|
model: modelName,
|
|
@@ -4895,7 +5071,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4895
5071
|
} });
|
|
4896
5072
|
for (const pkColumn of pkColumns) variantRow[pkColumn] = baseCreated[pkColumn];
|
|
4897
5073
|
applyCreateDefaults(collectionCtx, namespaceId, variant.table, [variantRow], defaultValueCache);
|
|
4898
|
-
const variantCreated = (await queryPlanRows(scope, compileInsertReturning(contract, namespaceId, variant.table, [variantRow], void 0)).toArray())[0];
|
|
5074
|
+
const variantCreated = (await queryPlanRows(scope, compileInsertReturning(contract, namespaceId, variant.modelName, variant.table, [variantRow], void 0)).toArray())[0];
|
|
4899
5075
|
if (!variantCreated) throw ormError("ORM.MUTATION_ROW_MISSING", `MTI variant INSERT for model "${modelName}" into "${variant.table}" did not return a row`, { meta: {
|
|
4900
5076
|
operation: "create",
|
|
4901
5077
|
model: modelName,
|
|
@@ -4923,18 +5099,12 @@ var CollectionBase = class CollectionBase {
|
|
|
4923
5099
|
if (!polyInfo) return data.map((row) => mapModelDataToStorageRow(this.contract, this.namespaceId, this.modelName, row));
|
|
4924
5100
|
const variant = polyInfo.variants.get(variantName);
|
|
4925
5101
|
if (!variant) return data.map((row) => mapModelDataToStorageRow(this.contract, this.namespaceId, this.modelName, row));
|
|
4926
|
-
const
|
|
4927
|
-
const variantFieldToColumn = getFieldToColumnMap(this.contract, this.namespaceId, variant.modelName);
|
|
4928
|
-
const mergedFieldToColumn = {
|
|
4929
|
-
...baseFieldToColumn,
|
|
4930
|
-
...variantFieldToColumn
|
|
4931
|
-
};
|
|
5102
|
+
const mergedFieldToColumn = getModelAndVariantFieldColumns(this.contract, this.namespaceId, this.modelName, variant.modelName);
|
|
4932
5103
|
return data.map((row) => {
|
|
4933
5104
|
const mapped = {};
|
|
4934
5105
|
for (const [fieldName, value] of Object.entries(row)) {
|
|
4935
5106
|
if (value === void 0) continue;
|
|
4936
|
-
|
|
4937
|
-
mapped[columnName] = value;
|
|
5107
|
+
mapped[columnOfCallerField(this.contract, this.namespaceId, mergedFieldToColumn, variant.modelName, fieldName)] = value;
|
|
4938
5108
|
}
|
|
4939
5109
|
mapped[polyInfo.discriminatorColumn] = variant.value;
|
|
4940
5110
|
return mapped;
|
|
@@ -5003,7 +5173,7 @@ var CollectionBase = class CollectionBase {
|
|
|
5003
5173
|
model: this.modelName
|
|
5004
5174
|
} });
|
|
5005
5175
|
const { selectedForQuery: selectedForUpsert, hiddenColumns } = this.#augmentMutationSelection();
|
|
5006
|
-
const compiled = mergeAnnotations(compileUpsertReturning(this.contract, this.namespaceId, this.tableName, createValues, updateValues, conflictColumns, selectedForUpsert), annotationsMap);
|
|
5176
|
+
const compiled = mergeAnnotations(compileUpsertReturning(this.contract, this.namespaceId, this.modelName, this.tableName, createValues, updateValues, conflictColumns, selectedForUpsert), annotationsMap);
|
|
5007
5177
|
const row = await executeMutationReturningSingleRow({
|
|
5008
5178
|
context: this.ctx.context,
|
|
5009
5179
|
runtime: this.ctx.runtime,
|
|
@@ -5048,6 +5218,7 @@ var CollectionBase = class CollectionBase {
|
|
|
5048
5218
|
const identityCriterion = buildRowIdentityFilterFromRow(this.contract, this.namespaceId, this.modelName, updatedRow);
|
|
5049
5219
|
return this.#reloadMutationRowByIdentity(identityCriterion);
|
|
5050
5220
|
}
|
|
5221
|
+
assertModelFieldNames(this.contract, this.namespaceId, this.modelName, blindCast(data));
|
|
5051
5222
|
return withMutationScope(this.ctx.runtime, async (scope) => {
|
|
5052
5223
|
const scoped = this.#withRuntime(scope);
|
|
5053
5224
|
const identityWhere = await scoped.#findFirstMatchingRowIdentityWhere();
|
|
@@ -5069,7 +5240,7 @@ var CollectionBase = class CollectionBase {
|
|
|
5069
5240
|
}
|
|
5070
5241
|
applyUpdateDefaults(this.ctx, this.namespaceId, this.tableName, mappedData);
|
|
5071
5242
|
const { selectedForQuery: selectedForUpdate, hiddenColumns } = this.#augmentMutationSelection();
|
|
5072
|
-
const compiled = mergeAnnotations(compileUpdateReturning(this.contract, this.namespaceId, this.tableName, mappedData, this.state.filters, selectedForUpdate), annotationsMap);
|
|
5243
|
+
const compiled = mergeAnnotations(compileUpdateReturning(this.contract, this.namespaceId, this.modelName, this.tableName, mappedData, this.state.filters, selectedForUpdate), annotationsMap);
|
|
5073
5244
|
return dispatchMutationRows({
|
|
5074
5245
|
context: this.ctx.context,
|
|
5075
5246
|
runtime: this.ctx.runtime,
|
|
@@ -5121,7 +5292,7 @@ var CollectionBase = class CollectionBase {
|
|
|
5121
5292
|
#executeDeleteReturning(annotationsMap) {
|
|
5122
5293
|
if (this.state.includes.length > 0) return this.#executeDeleteReturningWithIncludes(annotationsMap);
|
|
5123
5294
|
const { selectedForQuery: selectedForDelete, hiddenColumns } = this.#augmentMutationSelection();
|
|
5124
|
-
const compiled = mergeAnnotations(compileDeleteReturning(this.contract, this.namespaceId, this.tableName, this.state.filters, selectedForDelete), annotationsMap);
|
|
5295
|
+
const compiled = mergeAnnotations(compileDeleteReturning(this.contract, this.namespaceId, this.modelName, this.tableName, this.state.filters, selectedForDelete), annotationsMap);
|
|
5125
5296
|
return dispatchMutationRows({
|
|
5126
5297
|
context: this.ctx.context,
|
|
5127
5298
|
runtime: this.ctx.runtime,
|
|
@@ -5177,7 +5348,6 @@ var CollectionBase = class CollectionBase {
|
|
|
5177
5348
|
return (await this.ctx.runtime.execute(compiled)).affectedRows;
|
|
5178
5349
|
}
|
|
5179
5350
|
#buildUpsertConflictCriterion(createValues, conflictColumns) {
|
|
5180
|
-
const columnToField = getColumnToFieldMap(this.contract, this.namespaceId, this.modelName);
|
|
5181
5351
|
const criterion = {};
|
|
5182
5352
|
for (const columnName of conflictColumns) {
|
|
5183
5353
|
if (!(columnName in createValues)) throw ormError("ORM.ARGUMENT_INVALID", `upsert() for model "${this.modelName}" requires create value for conflict column "${columnName}"`, { meta: {
|
|
@@ -5185,7 +5355,7 @@ var CollectionBase = class CollectionBase {
|
|
|
5185
5355
|
model: this.modelName,
|
|
5186
5356
|
column: columnName
|
|
5187
5357
|
} });
|
|
5188
|
-
const fieldName =
|
|
5358
|
+
const fieldName = fieldOfColumn(getModelColumnFields(this.contract, this.namespaceId, this.modelName), this.modelName, columnName);
|
|
5189
5359
|
criterion[fieldName] = createValues[columnName];
|
|
5190
5360
|
}
|
|
5191
5361
|
return criterion;
|
|
@@ -5230,10 +5400,9 @@ var CollectionBase = class CollectionBase {
|
|
|
5230
5400
|
includes: []
|
|
5231
5401
|
}).first();
|
|
5232
5402
|
if (!firstRow) return null;
|
|
5233
|
-
const columnToField = getColumnToFieldMap(this.contract, this.namespaceId, this.modelName);
|
|
5234
5403
|
const criterion = {};
|
|
5235
5404
|
for (const column of identityColumns) {
|
|
5236
|
-
const fieldName =
|
|
5405
|
+
const fieldName = fieldOfColumn(getModelColumnFields(this.contract, this.namespaceId, this.modelName), this.modelName, column);
|
|
5237
5406
|
const value = blindCast(firstRow)[fieldName];
|
|
5238
5407
|
if (value === void 0) throw new InternalError(`Missing identity field "${fieldName}" while resolving single-row scope for model "${this.modelName}"`);
|
|
5239
5408
|
criterion[fieldName] = value;
|