@zenstackhq/runtime 3.0.0-alpha.0 → 3.0.0-alpha.10
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-DguafRNB.d.cts → contract-BiU0iYAh.d.cts} +813 -709
- package/dist/{contract-DguafRNB.d.ts → contract-BiU0iYAh.d.ts} +813 -709
- package/dist/{utils/pg-utils.cjs → helpers.cjs} +8 -16
- package/dist/helpers.cjs.map +1 -0
- package/dist/helpers.d.cts +1 -0
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.js +6 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.cjs +517 -328
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -6
- package/dist/index.d.ts +28 -6
- package/dist/index.js +466 -282
- package/dist/index.js.map +1 -1
- package/dist/plugins/policy.cjs +115 -104
- package/dist/plugins/policy.cjs.map +1 -1
- package/dist/plugins/policy.d.cts +2 -4
- package/dist/plugins/policy.d.ts +2 -4
- package/dist/plugins/policy.js +87 -66
- package/dist/plugins/policy.js.map +1 -1
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.js.map +1 -1
- package/package.json +23 -46
- package/dist/client.cjs +0 -6094
- package/dist/client.cjs.map +0 -1
- package/dist/client.d.cts +0 -19
- package/dist/client.d.ts +0 -19
- package/dist/client.js +0 -6060
- package/dist/client.js.map +0 -1
- package/dist/utils/pg-utils.cjs.map +0 -1
- package/dist/utils/pg-utils.d.cts +0 -8
- package/dist/utils/pg-utils.d.ts +0 -8
- package/dist/utils/pg-utils.js +0 -16
- package/dist/utils/pg-utils.js.map +0 -1
- package/dist/utils/sqlite-utils.cjs +0 -55
- package/dist/utils/sqlite-utils.cjs.map +0 -1
- package/dist/utils/sqlite-utils.d.cts +0 -8
- package/dist/utils/sqlite-utils.d.ts +0 -8
- package/dist/utils/sqlite-utils.js +0 -22
- package/dist/utils/sqlite-utils.js.map +0 -1
package/dist/plugins/policy.cjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
7
|
var __export = (target, all) => {
|
|
@@ -18,14 +16,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
16
|
}
|
|
19
17
|
return to;
|
|
20
18
|
};
|
|
21
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
-
mod
|
|
28
|
-
));
|
|
29
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
20
|
|
|
31
21
|
// src/plugins/policy/index.ts
|
|
@@ -49,16 +39,16 @@ var RejectedByPolicyError = class extends Error {
|
|
|
49
39
|
};
|
|
50
40
|
|
|
51
41
|
// src/plugins/policy/policy-handler.ts
|
|
42
|
+
var import_common_helpers6 = require("@zenstackhq/common-helpers");
|
|
52
43
|
var import_kysely7 = require("kysely");
|
|
53
|
-
var import_tiny_invariant6 = __toESM(require("tiny-invariant"), 1);
|
|
54
44
|
var import_ts_pattern7 = require("ts-pattern");
|
|
55
45
|
|
|
56
46
|
// src/client/crud/dialects/index.ts
|
|
57
47
|
var import_ts_pattern4 = require("ts-pattern");
|
|
58
48
|
|
|
59
49
|
// src/client/crud/dialects/postgresql.ts
|
|
50
|
+
var import_common_helpers2 = require("@zenstackhq/common-helpers");
|
|
60
51
|
var import_kysely2 = require("kysely");
|
|
61
|
-
var import_tiny_invariant2 = __toESM(require("tiny-invariant"), 1);
|
|
62
52
|
var import_ts_pattern2 = require("ts-pattern");
|
|
63
53
|
|
|
64
54
|
// src/client/errors.ts
|
|
@@ -66,17 +56,16 @@ var QueryError = class extends Error {
|
|
|
66
56
|
static {
|
|
67
57
|
__name(this, "QueryError");
|
|
68
58
|
}
|
|
69
|
-
constructor(message) {
|
|
70
|
-
super(message
|
|
59
|
+
constructor(message, cause) {
|
|
60
|
+
super(message, {
|
|
61
|
+
cause
|
|
62
|
+
});
|
|
71
63
|
}
|
|
72
64
|
};
|
|
73
65
|
var InternalError = class extends Error {
|
|
74
66
|
static {
|
|
75
67
|
__name(this, "InternalError");
|
|
76
68
|
}
|
|
77
|
-
constructor(message) {
|
|
78
|
-
super(message);
|
|
79
|
-
}
|
|
80
69
|
};
|
|
81
70
|
|
|
82
71
|
// src/client/query-utils.ts
|
|
@@ -87,7 +76,7 @@ __name(getModel, "getModel");
|
|
|
87
76
|
function requireModel(schema, model) {
|
|
88
77
|
const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
|
|
89
78
|
if (!matchedName) {
|
|
90
|
-
throw new QueryError(`Model "${model}" not found`);
|
|
79
|
+
throw new QueryError(`Model "${model}" not found in schema`);
|
|
91
80
|
}
|
|
92
81
|
return schema.models[matchedName];
|
|
93
82
|
}
|
|
@@ -150,6 +139,11 @@ function getRelationForeignKeyFieldPairs(schema, model, relationField) {
|
|
|
150
139
|
}
|
|
151
140
|
}
|
|
152
141
|
__name(getRelationForeignKeyFieldPairs, "getRelationForeignKeyFieldPairs");
|
|
142
|
+
function isRelationField(schema, model, field) {
|
|
143
|
+
const fieldDef = requireField(schema, model, field);
|
|
144
|
+
return !!fieldDef.relation;
|
|
145
|
+
}
|
|
146
|
+
__name(isRelationField, "isRelationField");
|
|
153
147
|
function getUniqueFields(schema, model) {
|
|
154
148
|
const modelDef = requireModel(schema, model);
|
|
155
149
|
const result = [];
|
|
@@ -186,7 +180,7 @@ function buildFieldRef(schema, model, field, options, eb, modelAlias) {
|
|
|
186
180
|
computer = computedFields?.[model]?.[field];
|
|
187
181
|
}
|
|
188
182
|
if (!computer) {
|
|
189
|
-
throw new QueryError(`Computed field "${field}" implementation not provided`);
|
|
183
|
+
throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
|
|
190
184
|
}
|
|
191
185
|
return computer(eb);
|
|
192
186
|
}
|
|
@@ -265,8 +259,8 @@ function flattenCompoundUniqueFilters(schema, model, filter) {
|
|
|
265
259
|
__name(flattenCompoundUniqueFilters, "flattenCompoundUniqueFilters");
|
|
266
260
|
|
|
267
261
|
// src/client/crud/dialects/base.ts
|
|
262
|
+
var import_common_helpers = require("@zenstackhq/common-helpers");
|
|
268
263
|
var import_kysely = require("kysely");
|
|
269
|
-
var import_tiny_invariant = __toESM(require("tiny-invariant"), 1);
|
|
270
264
|
var import_ts_pattern = require("ts-pattern");
|
|
271
265
|
|
|
272
266
|
// src/utils/enumerate.ts
|
|
@@ -284,7 +278,6 @@ function enumerate(x) {
|
|
|
284
278
|
__name(enumerate, "enumerate");
|
|
285
279
|
|
|
286
280
|
// src/client/crud/dialects/base.ts
|
|
287
|
-
var import_is_plain_object = require("is-plain-object");
|
|
288
281
|
var BaseCrudDialect = class {
|
|
289
282
|
static {
|
|
290
283
|
__name(this, "BaseCrudDialect");
|
|
@@ -295,7 +288,7 @@ var BaseCrudDialect = class {
|
|
|
295
288
|
this.schema = schema;
|
|
296
289
|
this.options = options;
|
|
297
290
|
}
|
|
298
|
-
transformPrimitive(value, _type) {
|
|
291
|
+
transformPrimitive(value, _type, _forArrayField) {
|
|
299
292
|
return value;
|
|
300
293
|
}
|
|
301
294
|
buildFilter(eb, model, modelAlias, where) {
|
|
@@ -438,7 +431,7 @@ var BaseCrudDialect = class {
|
|
|
438
431
|
if (_value === void 0) {
|
|
439
432
|
continue;
|
|
440
433
|
}
|
|
441
|
-
const value = this.transformPrimitive(_value, fieldType);
|
|
434
|
+
const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
|
|
442
435
|
switch (key) {
|
|
443
436
|
case "equals": {
|
|
444
437
|
clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
|
|
@@ -476,13 +469,17 @@ var BaseCrudDialect = class {
|
|
|
476
469
|
if (isEnum(this.schema, fieldDef.type)) {
|
|
477
470
|
return this.buildEnumFilter(eb, modelAlias, field, fieldDef, payload);
|
|
478
471
|
}
|
|
479
|
-
return (0, import_ts_pattern.match)(fieldDef.type).with("String", () => this.buildStringFilter(eb, modelAlias, field, payload)).with(import_ts_pattern.P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, model, modelAlias, field, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, modelAlias, field, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, modelAlias, field, payload)).with("Bytes", () => this.buildBytesFilter(eb, modelAlias, field, payload)).
|
|
472
|
+
return (0, import_ts_pattern.match)(fieldDef.type).with("String", () => this.buildStringFilter(eb, modelAlias, field, payload)).with(import_ts_pattern.P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, model, modelAlias, field, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, modelAlias, field, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, modelAlias, field, payload)).with("Bytes", () => this.buildBytesFilter(eb, modelAlias, field, payload)).with("Json", () => {
|
|
473
|
+
throw new InternalError("JSON filters are not supported yet");
|
|
474
|
+
}).with("Unsupported", () => {
|
|
475
|
+
throw new QueryError(`Unsupported field cannot be used in filters`);
|
|
476
|
+
}).exhaustive();
|
|
480
477
|
}
|
|
481
478
|
buildLiteralFilter(eb, lhs, type, rhs) {
|
|
482
|
-
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type) : rhs);
|
|
479
|
+
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
|
|
483
480
|
}
|
|
484
481
|
buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
|
|
485
|
-
if (payload === null || !(0,
|
|
482
|
+
if (payload === null || !(0, import_common_helpers.isPlainObject)(payload)) {
|
|
486
483
|
return {
|
|
487
484
|
conditions: [
|
|
488
485
|
this.buildLiteralFilter(eb, lhs, type, payload)
|
|
@@ -498,14 +495,14 @@ var BaseCrudDialect = class {
|
|
|
498
495
|
}
|
|
499
496
|
const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
|
|
500
497
|
const condition = (0, import_ts_pattern.match)(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
|
|
501
|
-
(0,
|
|
498
|
+
(0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
|
|
502
499
|
if (rhs.length === 0) {
|
|
503
500
|
return this.false(eb);
|
|
504
501
|
} else {
|
|
505
502
|
return eb(lhs, "in", rhs);
|
|
506
503
|
}
|
|
507
504
|
}).with("notIn", () => {
|
|
508
|
-
(0,
|
|
505
|
+
(0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
|
|
509
506
|
if (rhs.length === 0) {
|
|
510
507
|
return this.true(eb);
|
|
511
508
|
} else {
|
|
@@ -566,22 +563,22 @@ var BaseCrudDialect = class {
|
|
|
566
563
|
}
|
|
567
564
|
}
|
|
568
565
|
buildNumberFilter(eb, model, table, field, type, payload) {
|
|
569
|
-
const { conditions } = this.buildStandardFilter(eb, type, payload, buildFieldRef(this.schema, model, field, this.options, eb), (value) => this.transformPrimitive(value, type), (value) => this.buildNumberFilter(eb, model, table, field, type, value));
|
|
566
|
+
const { conditions } = this.buildStandardFilter(eb, type, payload, buildFieldRef(this.schema, model, field, this.options, eb), (value) => this.transformPrimitive(value, type, false), (value) => this.buildNumberFilter(eb, model, table, field, type, value));
|
|
570
567
|
return this.and(eb, ...conditions);
|
|
571
568
|
}
|
|
572
569
|
buildBooleanFilter(eb, table, field, payload) {
|
|
573
|
-
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Boolean"), (value) => this.buildBooleanFilter(eb, table, field, value), true, [
|
|
570
|
+
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, table, field, value), true, [
|
|
574
571
|
"equals",
|
|
575
572
|
"not"
|
|
576
573
|
]);
|
|
577
574
|
return this.and(eb, ...conditions);
|
|
578
575
|
}
|
|
579
576
|
buildDateTimeFilter(eb, table, field, payload) {
|
|
580
|
-
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "DateTime"), (value) => this.buildDateTimeFilter(eb, table, field, value), true);
|
|
577
|
+
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, table, field, value), true);
|
|
581
578
|
return this.and(eb, ...conditions);
|
|
582
579
|
}
|
|
583
580
|
buildBytesFilter(eb, table, field, payload) {
|
|
584
|
-
const conditions = this.buildStandardFilter(eb, "Bytes", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Bytes"), (value) => this.buildBytesFilter(eb, table, field, value), true, [
|
|
581
|
+
const conditions = this.buildStandardFilter(eb, "Bytes", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, table, field, value), true, [
|
|
585
582
|
"equals",
|
|
586
583
|
"in",
|
|
587
584
|
"notIn",
|
|
@@ -619,9 +616,9 @@ var BaseCrudDialect = class {
|
|
|
619
616
|
"_min",
|
|
620
617
|
"_max"
|
|
621
618
|
].includes(field)) {
|
|
622
|
-
(0,
|
|
619
|
+
(0, import_common_helpers.invariant)(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
|
|
623
620
|
for (const [k, v] of Object.entries(value)) {
|
|
624
|
-
(0,
|
|
621
|
+
(0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
|
|
625
622
|
result = result.orderBy((eb) => eb.fn(field.slice(1), [
|
|
626
623
|
import_kysely.sql.ref(k)
|
|
627
624
|
]), import_kysely.sql.raw(this.negateSort(v, negated)));
|
|
@@ -630,9 +627,9 @@ var BaseCrudDialect = class {
|
|
|
630
627
|
}
|
|
631
628
|
switch (field) {
|
|
632
629
|
case "_count": {
|
|
633
|
-
(0,
|
|
630
|
+
(0, import_common_helpers.invariant)(value && typeof value === "object", 'invalid orderBy value for field "_count"');
|
|
634
631
|
for (const [k, v] of Object.entries(value)) {
|
|
635
|
-
(0,
|
|
632
|
+
(0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
|
|
636
633
|
result = result.orderBy((eb) => eb.fn.count(import_kysely.sql.ref(k)), import_kysely.sql.raw(this.negateSort(v, negated)));
|
|
637
634
|
}
|
|
638
635
|
continue;
|
|
@@ -654,7 +651,7 @@ var BaseCrudDialect = class {
|
|
|
654
651
|
throw new QueryError(`invalid orderBy value for field "${field}"`);
|
|
655
652
|
}
|
|
656
653
|
if ("_count" in value) {
|
|
657
|
-
(0,
|
|
654
|
+
(0, import_common_helpers.invariant)(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
|
|
658
655
|
const sort = this.negateSort(value._count, negated);
|
|
659
656
|
result = result.orderBy((eb) => {
|
|
660
657
|
let subQuery = eb.selectFrom(relationModel);
|
|
@@ -680,10 +677,10 @@ var BaseCrudDialect = class {
|
|
|
680
677
|
return negated ? sort === "asc" ? "desc" : "asc" : sort;
|
|
681
678
|
}
|
|
682
679
|
true(eb) {
|
|
683
|
-
return eb.lit(this.transformPrimitive(true, "Boolean"));
|
|
680
|
+
return eb.lit(this.transformPrimitive(true, "Boolean", false));
|
|
684
681
|
}
|
|
685
682
|
false(eb) {
|
|
686
|
-
return eb.lit(this.transformPrimitive(false, "Boolean"));
|
|
683
|
+
return eb.lit(this.transformPrimitive(false, "Boolean", false));
|
|
687
684
|
}
|
|
688
685
|
isTrue(expression) {
|
|
689
686
|
const node = expression.toOperationNode();
|
|
@@ -732,14 +729,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
732
729
|
get provider() {
|
|
733
730
|
return "postgresql";
|
|
734
731
|
}
|
|
735
|
-
transformPrimitive(value, type) {
|
|
732
|
+
transformPrimitive(value, type, forArrayField) {
|
|
736
733
|
if (value === void 0) {
|
|
737
734
|
return value;
|
|
738
735
|
}
|
|
739
736
|
if (Array.isArray(value)) {
|
|
740
|
-
|
|
737
|
+
if (type === "Json" && !forArrayField) {
|
|
738
|
+
return JSON.stringify(value);
|
|
739
|
+
} else {
|
|
740
|
+
return value.map((v) => this.transformPrimitive(v, type, false));
|
|
741
|
+
}
|
|
741
742
|
} else {
|
|
742
|
-
return (0, import_ts_pattern2.match)(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).otherwise(() => value);
|
|
743
|
+
return (0, import_ts_pattern2.match)(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).with("Decimal", () => value !== null ? value.toString() : value).otherwise(() => value);
|
|
743
744
|
}
|
|
744
745
|
}
|
|
745
746
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
@@ -772,8 +773,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
772
773
|
if (m2m) {
|
|
773
774
|
const parentIds = getIdFields(this.schema, model);
|
|
774
775
|
const relationIds = getIdFields(this.schema, relationModel);
|
|
775
|
-
(0,
|
|
776
|
-
(0,
|
|
776
|
+
(0, import_common_helpers2.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
777
|
+
(0, import_common_helpers2.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
777
778
|
subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentName}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
|
|
778
779
|
} else {
|
|
779
780
|
const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, relationModel);
|
|
@@ -806,25 +807,33 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
806
807
|
buildFieldRef(this.schema, relationModel, field, this.options, eb)
|
|
807
808
|
]).flatMap((v) => v));
|
|
808
809
|
} else if (payload.select) {
|
|
809
|
-
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) =>
|
|
810
|
-
|
|
811
|
-
buildFieldRef(this.schema, relationModel, field, this.options, eb)
|
|
812
|
-
|
|
810
|
+
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => {
|
|
811
|
+
const fieldDef = requireField(this.schema, relationModel, field);
|
|
812
|
+
const fieldValue = fieldDef.relation ? eb.ref(`${parentName}$${relationField}$${field}.$j`) : buildFieldRef(this.schema, relationModel, field, this.options, eb);
|
|
813
|
+
return [
|
|
814
|
+
import_kysely2.sql.lit(field),
|
|
815
|
+
fieldValue
|
|
816
|
+
];
|
|
817
|
+
}).flatMap((v) => v));
|
|
813
818
|
}
|
|
814
819
|
if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
|
|
815
820
|
objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
|
|
816
821
|
import_kysely2.sql.lit(field),
|
|
822
|
+
// reference the synthesized JSON field
|
|
817
823
|
eb.ref(`${parentName}$${relationField}$${field}.$j`)
|
|
818
824
|
]).flatMap((v) => v));
|
|
819
825
|
}
|
|
820
826
|
return objArgs;
|
|
821
827
|
}
|
|
822
|
-
buildRelationJoins(
|
|
828
|
+
buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
|
|
823
829
|
let result = qb;
|
|
824
|
-
if (typeof payload === "object"
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
830
|
+
if (typeof payload === "object") {
|
|
831
|
+
const selectInclude = payload.include ?? payload.select;
|
|
832
|
+
if (selectInclude && typeof selectInclude === "object") {
|
|
833
|
+
Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
|
|
834
|
+
result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
|
|
835
|
+
});
|
|
836
|
+
}
|
|
828
837
|
}
|
|
829
838
|
return result;
|
|
830
839
|
}
|
|
@@ -867,8 +876,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
867
876
|
};
|
|
868
877
|
|
|
869
878
|
// src/client/crud/dialects/sqlite.ts
|
|
879
|
+
var import_common_helpers3 = require("@zenstackhq/common-helpers");
|
|
870
880
|
var import_kysely3 = require("kysely");
|
|
871
|
-
var import_tiny_invariant3 = __toESM(require("tiny-invariant"), 1);
|
|
872
881
|
var import_ts_pattern3 = require("ts-pattern");
|
|
873
882
|
var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
874
883
|
static {
|
|
@@ -877,14 +886,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
877
886
|
get provider() {
|
|
878
887
|
return "sqlite";
|
|
879
888
|
}
|
|
880
|
-
transformPrimitive(value, type) {
|
|
889
|
+
transformPrimitive(value, type, _forArrayField) {
|
|
881
890
|
if (value === void 0) {
|
|
882
891
|
return value;
|
|
883
892
|
}
|
|
884
893
|
if (Array.isArray(value)) {
|
|
885
|
-
return value.map((v) => this.transformPrimitive(v, type));
|
|
894
|
+
return value.map((v) => this.transformPrimitive(v, type, false));
|
|
886
895
|
} else {
|
|
887
|
-
return (0, import_ts_pattern3.match)(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).otherwise(() => value);
|
|
896
|
+
return (0, import_ts_pattern3.match)(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);
|
|
888
897
|
}
|
|
889
898
|
}
|
|
890
899
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
@@ -915,8 +924,8 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
915
924
|
if (m2m) {
|
|
916
925
|
const parentIds = getIdFields(this.schema, model);
|
|
917
926
|
const relationIds = getIdFields(this.schema, relationModel);
|
|
918
|
-
(0,
|
|
919
|
-
(0,
|
|
927
|
+
(0, import_common_helpers3.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
928
|
+
(0, import_common_helpers3.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
920
929
|
subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentName}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
|
|
921
930
|
} else {
|
|
922
931
|
const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
|
|
@@ -1412,12 +1421,12 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
|
|
|
1412
1421
|
};
|
|
1413
1422
|
|
|
1414
1423
|
// src/plugins/policy/expression-transformer.ts
|
|
1424
|
+
var import_common_helpers5 = require("@zenstackhq/common-helpers");
|
|
1415
1425
|
var import_kysely6 = require("kysely");
|
|
1416
|
-
var import_tiny_invariant5 = __toESM(require("tiny-invariant"), 1);
|
|
1417
1426
|
var import_ts_pattern6 = require("ts-pattern");
|
|
1418
1427
|
|
|
1419
1428
|
// src/plugins/policy/expression-evaluator.ts
|
|
1420
|
-
var
|
|
1429
|
+
var import_common_helpers4 = require("@zenstackhq/common-helpers");
|
|
1421
1430
|
var import_ts_pattern5 = require("ts-pattern");
|
|
1422
1431
|
var ExpressionEvaluator = class {
|
|
1423
1432
|
static {
|
|
@@ -1461,18 +1470,18 @@ var ExpressionEvaluator = class {
|
|
|
1461
1470
|
const right = this.evaluate(expr2.right, context);
|
|
1462
1471
|
return (0, import_ts_pattern5.match)(expr2.op).with("==", () => left === right).with("!=", () => left !== right).with(">", () => left > right).with(">=", () => left >= right).with("<", () => left < right).with("<=", () => left <= right).with("&&", () => left && right).with("||", () => left || right).with("in", () => {
|
|
1463
1472
|
const _right = right ?? [];
|
|
1464
|
-
(0,
|
|
1473
|
+
(0, import_common_helpers4.invariant)(Array.isArray(_right), 'expected array for "in" operator');
|
|
1465
1474
|
return _right.includes(left);
|
|
1466
1475
|
}).exhaustive();
|
|
1467
1476
|
}
|
|
1468
1477
|
evaluateCollectionPredicate(expr2, context) {
|
|
1469
1478
|
const op = expr2.op;
|
|
1470
|
-
(0,
|
|
1479
|
+
(0, import_common_helpers4.invariant)(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
|
|
1471
1480
|
const left = this.evaluate(expr2.left, context);
|
|
1472
1481
|
if (!left) {
|
|
1473
1482
|
return false;
|
|
1474
1483
|
}
|
|
1475
|
-
(0,
|
|
1484
|
+
(0, import_common_helpers4.invariant)(Array.isArray(left), "expected array");
|
|
1476
1485
|
return (0, import_ts_pattern5.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
|
|
1477
1486
|
...context,
|
|
1478
1487
|
thisValue: item
|
|
@@ -1489,11 +1498,11 @@ var ExpressionEvaluator = class {
|
|
|
1489
1498
|
// src/plugins/policy/utils.ts
|
|
1490
1499
|
var import_kysely5 = require("kysely");
|
|
1491
1500
|
function trueNode(dialect) {
|
|
1492
|
-
return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
|
|
1501
|
+
return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
|
|
1493
1502
|
}
|
|
1494
1503
|
__name(trueNode, "trueNode");
|
|
1495
1504
|
function falseNode(dialect) {
|
|
1496
|
-
return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
|
|
1505
|
+
return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
|
|
1497
1506
|
}
|
|
1498
1507
|
__name(falseNode, "falseNode");
|
|
1499
1508
|
function isTrueNode(node) {
|
|
@@ -1694,20 +1703,20 @@ var ExpressionTransformer = class {
|
|
|
1694
1703
|
return import_kysely6.BinaryOperationNode.create(left, this.transformOperator(op), right);
|
|
1695
1704
|
}
|
|
1696
1705
|
transformCollectionPredicate(expr2, context) {
|
|
1697
|
-
(0,
|
|
1706
|
+
(0, import_common_helpers5.invariant)(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
|
|
1698
1707
|
if (this.isAuthCall(expr2.left) || this.isAuthMember(expr2.left)) {
|
|
1699
1708
|
const value = new ExpressionEvaluator().evaluate(expr2, {
|
|
1700
1709
|
auth: this.auth
|
|
1701
1710
|
});
|
|
1702
1711
|
return this.transformValue(value, "Boolean");
|
|
1703
1712
|
}
|
|
1704
|
-
(0,
|
|
1713
|
+
(0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
|
|
1705
1714
|
let newContextModel;
|
|
1706
1715
|
if (ExpressionUtils.isField(expr2.left)) {
|
|
1707
1716
|
const fieldDef = requireField(this.schema, context.model, expr2.left.field);
|
|
1708
1717
|
newContextModel = fieldDef.type;
|
|
1709
1718
|
} else {
|
|
1710
|
-
(0,
|
|
1719
|
+
(0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.left.receiver));
|
|
1711
1720
|
const fieldDef = requireField(this.schema, context.model, expr2.left.receiver.field);
|
|
1712
1721
|
newContextModel = fieldDef.type;
|
|
1713
1722
|
for (const member of expr2.left.members) {
|
|
@@ -1751,10 +1760,10 @@ var ExpressionTransformer = class {
|
|
|
1751
1760
|
}
|
|
1752
1761
|
}
|
|
1753
1762
|
transformValue(value, type) {
|
|
1754
|
-
return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type) ?? null);
|
|
1763
|
+
return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type, false) ?? null);
|
|
1755
1764
|
}
|
|
1756
1765
|
_unary(expr2, context) {
|
|
1757
|
-
(0,
|
|
1766
|
+
(0, import_common_helpers5.invariant)(expr2.op === "!", 'only "!" operator is supported');
|
|
1758
1767
|
return import_kysely6.BinaryOperationNode.create(this.transform(expr2.operand, context), this.transformOperator("!="), trueNode(this.dialect));
|
|
1759
1768
|
}
|
|
1760
1769
|
transformOperator(op) {
|
|
@@ -1797,10 +1806,10 @@ var ExpressionTransformer = class {
|
|
|
1797
1806
|
if (this.isAuthCall(expr2.receiver)) {
|
|
1798
1807
|
return this.valueMemberAccess(this.auth, expr2, this.authType);
|
|
1799
1808
|
}
|
|
1800
|
-
(0,
|
|
1809
|
+
(0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.receiver), "expect receiver to be field expression");
|
|
1801
1810
|
const { memberFilter, memberSelect, ...restContext } = context;
|
|
1802
1811
|
const receiver = this.transform(expr2.receiver, restContext);
|
|
1803
|
-
(0,
|
|
1812
|
+
(0, import_common_helpers5.invariant)(import_kysely6.SelectQueryNode.is(receiver), "expected receiver to be select query");
|
|
1804
1813
|
const receiverField = requireField(this.schema, context.model, expr2.receiver.field);
|
|
1805
1814
|
const memberFields = [];
|
|
1806
1815
|
let currType = receiverField.type;
|
|
@@ -1824,7 +1833,7 @@ var ExpressionTransformer = class {
|
|
|
1824
1833
|
thisEntity: void 0
|
|
1825
1834
|
});
|
|
1826
1835
|
if (currNode) {
|
|
1827
|
-
(0,
|
|
1836
|
+
(0, import_common_helpers5.invariant)(import_kysely6.SelectQueryNode.is(currNode), "expected select query node");
|
|
1828
1837
|
currNode = {
|
|
1829
1838
|
...relation,
|
|
1830
1839
|
selections: [
|
|
@@ -1841,8 +1850,8 @@ var ExpressionTransformer = class {
|
|
|
1841
1850
|
};
|
|
1842
1851
|
}
|
|
1843
1852
|
} else {
|
|
1844
|
-
(0,
|
|
1845
|
-
(0,
|
|
1853
|
+
(0, import_common_helpers5.invariant)(i === expr2.members.length - 1, "plain field access must be the last segment");
|
|
1854
|
+
(0, import_common_helpers5.invariant)(!currNode, "plain field access must be the last segment");
|
|
1846
1855
|
currNode = import_kysely6.ColumnNode.create(member);
|
|
1847
1856
|
}
|
|
1848
1857
|
}
|
|
@@ -1994,7 +2003,7 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
|
|
|
1994
2003
|
get kysely() {
|
|
1995
2004
|
return this.client.$qb;
|
|
1996
2005
|
}
|
|
1997
|
-
async handle(node, proceed
|
|
2006
|
+
async handle(node, proceed) {
|
|
1998
2007
|
if (!this.isCrudQueryNode(node)) {
|
|
1999
2008
|
throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
|
|
2000
2009
|
}
|
|
@@ -2014,27 +2023,20 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
|
|
|
2014
2023
|
if (!mutationRequiresTransaction && !node.returning) {
|
|
2015
2024
|
return proceed(this.transformNode(node));
|
|
2016
2025
|
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
const
|
|
2024
|
-
if (
|
|
2025
|
-
|
|
2026
|
-
if (readBackResult.rows.length !== result2.rows.length) {
|
|
2027
|
-
readBackError = true;
|
|
2028
|
-
}
|
|
2029
|
-
return readBackResult;
|
|
2030
|
-
} else {
|
|
2031
|
-
return result2;
|
|
2026
|
+
if (import_kysely7.InsertQueryNode.is(node)) {
|
|
2027
|
+
await this.enforcePreCreatePolicy(node, proceed);
|
|
2028
|
+
}
|
|
2029
|
+
const transformedNode = this.transformNode(node);
|
|
2030
|
+
const result = await proceed(transformedNode);
|
|
2031
|
+
if (!this.onlyReturningId(node)) {
|
|
2032
|
+
const readBackResult = await this.processReadBack(node, result, proceed);
|
|
2033
|
+
if (readBackResult.rows.length !== result.rows.length) {
|
|
2034
|
+
throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
|
|
2032
2035
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
+
return readBackResult;
|
|
2037
|
+
} else {
|
|
2038
|
+
return result;
|
|
2036
2039
|
}
|
|
2037
|
-
return result;
|
|
2038
2040
|
}
|
|
2039
2041
|
onlyReturningId(node) {
|
|
2040
2042
|
if (!node.returning) {
|
|
@@ -2087,19 +2089,19 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
|
|
|
2087
2089
|
}
|
|
2088
2090
|
}
|
|
2089
2091
|
unwrapCreateValueRow(data, model, fields) {
|
|
2090
|
-
(0,
|
|
2092
|
+
(0, import_common_helpers6.invariant)(data.length === fields.length, "data length must match fields length");
|
|
2091
2093
|
const result = [];
|
|
2092
2094
|
for (let i = 0; i < data.length; i++) {
|
|
2093
2095
|
const item = data[i];
|
|
2094
2096
|
const fieldDef = requireField(this.client.$schema, model, fields[i]);
|
|
2095
2097
|
if (typeof item === "object" && item && "kind" in item) {
|
|
2096
|
-
(0,
|
|
2098
|
+
(0, import_common_helpers6.invariant)(item.kind === "ValueNode", "expecting a ValueNode");
|
|
2097
2099
|
result.push({
|
|
2098
|
-
node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
|
|
2100
|
+
node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
|
|
2099
2101
|
raw: item.value
|
|
2100
2102
|
});
|
|
2101
2103
|
} else {
|
|
2102
|
-
const value = this.dialect.transformPrimitive(item, fieldDef.type);
|
|
2104
|
+
const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
|
|
2103
2105
|
if (Array.isArray(value)) {
|
|
2104
2106
|
result.push({
|
|
2105
2107
|
node: import_kysely7.RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
|
|
@@ -2301,8 +2303,8 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
|
|
|
2301
2303
|
const modelDef = requireModel(this.client.$schema, modelName);
|
|
2302
2304
|
const result = [];
|
|
2303
2305
|
const extractOperations = /* @__PURE__ */ __name((expr2) => {
|
|
2304
|
-
(0,
|
|
2305
|
-
(0,
|
|
2306
|
+
(0, import_common_helpers6.invariant)(ExpressionUtils.isLiteral(expr2), "expecting a literal");
|
|
2307
|
+
(0, import_common_helpers6.invariant)(typeof expr2.value === "string", "expecting a string literal");
|
|
2306
2308
|
return expr2.value.split(",").filter((v) => !!v).map((v) => v.trim());
|
|
2307
2309
|
}, "extractOperations");
|
|
2308
2310
|
if (modelDef.attributes) {
|
|
@@ -2330,9 +2332,18 @@ var PolicyPlugin = class {
|
|
|
2330
2332
|
get description() {
|
|
2331
2333
|
return "Enforces access policies defined in the schema.";
|
|
2332
2334
|
}
|
|
2333
|
-
onKyselyQuery({
|
|
2335
|
+
onKyselyQuery({
|
|
2336
|
+
query,
|
|
2337
|
+
client,
|
|
2338
|
+
proceed
|
|
2339
|
+
/*, transaction*/
|
|
2340
|
+
}) {
|
|
2334
2341
|
const handler = new PolicyHandler(client);
|
|
2335
|
-
return handler.handle(
|
|
2342
|
+
return handler.handle(
|
|
2343
|
+
query,
|
|
2344
|
+
proceed
|
|
2345
|
+
/*, transaction*/
|
|
2346
|
+
);
|
|
2336
2347
|
}
|
|
2337
2348
|
};
|
|
2338
2349
|
// Annotate the CommonJS export names for ESM import in node:
|