@zenstackhq/runtime 3.0.0-alpha.11 → 3.0.0-alpha.13
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/{contract-BQGRBbOU.d.cts → contract-CBOBlAuw.d.cts} +82 -51
- package/dist/{contract-BQGRBbOU.d.ts → contract-CBOBlAuw.d.ts} +82 -51
- package/dist/index.cjs +664 -243
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +664 -243
- package/dist/index.js.map +1 -1
- package/dist/plugins/{policy.cjs → policy/index.cjs} +225 -125
- package/dist/plugins/policy/index.cjs.map +1 -0
- package/dist/plugins/{policy.d.ts → policy/index.d.cts} +1 -1
- package/dist/plugins/{policy.d.cts → policy/index.d.ts} +1 -1
- package/dist/plugins/{policy.js → policy/index.js} +225 -125
- package/dist/plugins/policy/index.js.map +1 -0
- package/dist/plugins/policy/plugin.zmodel +33 -0
- package/package.json +12 -12
- package/dist/plugins/policy.cjs.map +0 -1
- package/dist/plugins/policy.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -14,6 +14,85 @@ import { match as match19 } from "ts-pattern";
|
|
|
14
14
|
import { sql as sql5 } from "kysely";
|
|
15
15
|
import { match as match9 } from "ts-pattern";
|
|
16
16
|
|
|
17
|
+
// src/schema/expression.ts
|
|
18
|
+
var ExpressionUtils = {
|
|
19
|
+
literal: /* @__PURE__ */ __name((value) => {
|
|
20
|
+
return {
|
|
21
|
+
kind: "literal",
|
|
22
|
+
value
|
|
23
|
+
};
|
|
24
|
+
}, "literal"),
|
|
25
|
+
array: /* @__PURE__ */ __name((items) => {
|
|
26
|
+
return {
|
|
27
|
+
kind: "array",
|
|
28
|
+
items
|
|
29
|
+
};
|
|
30
|
+
}, "array"),
|
|
31
|
+
call: /* @__PURE__ */ __name((functionName, args) => {
|
|
32
|
+
return {
|
|
33
|
+
kind: "call",
|
|
34
|
+
function: functionName,
|
|
35
|
+
args
|
|
36
|
+
};
|
|
37
|
+
}, "call"),
|
|
38
|
+
binary: /* @__PURE__ */ __name((left, op, right) => {
|
|
39
|
+
return {
|
|
40
|
+
kind: "binary",
|
|
41
|
+
op,
|
|
42
|
+
left,
|
|
43
|
+
right
|
|
44
|
+
};
|
|
45
|
+
}, "binary"),
|
|
46
|
+
unary: /* @__PURE__ */ __name((op, operand) => {
|
|
47
|
+
return {
|
|
48
|
+
kind: "unary",
|
|
49
|
+
op,
|
|
50
|
+
operand
|
|
51
|
+
};
|
|
52
|
+
}, "unary"),
|
|
53
|
+
field: /* @__PURE__ */ __name((field) => {
|
|
54
|
+
return {
|
|
55
|
+
kind: "field",
|
|
56
|
+
field
|
|
57
|
+
};
|
|
58
|
+
}, "field"),
|
|
59
|
+
member: /* @__PURE__ */ __name((receiver, members) => {
|
|
60
|
+
return {
|
|
61
|
+
kind: "member",
|
|
62
|
+
receiver,
|
|
63
|
+
members
|
|
64
|
+
};
|
|
65
|
+
}, "member"),
|
|
66
|
+
_this: /* @__PURE__ */ __name(() => {
|
|
67
|
+
return {
|
|
68
|
+
kind: "this"
|
|
69
|
+
};
|
|
70
|
+
}, "_this"),
|
|
71
|
+
_null: /* @__PURE__ */ __name(() => {
|
|
72
|
+
return {
|
|
73
|
+
kind: "null"
|
|
74
|
+
};
|
|
75
|
+
}, "_null"),
|
|
76
|
+
and: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
77
|
+
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
|
|
78
|
+
}, "and"),
|
|
79
|
+
or: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
80
|
+
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
|
|
81
|
+
}, "or"),
|
|
82
|
+
is: /* @__PURE__ */ __name((value, kind) => {
|
|
83
|
+
return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
|
|
84
|
+
}, "is"),
|
|
85
|
+
isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
|
|
86
|
+
isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
|
|
87
|
+
isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
|
|
88
|
+
isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
|
|
89
|
+
isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
|
|
90
|
+
isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
|
|
91
|
+
isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
|
|
92
|
+
isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
|
|
93
|
+
isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
|
|
94
|
+
};
|
|
95
|
+
|
|
17
96
|
// src/client/errors.ts
|
|
18
97
|
var InputValidationError = class extends Error {
|
|
19
98
|
static {
|
|
@@ -135,6 +214,11 @@ function isRelationField(schema, model, field) {
|
|
|
135
214
|
return !!fieldDef.relation;
|
|
136
215
|
}
|
|
137
216
|
__name(isRelationField, "isRelationField");
|
|
217
|
+
function isInheritedField(schema, model, field) {
|
|
218
|
+
const fieldDef = requireField(schema, model, field);
|
|
219
|
+
return !!fieldDef.originModel;
|
|
220
|
+
}
|
|
221
|
+
__name(isInheritedField, "isInheritedField");
|
|
138
222
|
function getUniqueFields(schema, model) {
|
|
139
223
|
const modelDef = requireModel(schema, model);
|
|
140
224
|
const result = [];
|
|
@@ -287,6 +371,46 @@ function safeJSONStringify(value) {
|
|
|
287
371
|
});
|
|
288
372
|
}
|
|
289
373
|
__name(safeJSONStringify, "safeJSONStringify");
|
|
374
|
+
function extractFields(object, fields) {
|
|
375
|
+
return fields.reduce((acc, field) => {
|
|
376
|
+
if (field in object) {
|
|
377
|
+
acc[field] = object[field];
|
|
378
|
+
}
|
|
379
|
+
return acc;
|
|
380
|
+
}, {});
|
|
381
|
+
}
|
|
382
|
+
__name(extractFields, "extractFields");
|
|
383
|
+
function extractIdFields(entity, schema, model) {
|
|
384
|
+
const idFields = getIdFields(schema, model);
|
|
385
|
+
return extractFields(entity, idFields);
|
|
386
|
+
}
|
|
387
|
+
__name(extractIdFields, "extractIdFields");
|
|
388
|
+
function getDiscriminatorField(schema, model) {
|
|
389
|
+
const modelDef = requireModel(schema, model);
|
|
390
|
+
const delegateAttr = modelDef.attributes?.find((attr) => attr.name === "@@delegate");
|
|
391
|
+
if (!delegateAttr) {
|
|
392
|
+
return void 0;
|
|
393
|
+
}
|
|
394
|
+
const discriminator = delegateAttr.args?.find((arg) => arg.name === "discriminator");
|
|
395
|
+
if (!discriminator || !ExpressionUtils.isField(discriminator.value)) {
|
|
396
|
+
throw new InternalError(`Discriminator field not defined for model "${model}"`);
|
|
397
|
+
}
|
|
398
|
+
return discriminator.value.field;
|
|
399
|
+
}
|
|
400
|
+
__name(getDiscriminatorField, "getDiscriminatorField");
|
|
401
|
+
function getDelegateDescendantModels(schema, model, collected = /* @__PURE__ */ new Set()) {
|
|
402
|
+
const subModels = Object.values(schema.models).filter((m) => m.baseModel === model);
|
|
403
|
+
subModels.forEach((def) => {
|
|
404
|
+
if (!collected.has(def)) {
|
|
405
|
+
collected.add(def);
|
|
406
|
+
getDelegateDescendantModels(schema, def.name, collected);
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
return [
|
|
410
|
+
...collected
|
|
411
|
+
];
|
|
412
|
+
}
|
|
413
|
+
__name(getDelegateDescendantModels, "getDelegateDescendantModels");
|
|
290
414
|
|
|
291
415
|
// src/client/crud/operations/base.ts
|
|
292
416
|
import { createId } from "@paralleldrive/cuid2";
|
|
@@ -323,6 +447,16 @@ import { invariant as invariant2 } from "@zenstackhq/common-helpers";
|
|
|
323
447
|
import { sql as sql2 } from "kysely";
|
|
324
448
|
import { match as match2 } from "ts-pattern";
|
|
325
449
|
|
|
450
|
+
// src/client/constants.ts
|
|
451
|
+
var CONTEXT_COMMENT_PREFIX = "-- $$context:";
|
|
452
|
+
var NUMERIC_FIELD_TYPES = [
|
|
453
|
+
"Int",
|
|
454
|
+
"Float",
|
|
455
|
+
"BigInt",
|
|
456
|
+
"Decimal"
|
|
457
|
+
];
|
|
458
|
+
var DELEGATE_JOINED_FIELD_PREFIX = "$delegate$";
|
|
459
|
+
|
|
326
460
|
// src/client/crud/dialects/base.ts
|
|
327
461
|
import { invariant, isPlainObject } from "@zenstackhq/common-helpers";
|
|
328
462
|
import { sql } from "kysely";
|
|
@@ -356,6 +490,17 @@ var BaseCrudDialect = class {
|
|
|
356
490
|
transformPrimitive(value, _type, _forArrayField) {
|
|
357
491
|
return value;
|
|
358
492
|
}
|
|
493
|
+
// #region common query builders
|
|
494
|
+
buildSelectModel(eb, model) {
|
|
495
|
+
const modelDef = requireModel(this.schema, model);
|
|
496
|
+
let result = eb.selectFrom(model);
|
|
497
|
+
let joinBase = modelDef.baseModel;
|
|
498
|
+
while (joinBase) {
|
|
499
|
+
result = this.buildDelegateJoin(model, joinBase, result);
|
|
500
|
+
joinBase = requireModel(this.schema, joinBase).baseModel;
|
|
501
|
+
}
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
359
504
|
buildFilter(eb, model, modelAlias, where) {
|
|
360
505
|
if (where === true || where === void 0) {
|
|
361
506
|
return this.true(eb);
|
|
@@ -379,10 +524,13 @@ var BaseCrudDialect = class {
|
|
|
379
524
|
const fieldDef = requireField(this.schema, model, key);
|
|
380
525
|
if (fieldDef.relation) {
|
|
381
526
|
result = this.and(eb, result, this.buildRelationFilter(eb, model, modelAlias, key, fieldDef, payload));
|
|
382
|
-
} else if (fieldDef.array) {
|
|
383
|
-
result = this.and(eb, result, this.buildArrayFilter(eb, model, modelAlias, key, fieldDef, payload));
|
|
384
527
|
} else {
|
|
385
|
-
|
|
528
|
+
const fieldRef = buildFieldRef(this.schema, fieldDef.originModel ?? model, key, this.options, eb, fieldDef.originModel ?? modelAlias);
|
|
529
|
+
if (fieldDef.array) {
|
|
530
|
+
result = this.and(eb, result, this.buildArrayFilter(eb, fieldRef, fieldDef, payload));
|
|
531
|
+
} else {
|
|
532
|
+
result = this.and(eb, result, this.buildPrimitiveFilter(eb, fieldRef, fieldDef, payload));
|
|
533
|
+
}
|
|
386
534
|
}
|
|
387
535
|
}
|
|
388
536
|
if ("$expr" in _where && typeof _where["$expr"] === "function") {
|
|
@@ -400,19 +548,26 @@ var BaseCrudDialect = class {
|
|
|
400
548
|
return this.buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload);
|
|
401
549
|
}
|
|
402
550
|
}
|
|
403
|
-
buildToOneRelationFilter(eb, model,
|
|
551
|
+
buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
|
|
404
552
|
if (payload === null) {
|
|
405
553
|
const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, model, field);
|
|
406
|
-
if (ownedByModel) {
|
|
407
|
-
return this.and(eb, ...keyPairs.map(({ fk }) => eb(sql.ref(`${
|
|
554
|
+
if (ownedByModel && !fieldDef.originModel) {
|
|
555
|
+
return this.and(eb, ...keyPairs.map(({ fk }) => eb(sql.ref(`${modelAlias}.${fk}`), "is", null)));
|
|
408
556
|
} else {
|
|
409
|
-
return this.buildToOneRelationFilter(eb, model,
|
|
557
|
+
return this.buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, {
|
|
410
558
|
is: null
|
|
411
559
|
});
|
|
412
560
|
}
|
|
413
561
|
}
|
|
414
|
-
const joinAlias = `${
|
|
415
|
-
const joinPairs = buildJoinPairs(
|
|
562
|
+
const joinAlias = `${modelAlias}$${field}`;
|
|
563
|
+
const joinPairs = buildJoinPairs(
|
|
564
|
+
this.schema,
|
|
565
|
+
model,
|
|
566
|
+
// if field is from a base, use the base model to join
|
|
567
|
+
fieldDef.originModel ?? modelAlias,
|
|
568
|
+
field,
|
|
569
|
+
joinAlias
|
|
570
|
+
);
|
|
416
571
|
const filterResultField = `${field}$filter`;
|
|
417
572
|
const joinSelect = eb.selectFrom(`${fieldDef.type} as ${joinAlias}`).where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql.ref(left), "=", sql.ref(right))))).select(() => eb.fn.count(eb.lit(1)).as(filterResultField));
|
|
418
573
|
const conditions = [];
|
|
@@ -473,25 +628,24 @@ var BaseCrudDialect = class {
|
|
|
473
628
|
}
|
|
474
629
|
switch (key) {
|
|
475
630
|
case "some": {
|
|
476
|
-
result = this.and(eb, result, eb(
|
|
631
|
+
result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationModel, subPayload)), ">", 0));
|
|
477
632
|
break;
|
|
478
633
|
}
|
|
479
634
|
case "every": {
|
|
480
|
-
result = this.and(eb, result, eb(
|
|
635
|
+
result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => eb1.not(this.buildFilter(eb1, relationModel, relationModel, subPayload))), "=", 0));
|
|
481
636
|
break;
|
|
482
637
|
}
|
|
483
638
|
case "none": {
|
|
484
|
-
result = this.and(eb, result, eb(
|
|
639
|
+
result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationModel, subPayload)), "=", 0));
|
|
485
640
|
break;
|
|
486
641
|
}
|
|
487
642
|
}
|
|
488
643
|
}
|
|
489
644
|
return result;
|
|
490
645
|
}
|
|
491
|
-
buildArrayFilter(eb,
|
|
646
|
+
buildArrayFilter(eb, fieldRef, fieldDef, payload) {
|
|
492
647
|
const clauses = [];
|
|
493
648
|
const fieldType = fieldDef.type;
|
|
494
|
-
const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb, modelAlias);
|
|
495
649
|
for (const [key, _value] of Object.entries(payload)) {
|
|
496
650
|
if (_value === void 0) {
|
|
497
651
|
continue;
|
|
@@ -527,14 +681,14 @@ var BaseCrudDialect = class {
|
|
|
527
681
|
}
|
|
528
682
|
return this.and(eb, ...clauses);
|
|
529
683
|
}
|
|
530
|
-
buildPrimitiveFilter(eb,
|
|
684
|
+
buildPrimitiveFilter(eb, fieldRef, fieldDef, payload) {
|
|
531
685
|
if (payload === null) {
|
|
532
|
-
return eb(
|
|
686
|
+
return eb(fieldRef, "is", null);
|
|
533
687
|
}
|
|
534
688
|
if (isEnum(this.schema, fieldDef.type)) {
|
|
535
|
-
return this.buildEnumFilter(eb,
|
|
689
|
+
return this.buildEnumFilter(eb, fieldRef, fieldDef, payload);
|
|
536
690
|
}
|
|
537
|
-
return match(fieldDef.type).with("String", () => this.buildStringFilter(eb,
|
|
691
|
+
return match(fieldDef.type).with("String", () => this.buildStringFilter(eb, fieldRef, payload)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, fieldRef, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, fieldRef, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, fieldRef, payload)).with("Bytes", () => this.buildBytesFilter(eb, fieldRef, payload)).with("Json", () => {
|
|
538
692
|
throw new InternalError("JSON filters are not supported yet");
|
|
539
693
|
}).with("Unsupported", () => {
|
|
540
694
|
throw new QueryError(`Unsupported field cannot be used in filters`);
|
|
@@ -590,9 +744,7 @@ var BaseCrudDialect = class {
|
|
|
590
744
|
consumedKeys
|
|
591
745
|
};
|
|
592
746
|
}
|
|
593
|
-
buildStringFilter(eb,
|
|
594
|
-
const fieldDef = getField(this.schema, table, field);
|
|
595
|
-
let fieldRef = fieldDef?.computed ? sql.ref(field) : sql.ref(`${table}.${field}`);
|
|
747
|
+
buildStringFilter(eb, fieldRef, payload) {
|
|
596
748
|
let insensitive = false;
|
|
597
749
|
if (payload && typeof payload === "object" && "mode" in payload && payload.mode === "insensitive") {
|
|
598
750
|
insensitive = true;
|
|
@@ -600,7 +752,7 @@ var BaseCrudDialect = class {
|
|
|
600
752
|
fieldRef
|
|
601
753
|
]);
|
|
602
754
|
}
|
|
603
|
-
const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => this.prepStringCasing(eb, value, insensitive), (value) => this.buildStringFilter(eb,
|
|
755
|
+
const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => this.prepStringCasing(eb, value, insensitive), (value) => this.buildStringFilter(eb, fieldRef, value));
|
|
604
756
|
if (payload && typeof payload === "object") {
|
|
605
757
|
for (const [key, value] of Object.entries(payload)) {
|
|
606
758
|
if (key === "mode" || consumedKeys.includes(key)) {
|
|
@@ -627,23 +779,23 @@ var BaseCrudDialect = class {
|
|
|
627
779
|
return value === null ? null : sql.lit(value);
|
|
628
780
|
}
|
|
629
781
|
}
|
|
630
|
-
buildNumberFilter(eb,
|
|
631
|
-
const { conditions } = this.buildStandardFilter(eb, type, payload,
|
|
782
|
+
buildNumberFilter(eb, fieldRef, type, payload) {
|
|
783
|
+
const { conditions } = this.buildStandardFilter(eb, type, payload, fieldRef, (value) => this.transformPrimitive(value, type, false), (value) => this.buildNumberFilter(eb, fieldRef, type, value));
|
|
632
784
|
return this.and(eb, ...conditions);
|
|
633
785
|
}
|
|
634
|
-
buildBooleanFilter(eb,
|
|
635
|
-
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload,
|
|
786
|
+
buildBooleanFilter(eb, fieldRef, payload) {
|
|
787
|
+
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, fieldRef, (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, fieldRef, value), true, [
|
|
636
788
|
"equals",
|
|
637
789
|
"not"
|
|
638
790
|
]);
|
|
639
791
|
return this.and(eb, ...conditions);
|
|
640
792
|
}
|
|
641
|
-
buildDateTimeFilter(eb,
|
|
642
|
-
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload,
|
|
793
|
+
buildDateTimeFilter(eb, fieldRef, payload) {
|
|
794
|
+
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, fieldRef, (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, fieldRef, value), true);
|
|
643
795
|
return this.and(eb, ...conditions);
|
|
644
796
|
}
|
|
645
|
-
buildBytesFilter(eb,
|
|
646
|
-
const conditions = this.buildStandardFilter(eb, "Bytes", payload,
|
|
797
|
+
buildBytesFilter(eb, fieldRef, payload) {
|
|
798
|
+
const conditions = this.buildStandardFilter(eb, "Bytes", payload, fieldRef, (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, fieldRef, value), true, [
|
|
647
799
|
"equals",
|
|
648
800
|
"in",
|
|
649
801
|
"notIn",
|
|
@@ -651,8 +803,8 @@ var BaseCrudDialect = class {
|
|
|
651
803
|
]);
|
|
652
804
|
return this.and(eb, ...conditions.conditions);
|
|
653
805
|
}
|
|
654
|
-
buildEnumFilter(eb,
|
|
655
|
-
const conditions = this.buildStandardFilter(eb, "String", payload,
|
|
806
|
+
buildEnumFilter(eb, fieldRef, fieldDef, payload) {
|
|
807
|
+
const conditions = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => value, (value) => this.buildEnumFilter(eb, fieldRef, fieldDef, value), true, [
|
|
656
808
|
"equals",
|
|
657
809
|
"in",
|
|
658
810
|
"notIn",
|
|
@@ -719,7 +871,7 @@ var BaseCrudDialect = class {
|
|
|
719
871
|
invariant(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
|
|
720
872
|
const sort = this.negateSort(value._count, negated);
|
|
721
873
|
result = result.orderBy((eb) => {
|
|
722
|
-
let subQuery =
|
|
874
|
+
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
723
875
|
const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, relationModel);
|
|
724
876
|
subQuery = subQuery.where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql.ref(left), "=", sql.ref(right)))));
|
|
725
877
|
subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
|
|
@@ -738,6 +890,56 @@ var BaseCrudDialect = class {
|
|
|
738
890
|
});
|
|
739
891
|
return result;
|
|
740
892
|
}
|
|
893
|
+
buildSelectAllFields(model, query, omit) {
|
|
894
|
+
const modelDef = requireModel(this.schema, model);
|
|
895
|
+
let result = query;
|
|
896
|
+
for (const field of Object.keys(modelDef.fields)) {
|
|
897
|
+
if (isRelationField(this.schema, model, field)) {
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
if (omit?.[field] === true) {
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
903
|
+
result = this.buildSelectField(result, model, model, field);
|
|
904
|
+
}
|
|
905
|
+
const descendants = getDelegateDescendantModels(this.schema, model);
|
|
906
|
+
for (const subModel of descendants) {
|
|
907
|
+
result = this.buildDelegateJoin(model, subModel.name, result);
|
|
908
|
+
result = result.select((eb) => {
|
|
909
|
+
const jsonObject = {};
|
|
910
|
+
for (const field of Object.keys(subModel.fields)) {
|
|
911
|
+
if (isRelationField(this.schema, subModel.name, field) || isInheritedField(this.schema, subModel.name, field)) {
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
jsonObject[field] = eb.ref(`${subModel.name}.${field}`);
|
|
915
|
+
}
|
|
916
|
+
return this.buildJsonObject(eb, jsonObject).as(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`);
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
return result;
|
|
920
|
+
}
|
|
921
|
+
buildSelectField(query, model, modelAlias, field) {
|
|
922
|
+
const fieldDef = requireField(this.schema, model, field);
|
|
923
|
+
if (fieldDef.computed) {
|
|
924
|
+
return query.select((eb) => buildFieldRef(this.schema, model, field, this.options, eb).as(field));
|
|
925
|
+
} else if (!fieldDef.originModel) {
|
|
926
|
+
return query.select(sql.ref(`${modelAlias}.${field}`).as(field));
|
|
927
|
+
} else {
|
|
928
|
+
return this.buildSelectField(query, fieldDef.originModel, fieldDef.originModel, field);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
buildDelegateJoin(thisModel, otherModel, query) {
|
|
932
|
+
const idFields = getIdFields(this.schema, thisModel);
|
|
933
|
+
query = query.leftJoin(otherModel, (qb) => {
|
|
934
|
+
for (const idField of idFields) {
|
|
935
|
+
qb = qb.onRef(`${thisModel}.${idField}`, "=", `${otherModel}.${idField}`);
|
|
936
|
+
}
|
|
937
|
+
return qb;
|
|
938
|
+
});
|
|
939
|
+
return query;
|
|
940
|
+
}
|
|
941
|
+
// #endregion
|
|
942
|
+
// #region utils
|
|
741
943
|
negateSort(sort, negated) {
|
|
742
944
|
return negated ? sort === "asc" ? "desc" : "asc" : sort;
|
|
743
945
|
}
|
|
@@ -819,7 +1021,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
819
1021
|
const joinTableName = `${parentName}$${relationField}`;
|
|
820
1022
|
let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
|
|
821
1023
|
result = eb.selectFrom(() => {
|
|
822
|
-
let subQuery =
|
|
1024
|
+
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
1025
|
+
subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
|
|
823
1026
|
if (payload && typeof payload === "object") {
|
|
824
1027
|
if (payload.where) {
|
|
825
1028
|
subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
|
|
@@ -866,6 +1069,13 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
866
1069
|
buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName) {
|
|
867
1070
|
const relationModelDef = requireModel(this.schema, relationModel);
|
|
868
1071
|
const objArgs = [];
|
|
1072
|
+
const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
|
|
1073
|
+
if (descendantModels.length > 0) {
|
|
1074
|
+
objArgs.push(...descendantModels.map((subModel) => [
|
|
1075
|
+
sql2.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
|
|
1076
|
+
eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
|
|
1077
|
+
]).flatMap((v) => v));
|
|
1078
|
+
}
|
|
869
1079
|
if (payload === true || !payload.select) {
|
|
870
1080
|
objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
|
|
871
1081
|
sql2.lit(field),
|
|
@@ -958,7 +1168,11 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
958
1168
|
if (Array.isArray(value)) {
|
|
959
1169
|
return value.map((v) => this.transformPrimitive(v, type, false));
|
|
960
1170
|
} else {
|
|
961
|
-
|
|
1171
|
+
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
1172
|
+
return JSON.stringify(value);
|
|
1173
|
+
} else {
|
|
1174
|
+
return match3(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).with("Json", () => JSON.stringify(value)).otherwise(() => value);
|
|
1175
|
+
}
|
|
962
1176
|
}
|
|
963
1177
|
}
|
|
964
1178
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
@@ -970,7 +1184,8 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
970
1184
|
const relationModelDef = requireModel(this.schema, relationModel);
|
|
971
1185
|
const subQueryName = `${parentName}$${relationField}`;
|
|
972
1186
|
let tbl = eb.selectFrom(() => {
|
|
973
|
-
let subQuery =
|
|
1187
|
+
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
1188
|
+
subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
|
|
974
1189
|
if (payload && typeof payload === "object") {
|
|
975
1190
|
if (payload.where) {
|
|
976
1191
|
subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
|
|
@@ -1006,6 +1221,13 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
1006
1221
|
});
|
|
1007
1222
|
tbl = tbl.select(() => {
|
|
1008
1223
|
const objArgs = [];
|
|
1224
|
+
const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
|
|
1225
|
+
if (descendantModels.length > 0) {
|
|
1226
|
+
objArgs.push(...descendantModels.map((subModel) => [
|
|
1227
|
+
sql3.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
|
|
1228
|
+
eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
|
|
1229
|
+
]).flatMap((v) => v));
|
|
1230
|
+
}
|
|
1009
1231
|
if (payload === true || !payload.select) {
|
|
1010
1232
|
objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
|
|
1011
1233
|
sql3.lit(field),
|
|
@@ -1088,85 +1310,6 @@ function getCrudDialect(schema, options) {
|
|
|
1088
1310
|
}
|
|
1089
1311
|
__name(getCrudDialect, "getCrudDialect");
|
|
1090
1312
|
|
|
1091
|
-
// src/schema/expression.ts
|
|
1092
|
-
var ExpressionUtils = {
|
|
1093
|
-
literal: /* @__PURE__ */ __name((value) => {
|
|
1094
|
-
return {
|
|
1095
|
-
kind: "literal",
|
|
1096
|
-
value
|
|
1097
|
-
};
|
|
1098
|
-
}, "literal"),
|
|
1099
|
-
array: /* @__PURE__ */ __name((items) => {
|
|
1100
|
-
return {
|
|
1101
|
-
kind: "array",
|
|
1102
|
-
items
|
|
1103
|
-
};
|
|
1104
|
-
}, "array"),
|
|
1105
|
-
call: /* @__PURE__ */ __name((functionName, args) => {
|
|
1106
|
-
return {
|
|
1107
|
-
kind: "call",
|
|
1108
|
-
function: functionName,
|
|
1109
|
-
args
|
|
1110
|
-
};
|
|
1111
|
-
}, "call"),
|
|
1112
|
-
binary: /* @__PURE__ */ __name((left, op, right) => {
|
|
1113
|
-
return {
|
|
1114
|
-
kind: "binary",
|
|
1115
|
-
op,
|
|
1116
|
-
left,
|
|
1117
|
-
right
|
|
1118
|
-
};
|
|
1119
|
-
}, "binary"),
|
|
1120
|
-
unary: /* @__PURE__ */ __name((op, operand) => {
|
|
1121
|
-
return {
|
|
1122
|
-
kind: "unary",
|
|
1123
|
-
op,
|
|
1124
|
-
operand
|
|
1125
|
-
};
|
|
1126
|
-
}, "unary"),
|
|
1127
|
-
field: /* @__PURE__ */ __name((field) => {
|
|
1128
|
-
return {
|
|
1129
|
-
kind: "field",
|
|
1130
|
-
field
|
|
1131
|
-
};
|
|
1132
|
-
}, "field"),
|
|
1133
|
-
member: /* @__PURE__ */ __name((receiver, members) => {
|
|
1134
|
-
return {
|
|
1135
|
-
kind: "member",
|
|
1136
|
-
receiver,
|
|
1137
|
-
members
|
|
1138
|
-
};
|
|
1139
|
-
}, "member"),
|
|
1140
|
-
_this: /* @__PURE__ */ __name(() => {
|
|
1141
|
-
return {
|
|
1142
|
-
kind: "this"
|
|
1143
|
-
};
|
|
1144
|
-
}, "_this"),
|
|
1145
|
-
_null: /* @__PURE__ */ __name(() => {
|
|
1146
|
-
return {
|
|
1147
|
-
kind: "null"
|
|
1148
|
-
};
|
|
1149
|
-
}, "_null"),
|
|
1150
|
-
and: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
1151
|
-
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
|
|
1152
|
-
}, "and"),
|
|
1153
|
-
or: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
1154
|
-
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
|
|
1155
|
-
}, "or"),
|
|
1156
|
-
is: /* @__PURE__ */ __name((value, kind) => {
|
|
1157
|
-
return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
|
|
1158
|
-
}, "is"),
|
|
1159
|
-
isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
|
|
1160
|
-
isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
|
|
1161
|
-
isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
|
|
1162
|
-
isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
|
|
1163
|
-
isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
|
|
1164
|
-
isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
|
|
1165
|
-
isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
|
|
1166
|
-
isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
|
|
1167
|
-
isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
|
|
1168
|
-
};
|
|
1169
|
-
|
|
1170
1313
|
// src/utils/default-operation-node-visitor.ts
|
|
1171
1314
|
import { OperationNodeVisitor } from "kysely";
|
|
1172
1315
|
var DefaultOperationNodeVisitor = class extends OperationNodeVisitor {
|
|
@@ -2433,10 +2576,10 @@ function clone(value) {
|
|
|
2433
2576
|
__name(clone, "clone");
|
|
2434
2577
|
|
|
2435
2578
|
// src/utils/object-utils.ts
|
|
2436
|
-
function
|
|
2579
|
+
function extractFields2(obj, fields) {
|
|
2437
2580
|
return Object.fromEntries(Object.entries(obj).filter(([key]) => fields.includes(key)));
|
|
2438
2581
|
}
|
|
2439
|
-
__name(
|
|
2582
|
+
__name(extractFields2, "extractFields");
|
|
2440
2583
|
function fieldsToSelectObject(fields) {
|
|
2441
2584
|
return Object.fromEntries(fields.map((f) => [
|
|
2442
2585
|
f,
|
|
@@ -2445,15 +2588,6 @@ function fieldsToSelectObject(fields) {
|
|
|
2445
2588
|
}
|
|
2446
2589
|
__name(fieldsToSelectObject, "fieldsToSelectObject");
|
|
2447
2590
|
|
|
2448
|
-
// src/client/constants.ts
|
|
2449
|
-
var CONTEXT_COMMENT_PREFIX = "-- $$context:";
|
|
2450
|
-
var NUMERIC_FIELD_TYPES = [
|
|
2451
|
-
"Int",
|
|
2452
|
-
"Float",
|
|
2453
|
-
"BigInt",
|
|
2454
|
-
"Decimal"
|
|
2455
|
-
];
|
|
2456
|
-
|
|
2457
2591
|
// src/client/crud/operations/base.ts
|
|
2458
2592
|
var BaseOperationHandler = class {
|
|
2459
2593
|
static {
|
|
@@ -2507,7 +2641,7 @@ var BaseOperationHandler = class {
|
|
|
2507
2641
|
return query.executeTakeFirst();
|
|
2508
2642
|
}
|
|
2509
2643
|
async read(kysely, model, args) {
|
|
2510
|
-
let query =
|
|
2644
|
+
let query = this.dialect.buildSelectModel(expressionBuilder2(), model);
|
|
2511
2645
|
if (args?.where) {
|
|
2512
2646
|
query = query.where((eb) => this.dialect.buildFilter(eb, model, model, args?.where));
|
|
2513
2647
|
}
|
|
@@ -2532,7 +2666,7 @@ var BaseOperationHandler = class {
|
|
|
2532
2666
|
if (args && "select" in args && args.select) {
|
|
2533
2667
|
query = this.buildFieldSelection(model, query, args.select, model);
|
|
2534
2668
|
} else {
|
|
2535
|
-
query = this.
|
|
2669
|
+
query = this.dialect.buildSelectAllFields(model, query, args?.omit);
|
|
2536
2670
|
}
|
|
2537
2671
|
if (args && "include" in args && args.include) {
|
|
2538
2672
|
query = this.buildFieldSelection(model, query, args.include, model);
|
|
@@ -2545,14 +2679,18 @@ var BaseOperationHandler = class {
|
|
|
2545
2679
|
operation: "read"
|
|
2546
2680
|
}));
|
|
2547
2681
|
let result = [];
|
|
2682
|
+
const queryId = {
|
|
2683
|
+
queryId: `zenstack-${createId()}`
|
|
2684
|
+
};
|
|
2685
|
+
const compiled = kysely.getExecutor().compileQuery(query.toOperationNode(), queryId);
|
|
2548
2686
|
try {
|
|
2549
|
-
|
|
2687
|
+
const r = await kysely.getExecutor().executeQuery(compiled, queryId);
|
|
2688
|
+
result = r.rows;
|
|
2550
2689
|
} catch (err) {
|
|
2551
|
-
|
|
2552
|
-
let message = `Failed to execute query: ${err}, sql: ${sql11}`;
|
|
2690
|
+
let message = `Failed to execute query: ${err}, sql: ${compiled.sql}`;
|
|
2553
2691
|
if (this.options.debug) {
|
|
2554
2692
|
message += `, parameters:
|
|
2555
|
-
${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
2693
|
+
${compiled.parameters.map((p) => inspect(p)).join("\n")}`;
|
|
2556
2694
|
}
|
|
2557
2695
|
throw new QueryError(message, err);
|
|
2558
2696
|
}
|
|
@@ -2589,12 +2727,16 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2589
2727
|
}
|
|
2590
2728
|
const fieldDef = this.requireField(model, field);
|
|
2591
2729
|
if (!fieldDef.relation) {
|
|
2592
|
-
result = this.
|
|
2730
|
+
result = this.dialect.buildSelectField(result, model, parentAlias, field);
|
|
2593
2731
|
} else {
|
|
2594
2732
|
if (!fieldDef.array && !fieldDef.optional && payload.where) {
|
|
2595
2733
|
throw new QueryError(`Field "${field}" doesn't support filtering`);
|
|
2596
2734
|
}
|
|
2597
|
-
|
|
2735
|
+
if (fieldDef.originModel) {
|
|
2736
|
+
result = this.dialect.buildRelationSelection(result, fieldDef.originModel, field, fieldDef.originModel, payload);
|
|
2737
|
+
} else {
|
|
2738
|
+
result = this.dialect.buildRelationSelection(result, model, field, parentAlias, payload);
|
|
2739
|
+
}
|
|
2598
2740
|
}
|
|
2599
2741
|
}
|
|
2600
2742
|
return result;
|
|
@@ -2627,18 +2769,6 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2627
2769
|
query = query.select((eb2) => this.dialect.buildJsonObject(eb2, jsonObject).as("_count"));
|
|
2628
2770
|
return query;
|
|
2629
2771
|
}
|
|
2630
|
-
buildSelectAllScalarFields(model, query, omit) {
|
|
2631
|
-
const modelDef = this.requireModel(model);
|
|
2632
|
-
return Object.keys(modelDef.fields).filter((f) => !isRelationField(this.schema, model, f)).filter((f) => omit?.[f] !== true).reduce((acc, f) => this.selectField(acc, model, model, f), query);
|
|
2633
|
-
}
|
|
2634
|
-
selectField(query, model, modelAlias, field) {
|
|
2635
|
-
const fieldDef = this.requireField(model, field);
|
|
2636
|
-
if (!fieldDef.computed) {
|
|
2637
|
-
return query.select(sql4.ref(`${modelAlias}.${field}`).as(field));
|
|
2638
|
-
} else {
|
|
2639
|
-
return query.select((eb) => buildFieldRef(this.schema, model, field, this.options, eb).as(field));
|
|
2640
|
-
}
|
|
2641
|
-
}
|
|
2642
2772
|
buildCursorFilter(model, query, cursor, orderBy, negateOrderBy) {
|
|
2643
2773
|
if (!orderBy) {
|
|
2644
2774
|
orderBy = makeDefaultOrderBy(this.schema, model);
|
|
@@ -2661,9 +2791,12 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2661
2791
|
result = result.where((eb2) => eb2.or(filters));
|
|
2662
2792
|
return result;
|
|
2663
2793
|
}
|
|
2664
|
-
async create(kysely, model, data, fromRelation) {
|
|
2794
|
+
async create(kysely, model, data, fromRelation, creatingForDelegate = false) {
|
|
2665
2795
|
const modelDef = this.requireModel(model);
|
|
2666
|
-
|
|
2796
|
+
if (modelDef.isDelegate && !creatingForDelegate) {
|
|
2797
|
+
throw new QueryError(`Model "${this.model}" is a delegate and cannot be created directly.`);
|
|
2798
|
+
}
|
|
2799
|
+
let createFields = {};
|
|
2667
2800
|
let parentUpdateTask = void 0;
|
|
2668
2801
|
let m2m = void 0;
|
|
2669
2802
|
if (fromRelation) {
|
|
@@ -2711,9 +2844,13 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2711
2844
|
}
|
|
2712
2845
|
}
|
|
2713
2846
|
}
|
|
2847
|
+
if (modelDef.baseModel) {
|
|
2848
|
+
const baseCreateResult = await this.processBaseModelCreate(kysely, modelDef.baseModel, createFields, model);
|
|
2849
|
+
createFields = baseCreateResult.remainingFields;
|
|
2850
|
+
}
|
|
2714
2851
|
const updatedData = this.fillGeneratedValues(modelDef, createFields);
|
|
2715
2852
|
const idFields = getIdFields(this.schema, model);
|
|
2716
|
-
const query = kysely.insertInto(model).values(updatedData).returning(idFields).modifyEnd(this.makeContextComment({
|
|
2853
|
+
const query = kysely.insertInto(model).$if(Object.keys(updatedData).length === 0, (qb) => qb.defaultValues()).$if(Object.keys(updatedData).length > 0, (qb) => qb.values(updatedData)).returning(idFields).modifyEnd(this.makeContextComment({
|
|
2717
2854
|
model,
|
|
2718
2855
|
operation: "create"
|
|
2719
2856
|
}));
|
|
@@ -2732,6 +2869,28 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2732
2869
|
}
|
|
2733
2870
|
return createdEntity;
|
|
2734
2871
|
}
|
|
2872
|
+
async processBaseModelCreate(kysely, model, createFields, forModel) {
|
|
2873
|
+
const thisCreateFields = {};
|
|
2874
|
+
const remainingFields = {};
|
|
2875
|
+
Object.entries(createFields).forEach(([field, value]) => {
|
|
2876
|
+
const fieldDef = this.getField(model, field);
|
|
2877
|
+
if (fieldDef) {
|
|
2878
|
+
thisCreateFields[field] = value;
|
|
2879
|
+
} else {
|
|
2880
|
+
remainingFields[field] = value;
|
|
2881
|
+
}
|
|
2882
|
+
});
|
|
2883
|
+
const discriminatorField = getDiscriminatorField(this.schema, model);
|
|
2884
|
+
invariant7(discriminatorField, `Base model "${model}" must have a discriminator field`);
|
|
2885
|
+
thisCreateFields[discriminatorField] = forModel;
|
|
2886
|
+
const baseEntity = await this.create(kysely, model, thisCreateFields, void 0, true);
|
|
2887
|
+
const idValues = extractIdFields(baseEntity, this.schema, model);
|
|
2888
|
+
Object.assign(remainingFields, idValues);
|
|
2889
|
+
return {
|
|
2890
|
+
baseEntity,
|
|
2891
|
+
remainingFields
|
|
2892
|
+
};
|
|
2893
|
+
}
|
|
2735
2894
|
buildFkAssignments(model, relationField, entity) {
|
|
2736
2895
|
const parentFkFields = {};
|
|
2737
2896
|
invariant7(relationField, "parentField must be defined if parentModel is defined");
|
|
@@ -2806,7 +2965,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2806
2965
|
case "connect": {
|
|
2807
2966
|
const referencedPkFields = relationField.relation.references;
|
|
2808
2967
|
invariant7(referencedPkFields, "relation must have fields info");
|
|
2809
|
-
const extractedFks =
|
|
2968
|
+
const extractedFks = extractFields2(subPayload, referencedPkFields);
|
|
2810
2969
|
if (Object.keys(extractedFks).length === referencedPkFields.length) {
|
|
2811
2970
|
result = extractedFks;
|
|
2812
2971
|
} else {
|
|
@@ -2901,7 +3060,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2901
3060
|
}
|
|
2902
3061
|
relationKeyPairs = keyPairs;
|
|
2903
3062
|
}
|
|
2904
|
-
|
|
3063
|
+
let createData = enumerate(input.data).map((item) => {
|
|
2905
3064
|
const newItem = {};
|
|
2906
3065
|
for (const [name, value] of Object.entries(item)) {
|
|
2907
3066
|
const fieldDef = this.requireField(model, name);
|
|
@@ -2915,6 +3074,13 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2915
3074
|
}
|
|
2916
3075
|
return this.fillGeneratedValues(modelDef, newItem);
|
|
2917
3076
|
});
|
|
3077
|
+
if (modelDef.baseModel) {
|
|
3078
|
+
if (input.skipDuplicates) {
|
|
3079
|
+
throw new QueryError('"skipDuplicates" options is not supported for polymorphic models');
|
|
3080
|
+
}
|
|
3081
|
+
const baseCreateResult = await this.processBaseModelCreateMany(kysely, modelDef.baseModel, createData, !!input.skipDuplicates, model);
|
|
3082
|
+
createData = baseCreateResult.remainingFieldRows;
|
|
3083
|
+
}
|
|
2918
3084
|
const query = kysely.insertInto(model).values(createData).$if(!!input.skipDuplicates, (qb) => qb.onConflict((oc) => oc.doNothing())).modifyEnd(this.makeContextComment({
|
|
2919
3085
|
model,
|
|
2920
3086
|
operation: "create"
|
|
@@ -2930,10 +3096,46 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2930
3096
|
return result;
|
|
2931
3097
|
}
|
|
2932
3098
|
}
|
|
3099
|
+
async processBaseModelCreateMany(kysely, model, createRows, skipDuplicates, forModel) {
|
|
3100
|
+
const thisCreateRows = [];
|
|
3101
|
+
const remainingFieldRows = [];
|
|
3102
|
+
const discriminatorField = getDiscriminatorField(this.schema, model);
|
|
3103
|
+
invariant7(discriminatorField, `Base model "${model}" must have a discriminator field`);
|
|
3104
|
+
for (const createFields of createRows) {
|
|
3105
|
+
const thisCreateFields = {};
|
|
3106
|
+
const remainingFields = {};
|
|
3107
|
+
Object.entries(createFields).forEach(([field, value]) => {
|
|
3108
|
+
const fieldDef = this.getField(model, field);
|
|
3109
|
+
if (fieldDef) {
|
|
3110
|
+
thisCreateFields[field] = value;
|
|
3111
|
+
} else {
|
|
3112
|
+
remainingFields[field] = value;
|
|
3113
|
+
}
|
|
3114
|
+
});
|
|
3115
|
+
thisCreateFields[discriminatorField] = forModel;
|
|
3116
|
+
thisCreateRows.push(thisCreateFields);
|
|
3117
|
+
remainingFieldRows.push(remainingFields);
|
|
3118
|
+
}
|
|
3119
|
+
const baseEntities = await this.createMany(kysely, model, {
|
|
3120
|
+
data: thisCreateRows,
|
|
3121
|
+
skipDuplicates
|
|
3122
|
+
}, true);
|
|
3123
|
+
for (let i = 0; i < baseEntities.length; i++) {
|
|
3124
|
+
const idValues = extractIdFields(baseEntities[i], this.schema, model);
|
|
3125
|
+
Object.assign(remainingFieldRows[i], idValues);
|
|
3126
|
+
}
|
|
3127
|
+
return {
|
|
3128
|
+
baseEntities,
|
|
3129
|
+
remainingFieldRows
|
|
3130
|
+
};
|
|
3131
|
+
}
|
|
2933
3132
|
fillGeneratedValues(modelDef, data) {
|
|
2934
3133
|
const fields = modelDef.fields;
|
|
2935
3134
|
const values = clone(data);
|
|
2936
|
-
for (const field
|
|
3135
|
+
for (const [field, fieldDef] of Object.entries(fields)) {
|
|
3136
|
+
if (fieldDef.originModel) {
|
|
3137
|
+
continue;
|
|
3138
|
+
}
|
|
2937
3139
|
if (!(field in data)) {
|
|
2938
3140
|
if (typeof fields[field]?.default === "object" && "kind" in fields[field].default) {
|
|
2939
3141
|
const generated = this.evalGenerator(fields[field].default);
|
|
@@ -3010,28 +3212,33 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3010
3212
|
}
|
|
3011
3213
|
}
|
|
3012
3214
|
if (Object.keys(finalData).length === 0) {
|
|
3013
|
-
|
|
3014
|
-
|
|
3215
|
+
return combinedWhere;
|
|
3216
|
+
}
|
|
3217
|
+
let needIdRead = false;
|
|
3218
|
+
if (modelDef.baseModel && !this.isIdFilter(model, combinedWhere)) {
|
|
3219
|
+
needIdRead = true;
|
|
3220
|
+
}
|
|
3221
|
+
if (needIdRead) {
|
|
3222
|
+
const readResult = await this.readUnique(kysely, model, {
|
|
3223
|
+
where: combinedWhere,
|
|
3224
|
+
select: this.makeIdSelect(model)
|
|
3015
3225
|
});
|
|
3016
|
-
if (!
|
|
3226
|
+
if (!readResult && throwIfNotFound) {
|
|
3017
3227
|
throw new NotFoundError(model);
|
|
3018
3228
|
}
|
|
3019
|
-
|
|
3229
|
+
combinedWhere = readResult;
|
|
3230
|
+
}
|
|
3231
|
+
if (modelDef.baseModel) {
|
|
3232
|
+
const baseUpdateResult = await this.processBaseModelUpdate(kysely, modelDef.baseModel, combinedWhere, finalData, throwIfNotFound);
|
|
3233
|
+
finalData = baseUpdateResult.remainingFields;
|
|
3234
|
+
combinedWhere = baseUpdateResult.baseEntity;
|
|
3020
3235
|
}
|
|
3021
3236
|
const updateFields = {};
|
|
3022
3237
|
let thisEntity = void 0;
|
|
3023
3238
|
for (const field in finalData) {
|
|
3024
3239
|
const fieldDef = this.requireField(model, field);
|
|
3025
3240
|
if (isScalarField(this.schema, model, field) || isForeignKeyField(this.schema, model, field)) {
|
|
3026
|
-
|
|
3027
|
-
updateFields[field] = this.transformIncrementalUpdate(model, field, fieldDef, finalData[field]);
|
|
3028
|
-
continue;
|
|
3029
|
-
}
|
|
3030
|
-
if (fieldDef.array && typeof finalData[field] === "object" && !Array.isArray(finalData[field]) && finalData[field]) {
|
|
3031
|
-
updateFields[field] = this.transformScalarListUpdate(model, field, fieldDef, finalData[field]);
|
|
3032
|
-
continue;
|
|
3033
|
-
}
|
|
3034
|
-
updateFields[field] = this.dialect.transformPrimitive(finalData[field], fieldDef.type, !!fieldDef.array);
|
|
3241
|
+
updateFields[field] = this.processScalarFieldUpdateData(model, field, finalData);
|
|
3035
3242
|
} else {
|
|
3036
3243
|
if (!allowRelationUpdate) {
|
|
3037
3244
|
throw new QueryError(`Relation update not allowed for field "${field}"`);
|
|
@@ -3053,9 +3260,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3053
3260
|
}
|
|
3054
3261
|
}
|
|
3055
3262
|
if (Object.keys(updateFields).length === 0) {
|
|
3056
|
-
return
|
|
3057
|
-
where: combinedWhere
|
|
3058
|
-
});
|
|
3263
|
+
return combinedWhere;
|
|
3059
3264
|
} else {
|
|
3060
3265
|
const idFields = getIdFields(this.schema, model);
|
|
3061
3266
|
const query = kysely.updateTable(model).where((eb) => this.dialect.buildFilter(eb, model, model, combinedWhere)).set(updateFields).returning(idFields).modifyEnd(this.makeContextComment({
|
|
@@ -3073,6 +3278,55 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3073
3278
|
return updatedEntity;
|
|
3074
3279
|
}
|
|
3075
3280
|
}
|
|
3281
|
+
processScalarFieldUpdateData(model, field, data) {
|
|
3282
|
+
const fieldDef = this.requireField(model, field);
|
|
3283
|
+
if (this.isNumericIncrementalUpdate(fieldDef, data[field])) {
|
|
3284
|
+
return this.transformIncrementalUpdate(model, field, fieldDef, data[field]);
|
|
3285
|
+
}
|
|
3286
|
+
if (fieldDef.array && typeof data[field] === "object" && !Array.isArray(data[field]) && data[field]) {
|
|
3287
|
+
return this.transformScalarListUpdate(model, field, fieldDef, data[field]);
|
|
3288
|
+
}
|
|
3289
|
+
return this.dialect.transformPrimitive(data[field], fieldDef.type, !!fieldDef.array);
|
|
3290
|
+
}
|
|
3291
|
+
isNumericIncrementalUpdate(fieldDef, value) {
|
|
3292
|
+
if (!this.isNumericField(fieldDef)) {
|
|
3293
|
+
return false;
|
|
3294
|
+
}
|
|
3295
|
+
if (typeof value !== "object" || !value) {
|
|
3296
|
+
return false;
|
|
3297
|
+
}
|
|
3298
|
+
return [
|
|
3299
|
+
"increment",
|
|
3300
|
+
"decrement",
|
|
3301
|
+
"multiply",
|
|
3302
|
+
"divide",
|
|
3303
|
+
"set"
|
|
3304
|
+
].some((key) => key in value);
|
|
3305
|
+
}
|
|
3306
|
+
isIdFilter(model, filter) {
|
|
3307
|
+
if (!filter || typeof filter !== "object") {
|
|
3308
|
+
return false;
|
|
3309
|
+
}
|
|
3310
|
+
const idFields = getIdFields(this.schema, model);
|
|
3311
|
+
return idFields.length === Object.keys(filter).length && idFields.every((field) => field in filter);
|
|
3312
|
+
}
|
|
3313
|
+
async processBaseModelUpdate(kysely, model, where, updateFields, throwIfNotFound) {
|
|
3314
|
+
const thisUpdateFields = {};
|
|
3315
|
+
const remainingFields = {};
|
|
3316
|
+
Object.entries(updateFields).forEach(([field, value]) => {
|
|
3317
|
+
const fieldDef = this.getField(model, field);
|
|
3318
|
+
if (fieldDef) {
|
|
3319
|
+
thisUpdateFields[field] = value;
|
|
3320
|
+
} else {
|
|
3321
|
+
remainingFields[field] = value;
|
|
3322
|
+
}
|
|
3323
|
+
});
|
|
3324
|
+
const baseEntity = await this.update(kysely, model, where, thisUpdateFields, void 0, void 0, throwIfNotFound);
|
|
3325
|
+
return {
|
|
3326
|
+
baseEntity,
|
|
3327
|
+
remainingFields
|
|
3328
|
+
};
|
|
3329
|
+
}
|
|
3076
3330
|
transformIncrementalUpdate(model, field, fieldDef, payload) {
|
|
3077
3331
|
invariant7(Object.keys(payload).length === 1, 'Only one of "set", "increment", "decrement", "multiply", or "divide" can be provided');
|
|
3078
3332
|
const key = Object.keys(payload)[0];
|
|
@@ -3101,7 +3355,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3101
3355
|
makeContextComment(context) {
|
|
3102
3356
|
return sql4.raw(`${CONTEXT_COMMENT_PREFIX}${JSON.stringify(context)}`);
|
|
3103
3357
|
}
|
|
3104
|
-
async updateMany(kysely, model, where, data, limit, returnData) {
|
|
3358
|
+
async updateMany(kysely, model, where, data, limit, returnData, filterModel) {
|
|
3105
3359
|
if (typeof data !== "object") {
|
|
3106
3360
|
throw new InternalError("data must be an object");
|
|
3107
3361
|
}
|
|
@@ -3110,25 +3364,43 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3110
3364
|
count: 0
|
|
3111
3365
|
};
|
|
3112
3366
|
}
|
|
3113
|
-
const
|
|
3367
|
+
const modelDef = this.requireModel(model);
|
|
3368
|
+
if (modelDef.baseModel && limit !== void 0) {
|
|
3369
|
+
throw new QueryError("Updating with a limit is not supported for polymorphic models");
|
|
3370
|
+
}
|
|
3371
|
+
filterModel ??= model;
|
|
3372
|
+
let updateFields = {};
|
|
3114
3373
|
for (const field in data) {
|
|
3115
|
-
const fieldDef = this.requireField(model, field);
|
|
3116
3374
|
if (isRelationField(this.schema, model, field)) {
|
|
3117
3375
|
continue;
|
|
3118
3376
|
}
|
|
3119
|
-
updateFields[field] = this.
|
|
3377
|
+
updateFields[field] = this.processScalarFieldUpdateData(model, field, data);
|
|
3378
|
+
}
|
|
3379
|
+
let shouldFallbackToIdFilter = false;
|
|
3380
|
+
if (limit !== void 0 && !this.dialect.supportsUpdateWithLimit) {
|
|
3381
|
+
shouldFallbackToIdFilter = true;
|
|
3382
|
+
}
|
|
3383
|
+
if (modelDef.isDelegate || modelDef.baseModel) {
|
|
3384
|
+
shouldFallbackToIdFilter = true;
|
|
3385
|
+
}
|
|
3386
|
+
let resultFromBaseModel = void 0;
|
|
3387
|
+
if (modelDef.baseModel) {
|
|
3388
|
+
const baseResult = await this.processBaseModelUpdateMany(kysely, modelDef.baseModel, where, updateFields, filterModel);
|
|
3389
|
+
updateFields = baseResult.remainingFields;
|
|
3390
|
+
resultFromBaseModel = baseResult.baseResult;
|
|
3391
|
+
}
|
|
3392
|
+
if (Object.keys(updateFields).length === 0) {
|
|
3393
|
+
return resultFromBaseModel ?? (returnData ? [] : {
|
|
3394
|
+
count: 0
|
|
3395
|
+
});
|
|
3120
3396
|
}
|
|
3121
3397
|
let query = kysely.updateTable(model).set(updateFields);
|
|
3122
|
-
if (
|
|
3123
|
-
query = query.where((eb) => this.dialect.buildFilter(eb, model, model, where));
|
|
3398
|
+
if (!shouldFallbackToIdFilter) {
|
|
3399
|
+
query = query.where((eb) => this.dialect.buildFilter(eb, model, model, where)).$if(limit !== void 0, (qb) => qb.limit(limit));
|
|
3124
3400
|
} else {
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
query = query.where((eb) => eb(eb.refTuple(
|
|
3129
|
-
...this.buildIdFieldRefs(kysely, model)
|
|
3130
|
-
), "in", kysely.selectFrom(model).where((eb2) => this.dialect.buildFilter(eb2, model, model, where)).select(this.buildIdFieldRefs(kysely, model)).limit(limit)));
|
|
3131
|
-
}
|
|
3401
|
+
query = query.where((eb) => eb(eb.refTuple(
|
|
3402
|
+
...this.buildIdFieldRefs(kysely, model)
|
|
3403
|
+
), "in", this.dialect.buildSelectModel(eb, filterModel).where(this.dialect.buildFilter(eb, filterModel, filterModel, where)).select(this.buildIdFieldRefs(kysely, filterModel)).$if(limit !== void 0, (qb) => qb.limit(limit))));
|
|
3132
3404
|
}
|
|
3133
3405
|
query = query.modifyEnd(this.makeContextComment({
|
|
3134
3406
|
model,
|
|
@@ -3145,9 +3417,26 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3145
3417
|
return result;
|
|
3146
3418
|
}
|
|
3147
3419
|
}
|
|
3420
|
+
async processBaseModelUpdateMany(kysely, model, where, updateFields, filterModel) {
|
|
3421
|
+
const thisUpdateFields = {};
|
|
3422
|
+
const remainingFields = {};
|
|
3423
|
+
Object.entries(updateFields).forEach(([field, value]) => {
|
|
3424
|
+
const fieldDef = this.getField(model, field);
|
|
3425
|
+
if (fieldDef) {
|
|
3426
|
+
thisUpdateFields[field] = value;
|
|
3427
|
+
} else {
|
|
3428
|
+
remainingFields[field] = value;
|
|
3429
|
+
}
|
|
3430
|
+
});
|
|
3431
|
+
const baseResult = await this.updateMany(kysely, model, where, thisUpdateFields, void 0, false, filterModel);
|
|
3432
|
+
return {
|
|
3433
|
+
baseResult,
|
|
3434
|
+
remainingFields
|
|
3435
|
+
};
|
|
3436
|
+
}
|
|
3148
3437
|
buildIdFieldRefs(kysely, model) {
|
|
3149
3438
|
const idFields = getIdFields(this.schema, model);
|
|
3150
|
-
return idFields.map((f) => kysely.dynamic.ref(f));
|
|
3439
|
+
return idFields.map((f) => kysely.dynamic.ref(`${model}.${f}`));
|
|
3151
3440
|
}
|
|
3152
3441
|
async processRelationUpdates(kysely, model, field, fieldDef, parentIds, args, throwIfNotFound) {
|
|
3153
3442
|
const tasks = [];
|
|
@@ -3461,7 +3750,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3461
3750
|
OR: deleteConditions
|
|
3462
3751
|
}
|
|
3463
3752
|
]
|
|
3464
|
-
}
|
|
3753
|
+
});
|
|
3465
3754
|
} else {
|
|
3466
3755
|
const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, fromRelation.model, fromRelation.field);
|
|
3467
3756
|
if (ownedByModel) {
|
|
@@ -3484,7 +3773,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3484
3773
|
OR: deleteConditions
|
|
3485
3774
|
}
|
|
3486
3775
|
]
|
|
3487
|
-
}
|
|
3776
|
+
});
|
|
3488
3777
|
} else {
|
|
3489
3778
|
deleteResult = await this.delete(kysely, model, {
|
|
3490
3779
|
AND: [
|
|
@@ -3496,7 +3785,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3496
3785
|
OR: deleteConditions
|
|
3497
3786
|
}
|
|
3498
3787
|
]
|
|
3499
|
-
}
|
|
3788
|
+
});
|
|
3500
3789
|
}
|
|
3501
3790
|
}
|
|
3502
3791
|
if (throwForNotFound && expectedDeleteCount > deleteResult.count) {
|
|
@@ -3507,33 +3796,59 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3507
3796
|
return enumerate(data).map((item) => flattenCompoundUniqueFilters(this.schema, model, item));
|
|
3508
3797
|
}
|
|
3509
3798
|
// #endregion
|
|
3510
|
-
async delete(kysely, model, where, limit,
|
|
3799
|
+
async delete(kysely, model, where, limit, filterModel) {
|
|
3800
|
+
filterModel ??= model;
|
|
3801
|
+
const modelDef = this.requireModel(model);
|
|
3802
|
+
if (modelDef.baseModel) {
|
|
3803
|
+
if (limit !== void 0) {
|
|
3804
|
+
throw new QueryError("Deleting with a limit is not supported for polymorphic models");
|
|
3805
|
+
}
|
|
3806
|
+
return this.processBaseModelDelete(kysely, modelDef.baseModel, where, limit, filterModel);
|
|
3807
|
+
}
|
|
3511
3808
|
let query = kysely.deleteFrom(model);
|
|
3512
|
-
|
|
3809
|
+
let needIdFilter = false;
|
|
3810
|
+
if (limit !== void 0 && !this.dialect.supportsDeleteWithLimit) {
|
|
3811
|
+
needIdFilter = true;
|
|
3812
|
+
}
|
|
3813
|
+
if (modelDef.isDelegate || modelDef.baseModel) {
|
|
3814
|
+
needIdFilter = true;
|
|
3815
|
+
}
|
|
3816
|
+
if (!needIdFilter) {
|
|
3513
3817
|
query = query.where((eb) => this.dialect.buildFilter(eb, model, model, where));
|
|
3514
3818
|
} else {
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
query = query.where((eb) => eb(eb.refTuple(
|
|
3519
|
-
...this.buildIdFieldRefs(kysely, model)
|
|
3520
|
-
), "in", kysely.selectFrom(model).where((eb2) => this.dialect.buildFilter(eb2, model, model, where)).select(this.buildIdFieldRefs(kysely, model)).limit(limit)));
|
|
3521
|
-
}
|
|
3819
|
+
query = query.where((eb) => eb(eb.refTuple(
|
|
3820
|
+
...this.buildIdFieldRefs(kysely, model)
|
|
3821
|
+
), "in", this.dialect.buildSelectModel(eb, filterModel).where((eb2) => this.dialect.buildFilter(eb2, filterModel, filterModel, where)).select(this.buildIdFieldRefs(kysely, filterModel)).$if(limit !== void 0, (qb) => qb.limit(limit))));
|
|
3522
3822
|
}
|
|
3823
|
+
await this.processDelegateRelationDelete(kysely, modelDef, where, limit);
|
|
3523
3824
|
query = query.modifyEnd(this.makeContextComment({
|
|
3524
3825
|
model,
|
|
3525
3826
|
operation: "delete"
|
|
3526
3827
|
}));
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
}
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3828
|
+
const result = await query.executeTakeFirstOrThrow();
|
|
3829
|
+
return {
|
|
3830
|
+
count: Number(result.numDeletedRows)
|
|
3831
|
+
};
|
|
3832
|
+
}
|
|
3833
|
+
async processDelegateRelationDelete(kysely, modelDef, where, limit) {
|
|
3834
|
+
for (const fieldDef of Object.values(modelDef.fields)) {
|
|
3835
|
+
if (fieldDef.relation && fieldDef.relation.opposite) {
|
|
3836
|
+
const oppositeModelDef = this.requireModel(fieldDef.type);
|
|
3837
|
+
const oppositeRelation = this.requireField(fieldDef.type, fieldDef.relation.opposite);
|
|
3838
|
+
if (oppositeModelDef.baseModel && oppositeRelation.relation?.onDelete === "Cascade") {
|
|
3839
|
+
if (limit !== void 0) {
|
|
3840
|
+
throw new QueryError("Deleting with a limit is not supported for polymorphic models");
|
|
3841
|
+
}
|
|
3842
|
+
await this.delete(kysely, fieldDef.type, {
|
|
3843
|
+
[fieldDef.relation.opposite]: where
|
|
3844
|
+
}, void 0);
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3535
3847
|
}
|
|
3536
3848
|
}
|
|
3849
|
+
async processBaseModelDelete(kysely, model, where, limit, filterModel) {
|
|
3850
|
+
return this.delete(kysely, model, where, limit, filterModel);
|
|
3851
|
+
}
|
|
3537
3852
|
makeIdSelect(model) {
|
|
3538
3853
|
const modelDef = this.requireModel(model);
|
|
3539
3854
|
return modelDef.idFields.reduce((acc, f) => {
|
|
@@ -3567,9 +3882,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3567
3882
|
return callback(this.kysely);
|
|
3568
3883
|
} else {
|
|
3569
3884
|
let txBuilder = this.kysely.transaction();
|
|
3570
|
-
|
|
3571
|
-
txBuilder = txBuilder.setIsolationLevel(isolationLevel);
|
|
3572
|
-
}
|
|
3885
|
+
txBuilder = txBuilder.setIsolationLevel(isolationLevel ?? "repeatable read");
|
|
3573
3886
|
return txBuilder.execute(callback);
|
|
3574
3887
|
}
|
|
3575
3888
|
}
|
|
@@ -3622,7 +3935,22 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
|
|
|
3622
3935
|
const normalizedArgs = this.normalizeArgs(args);
|
|
3623
3936
|
const parsedArgs = this.inputValidator.validateAggregateArgs(this.model, normalizedArgs);
|
|
3624
3937
|
let query = this.kysely.selectFrom((eb) => {
|
|
3625
|
-
let subQuery =
|
|
3938
|
+
let subQuery = this.dialect.buildSelectModel(eb, this.model).where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
|
|
3939
|
+
const selectedFields = [];
|
|
3940
|
+
for (const [key, value] of Object.entries(parsedArgs)) {
|
|
3941
|
+
if (key.startsWith("_") && value && typeof value === "object") {
|
|
3942
|
+
Object.entries(value).filter(([field]) => field !== "_all").filter(([, val]) => val === true).forEach(([field]) => {
|
|
3943
|
+
if (!selectedFields.includes(field)) selectedFields.push(field);
|
|
3944
|
+
});
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
if (selectedFields.length > 0) {
|
|
3948
|
+
for (const field of selectedFields) {
|
|
3949
|
+
subQuery = this.dialect.buildSelectField(subQuery, this.model, this.model, field);
|
|
3950
|
+
}
|
|
3951
|
+
} else {
|
|
3952
|
+
subQuery = subQuery.select(() => eb.lit(1).as("_all"));
|
|
3953
|
+
}
|
|
3626
3954
|
const skip = parsedArgs?.skip;
|
|
3627
3955
|
let take = parsedArgs?.take;
|
|
3628
3956
|
let negateOrderBy = false;
|
|
@@ -3715,13 +4043,23 @@ var CountOperationHandler = class extends BaseOperationHandler {
|
|
|
3715
4043
|
async handle(_operation, args) {
|
|
3716
4044
|
const normalizedArgs = this.normalizeArgs(args);
|
|
3717
4045
|
const parsedArgs = this.inputValidator.validateCountArgs(this.model, normalizedArgs);
|
|
4046
|
+
const subQueryName = "$sub";
|
|
3718
4047
|
let query = this.kysely.selectFrom((eb) => {
|
|
3719
|
-
let subQuery =
|
|
4048
|
+
let subQuery = this.dialect.buildSelectModel(eb, this.model).where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
|
|
4049
|
+
if (parsedArgs?.select && typeof parsedArgs.select === "object") {
|
|
4050
|
+
for (const [key, value] of Object.entries(parsedArgs.select)) {
|
|
4051
|
+
if (key !== "_all" && value === true) {
|
|
4052
|
+
subQuery = this.dialect.buildSelectField(subQuery, this.model, this.model, key);
|
|
4053
|
+
}
|
|
4054
|
+
}
|
|
4055
|
+
} else {
|
|
4056
|
+
subQuery = subQuery.select(() => eb.lit(1).as("_all"));
|
|
4057
|
+
}
|
|
3720
4058
|
subQuery = this.dialect.buildSkipTake(subQuery, parsedArgs?.skip, parsedArgs?.take);
|
|
3721
|
-
return subQuery.as(
|
|
4059
|
+
return subQuery.as(subQueryName);
|
|
3722
4060
|
});
|
|
3723
4061
|
if (parsedArgs?.select && typeof parsedArgs.select === "object") {
|
|
3724
|
-
query = query.select((eb) => Object.keys(parsedArgs.select).map((key) => key === "_all" ? eb.cast(eb.fn.countAll(), "integer").as("_all") : eb.cast(eb.fn.count(sql6.ref(`$
|
|
4062
|
+
query = query.select((eb) => Object.keys(parsedArgs.select).map((key) => key === "_all" ? eb.cast(eb.fn.countAll(), "integer").as("_all") : eb.cast(eb.fn.count(sql6.ref(`${subQueryName}.${key}`)), "integer").as(key)));
|
|
3725
4063
|
return query.executeTakeFirstOrThrow();
|
|
3726
4064
|
} else {
|
|
3727
4065
|
query = query.select((eb) => eb.cast(eb.fn.countAll(), "integer").as("count"));
|
|
@@ -3805,15 +4143,19 @@ var DeleteOperationHandler = class extends BaseOperationHandler {
|
|
|
3805
4143
|
if (!existing) {
|
|
3806
4144
|
throw new NotFoundError(this.model);
|
|
3807
4145
|
}
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
4146
|
+
await this.safeTransaction(async (tx) => {
|
|
4147
|
+
const result = await this.delete(tx, this.model, args.where, void 0);
|
|
4148
|
+
if (result.count === 0) {
|
|
4149
|
+
throw new NotFoundError(this.model);
|
|
4150
|
+
}
|
|
4151
|
+
});
|
|
3812
4152
|
return existing;
|
|
3813
4153
|
}
|
|
3814
4154
|
async runDeleteMany(args) {
|
|
3815
|
-
|
|
3816
|
-
|
|
4155
|
+
return await this.safeTransaction(async (tx) => {
|
|
4156
|
+
const result = await this.delete(tx, this.model, args?.where, args?.limit);
|
|
4157
|
+
return result;
|
|
4158
|
+
});
|
|
3817
4159
|
}
|
|
3818
4160
|
};
|
|
3819
4161
|
|
|
@@ -3954,22 +4296,35 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
|
|
|
3954
4296
|
return match13(operation).with("update", () => this.runUpdate(this.inputValidator.validateUpdateArgs(this.model, normalizedArgs))).with("updateMany", () => this.runUpdateMany(this.inputValidator.validateUpdateManyArgs(this.model, normalizedArgs))).with("updateManyAndReturn", () => this.runUpdateManyAndReturn(this.inputValidator.validateUpdateManyAndReturnArgs(this.model, normalizedArgs))).with("upsert", () => this.runUpsert(this.inputValidator.validateUpsertArgs(this.model, normalizedArgs))).exhaustive();
|
|
3955
4297
|
}
|
|
3956
4298
|
async runUpdate(args) {
|
|
3957
|
-
const
|
|
3958
|
-
const
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
4299
|
+
const readBackResult = await this.safeTransaction(async (tx) => {
|
|
4300
|
+
const updateResult = await this.update(tx, this.model, args.where, args.data);
|
|
4301
|
+
const readFilter = updateResult ?? args.where;
|
|
4302
|
+
let readBackResult2 = void 0;
|
|
4303
|
+
try {
|
|
4304
|
+
readBackResult2 = await this.readUnique(tx, this.model, {
|
|
4305
|
+
select: args.select,
|
|
4306
|
+
include: args.include,
|
|
4307
|
+
omit: args.omit,
|
|
4308
|
+
where: readFilter
|
|
4309
|
+
});
|
|
4310
|
+
} catch {
|
|
4311
|
+
}
|
|
4312
|
+
return readBackResult2;
|
|
3965
4313
|
});
|
|
3966
|
-
if (!
|
|
3967
|
-
|
|
4314
|
+
if (!readBackResult) {
|
|
4315
|
+
if (this.hasPolicyEnabled) {
|
|
4316
|
+
throw new RejectedByPolicyError(this.model, "result is not allowed to be read back");
|
|
4317
|
+
} else {
|
|
4318
|
+
return null;
|
|
4319
|
+
}
|
|
4320
|
+
} else {
|
|
4321
|
+
return readBackResult;
|
|
3968
4322
|
}
|
|
3969
|
-
return result;
|
|
3970
4323
|
}
|
|
3971
4324
|
async runUpdateMany(args) {
|
|
3972
|
-
return this.
|
|
4325
|
+
return this.safeTransaction(async (tx) => {
|
|
4326
|
+
return this.updateMany(tx, this.model, args.where, args.data, args.limit, false);
|
|
4327
|
+
});
|
|
3973
4328
|
}
|
|
3974
4329
|
async runUpdateManyAndReturn(args) {
|
|
3975
4330
|
if (!args) {
|
|
@@ -4108,17 +4463,45 @@ var InputValidator = class {
|
|
|
4108
4463
|
return result;
|
|
4109
4464
|
}
|
|
4110
4465
|
makePrimitiveSchema(type) {
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
z.
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4466
|
+
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
4467
|
+
return this.makeTypeDefSchema(type);
|
|
4468
|
+
} else {
|
|
4469
|
+
return match14(type).with("String", () => z.string()).with("Int", () => z.number()).with("Float", () => z.number()).with("Boolean", () => z.boolean()).with("BigInt", () => z.union([
|
|
4470
|
+
z.number(),
|
|
4471
|
+
z.bigint()
|
|
4472
|
+
])).with("Decimal", () => z.union([
|
|
4473
|
+
z.number(),
|
|
4474
|
+
z.instanceof(Decimal),
|
|
4475
|
+
z.string()
|
|
4476
|
+
])).with("DateTime", () => z.union([
|
|
4477
|
+
z.date(),
|
|
4478
|
+
z.string().datetime()
|
|
4479
|
+
])).with("Bytes", () => z.instanceof(Uint8Array)).otherwise(() => z.unknown());
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
makeTypeDefSchema(type) {
|
|
4483
|
+
const key = `$typedef-${type}`;
|
|
4484
|
+
let schema = this.schemaCache.get(key);
|
|
4485
|
+
if (schema) {
|
|
4486
|
+
return schema;
|
|
4487
|
+
}
|
|
4488
|
+
const typeDef = this.schema.typeDefs?.[type];
|
|
4489
|
+
invariant8(typeDef, `Type definition "${type}" not found in schema`);
|
|
4490
|
+
schema = z.looseObject(Object.fromEntries(Object.entries(typeDef.fields).map(([field, def]) => {
|
|
4491
|
+
let fieldSchema = this.makePrimitiveSchema(def.type);
|
|
4492
|
+
if (def.array) {
|
|
4493
|
+
fieldSchema = fieldSchema.array();
|
|
4494
|
+
}
|
|
4495
|
+
if (def.optional) {
|
|
4496
|
+
fieldSchema = fieldSchema.optional();
|
|
4497
|
+
}
|
|
4498
|
+
return [
|
|
4499
|
+
field,
|
|
4500
|
+
fieldSchema
|
|
4501
|
+
];
|
|
4502
|
+
})));
|
|
4503
|
+
this.schemaCache.set(key, schema);
|
|
4504
|
+
return schema;
|
|
4122
4505
|
}
|
|
4123
4506
|
makeWhereSchema(model, unique, withoutRelationFields = false) {
|
|
4124
4507
|
const modelDef = getModel(this.schema, model);
|
|
@@ -4240,8 +4623,14 @@ var InputValidator = class {
|
|
|
4240
4623
|
});
|
|
4241
4624
|
}
|
|
4242
4625
|
makePrimitiveFilterSchema(type, optional) {
|
|
4626
|
+
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
4627
|
+
return this.makeTypeDefFilterSchema(type, optional);
|
|
4628
|
+
}
|
|
4243
4629
|
return match14(type).with("String", () => this.makeStringFilterSchema(optional)).with(P2.union("Int", "Float", "Decimal", "BigInt"), (type2) => this.makeNumberFilterSchema(this.makePrimitiveSchema(type2), optional)).with("Boolean", () => this.makeBooleanFilterSchema(optional)).with("DateTime", () => this.makeDateTimeFilterSchema(optional)).with("Bytes", () => this.makeBytesFilterSchema(optional)).with("Json", () => z.any()).with("Unsupported", () => z.never()).exhaustive();
|
|
4244
4630
|
}
|
|
4631
|
+
makeTypeDefFilterSchema(_type, _optional) {
|
|
4632
|
+
return z.never();
|
|
4633
|
+
}
|
|
4245
4634
|
makeDateTimeFilterSchema(optional) {
|
|
4246
4635
|
return this.makeCommonPrimitiveFilterSchema(z.union([
|
|
4247
4636
|
z.string().datetime(),
|
|
@@ -4446,6 +4835,9 @@ var InputValidator = class {
|
|
|
4446
4835
|
if (fieldDef.computed) {
|
|
4447
4836
|
return;
|
|
4448
4837
|
}
|
|
4838
|
+
if (this.isDelegateDiscriminator(fieldDef)) {
|
|
4839
|
+
return;
|
|
4840
|
+
}
|
|
4449
4841
|
if (fieldDef.relation) {
|
|
4450
4842
|
if (withoutRelationFields) {
|
|
4451
4843
|
return;
|
|
@@ -4518,6 +4910,13 @@ var InputValidator = class {
|
|
|
4518
4910
|
]);
|
|
4519
4911
|
}
|
|
4520
4912
|
}
|
|
4913
|
+
isDelegateDiscriminator(fieldDef) {
|
|
4914
|
+
if (!fieldDef.originModel) {
|
|
4915
|
+
return false;
|
|
4916
|
+
}
|
|
4917
|
+
const discriminatorField = getDiscriminatorField(this.schema, fieldDef.originModel);
|
|
4918
|
+
return discriminatorField === fieldDef.name;
|
|
4919
|
+
}
|
|
4521
4920
|
makeRelationManipulationSchema(fieldDef, withoutFields, mode) {
|
|
4522
4921
|
const fieldType = fieldDef.type;
|
|
4523
4922
|
const array = !!fieldDef.array;
|
|
@@ -5201,7 +5600,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
5201
5600
|
this.requireCurrentModel(contextNode);
|
|
5202
5601
|
model = model ?? this.currentModel;
|
|
5203
5602
|
const modelDef = requireModel(this.schema, model);
|
|
5204
|
-
const scalarFields = Object.entries(modelDef.fields).filter(([, fieldDef]) => !fieldDef.relation && !fieldDef.computed).map(([fieldName]) => fieldName);
|
|
5603
|
+
const scalarFields = Object.entries(modelDef.fields).filter(([, fieldDef]) => !fieldDef.relation && !fieldDef.computed && !fieldDef.originModel).map(([fieldName]) => fieldName);
|
|
5205
5604
|
return scalarFields;
|
|
5206
5605
|
}
|
|
5207
5606
|
};
|
|
@@ -5618,7 +6017,7 @@ var SchemaDbPusher = class {
|
|
|
5618
6017
|
}
|
|
5619
6018
|
}
|
|
5620
6019
|
table = this.addPrimaryKeyConstraint(table, model, modelDef);
|
|
5621
|
-
table = this.addUniqueConstraint(table, modelDef);
|
|
6020
|
+
table = this.addUniqueConstraint(table, model, modelDef);
|
|
5622
6021
|
return table;
|
|
5623
6022
|
}
|
|
5624
6023
|
isComputedField(fieldDef) {
|
|
@@ -5635,7 +6034,7 @@ var SchemaDbPusher = class {
|
|
|
5635
6034
|
}
|
|
5636
6035
|
return table;
|
|
5637
6036
|
}
|
|
5638
|
-
addUniqueConstraint(table, modelDef) {
|
|
6037
|
+
addUniqueConstraint(table, model, modelDef) {
|
|
5639
6038
|
for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
|
|
5640
6039
|
invariant10(typeof value === "object", "expecting an object");
|
|
5641
6040
|
if ("type" in value) {
|
|
@@ -5643,8 +6042,11 @@ var SchemaDbPusher = class {
|
|
|
5643
6042
|
if (fieldDef.unique) {
|
|
5644
6043
|
continue;
|
|
5645
6044
|
}
|
|
6045
|
+
table = table.addUniqueConstraint(`unique_${model}_${key}`, [
|
|
6046
|
+
key
|
|
6047
|
+
]);
|
|
5646
6048
|
} else {
|
|
5647
|
-
table = table.addUniqueConstraint(`unique_${key}`, Object.keys(value));
|
|
6049
|
+
table = table.addUniqueConstraint(`unique_${model}_${key}`, Object.keys(value));
|
|
5648
6050
|
}
|
|
5649
6051
|
}
|
|
5650
6052
|
return table;
|
|
@@ -5787,6 +6189,21 @@ var ResultProcessor = class {
|
|
|
5787
6189
|
data[key] = typeof value === "string" ? JSON.parse(value) : value;
|
|
5788
6190
|
continue;
|
|
5789
6191
|
}
|
|
6192
|
+
if (key.startsWith(DELEGATE_JOINED_FIELD_PREFIX)) {
|
|
6193
|
+
if (value) {
|
|
6194
|
+
const subRow = this.transformJson(value);
|
|
6195
|
+
const subModel = key.slice(DELEGATE_JOINED_FIELD_PREFIX.length);
|
|
6196
|
+
const idValues = getIdValues(this.schema, subModel, subRow);
|
|
6197
|
+
if (Object.values(idValues).some((v) => v === null || v === void 0)) {
|
|
6198
|
+
delete data[key];
|
|
6199
|
+
continue;
|
|
6200
|
+
}
|
|
6201
|
+
const processedSubRow = this.processRow(subRow, subModel);
|
|
6202
|
+
Object.assign(data, processedSubRow);
|
|
6203
|
+
}
|
|
6204
|
+
delete data[key];
|
|
6205
|
+
continue;
|
|
6206
|
+
}
|
|
5790
6207
|
const fieldDef = getField(this.schema, model, key);
|
|
5791
6208
|
if (!fieldDef) {
|
|
5792
6209
|
continue;
|
|
@@ -5826,7 +6243,11 @@ var ResultProcessor = class {
|
|
|
5826
6243
|
return this.doProcessResult(relationData, fieldDef.type);
|
|
5827
6244
|
}
|
|
5828
6245
|
transformScalar(value, type) {
|
|
5829
|
-
|
|
6246
|
+
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
6247
|
+
return this.transformJson(value);
|
|
6248
|
+
} else {
|
|
6249
|
+
return match18(type).with("Boolean", () => this.transformBoolean(value)).with("DateTime", () => this.transformDate(value)).with("Bytes", () => this.transformBytes(value)).with("Decimal", () => this.transformDecimal(value)).with("BigInt", () => this.transformBigInt(value)).with("Json", () => this.transformJson(value)).otherwise(() => value);
|
|
6250
|
+
}
|
|
5830
6251
|
}
|
|
5831
6252
|
transformDecimal(value) {
|
|
5832
6253
|
if (value instanceof Decimal2) {
|