@zenstackhq/runtime 3.0.0-alpha.12 → 3.0.0-alpha.14
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-BEAyf7Es.d.cts → contract-BYc34jr_.d.cts} +78 -54
- package/dist/{contract-BEAyf7Es.d.ts → contract-BYc34jr_.d.ts} +78 -54
- package/dist/index.cjs +821 -311
- 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 +821 -311
- 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 {
|
|
@@ -2497,17 +2631,17 @@ var BaseOperationHandler = class {
|
|
|
2497
2631
|
getField(model, field) {
|
|
2498
2632
|
return getField(this.schema, model, field);
|
|
2499
2633
|
}
|
|
2500
|
-
exists(kysely, model, filter) {
|
|
2634
|
+
async exists(kysely, model, filter) {
|
|
2501
2635
|
const idFields = getIdFields(this.schema, model);
|
|
2502
2636
|
const _filter = flattenCompoundUniqueFilters(this.schema, model, filter);
|
|
2503
2637
|
const query = kysely.selectFrom(model).where((eb) => eb.and(_filter)).select(idFields.map((f) => kysely.dynamic.ref(f))).limit(1).modifyEnd(this.makeContextComment({
|
|
2504
2638
|
model,
|
|
2505
2639
|
operation: "read"
|
|
2506
2640
|
}));
|
|
2507
|
-
return
|
|
2641
|
+
return this.executeQueryTakeFirst(kysely, query, "exists");
|
|
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) {
|
|
@@ -2682,7 +2815,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
2682
2815
|
model: fromRelation.model,
|
|
2683
2816
|
operation: "update"
|
|
2684
2817
|
}));
|
|
2685
|
-
return
|
|
2818
|
+
return this.executeQuery(kysely, query2, "update");
|
|
2686
2819
|
}, "parentUpdateTask");
|
|
2687
2820
|
}
|
|
2688
2821
|
}
|
|
@@ -2711,13 +2844,17 @@ ${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
|
}));
|
|
2720
|
-
const createdEntity = await
|
|
2857
|
+
const createdEntity = await this.executeQueryTakeFirst(kysely, query, "create");
|
|
2721
2858
|
if (Object.keys(postCreateRelations).length > 0) {
|
|
2722
2859
|
const relationPromises = Object.entries(postCreateRelations).map(([field, subPayload]) => {
|
|
2723
2860
|
return this.processNoneOwnedRelationForCreate(kysely, model, field, subPayload, createdEntity);
|
|
@@ -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,14 +3074,21 @@ ${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"
|
|
2921
3087
|
}));
|
|
2922
3088
|
if (!returnData) {
|
|
2923
|
-
const result = await
|
|
3089
|
+
const result = await this.executeQuery(kysely, query, "createMany");
|
|
2924
3090
|
return {
|
|
2925
|
-
count: Number(result.
|
|
3091
|
+
count: Number(result.numAffectedRows)
|
|
2926
3092
|
};
|
|
2927
3093
|
} else {
|
|
2928
3094
|
const idFields = getIdFields(this.schema, model);
|
|
@@ -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,16 +3260,14 @@ ${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({
|
|
3062
3267
|
model,
|
|
3063
3268
|
operation: "update"
|
|
3064
3269
|
}));
|
|
3065
|
-
const updatedEntity = await
|
|
3270
|
+
const updatedEntity = await this.executeQueryTakeFirst(kysely, query, "update");
|
|
3066
3271
|
if (!updatedEntity) {
|
|
3067
3272
|
if (throwIfNotFound) {
|
|
3068
3273
|
throw new NotFoundError(model);
|
|
@@ -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,34 +3364,52 @@ ${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,
|
|
3135
3407
|
operation: "update"
|
|
3136
3408
|
}));
|
|
3137
3409
|
if (!returnData) {
|
|
3138
|
-
const result = await
|
|
3410
|
+
const result = await this.executeQuery(kysely, query, "update");
|
|
3139
3411
|
return {
|
|
3140
|
-
count: Number(result.
|
|
3412
|
+
count: Number(result.numAffectedRows)
|
|
3141
3413
|
};
|
|
3142
3414
|
} else {
|
|
3143
3415
|
const idFields = getIdFields(this.schema, 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 = [];
|
|
@@ -3265,7 +3554,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3265
3554
|
model: fromRelation.model,
|
|
3266
3555
|
operation: "update"
|
|
3267
3556
|
}));
|
|
3268
|
-
updateResult = await
|
|
3557
|
+
updateResult = await this.executeQuery(kysely, query, "connect");
|
|
3269
3558
|
} else {
|
|
3270
3559
|
const relationFieldDef = this.requireField(fromRelation.model, fromRelation.field);
|
|
3271
3560
|
if (!relationFieldDef.array) {
|
|
@@ -3276,7 +3565,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3276
3565
|
model: fromRelation.model,
|
|
3277
3566
|
operation: "update"
|
|
3278
3567
|
}));
|
|
3279
|
-
await
|
|
3568
|
+
await this.executeQuery(kysely, query2, "disconnect");
|
|
3280
3569
|
}
|
|
3281
3570
|
const query = kysely.updateTable(model).where((eb) => eb.or(_data.map((d) => eb.and(d)))).set(keyPairs.reduce((acc, { fk, pk }) => ({
|
|
3282
3571
|
...acc,
|
|
@@ -3285,9 +3574,9 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3285
3574
|
model,
|
|
3286
3575
|
operation: "update"
|
|
3287
3576
|
}));
|
|
3288
|
-
updateResult = await
|
|
3577
|
+
updateResult = await this.executeQuery(kysely, query, "connect");
|
|
3289
3578
|
}
|
|
3290
|
-
if (_data.length > updateResult.
|
|
3579
|
+
if (_data.length > updateResult.numAffectedRows) {
|
|
3291
3580
|
throw new NotFoundError(model);
|
|
3292
3581
|
}
|
|
3293
3582
|
}
|
|
@@ -3355,7 +3644,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3355
3644
|
model: fromRelation.model,
|
|
3356
3645
|
operation: "update"
|
|
3357
3646
|
}));
|
|
3358
|
-
await
|
|
3647
|
+
await this.executeQuery(kysely, query, "disconnect");
|
|
3359
3648
|
} else {
|
|
3360
3649
|
const query = kysely.updateTable(model).where(eb.and([
|
|
3361
3650
|
// fk filter
|
|
@@ -3372,7 +3661,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3372
3661
|
model,
|
|
3373
3662
|
operation: "update"
|
|
3374
3663
|
}));
|
|
3375
|
-
await
|
|
3664
|
+
await this.executeQuery(kysely, query, "disconnect");
|
|
3376
3665
|
}
|
|
3377
3666
|
}
|
|
3378
3667
|
}
|
|
@@ -3410,7 +3699,7 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3410
3699
|
model,
|
|
3411
3700
|
operation: "update"
|
|
3412
3701
|
}));
|
|
3413
|
-
await
|
|
3702
|
+
await this.executeQuery(kysely, query, "disconnect");
|
|
3414
3703
|
if (_data.length > 0) {
|
|
3415
3704
|
const query2 = kysely.updateTable(model).where((eb) => eb.or(_data.map((d) => eb.and(d)))).set(keyPairs.reduce((acc, { fk, pk }) => ({
|
|
3416
3705
|
...acc,
|
|
@@ -3419,8 +3708,8 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3419
3708
|
model,
|
|
3420
3709
|
operation: "update"
|
|
3421
3710
|
}));
|
|
3422
|
-
const r = await
|
|
3423
|
-
if (_data.length > r.
|
|
3711
|
+
const r = await this.executeQuery(kysely, query2, "connect");
|
|
3712
|
+
if (_data.length > r.numAffectedRows) {
|
|
3424
3713
|
throw new NotFoundError(model);
|
|
3425
3714
|
}
|
|
3426
3715
|
}
|
|
@@ -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 this.executeQuery(kysely, query, "delete");
|
|
3829
|
+
return {
|
|
3830
|
+
count: Number(result.numAffectedRows)
|
|
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
|
}
|
|
@@ -3611,6 +3924,25 @@ ${parameters.map((p) => inspect(p)).join("\n")}`;
|
|
|
3611
3924
|
}
|
|
3612
3925
|
}
|
|
3613
3926
|
}
|
|
3927
|
+
makeQueryId(operation) {
|
|
3928
|
+
return {
|
|
3929
|
+
queryId: `${operation}-${createId()}`
|
|
3930
|
+
};
|
|
3931
|
+
}
|
|
3932
|
+
executeQuery(kysely, query, operation) {
|
|
3933
|
+
return kysely.executeQuery(query.compile(), this.makeQueryId(operation));
|
|
3934
|
+
}
|
|
3935
|
+
async executeQueryTakeFirst(kysely, query, operation) {
|
|
3936
|
+
const result = await kysely.executeQuery(query.compile(), this.makeQueryId(operation));
|
|
3937
|
+
return result.rows[0];
|
|
3938
|
+
}
|
|
3939
|
+
async executeQueryTakeFirstOrThrow(kysely, query, operation) {
|
|
3940
|
+
const result = await kysely.executeQuery(query.compile(), this.makeQueryId(operation));
|
|
3941
|
+
if (result.rows.length === 0) {
|
|
3942
|
+
throw new QueryError("No rows found");
|
|
3943
|
+
}
|
|
3944
|
+
return result.rows[0];
|
|
3945
|
+
}
|
|
3614
3946
|
};
|
|
3615
3947
|
|
|
3616
3948
|
// src/client/crud/operations/aggregate.ts
|
|
@@ -3622,7 +3954,22 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
|
|
|
3622
3954
|
const normalizedArgs = this.normalizeArgs(args);
|
|
3623
3955
|
const parsedArgs = this.inputValidator.validateAggregateArgs(this.model, normalizedArgs);
|
|
3624
3956
|
let query = this.kysely.selectFrom((eb) => {
|
|
3625
|
-
let subQuery =
|
|
3957
|
+
let subQuery = this.dialect.buildSelectModel(eb, this.model).where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
|
|
3958
|
+
const selectedFields = [];
|
|
3959
|
+
for (const [key, value] of Object.entries(parsedArgs)) {
|
|
3960
|
+
if (key.startsWith("_") && value && typeof value === "object") {
|
|
3961
|
+
Object.entries(value).filter(([field]) => field !== "_all").filter(([, val]) => val === true).forEach(([field]) => {
|
|
3962
|
+
if (!selectedFields.includes(field)) selectedFields.push(field);
|
|
3963
|
+
});
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
if (selectedFields.length > 0) {
|
|
3967
|
+
for (const field of selectedFields) {
|
|
3968
|
+
subQuery = this.dialect.buildSelectField(subQuery, this.model, this.model, field);
|
|
3969
|
+
}
|
|
3970
|
+
} else {
|
|
3971
|
+
subQuery = subQuery.select(() => eb.lit(1).as("_all"));
|
|
3972
|
+
}
|
|
3626
3973
|
const skip = parsedArgs?.skip;
|
|
3627
3974
|
let take = parsedArgs?.take;
|
|
3628
3975
|
let negateOrderBy = false;
|
|
@@ -3668,9 +4015,9 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
|
|
|
3668
4015
|
}
|
|
3669
4016
|
}
|
|
3670
4017
|
}
|
|
3671
|
-
const result = await
|
|
4018
|
+
const result = await this.executeQuery(this.kysely, query, "aggregate");
|
|
3672
4019
|
const ret = {};
|
|
3673
|
-
for (const [key, value] of Object.entries(result)) {
|
|
4020
|
+
for (const [key, value] of Object.entries(result.rows[0])) {
|
|
3674
4021
|
if (key === "_count") {
|
|
3675
4022
|
ret[key] = value;
|
|
3676
4023
|
continue;
|
|
@@ -3715,18 +4062,29 @@ var CountOperationHandler = class extends BaseOperationHandler {
|
|
|
3715
4062
|
async handle(_operation, args) {
|
|
3716
4063
|
const normalizedArgs = this.normalizeArgs(args);
|
|
3717
4064
|
const parsedArgs = this.inputValidator.validateCountArgs(this.model, normalizedArgs);
|
|
4065
|
+
const subQueryName = "$sub";
|
|
3718
4066
|
let query = this.kysely.selectFrom((eb) => {
|
|
3719
|
-
let subQuery =
|
|
4067
|
+
let subQuery = this.dialect.buildSelectModel(eb, this.model).where((eb1) => this.dialect.buildFilter(eb1, this.model, this.model, parsedArgs?.where));
|
|
4068
|
+
if (parsedArgs?.select && typeof parsedArgs.select === "object") {
|
|
4069
|
+
for (const [key, value] of Object.entries(parsedArgs.select)) {
|
|
4070
|
+
if (key !== "_all" && value === true) {
|
|
4071
|
+
subQuery = this.dialect.buildSelectField(subQuery, this.model, this.model, key);
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
} else {
|
|
4075
|
+
subQuery = subQuery.select(() => eb.lit(1).as("_all"));
|
|
4076
|
+
}
|
|
3720
4077
|
subQuery = this.dialect.buildSkipTake(subQuery, parsedArgs?.skip, parsedArgs?.take);
|
|
3721
|
-
return subQuery.as(
|
|
4078
|
+
return subQuery.as(subQueryName);
|
|
3722
4079
|
});
|
|
3723
4080
|
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(`$
|
|
3725
|
-
|
|
4081
|
+
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)));
|
|
4082
|
+
const result = await this.executeQuery(this.kysely, query, "count");
|
|
4083
|
+
return result.rows[0];
|
|
3726
4084
|
} else {
|
|
3727
4085
|
query = query.select((eb) => eb.cast(eb.fn.countAll(), "integer").as("count"));
|
|
3728
|
-
const result = await
|
|
3729
|
-
return result.count;
|
|
4086
|
+
const result = await this.executeQuery(this.kysely, query, "count");
|
|
4087
|
+
return result.rows[0].count;
|
|
3730
4088
|
}
|
|
3731
4089
|
}
|
|
3732
4090
|
};
|
|
@@ -3805,15 +4163,19 @@ var DeleteOperationHandler = class extends BaseOperationHandler {
|
|
|
3805
4163
|
if (!existing) {
|
|
3806
4164
|
throw new NotFoundError(this.model);
|
|
3807
4165
|
}
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
4166
|
+
await this.safeTransaction(async (tx) => {
|
|
4167
|
+
const result = await this.delete(tx, this.model, args.where);
|
|
4168
|
+
if (result.count === 0) {
|
|
4169
|
+
throw new NotFoundError(this.model);
|
|
4170
|
+
}
|
|
4171
|
+
});
|
|
3812
4172
|
return existing;
|
|
3813
4173
|
}
|
|
3814
4174
|
async runDeleteMany(args) {
|
|
3815
|
-
|
|
3816
|
-
|
|
4175
|
+
return await this.safeTransaction(async (tx) => {
|
|
4176
|
+
const result = await this.delete(tx, this.model, args?.where, args?.limit);
|
|
4177
|
+
return result;
|
|
4178
|
+
});
|
|
3817
4179
|
}
|
|
3818
4180
|
};
|
|
3819
4181
|
|
|
@@ -3901,8 +4263,8 @@ var GroupByOperationHandler = class extends BaseOperationHandler {
|
|
|
3901
4263
|
}
|
|
3902
4264
|
}
|
|
3903
4265
|
}
|
|
3904
|
-
const result = await
|
|
3905
|
-
return result.map((row) => this.postProcessRow(row));
|
|
4266
|
+
const result = await this.executeQuery(this.kysely, query, "groupBy");
|
|
4267
|
+
return result.rows.map((row) => this.postProcessRow(row));
|
|
3906
4268
|
}
|
|
3907
4269
|
postProcessRow(row) {
|
|
3908
4270
|
const ret = {};
|
|
@@ -3954,22 +4316,35 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
|
|
|
3954
4316
|
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
4317
|
}
|
|
3956
4318
|
async runUpdate(args) {
|
|
3957
|
-
const
|
|
3958
|
-
const
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
4319
|
+
const readBackResult = await this.safeTransaction(async (tx) => {
|
|
4320
|
+
const updateResult = await this.update(tx, this.model, args.where, args.data);
|
|
4321
|
+
const readFilter = updateResult ?? args.where;
|
|
4322
|
+
let readBackResult2 = void 0;
|
|
4323
|
+
try {
|
|
4324
|
+
readBackResult2 = await this.readUnique(tx, this.model, {
|
|
4325
|
+
select: args.select,
|
|
4326
|
+
include: args.include,
|
|
4327
|
+
omit: args.omit,
|
|
4328
|
+
where: readFilter
|
|
4329
|
+
});
|
|
4330
|
+
} catch {
|
|
4331
|
+
}
|
|
4332
|
+
return readBackResult2;
|
|
3965
4333
|
});
|
|
3966
|
-
if (!
|
|
3967
|
-
|
|
4334
|
+
if (!readBackResult) {
|
|
4335
|
+
if (this.hasPolicyEnabled) {
|
|
4336
|
+
throw new RejectedByPolicyError(this.model, "result is not allowed to be read back");
|
|
4337
|
+
} else {
|
|
4338
|
+
return null;
|
|
4339
|
+
}
|
|
4340
|
+
} else {
|
|
4341
|
+
return readBackResult;
|
|
3968
4342
|
}
|
|
3969
|
-
return result;
|
|
3970
4343
|
}
|
|
3971
4344
|
async runUpdateMany(args) {
|
|
3972
|
-
return this.
|
|
4345
|
+
return this.safeTransaction(async (tx) => {
|
|
4346
|
+
return this.updateMany(tx, this.model, args.where, args.data, args.limit, false);
|
|
4347
|
+
});
|
|
3973
4348
|
}
|
|
3974
4349
|
async runUpdateManyAndReturn(args) {
|
|
3975
4350
|
if (!args) {
|
|
@@ -4108,17 +4483,45 @@ var InputValidator = class {
|
|
|
4108
4483
|
return result;
|
|
4109
4484
|
}
|
|
4110
4485
|
makePrimitiveSchema(type) {
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
z.
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4486
|
+
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
4487
|
+
return this.makeTypeDefSchema(type);
|
|
4488
|
+
} else {
|
|
4489
|
+
return match14(type).with("String", () => z.string()).with("Int", () => z.number()).with("Float", () => z.number()).with("Boolean", () => z.boolean()).with("BigInt", () => z.union([
|
|
4490
|
+
z.number(),
|
|
4491
|
+
z.bigint()
|
|
4492
|
+
])).with("Decimal", () => z.union([
|
|
4493
|
+
z.number(),
|
|
4494
|
+
z.instanceof(Decimal),
|
|
4495
|
+
z.string()
|
|
4496
|
+
])).with("DateTime", () => z.union([
|
|
4497
|
+
z.date(),
|
|
4498
|
+
z.string().datetime()
|
|
4499
|
+
])).with("Bytes", () => z.instanceof(Uint8Array)).otherwise(() => z.unknown());
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4502
|
+
makeTypeDefSchema(type) {
|
|
4503
|
+
const key = `$typedef-${type}`;
|
|
4504
|
+
let schema = this.schemaCache.get(key);
|
|
4505
|
+
if (schema) {
|
|
4506
|
+
return schema;
|
|
4507
|
+
}
|
|
4508
|
+
const typeDef = this.schema.typeDefs?.[type];
|
|
4509
|
+
invariant8(typeDef, `Type definition "${type}" not found in schema`);
|
|
4510
|
+
schema = z.looseObject(Object.fromEntries(Object.entries(typeDef.fields).map(([field, def]) => {
|
|
4511
|
+
let fieldSchema = this.makePrimitiveSchema(def.type);
|
|
4512
|
+
if (def.array) {
|
|
4513
|
+
fieldSchema = fieldSchema.array();
|
|
4514
|
+
}
|
|
4515
|
+
if (def.optional) {
|
|
4516
|
+
fieldSchema = fieldSchema.optional();
|
|
4517
|
+
}
|
|
4518
|
+
return [
|
|
4519
|
+
field,
|
|
4520
|
+
fieldSchema
|
|
4521
|
+
];
|
|
4522
|
+
})));
|
|
4523
|
+
this.schemaCache.set(key, schema);
|
|
4524
|
+
return schema;
|
|
4122
4525
|
}
|
|
4123
4526
|
makeWhereSchema(model, unique, withoutRelationFields = false) {
|
|
4124
4527
|
const modelDef = getModel(this.schema, model);
|
|
@@ -4240,8 +4643,14 @@ var InputValidator = class {
|
|
|
4240
4643
|
});
|
|
4241
4644
|
}
|
|
4242
4645
|
makePrimitiveFilterSchema(type, optional) {
|
|
4646
|
+
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
4647
|
+
return this.makeTypeDefFilterSchema(type, optional);
|
|
4648
|
+
}
|
|
4243
4649
|
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
4650
|
}
|
|
4651
|
+
makeTypeDefFilterSchema(_type, _optional) {
|
|
4652
|
+
return z.never();
|
|
4653
|
+
}
|
|
4245
4654
|
makeDateTimeFilterSchema(optional) {
|
|
4246
4655
|
return this.makeCommonPrimitiveFilterSchema(z.union([
|
|
4247
4656
|
z.string().datetime(),
|
|
@@ -4446,6 +4855,9 @@ var InputValidator = class {
|
|
|
4446
4855
|
if (fieldDef.computed) {
|
|
4447
4856
|
return;
|
|
4448
4857
|
}
|
|
4858
|
+
if (this.isDelegateDiscriminator(fieldDef)) {
|
|
4859
|
+
return;
|
|
4860
|
+
}
|
|
4449
4861
|
if (fieldDef.relation) {
|
|
4450
4862
|
if (withoutRelationFields) {
|
|
4451
4863
|
return;
|
|
@@ -4518,6 +4930,13 @@ var InputValidator = class {
|
|
|
4518
4930
|
]);
|
|
4519
4931
|
}
|
|
4520
4932
|
}
|
|
4933
|
+
isDelegateDiscriminator(fieldDef) {
|
|
4934
|
+
if (!fieldDef.originModel) {
|
|
4935
|
+
return false;
|
|
4936
|
+
}
|
|
4937
|
+
const discriminatorField = getDiscriminatorField(this.schema, fieldDef.originModel);
|
|
4938
|
+
return discriminatorField === fieldDef.name;
|
|
4939
|
+
}
|
|
4521
4940
|
makeRelationManipulationSchema(fieldDef, withoutFields, mode) {
|
|
4522
4941
|
const fieldType = fieldDef.type;
|
|
4523
4942
|
const array = !!fieldDef.array;
|
|
@@ -4848,11 +5267,11 @@ var ZenStackDriver = class {
|
|
|
4848
5267
|
}
|
|
4849
5268
|
#driver;
|
|
4850
5269
|
#log;
|
|
4851
|
-
txConnection;
|
|
4852
5270
|
#initPromise;
|
|
4853
5271
|
#initDone;
|
|
4854
5272
|
#destroyPromise;
|
|
4855
5273
|
#connections = /* @__PURE__ */ new WeakSet();
|
|
5274
|
+
#txConnections = /* @__PURE__ */ new WeakMap();
|
|
4856
5275
|
constructor(driver, log) {
|
|
4857
5276
|
this.#initDone = false;
|
|
4858
5277
|
this.#driver = driver;
|
|
@@ -4893,21 +5312,30 @@ var ZenStackDriver = class {
|
|
|
4893
5312
|
}
|
|
4894
5313
|
async beginTransaction(connection, settings) {
|
|
4895
5314
|
const result = await this.#driver.beginTransaction(connection, settings);
|
|
4896
|
-
this.
|
|
5315
|
+
this.#txConnections.set(connection, []);
|
|
4897
5316
|
return result;
|
|
4898
5317
|
}
|
|
4899
|
-
commitTransaction(connection) {
|
|
5318
|
+
async commitTransaction(connection) {
|
|
4900
5319
|
try {
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
this.
|
|
5320
|
+
const result = await this.#driver.commitTransaction(connection);
|
|
5321
|
+
const callbacks = this.#txConnections.get(connection);
|
|
5322
|
+
this.#txConnections.delete(connection);
|
|
5323
|
+
if (callbacks) {
|
|
5324
|
+
for (const callback of callbacks) {
|
|
5325
|
+
await callback();
|
|
5326
|
+
}
|
|
5327
|
+
}
|
|
5328
|
+
return result;
|
|
5329
|
+
} catch (err) {
|
|
5330
|
+
this.#txConnections.delete(connection);
|
|
5331
|
+
throw err;
|
|
4904
5332
|
}
|
|
4905
5333
|
}
|
|
4906
|
-
rollbackTransaction(connection) {
|
|
5334
|
+
async rollbackTransaction(connection) {
|
|
4907
5335
|
try {
|
|
4908
|
-
return this.#driver.rollbackTransaction(connection);
|
|
5336
|
+
return await this.#driver.rollbackTransaction(connection);
|
|
4909
5337
|
} finally {
|
|
4910
|
-
this.
|
|
5338
|
+
this.#txConnections.delete(connection);
|
|
4911
5339
|
}
|
|
4912
5340
|
}
|
|
4913
5341
|
async destroy() {
|
|
@@ -4985,6 +5413,22 @@ var ZenStackDriver = class {
|
|
|
4985
5413
|
#calculateDurationMillis(startTime) {
|
|
4986
5414
|
return performanceNow() - startTime;
|
|
4987
5415
|
}
|
|
5416
|
+
isTransactionConnection(connection) {
|
|
5417
|
+
return this.#txConnections.has(connection);
|
|
5418
|
+
}
|
|
5419
|
+
registerTransactionCommitCallback(connection, callback) {
|
|
5420
|
+
if (!this.#txConnections.has(connection)) {
|
|
5421
|
+
return;
|
|
5422
|
+
}
|
|
5423
|
+
const callbacks = this.#txConnections.get(connection);
|
|
5424
|
+
if (callbacks) {
|
|
5425
|
+
callbacks.push(callback);
|
|
5426
|
+
} else {
|
|
5427
|
+
this.#txConnections.set(connection, [
|
|
5428
|
+
callback
|
|
5429
|
+
]);
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
4988
5432
|
};
|
|
4989
5433
|
function performanceNow() {
|
|
4990
5434
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
@@ -5201,7 +5645,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
|
|
|
5201
5645
|
this.requireCurrentModel(contextNode);
|
|
5202
5646
|
model = model ?? this.currentModel;
|
|
5203
5647
|
const modelDef = requireModel(this.schema, model);
|
|
5204
|
-
const scalarFields = Object.entries(modelDef.fields).filter(([, fieldDef]) => !fieldDef.relation && !fieldDef.computed).map(([fieldName]) => fieldName);
|
|
5648
|
+
const scalarFields = Object.entries(modelDef.fields).filter(([, fieldDef]) => !fieldDef.relation && !fieldDef.computed && !fieldDef.originModel).map(([fieldName]) => fieldName);
|
|
5205
5649
|
return scalarFields;
|
|
5206
5650
|
}
|
|
5207
5651
|
};
|
|
@@ -5226,7 +5670,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5226
5670
|
get options() {
|
|
5227
5671
|
return this.client.$options;
|
|
5228
5672
|
}
|
|
5229
|
-
async executeQuery(compiledQuery,
|
|
5673
|
+
async executeQuery(compiledQuery, _queryId) {
|
|
5230
5674
|
let queryNode = compiledQuery.query;
|
|
5231
5675
|
let mutationInterceptionInfo;
|
|
5232
5676
|
if (this.isMutationNode(queryNode) && this.hasMutationHooks) {
|
|
@@ -5237,7 +5681,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5237
5681
|
await this.callBeforeMutationHooks(queryNode, mutationInterceptionInfo);
|
|
5238
5682
|
}
|
|
5239
5683
|
const oldQueryNode = queryNode;
|
|
5240
|
-
if ((InsertQueryNode2.is(queryNode) ||
|
|
5684
|
+
if ((InsertQueryNode2.is(queryNode) || UpdateQueryNode2.is(queryNode)) && mutationInterceptionInfo?.loadAfterMutationEntity) {
|
|
5241
5685
|
queryNode = {
|
|
5242
5686
|
...queryNode,
|
|
5243
5687
|
returning: ReturningNode3.create([
|
|
@@ -5246,34 +5690,49 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5246
5690
|
};
|
|
5247
5691
|
}
|
|
5248
5692
|
const queryParams = compiledQuery.$raw ? compiledQuery.parameters : void 0;
|
|
5249
|
-
const result = await this.proceedQueryWithKyselyInterceptors(queryNode, queryParams
|
|
5693
|
+
const result = await this.proceedQueryWithKyselyInterceptors(queryNode, queryParams);
|
|
5250
5694
|
if (this.isMutationNode(queryNode)) {
|
|
5251
|
-
await this.
|
|
5695
|
+
await this.callAfterMutationHooks(result.result, queryNode, mutationInterceptionInfo, result.connection);
|
|
5252
5696
|
}
|
|
5253
5697
|
if (oldQueryNode !== queryNode) {
|
|
5254
5698
|
}
|
|
5255
|
-
return result;
|
|
5699
|
+
return result.result;
|
|
5256
5700
|
}, "task");
|
|
5257
5701
|
return task();
|
|
5258
5702
|
}
|
|
5259
|
-
proceedQueryWithKyselyInterceptors(queryNode, parameters
|
|
5260
|
-
let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters
|
|
5261
|
-
const hooks =
|
|
5703
|
+
proceedQueryWithKyselyInterceptors(queryNode, parameters) {
|
|
5704
|
+
let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters), "proceed");
|
|
5705
|
+
const hooks = [];
|
|
5706
|
+
for (const plugin of this.client.$options.plugins ?? []) {
|
|
5707
|
+
if (plugin.onKyselyQuery) {
|
|
5708
|
+
hooks.push(plugin.onKyselyQuery.bind(plugin));
|
|
5709
|
+
}
|
|
5710
|
+
}
|
|
5262
5711
|
for (const hook of hooks) {
|
|
5263
5712
|
const _proceed = proceed;
|
|
5264
|
-
proceed = /* @__PURE__ */ __name((query) => {
|
|
5265
|
-
|
|
5713
|
+
proceed = /* @__PURE__ */ __name(async (query) => {
|
|
5714
|
+
let connection;
|
|
5715
|
+
const _p = /* @__PURE__ */ __name(async (q) => {
|
|
5716
|
+
const r = await _proceed(q);
|
|
5717
|
+
connection = r.connection;
|
|
5718
|
+
return r.result;
|
|
5719
|
+
}, "_p");
|
|
5720
|
+
const hookResult = await hook({
|
|
5266
5721
|
client: this.client,
|
|
5267
5722
|
schema: this.client.$schema,
|
|
5268
5723
|
kysely: this.kysely,
|
|
5269
5724
|
query,
|
|
5270
|
-
proceed:
|
|
5725
|
+
proceed: _p
|
|
5271
5726
|
});
|
|
5727
|
+
return {
|
|
5728
|
+
result: hookResult,
|
|
5729
|
+
connection
|
|
5730
|
+
};
|
|
5272
5731
|
}, "proceed");
|
|
5273
5732
|
}
|
|
5274
5733
|
return proceed(queryNode);
|
|
5275
5734
|
}
|
|
5276
|
-
async proceedQuery(query, parameters
|
|
5735
|
+
async proceedQuery(query, parameters) {
|
|
5277
5736
|
const finalQuery = this.nameMapper.transformNode(query);
|
|
5278
5737
|
let compiled = this.compileQuery(finalQuery);
|
|
5279
5738
|
if (parameters) {
|
|
@@ -5283,7 +5742,13 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
|
|
|
5283
5742
|
};
|
|
5284
5743
|
}
|
|
5285
5744
|
try {
|
|
5286
|
-
return await
|
|
5745
|
+
return await this.provideConnection(async (connection) => {
|
|
5746
|
+
const result = await connection.executeQuery(compiled);
|
|
5747
|
+
return {
|
|
5748
|
+
result,
|
|
5749
|
+
connection
|
|
5750
|
+
};
|
|
5751
|
+
});
|
|
5287
5752
|
} catch (err) {
|
|
5288
5753
|
let message = `Failed to execute query: ${err}, sql: ${compiled.sql}`;
|
|
5289
5754
|
if (this.options.debug) {
|
|
@@ -5386,10 +5851,11 @@ ${compiled.parameters.map((p) => inspect2(p)).join("\n")}`;
|
|
|
5386
5851
|
return;
|
|
5387
5852
|
}
|
|
5388
5853
|
if (this.options.plugins) {
|
|
5854
|
+
const mutationModel = this.getMutationModel(queryNode);
|
|
5389
5855
|
for (const plugin of this.options.plugins) {
|
|
5390
5856
|
if (plugin.beforeEntityMutation) {
|
|
5391
5857
|
await plugin.beforeEntityMutation({
|
|
5392
|
-
model:
|
|
5858
|
+
model: mutationModel,
|
|
5393
5859
|
action: mutationInterceptionInfo.action,
|
|
5394
5860
|
queryNode,
|
|
5395
5861
|
entities: mutationInterceptionInfo.beforeMutationEntities
|
|
@@ -5398,30 +5864,45 @@ ${compiled.parameters.map((p) => inspect2(p)).join("\n")}`;
|
|
|
5398
5864
|
}
|
|
5399
5865
|
}
|
|
5400
5866
|
}
|
|
5401
|
-
async
|
|
5867
|
+
async callAfterMutationHooks(queryResult, queryNode, mutationInterceptionInfo, connection) {
|
|
5402
5868
|
if (!mutationInterceptionInfo?.intercept) {
|
|
5403
5869
|
return;
|
|
5404
5870
|
}
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5871
|
+
const hooks = [];
|
|
5872
|
+
for (const plugin of this.options.plugins ?? []) {
|
|
5873
|
+
if (plugin.afterEntityMutation) {
|
|
5874
|
+
hooks.push(plugin.afterEntityMutation.bind(plugin));
|
|
5875
|
+
}
|
|
5876
|
+
}
|
|
5877
|
+
if (hooks.length === 0) {
|
|
5878
|
+
return;
|
|
5879
|
+
}
|
|
5880
|
+
const mutationModel = this.getMutationModel(queryNode);
|
|
5881
|
+
const inTransaction = this.driver.isTransactionConnection(connection);
|
|
5882
|
+
for (const hook of hooks) {
|
|
5883
|
+
let afterMutationEntities = void 0;
|
|
5884
|
+
if (mutationInterceptionInfo.loadAfterMutationEntity) {
|
|
5885
|
+
if (InsertQueryNode2.is(queryNode) || UpdateQueryNode2.is(queryNode)) {
|
|
5886
|
+
afterMutationEntities = queryResult.rows;
|
|
5887
|
+
}
|
|
5888
|
+
}
|
|
5889
|
+
const action = /* @__PURE__ */ __name(async () => {
|
|
5890
|
+
try {
|
|
5891
|
+
await hook({
|
|
5892
|
+
model: mutationModel,
|
|
5419
5893
|
action: mutationInterceptionInfo.action,
|
|
5420
5894
|
queryNode,
|
|
5421
5895
|
beforeMutationEntities: mutationInterceptionInfo.beforeMutationEntities,
|
|
5422
5896
|
afterMutationEntities
|
|
5423
5897
|
});
|
|
5898
|
+
} catch (err) {
|
|
5899
|
+
console.error(`Error in afterEntityMutation hook for model "${mutationModel}": ${err}`);
|
|
5424
5900
|
}
|
|
5901
|
+
}, "action");
|
|
5902
|
+
if (inTransaction) {
|
|
5903
|
+
this.driver.registerTransactionCommitCallback(connection, action);
|
|
5904
|
+
} else {
|
|
5905
|
+
await action();
|
|
5425
5906
|
}
|
|
5426
5907
|
}
|
|
5427
5908
|
}
|
|
@@ -5618,7 +6099,7 @@ var SchemaDbPusher = class {
|
|
|
5618
6099
|
}
|
|
5619
6100
|
}
|
|
5620
6101
|
table = this.addPrimaryKeyConstraint(table, model, modelDef);
|
|
5621
|
-
table = this.addUniqueConstraint(table, modelDef);
|
|
6102
|
+
table = this.addUniqueConstraint(table, model, modelDef);
|
|
5622
6103
|
return table;
|
|
5623
6104
|
}
|
|
5624
6105
|
isComputedField(fieldDef) {
|
|
@@ -5635,7 +6116,7 @@ var SchemaDbPusher = class {
|
|
|
5635
6116
|
}
|
|
5636
6117
|
return table;
|
|
5637
6118
|
}
|
|
5638
|
-
addUniqueConstraint(table, modelDef) {
|
|
6119
|
+
addUniqueConstraint(table, model, modelDef) {
|
|
5639
6120
|
for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
|
|
5640
6121
|
invariant10(typeof value === "object", "expecting an object");
|
|
5641
6122
|
if ("type" in value) {
|
|
@@ -5643,8 +6124,11 @@ var SchemaDbPusher = class {
|
|
|
5643
6124
|
if (fieldDef.unique) {
|
|
5644
6125
|
continue;
|
|
5645
6126
|
}
|
|
6127
|
+
table = table.addUniqueConstraint(`unique_${model}_${key}`, [
|
|
6128
|
+
key
|
|
6129
|
+
]);
|
|
5646
6130
|
} else {
|
|
5647
|
-
table = table.addUniqueConstraint(`unique_${key}`, Object.keys(value));
|
|
6131
|
+
table = table.addUniqueConstraint(`unique_${model}_${key}`, Object.keys(value));
|
|
5648
6132
|
}
|
|
5649
6133
|
}
|
|
5650
6134
|
return table;
|
|
@@ -5787,6 +6271,21 @@ var ResultProcessor = class {
|
|
|
5787
6271
|
data[key] = typeof value === "string" ? JSON.parse(value) : value;
|
|
5788
6272
|
continue;
|
|
5789
6273
|
}
|
|
6274
|
+
if (key.startsWith(DELEGATE_JOINED_FIELD_PREFIX)) {
|
|
6275
|
+
if (value) {
|
|
6276
|
+
const subRow = this.transformJson(value);
|
|
6277
|
+
const subModel = key.slice(DELEGATE_JOINED_FIELD_PREFIX.length);
|
|
6278
|
+
const idValues = getIdValues(this.schema, subModel, subRow);
|
|
6279
|
+
if (Object.values(idValues).some((v) => v === null || v === void 0)) {
|
|
6280
|
+
delete data[key];
|
|
6281
|
+
continue;
|
|
6282
|
+
}
|
|
6283
|
+
const processedSubRow = this.processRow(subRow, subModel);
|
|
6284
|
+
Object.assign(data, processedSubRow);
|
|
6285
|
+
}
|
|
6286
|
+
delete data[key];
|
|
6287
|
+
continue;
|
|
6288
|
+
}
|
|
5790
6289
|
const fieldDef = getField(this.schema, model, key);
|
|
5791
6290
|
if (!fieldDef) {
|
|
5792
6291
|
continue;
|
|
@@ -5826,7 +6325,11 @@ var ResultProcessor = class {
|
|
|
5826
6325
|
return this.doProcessResult(relationData, fieldDef.type);
|
|
5827
6326
|
}
|
|
5828
6327
|
transformScalar(value, type) {
|
|
5829
|
-
|
|
6328
|
+
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
6329
|
+
return this.transformJson(value);
|
|
6330
|
+
} else {
|
|
6331
|
+
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);
|
|
6332
|
+
}
|
|
5830
6333
|
}
|
|
5831
6334
|
transformDecimal(value) {
|
|
5832
6335
|
if (value instanceof Decimal2) {
|
|
@@ -6038,19 +6541,26 @@ var ClientImpl = class _ClientImpl {
|
|
|
6038
6541
|
await new SchemaDbPusher(this.schema, this.kysely).push();
|
|
6039
6542
|
}
|
|
6040
6543
|
$use(plugin) {
|
|
6544
|
+
const newPlugins = [
|
|
6545
|
+
...this.$options.plugins ?? [],
|
|
6546
|
+
plugin
|
|
6547
|
+
];
|
|
6041
6548
|
const newOptions = {
|
|
6042
6549
|
...this.options,
|
|
6043
|
-
plugins:
|
|
6044
|
-
...this.options.plugins ?? [],
|
|
6045
|
-
plugin
|
|
6046
|
-
]
|
|
6550
|
+
plugins: newPlugins
|
|
6047
6551
|
};
|
|
6048
6552
|
return new _ClientImpl(this.schema, newOptions, this);
|
|
6049
6553
|
}
|
|
6050
6554
|
$unuse(pluginId) {
|
|
6555
|
+
const newPlugins = [];
|
|
6556
|
+
for (const plugin of this.options.plugins ?? []) {
|
|
6557
|
+
if (plugin.id !== pluginId) {
|
|
6558
|
+
newPlugins.push(plugin);
|
|
6559
|
+
}
|
|
6560
|
+
}
|
|
6051
6561
|
const newOptions = {
|
|
6052
6562
|
...this.options,
|
|
6053
|
-
plugins:
|
|
6563
|
+
plugins: newPlugins
|
|
6054
6564
|
};
|
|
6055
6565
|
return new _ClientImpl(this.schema, newOptions, this);
|
|
6056
6566
|
}
|