@zenstackhq/runtime 3.0.0-alpha.2 → 3.0.0-alpha.21
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-D8U59Syb.d.cts} +971 -785
- package/dist/{contract-DguafRNB.d.ts → contract-D8U59Syb.d.ts} +971 -785
- 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 +1787 -903
- 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 +1758 -879
- package/dist/index.js.map +1 -1
- package/dist/plugins/{policy.cjs → policy/index.cjs} +472 -271
- package/dist/plugins/policy/index.cjs.map +1 -0
- package/dist/plugins/{policy.d.ts → policy/index.d.cts} +2 -4
- package/dist/plugins/{policy.d.cts → policy/index.d.ts} +2 -4
- package/dist/plugins/{policy.js → policy/index.js} +447 -236
- package/dist/plugins/policy/index.js.map +1 -0
- package/dist/plugins/policy/plugin.zmodel +33 -0
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.js.map +1 -1
- package/package.json +27 -49
- 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/plugins/policy.cjs.map +0 -1
- package/dist/plugins/policy.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
|
@@ -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,34 +39,130 @@ 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
|
|
54
|
-
var import_ts_pattern7 = require("ts-pattern");
|
|
44
|
+
var import_ts_pattern8 = require("ts-pattern");
|
|
55
45
|
|
|
56
46
|
// src/client/crud/dialects/index.ts
|
|
57
|
-
var
|
|
47
|
+
var import_ts_pattern5 = 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
|
|
62
|
-
|
|
52
|
+
var import_ts_pattern3 = require("ts-pattern");
|
|
53
|
+
|
|
54
|
+
// src/client/constants.ts
|
|
55
|
+
var DELEGATE_JOINED_FIELD_PREFIX = "$delegate$";
|
|
56
|
+
var LOGICAL_COMBINATORS = [
|
|
57
|
+
"AND",
|
|
58
|
+
"OR",
|
|
59
|
+
"NOT"
|
|
60
|
+
];
|
|
61
|
+
var AGGREGATE_OPERATORS = [
|
|
62
|
+
"_count",
|
|
63
|
+
"_sum",
|
|
64
|
+
"_avg",
|
|
65
|
+
"_min",
|
|
66
|
+
"_max"
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
// src/client/query-utils.ts
|
|
70
|
+
var import_ts_pattern = require("ts-pattern");
|
|
71
|
+
|
|
72
|
+
// src/schema/expression.ts
|
|
73
|
+
var ExpressionUtils = {
|
|
74
|
+
literal: /* @__PURE__ */ __name((value) => {
|
|
75
|
+
return {
|
|
76
|
+
kind: "literal",
|
|
77
|
+
value
|
|
78
|
+
};
|
|
79
|
+
}, "literal"),
|
|
80
|
+
array: /* @__PURE__ */ __name((items) => {
|
|
81
|
+
return {
|
|
82
|
+
kind: "array",
|
|
83
|
+
items
|
|
84
|
+
};
|
|
85
|
+
}, "array"),
|
|
86
|
+
call: /* @__PURE__ */ __name((functionName, args) => {
|
|
87
|
+
return {
|
|
88
|
+
kind: "call",
|
|
89
|
+
function: functionName,
|
|
90
|
+
args
|
|
91
|
+
};
|
|
92
|
+
}, "call"),
|
|
93
|
+
binary: /* @__PURE__ */ __name((left, op, right) => {
|
|
94
|
+
return {
|
|
95
|
+
kind: "binary",
|
|
96
|
+
op,
|
|
97
|
+
left,
|
|
98
|
+
right
|
|
99
|
+
};
|
|
100
|
+
}, "binary"),
|
|
101
|
+
unary: /* @__PURE__ */ __name((op, operand) => {
|
|
102
|
+
return {
|
|
103
|
+
kind: "unary",
|
|
104
|
+
op,
|
|
105
|
+
operand
|
|
106
|
+
};
|
|
107
|
+
}, "unary"),
|
|
108
|
+
field: /* @__PURE__ */ __name((field) => {
|
|
109
|
+
return {
|
|
110
|
+
kind: "field",
|
|
111
|
+
field
|
|
112
|
+
};
|
|
113
|
+
}, "field"),
|
|
114
|
+
member: /* @__PURE__ */ __name((receiver, members) => {
|
|
115
|
+
return {
|
|
116
|
+
kind: "member",
|
|
117
|
+
receiver,
|
|
118
|
+
members
|
|
119
|
+
};
|
|
120
|
+
}, "member"),
|
|
121
|
+
_this: /* @__PURE__ */ __name(() => {
|
|
122
|
+
return {
|
|
123
|
+
kind: "this"
|
|
124
|
+
};
|
|
125
|
+
}, "_this"),
|
|
126
|
+
_null: /* @__PURE__ */ __name(() => {
|
|
127
|
+
return {
|
|
128
|
+
kind: "null"
|
|
129
|
+
};
|
|
130
|
+
}, "_null"),
|
|
131
|
+
and: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
132
|
+
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
|
|
133
|
+
}, "and"),
|
|
134
|
+
or: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
135
|
+
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
|
|
136
|
+
}, "or"),
|
|
137
|
+
is: /* @__PURE__ */ __name((value, kind) => {
|
|
138
|
+
return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
|
|
139
|
+
}, "is"),
|
|
140
|
+
isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
|
|
141
|
+
isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
|
|
142
|
+
isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
|
|
143
|
+
isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
|
|
144
|
+
isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
|
|
145
|
+
isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
|
|
146
|
+
isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
|
|
147
|
+
isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
|
|
148
|
+
isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
|
|
149
|
+
};
|
|
63
150
|
|
|
64
151
|
// src/client/errors.ts
|
|
65
152
|
var QueryError = class extends Error {
|
|
66
153
|
static {
|
|
67
154
|
__name(this, "QueryError");
|
|
68
155
|
}
|
|
69
|
-
constructor(message) {
|
|
70
|
-
super(message
|
|
156
|
+
constructor(message, cause) {
|
|
157
|
+
super(message, {
|
|
158
|
+
cause
|
|
159
|
+
});
|
|
71
160
|
}
|
|
72
161
|
};
|
|
73
162
|
var InternalError = class extends Error {
|
|
74
163
|
static {
|
|
75
164
|
__name(this, "InternalError");
|
|
76
165
|
}
|
|
77
|
-
constructor(message) {
|
|
78
|
-
super(message);
|
|
79
|
-
}
|
|
80
166
|
};
|
|
81
167
|
|
|
82
168
|
// src/client/query-utils.ts
|
|
@@ -87,7 +173,7 @@ __name(getModel, "getModel");
|
|
|
87
173
|
function requireModel(schema, model) {
|
|
88
174
|
const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
|
|
89
175
|
if (!matchedName) {
|
|
90
|
-
throw new QueryError(`Model "${model}" not found`);
|
|
176
|
+
throw new QueryError(`Model "${model}" not found in schema`);
|
|
91
177
|
}
|
|
92
178
|
return schema.models[matchedName];
|
|
93
179
|
}
|
|
@@ -150,6 +236,16 @@ function getRelationForeignKeyFieldPairs(schema, model, relationField) {
|
|
|
150
236
|
}
|
|
151
237
|
}
|
|
152
238
|
__name(getRelationForeignKeyFieldPairs, "getRelationForeignKeyFieldPairs");
|
|
239
|
+
function isRelationField(schema, model, field) {
|
|
240
|
+
const fieldDef = getField(schema, model, field);
|
|
241
|
+
return !!fieldDef?.relation;
|
|
242
|
+
}
|
|
243
|
+
__name(isRelationField, "isRelationField");
|
|
244
|
+
function isInheritedField(schema, model, field) {
|
|
245
|
+
const fieldDef = getField(schema, model, field);
|
|
246
|
+
return !!fieldDef?.originModel;
|
|
247
|
+
}
|
|
248
|
+
__name(isInheritedField, "isInheritedField");
|
|
153
249
|
function getUniqueFields(schema, model) {
|
|
154
250
|
const modelDef = requireModel(schema, model);
|
|
155
251
|
const result = [];
|
|
@@ -186,7 +282,7 @@ function buildFieldRef(schema, model, field, options, eb, modelAlias) {
|
|
|
186
282
|
computer = computedFields?.[model]?.[field];
|
|
187
283
|
}
|
|
188
284
|
if (!computer) {
|
|
189
|
-
throw new QueryError(`Computed field "${field}" implementation not provided`);
|
|
285
|
+
throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
|
|
190
286
|
}
|
|
191
287
|
return computer(eb);
|
|
192
288
|
}
|
|
@@ -263,11 +359,28 @@ function flattenCompoundUniqueFilters(schema, model, filter) {
|
|
|
263
359
|
return result;
|
|
264
360
|
}
|
|
265
361
|
__name(flattenCompoundUniqueFilters, "flattenCompoundUniqueFilters");
|
|
362
|
+
function getDelegateDescendantModels(schema, model, collected = /* @__PURE__ */ new Set()) {
|
|
363
|
+
const subModels = Object.values(schema.models).filter((m) => m.baseModel === model);
|
|
364
|
+
subModels.forEach((def) => {
|
|
365
|
+
if (!collected.has(def)) {
|
|
366
|
+
collected.add(def);
|
|
367
|
+
getDelegateDescendantModels(schema, def.name, collected);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
return [
|
|
371
|
+
...collected
|
|
372
|
+
];
|
|
373
|
+
}
|
|
374
|
+
__name(getDelegateDescendantModels, "getDelegateDescendantModels");
|
|
375
|
+
function aggregate(eb, expr2, op) {
|
|
376
|
+
return (0, import_ts_pattern.match)(op).with("_count", () => eb.fn.count(expr2)).with("_sum", () => eb.fn.sum(expr2)).with("_avg", () => eb.fn.avg(expr2)).with("_min", () => eb.fn.min(expr2)).with("_max", () => eb.fn.max(expr2)).exhaustive();
|
|
377
|
+
}
|
|
378
|
+
__name(aggregate, "aggregate");
|
|
266
379
|
|
|
267
380
|
// src/client/crud/dialects/base.ts
|
|
381
|
+
var import_common_helpers = require("@zenstackhq/common-helpers");
|
|
268
382
|
var import_kysely = require("kysely");
|
|
269
|
-
var
|
|
270
|
-
var import_ts_pattern = require("ts-pattern");
|
|
383
|
+
var import_ts_pattern2 = require("ts-pattern");
|
|
271
384
|
|
|
272
385
|
// src/utils/enumerate.ts
|
|
273
386
|
function enumerate(x) {
|
|
@@ -284,7 +397,6 @@ function enumerate(x) {
|
|
|
284
397
|
__name(enumerate, "enumerate");
|
|
285
398
|
|
|
286
399
|
// src/client/crud/dialects/base.ts
|
|
287
|
-
var import_is_plain_object = require("is-plain-object");
|
|
288
400
|
var BaseCrudDialect = class {
|
|
289
401
|
static {
|
|
290
402
|
__name(this, "BaseCrudDialect");
|
|
@@ -295,9 +407,20 @@ var BaseCrudDialect = class {
|
|
|
295
407
|
this.schema = schema;
|
|
296
408
|
this.options = options;
|
|
297
409
|
}
|
|
298
|
-
transformPrimitive(value, _type) {
|
|
410
|
+
transformPrimitive(value, _type, _forArrayField) {
|
|
299
411
|
return value;
|
|
300
412
|
}
|
|
413
|
+
// #region common query builders
|
|
414
|
+
buildSelectModel(eb, model) {
|
|
415
|
+
const modelDef = requireModel(this.schema, model);
|
|
416
|
+
let result = eb.selectFrom(model);
|
|
417
|
+
let joinBase = modelDef.baseModel;
|
|
418
|
+
while (joinBase) {
|
|
419
|
+
result = this.buildDelegateJoin(model, joinBase, result);
|
|
420
|
+
joinBase = requireModel(this.schema, joinBase).baseModel;
|
|
421
|
+
}
|
|
422
|
+
return result;
|
|
423
|
+
}
|
|
301
424
|
buildFilter(eb, model, modelAlias, where) {
|
|
302
425
|
if (where === true || where === void 0) {
|
|
303
426
|
return this.true(eb);
|
|
@@ -314,17 +437,20 @@ var BaseCrudDialect = class {
|
|
|
314
437
|
if (key.startsWith("$")) {
|
|
315
438
|
continue;
|
|
316
439
|
}
|
|
317
|
-
if (key
|
|
440
|
+
if (this.isLogicalCombinator(key)) {
|
|
318
441
|
result = this.and(eb, result, this.buildCompositeFilter(eb, model, modelAlias, key, payload));
|
|
319
442
|
continue;
|
|
320
443
|
}
|
|
321
444
|
const fieldDef = requireField(this.schema, model, key);
|
|
322
445
|
if (fieldDef.relation) {
|
|
323
446
|
result = this.and(eb, result, this.buildRelationFilter(eb, model, modelAlias, key, fieldDef, payload));
|
|
324
|
-
} else if (fieldDef.array) {
|
|
325
|
-
result = this.and(eb, result, this.buildArrayFilter(eb, model, modelAlias, key, fieldDef, payload));
|
|
326
447
|
} else {
|
|
327
|
-
|
|
448
|
+
const fieldRef = this.fieldRef(fieldDef.originModel ?? model, key, eb, fieldDef.originModel ?? modelAlias);
|
|
449
|
+
if (fieldDef.array) {
|
|
450
|
+
result = this.and(eb, result, this.buildArrayFilter(eb, fieldRef, fieldDef, payload));
|
|
451
|
+
} else {
|
|
452
|
+
result = this.and(eb, result, this.buildPrimitiveFilter(eb, fieldRef, fieldDef, payload));
|
|
453
|
+
}
|
|
328
454
|
}
|
|
329
455
|
}
|
|
330
456
|
if ("$expr" in _where && typeof _where["$expr"] === "function") {
|
|
@@ -332,8 +458,11 @@ var BaseCrudDialect = class {
|
|
|
332
458
|
}
|
|
333
459
|
return result;
|
|
334
460
|
}
|
|
461
|
+
isLogicalCombinator(key) {
|
|
462
|
+
return LOGICAL_COMBINATORS.includes(key);
|
|
463
|
+
}
|
|
335
464
|
buildCompositeFilter(eb, model, modelAlias, key, payload) {
|
|
336
|
-
return (0,
|
|
465
|
+
return (0, import_ts_pattern2.match)(key).with("AND", () => this.and(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("OR", () => this.or(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("NOT", () => eb.not(this.buildCompositeFilter(eb, model, modelAlias, "AND", payload))).exhaustive();
|
|
337
466
|
}
|
|
338
467
|
buildRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
|
|
339
468
|
if (!fieldDef.array) {
|
|
@@ -342,19 +471,26 @@ var BaseCrudDialect = class {
|
|
|
342
471
|
return this.buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload);
|
|
343
472
|
}
|
|
344
473
|
}
|
|
345
|
-
buildToOneRelationFilter(eb, model,
|
|
474
|
+
buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
|
|
346
475
|
if (payload === null) {
|
|
347
476
|
const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, model, field);
|
|
348
|
-
if (ownedByModel) {
|
|
349
|
-
return this.and(eb, ...keyPairs.map(({ fk }) => eb(import_kysely.sql.ref(`${
|
|
477
|
+
if (ownedByModel && !fieldDef.originModel) {
|
|
478
|
+
return this.and(eb, ...keyPairs.map(({ fk }) => eb(import_kysely.sql.ref(`${modelAlias}.${fk}`), "is", null)));
|
|
350
479
|
} else {
|
|
351
|
-
return this.buildToOneRelationFilter(eb, model,
|
|
480
|
+
return this.buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, {
|
|
352
481
|
is: null
|
|
353
482
|
});
|
|
354
483
|
}
|
|
355
484
|
}
|
|
356
|
-
const joinAlias = `${
|
|
357
|
-
const joinPairs = buildJoinPairs(
|
|
485
|
+
const joinAlias = `${modelAlias}$${field}`;
|
|
486
|
+
const joinPairs = buildJoinPairs(
|
|
487
|
+
this.schema,
|
|
488
|
+
model,
|
|
489
|
+
// if field is from a base, use the base model to join
|
|
490
|
+
fieldDef.originModel ?? modelAlias,
|
|
491
|
+
field,
|
|
492
|
+
joinAlias
|
|
493
|
+
);
|
|
358
494
|
const filterResultField = `${field}$filter`;
|
|
359
495
|
const joinSelect = eb.selectFrom(`${fieldDef.type} as ${joinAlias}`).where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely.sql.ref(left), "=", import_kysely.sql.ref(right))))).select(() => eb.fn.count(eb.lit(1)).as(filterResultField));
|
|
360
496
|
const conditions = [];
|
|
@@ -415,30 +551,29 @@ var BaseCrudDialect = class {
|
|
|
415
551
|
}
|
|
416
552
|
switch (key) {
|
|
417
553
|
case "some": {
|
|
418
|
-
result = this.and(eb, result, eb(
|
|
554
|
+
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));
|
|
419
555
|
break;
|
|
420
556
|
}
|
|
421
557
|
case "every": {
|
|
422
|
-
result = this.and(eb, result, eb(
|
|
558
|
+
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));
|
|
423
559
|
break;
|
|
424
560
|
}
|
|
425
561
|
case "none": {
|
|
426
|
-
result = this.and(eb, result, eb(
|
|
562
|
+
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));
|
|
427
563
|
break;
|
|
428
564
|
}
|
|
429
565
|
}
|
|
430
566
|
}
|
|
431
567
|
return result;
|
|
432
568
|
}
|
|
433
|
-
buildArrayFilter(eb,
|
|
569
|
+
buildArrayFilter(eb, fieldRef, fieldDef, payload) {
|
|
434
570
|
const clauses = [];
|
|
435
571
|
const fieldType = fieldDef.type;
|
|
436
|
-
const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb, modelAlias);
|
|
437
572
|
for (const [key, _value] of Object.entries(payload)) {
|
|
438
573
|
if (_value === void 0) {
|
|
439
574
|
continue;
|
|
440
575
|
}
|
|
441
|
-
const value = this.transformPrimitive(_value, fieldType);
|
|
576
|
+
const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
|
|
442
577
|
switch (key) {
|
|
443
578
|
case "equals": {
|
|
444
579
|
clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
|
|
@@ -469,20 +604,24 @@ var BaseCrudDialect = class {
|
|
|
469
604
|
}
|
|
470
605
|
return this.and(eb, ...clauses);
|
|
471
606
|
}
|
|
472
|
-
buildPrimitiveFilter(eb,
|
|
607
|
+
buildPrimitiveFilter(eb, fieldRef, fieldDef, payload) {
|
|
473
608
|
if (payload === null) {
|
|
474
|
-
return eb(
|
|
609
|
+
return eb(fieldRef, "is", null);
|
|
475
610
|
}
|
|
476
611
|
if (isEnum(this.schema, fieldDef.type)) {
|
|
477
|
-
return this.buildEnumFilter(eb,
|
|
612
|
+
return this.buildEnumFilter(eb, fieldRef, fieldDef, payload);
|
|
478
613
|
}
|
|
479
|
-
return (0,
|
|
614
|
+
return (0, import_ts_pattern2.match)(fieldDef.type).with("String", () => this.buildStringFilter(eb, fieldRef, payload)).with(import_ts_pattern2.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", () => {
|
|
615
|
+
throw new InternalError("JSON filters are not supported yet");
|
|
616
|
+
}).with("Unsupported", () => {
|
|
617
|
+
throw new QueryError(`Unsupported field cannot be used in filters`);
|
|
618
|
+
}).exhaustive();
|
|
480
619
|
}
|
|
481
620
|
buildLiteralFilter(eb, lhs, type, rhs) {
|
|
482
|
-
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type) : rhs);
|
|
621
|
+
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
|
|
483
622
|
}
|
|
484
|
-
buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
|
|
485
|
-
if (payload === null || !(0,
|
|
623
|
+
buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0, excludeKeys = []) {
|
|
624
|
+
if (payload === null || !(0, import_common_helpers.isPlainObject)(payload)) {
|
|
486
625
|
return {
|
|
487
626
|
conditions: [
|
|
488
627
|
this.buildLiteralFilter(eb, lhs, type, payload)
|
|
@@ -496,22 +635,29 @@ var BaseCrudDialect = class {
|
|
|
496
635
|
if (onlyForKeys && !onlyForKeys.includes(op)) {
|
|
497
636
|
continue;
|
|
498
637
|
}
|
|
638
|
+
if (excludeKeys.includes(op)) {
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
499
641
|
const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
|
|
500
|
-
const condition = (0,
|
|
501
|
-
(0,
|
|
642
|
+
const condition = (0, import_ts_pattern2.match)(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
|
|
643
|
+
(0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
|
|
502
644
|
if (rhs.length === 0) {
|
|
503
645
|
return this.false(eb);
|
|
504
646
|
} else {
|
|
505
647
|
return eb(lhs, "in", rhs);
|
|
506
648
|
}
|
|
507
649
|
}).with("notIn", () => {
|
|
508
|
-
(0,
|
|
650
|
+
(0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
|
|
509
651
|
if (rhs.length === 0) {
|
|
510
652
|
return this.true(eb);
|
|
511
653
|
} else {
|
|
512
654
|
return eb.not(eb(lhs, "in", rhs));
|
|
513
655
|
}
|
|
514
|
-
}).with("lt", () => eb(lhs, "<", rhs)).with("lte", () => eb(lhs, "<=", rhs)).with("gt", () => eb(lhs, ">", rhs)).with("gte", () => eb(lhs, ">=", rhs)).with("not", () => eb.not(recurse(value))).
|
|
656
|
+
}).with("lt", () => eb(lhs, "<", rhs)).with("lte", () => eb(lhs, "<=", rhs)).with("gt", () => eb(lhs, ">", rhs)).with("gte", () => eb(lhs, ">=", rhs)).with("not", () => eb.not(recurse(value))).with(import_ts_pattern2.P.union(...AGGREGATE_OPERATORS), (op2) => {
|
|
657
|
+
const innerResult = this.buildStandardFilter(eb, type, value, aggregate(eb, lhs, op2), getRhs, recurse, throwIfInvalid);
|
|
658
|
+
consumedKeys.push(...innerResult.consumedKeys);
|
|
659
|
+
return this.and(eb, ...innerResult.conditions);
|
|
660
|
+
}).otherwise(() => {
|
|
515
661
|
if (throwIfInvalid) {
|
|
516
662
|
throw new QueryError(`Invalid filter key: ${op}`);
|
|
517
663
|
} else {
|
|
@@ -528,24 +674,21 @@ var BaseCrudDialect = class {
|
|
|
528
674
|
consumedKeys
|
|
529
675
|
};
|
|
530
676
|
}
|
|
531
|
-
buildStringFilter(eb,
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
if (payload && typeof payload === "object" && "mode" in payload && payload.mode === "insensitive") {
|
|
536
|
-
insensitive = true;
|
|
537
|
-
fieldRef = eb.fn("lower", [
|
|
538
|
-
fieldRef
|
|
539
|
-
]);
|
|
677
|
+
buildStringFilter(eb, fieldRef, payload) {
|
|
678
|
+
let mode;
|
|
679
|
+
if (payload && typeof payload === "object" && "mode" in payload) {
|
|
680
|
+
mode = payload.mode;
|
|
540
681
|
}
|
|
541
|
-
const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload,
|
|
682
|
+
const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, mode === "insensitive" ? eb.fn("lower", [
|
|
683
|
+
fieldRef
|
|
684
|
+
]) : fieldRef, (value) => this.prepStringCasing(eb, value, mode), (value) => this.buildStringFilter(eb, fieldRef, value));
|
|
542
685
|
if (payload && typeof payload === "object") {
|
|
543
686
|
for (const [key, value] of Object.entries(payload)) {
|
|
544
687
|
if (key === "mode" || consumedKeys.includes(key)) {
|
|
545
688
|
continue;
|
|
546
689
|
}
|
|
547
|
-
const condition = (0,
|
|
548
|
-
throw new
|
|
690
|
+
const condition = (0, import_ts_pattern2.match)(key).with("contains", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`%${value}%`)) : eb(fieldRef, "like", import_kysely.sql.val(`%${value}%`))).with("startsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`${value}%`)) : eb(fieldRef, "like", import_kysely.sql.val(`${value}%`))).with("endsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`%${value}`)) : eb(fieldRef, "like", import_kysely.sql.val(`%${value}`))).otherwise(() => {
|
|
691
|
+
throw new QueryError(`Invalid string filter key: ${key}`);
|
|
549
692
|
});
|
|
550
693
|
if (condition) {
|
|
551
694
|
conditions.push(condition);
|
|
@@ -554,34 +697,37 @@ var BaseCrudDialect = class {
|
|
|
554
697
|
}
|
|
555
698
|
return this.and(eb, ...conditions);
|
|
556
699
|
}
|
|
557
|
-
prepStringCasing(eb, value,
|
|
700
|
+
prepStringCasing(eb, value, mode) {
|
|
701
|
+
if (!mode || mode === "default") {
|
|
702
|
+
return value === null ? value : import_kysely.sql.val(value);
|
|
703
|
+
}
|
|
558
704
|
if (typeof value === "string") {
|
|
559
|
-
return
|
|
560
|
-
import_kysely.sql.
|
|
561
|
-
])
|
|
705
|
+
return eb.fn("lower", [
|
|
706
|
+
import_kysely.sql.val(value)
|
|
707
|
+
]);
|
|
562
708
|
} else if (Array.isArray(value)) {
|
|
563
|
-
return value.map((v) => this.prepStringCasing(eb, v,
|
|
709
|
+
return value.map((v) => this.prepStringCasing(eb, v, mode));
|
|
564
710
|
} else {
|
|
565
|
-
return value === null ? null : import_kysely.sql.
|
|
711
|
+
return value === null ? null : import_kysely.sql.val(value);
|
|
566
712
|
}
|
|
567
713
|
}
|
|
568
|
-
buildNumberFilter(eb,
|
|
569
|
-
const { conditions } = this.buildStandardFilter(eb, type, payload,
|
|
714
|
+
buildNumberFilter(eb, fieldRef, type, payload) {
|
|
715
|
+
const { conditions } = this.buildStandardFilter(eb, type, payload, fieldRef, (value) => this.transformPrimitive(value, type, false), (value) => this.buildNumberFilter(eb, fieldRef, type, value));
|
|
570
716
|
return this.and(eb, ...conditions);
|
|
571
717
|
}
|
|
572
|
-
buildBooleanFilter(eb,
|
|
573
|
-
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload,
|
|
718
|
+
buildBooleanFilter(eb, fieldRef, payload) {
|
|
719
|
+
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, fieldRef, (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, fieldRef, value), true, [
|
|
574
720
|
"equals",
|
|
575
721
|
"not"
|
|
576
722
|
]);
|
|
577
723
|
return this.and(eb, ...conditions);
|
|
578
724
|
}
|
|
579
|
-
buildDateTimeFilter(eb,
|
|
580
|
-
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload,
|
|
725
|
+
buildDateTimeFilter(eb, fieldRef, payload) {
|
|
726
|
+
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, fieldRef, (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, fieldRef, value), true);
|
|
581
727
|
return this.and(eb, ...conditions);
|
|
582
728
|
}
|
|
583
|
-
buildBytesFilter(eb,
|
|
584
|
-
const conditions = this.buildStandardFilter(eb, "Bytes", payload,
|
|
729
|
+
buildBytesFilter(eb, fieldRef, payload) {
|
|
730
|
+
const conditions = this.buildStandardFilter(eb, "Bytes", payload, fieldRef, (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, fieldRef, value), true, [
|
|
585
731
|
"equals",
|
|
586
732
|
"in",
|
|
587
733
|
"notIn",
|
|
@@ -589,8 +735,8 @@ var BaseCrudDialect = class {
|
|
|
589
735
|
]);
|
|
590
736
|
return this.and(eb, ...conditions.conditions);
|
|
591
737
|
}
|
|
592
|
-
buildEnumFilter(eb,
|
|
593
|
-
const conditions = this.buildStandardFilter(eb, "String", payload,
|
|
738
|
+
buildEnumFilter(eb, fieldRef, fieldDef, payload) {
|
|
739
|
+
const conditions = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => value, (value) => this.buildEnumFilter(eb, fieldRef, fieldDef, value), true, [
|
|
594
740
|
"equals",
|
|
595
741
|
"in",
|
|
596
742
|
"notIn",
|
|
@@ -619,21 +765,19 @@ var BaseCrudDialect = class {
|
|
|
619
765
|
"_min",
|
|
620
766
|
"_max"
|
|
621
767
|
].includes(field)) {
|
|
622
|
-
(0,
|
|
768
|
+
(0, import_common_helpers.invariant)(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
|
|
623
769
|
for (const [k, v] of Object.entries(value)) {
|
|
624
|
-
(0,
|
|
625
|
-
result = result.orderBy((eb) => eb.
|
|
626
|
-
import_kysely.sql.ref(k)
|
|
627
|
-
]), import_kysely.sql.raw(this.negateSort(v, negated)));
|
|
770
|
+
(0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
|
|
771
|
+
result = result.orderBy((eb) => aggregate(eb, this.fieldRef(model, k, eb, modelAlias), field), import_kysely.sql.raw(this.negateSort(v, negated)));
|
|
628
772
|
}
|
|
629
773
|
continue;
|
|
630
774
|
}
|
|
631
775
|
switch (field) {
|
|
632
776
|
case "_count": {
|
|
633
|
-
(0,
|
|
777
|
+
(0, import_common_helpers.invariant)(value && typeof value === "object", 'invalid orderBy value for field "_count"');
|
|
634
778
|
for (const [k, v] of Object.entries(value)) {
|
|
635
|
-
(0,
|
|
636
|
-
result = result.orderBy((eb) => eb.fn.count(
|
|
779
|
+
(0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
|
|
780
|
+
result = result.orderBy((eb) => eb.fn.count(this.fieldRef(model, k, eb, modelAlias)), import_kysely.sql.raw(this.negateSort(v, negated)));
|
|
637
781
|
}
|
|
638
782
|
continue;
|
|
639
783
|
}
|
|
@@ -642,10 +786,11 @@ var BaseCrudDialect = class {
|
|
|
642
786
|
}
|
|
643
787
|
const fieldDef = requireField(this.schema, model, field);
|
|
644
788
|
if (!fieldDef.relation) {
|
|
789
|
+
const fieldRef = this.fieldRef(model, field, (0, import_kysely.expressionBuilder)(), modelAlias);
|
|
645
790
|
if (value === "asc" || value === "desc") {
|
|
646
|
-
result = result.orderBy(
|
|
791
|
+
result = result.orderBy(fieldRef, this.negateSort(value, negated));
|
|
647
792
|
} else if (value && typeof value === "object" && "nulls" in value && "sort" in value && (value.sort === "asc" || value.sort === "desc") && (value.nulls === "first" || value.nulls === "last")) {
|
|
648
|
-
result = result.orderBy(
|
|
793
|
+
result = result.orderBy(fieldRef, import_kysely.sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`));
|
|
649
794
|
}
|
|
650
795
|
} else {
|
|
651
796
|
const relationModel = fieldDef.type;
|
|
@@ -654,10 +799,10 @@ var BaseCrudDialect = class {
|
|
|
654
799
|
throw new QueryError(`invalid orderBy value for field "${field}"`);
|
|
655
800
|
}
|
|
656
801
|
if ("_count" in value) {
|
|
657
|
-
(0,
|
|
802
|
+
(0, import_common_helpers.invariant)(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
|
|
658
803
|
const sort = this.negateSort(value._count, negated);
|
|
659
804
|
result = result.orderBy((eb) => {
|
|
660
|
-
let subQuery =
|
|
805
|
+
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
661
806
|
const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, relationModel);
|
|
662
807
|
subQuery = subQuery.where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely.sql.ref(left), "=", import_kysely.sql.ref(right)))));
|
|
663
808
|
subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
|
|
@@ -676,14 +821,90 @@ var BaseCrudDialect = class {
|
|
|
676
821
|
});
|
|
677
822
|
return result;
|
|
678
823
|
}
|
|
824
|
+
buildSelectAllFields(model, query, omit) {
|
|
825
|
+
const modelDef = requireModel(this.schema, model);
|
|
826
|
+
let result = query;
|
|
827
|
+
for (const field of Object.keys(modelDef.fields)) {
|
|
828
|
+
if (isRelationField(this.schema, model, field)) {
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
if (omit?.[field] === true) {
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
834
|
+
result = this.buildSelectField(result, model, model, field);
|
|
835
|
+
}
|
|
836
|
+
const descendants = getDelegateDescendantModels(this.schema, model);
|
|
837
|
+
for (const subModel of descendants) {
|
|
838
|
+
result = this.buildDelegateJoin(model, subModel.name, result);
|
|
839
|
+
result = result.select((eb) => {
|
|
840
|
+
const jsonObject = {};
|
|
841
|
+
for (const field of Object.keys(subModel.fields)) {
|
|
842
|
+
if (isRelationField(this.schema, subModel.name, field) || isInheritedField(this.schema, subModel.name, field)) {
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
jsonObject[field] = eb.ref(`${subModel.name}.${field}`);
|
|
846
|
+
}
|
|
847
|
+
return this.buildJsonObject(eb, jsonObject).as(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`);
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
return result;
|
|
851
|
+
}
|
|
852
|
+
buildSelectField(query, model, modelAlias, field) {
|
|
853
|
+
const fieldDef = requireField(this.schema, model, field);
|
|
854
|
+
if (fieldDef.computed) {
|
|
855
|
+
return query.select((eb) => this.fieldRef(model, field, eb, modelAlias).as(field));
|
|
856
|
+
} else if (!fieldDef.originModel) {
|
|
857
|
+
return query.select(import_kysely.sql.ref(`${modelAlias}.${field}`).as(field));
|
|
858
|
+
} else {
|
|
859
|
+
return this.buildSelectField(query, fieldDef.originModel, fieldDef.originModel, field);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
buildDelegateJoin(thisModel, otherModel, query) {
|
|
863
|
+
const idFields = getIdFields(this.schema, thisModel);
|
|
864
|
+
query = query.leftJoin(otherModel, (qb) => {
|
|
865
|
+
for (const idField of idFields) {
|
|
866
|
+
qb = qb.onRef(`${thisModel}.${idField}`, "=", `${otherModel}.${idField}`);
|
|
867
|
+
}
|
|
868
|
+
return qb;
|
|
869
|
+
});
|
|
870
|
+
return query;
|
|
871
|
+
}
|
|
872
|
+
buildCountJson(model, eb, parentAlias, payload) {
|
|
873
|
+
const modelDef = requireModel(this.schema, model);
|
|
874
|
+
const toManyRelations = Object.entries(modelDef.fields).filter(([, field]) => field.relation && field.array);
|
|
875
|
+
const selections = payload === true ? {
|
|
876
|
+
select: toManyRelations.reduce((acc, [field]) => {
|
|
877
|
+
acc[field] = true;
|
|
878
|
+
return acc;
|
|
879
|
+
}, {})
|
|
880
|
+
} : payload;
|
|
881
|
+
const jsonObject = {};
|
|
882
|
+
for (const [field, value] of Object.entries(selections.select)) {
|
|
883
|
+
const fieldDef = requireField(this.schema, model, field);
|
|
884
|
+
const fieldModel = fieldDef.type;
|
|
885
|
+
const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
|
|
886
|
+
let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
|
|
887
|
+
for (const [left, right] of joinPairs) {
|
|
888
|
+
fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
|
|
889
|
+
}
|
|
890
|
+
if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
|
|
891
|
+
const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
|
|
892
|
+
fieldCountQuery = fieldCountQuery.where(filter);
|
|
893
|
+
}
|
|
894
|
+
jsonObject[field] = fieldCountQuery;
|
|
895
|
+
}
|
|
896
|
+
return this.buildJsonObject(eb, jsonObject);
|
|
897
|
+
}
|
|
898
|
+
// #endregion
|
|
899
|
+
// #region utils
|
|
679
900
|
negateSort(sort, negated) {
|
|
680
901
|
return negated ? sort === "asc" ? "desc" : "asc" : sort;
|
|
681
902
|
}
|
|
682
903
|
true(eb) {
|
|
683
|
-
return eb.lit(this.transformPrimitive(true, "Boolean"));
|
|
904
|
+
return eb.lit(this.transformPrimitive(true, "Boolean", false));
|
|
684
905
|
}
|
|
685
906
|
false(eb) {
|
|
686
|
-
return eb.lit(this.transformPrimitive(false, "Boolean"));
|
|
907
|
+
return eb.lit(this.transformPrimitive(false, "Boolean", false));
|
|
687
908
|
}
|
|
688
909
|
isTrue(expression) {
|
|
689
910
|
const node = expression.toOperationNode();
|
|
@@ -722,6 +943,9 @@ var BaseCrudDialect = class {
|
|
|
722
943
|
not(eb, ...args) {
|
|
723
944
|
return eb.not(this.and(eb, ...args));
|
|
724
945
|
}
|
|
946
|
+
fieldRef(model, field, eb, modelAlias) {
|
|
947
|
+
return buildFieldRef(this.schema, model, field, this.options, eb, modelAlias);
|
|
948
|
+
}
|
|
725
949
|
};
|
|
726
950
|
|
|
727
951
|
// src/client/crud/dialects/postgresql.ts
|
|
@@ -732,14 +956,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
732
956
|
get provider() {
|
|
733
957
|
return "postgresql";
|
|
734
958
|
}
|
|
735
|
-
transformPrimitive(value, type) {
|
|
959
|
+
transformPrimitive(value, type, forArrayField) {
|
|
736
960
|
if (value === void 0) {
|
|
737
961
|
return value;
|
|
738
962
|
}
|
|
739
963
|
if (Array.isArray(value)) {
|
|
740
|
-
|
|
964
|
+
if (type === "Json" && !forArrayField) {
|
|
965
|
+
return JSON.stringify(value);
|
|
966
|
+
} else {
|
|
967
|
+
return value.map((v) => this.transformPrimitive(v, type, false));
|
|
968
|
+
}
|
|
741
969
|
} else {
|
|
742
|
-
return (0,
|
|
970
|
+
return (0, import_ts_pattern3.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
971
|
}
|
|
744
972
|
}
|
|
745
973
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
@@ -753,7 +981,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
753
981
|
const joinTableName = `${parentName}$${relationField}`;
|
|
754
982
|
let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
|
|
755
983
|
result = eb.selectFrom(() => {
|
|
756
|
-
let subQuery =
|
|
984
|
+
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
985
|
+
subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
|
|
757
986
|
if (payload && typeof payload === "object") {
|
|
758
987
|
if (payload.where) {
|
|
759
988
|
subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
|
|
@@ -772,8 +1001,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
772
1001
|
if (m2m) {
|
|
773
1002
|
const parentIds = getIdFields(this.schema, model);
|
|
774
1003
|
const relationIds = getIdFields(this.schema, relationModel);
|
|
775
|
-
(0,
|
|
776
|
-
(0,
|
|
1004
|
+
(0, import_common_helpers2.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
1005
|
+
(0, import_common_helpers2.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
777
1006
|
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
1007
|
} else {
|
|
779
1008
|
const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, relationModel);
|
|
@@ -797,34 +1026,57 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
797
1026
|
});
|
|
798
1027
|
return qb;
|
|
799
1028
|
}
|
|
800
|
-
buildRelationObjectArgs(relationModel, relationField, eb, payload,
|
|
1029
|
+
buildRelationObjectArgs(relationModel, relationField, eb, payload, parentAlias) {
|
|
801
1030
|
const relationModelDef = requireModel(this.schema, relationModel);
|
|
802
1031
|
const objArgs = [];
|
|
1032
|
+
const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
|
|
1033
|
+
if (descendantModels.length > 0) {
|
|
1034
|
+
objArgs.push(...descendantModels.map((subModel) => [
|
|
1035
|
+
import_kysely2.sql.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
|
|
1036
|
+
eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
|
|
1037
|
+
]).flatMap((v) => v));
|
|
1038
|
+
}
|
|
803
1039
|
if (payload === true || !payload.select) {
|
|
804
1040
|
objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
|
|
805
1041
|
import_kysely2.sql.lit(field),
|
|
806
|
-
|
|
1042
|
+
this.fieldRef(relationModel, field, eb)
|
|
807
1043
|
]).flatMap((v) => v));
|
|
808
1044
|
} else if (payload.select) {
|
|
809
|
-
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) =>
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1045
|
+
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
|
|
1046
|
+
if (field === "_count") {
|
|
1047
|
+
const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
|
|
1048
|
+
return [
|
|
1049
|
+
import_kysely2.sql.lit(field),
|
|
1050
|
+
subJson
|
|
1051
|
+
];
|
|
1052
|
+
} else {
|
|
1053
|
+
const fieldDef = requireField(this.schema, relationModel, field);
|
|
1054
|
+
const fieldValue = fieldDef.relation ? eb.ref(`${parentAlias}$${relationField}$${field}.$j`) : this.fieldRef(relationModel, field, eb);
|
|
1055
|
+
return [
|
|
1056
|
+
import_kysely2.sql.lit(field),
|
|
1057
|
+
fieldValue
|
|
1058
|
+
];
|
|
1059
|
+
}
|
|
1060
|
+
}).flatMap((v) => v));
|
|
813
1061
|
}
|
|
814
1062
|
if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
|
|
815
1063
|
objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
|
|
816
1064
|
import_kysely2.sql.lit(field),
|
|
817
|
-
|
|
1065
|
+
// reference the synthesized JSON field
|
|
1066
|
+
eb.ref(`${parentAlias}$${relationField}$${field}.$j`)
|
|
818
1067
|
]).flatMap((v) => v));
|
|
819
1068
|
}
|
|
820
1069
|
return objArgs;
|
|
821
1070
|
}
|
|
822
|
-
buildRelationJoins(
|
|
1071
|
+
buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
|
|
823
1072
|
let result = qb;
|
|
824
|
-
if (typeof payload === "object"
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
1073
|
+
if (typeof payload === "object") {
|
|
1074
|
+
const selectInclude = payload.include ?? payload.select;
|
|
1075
|
+
if (selectInclude && typeof selectInclude === "object") {
|
|
1076
|
+
Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
|
|
1077
|
+
result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
828
1080
|
}
|
|
829
1081
|
return result;
|
|
830
1082
|
}
|
|
@@ -864,12 +1116,15 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
864
1116
|
return `ARRAY[${values.map((v) => typeof v === "string" ? `'${v}'` : v)}]`;
|
|
865
1117
|
}
|
|
866
1118
|
}
|
|
1119
|
+
get supportInsertWithDefault() {
|
|
1120
|
+
return true;
|
|
1121
|
+
}
|
|
867
1122
|
};
|
|
868
1123
|
|
|
869
1124
|
// src/client/crud/dialects/sqlite.ts
|
|
1125
|
+
var import_common_helpers3 = require("@zenstackhq/common-helpers");
|
|
870
1126
|
var import_kysely3 = require("kysely");
|
|
871
|
-
var
|
|
872
|
-
var import_ts_pattern3 = require("ts-pattern");
|
|
1127
|
+
var import_ts_pattern4 = require("ts-pattern");
|
|
873
1128
|
var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
874
1129
|
static {
|
|
875
1130
|
__name(this, "SqliteCrudDialect");
|
|
@@ -877,26 +1132,31 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
877
1132
|
get provider() {
|
|
878
1133
|
return "sqlite";
|
|
879
1134
|
}
|
|
880
|
-
transformPrimitive(value, type) {
|
|
1135
|
+
transformPrimitive(value, type, _forArrayField) {
|
|
881
1136
|
if (value === void 0) {
|
|
882
1137
|
return value;
|
|
883
1138
|
}
|
|
884
1139
|
if (Array.isArray(value)) {
|
|
885
|
-
return value.map((v) => this.transformPrimitive(v, type));
|
|
1140
|
+
return value.map((v) => this.transformPrimitive(v, type, false));
|
|
886
1141
|
} else {
|
|
887
|
-
|
|
1142
|
+
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
1143
|
+
return JSON.stringify(value);
|
|
1144
|
+
} else {
|
|
1145
|
+
return (0, import_ts_pattern4.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);
|
|
1146
|
+
}
|
|
888
1147
|
}
|
|
889
1148
|
}
|
|
890
1149
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
891
1150
|
return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
|
|
892
1151
|
}
|
|
893
|
-
buildRelationJSON(model, eb, relationField,
|
|
1152
|
+
buildRelationJSON(model, eb, relationField, parentAlias, payload) {
|
|
894
1153
|
const relationFieldDef = requireField(this.schema, model, relationField);
|
|
895
1154
|
const relationModel = relationFieldDef.type;
|
|
896
1155
|
const relationModelDef = requireModel(this.schema, relationModel);
|
|
897
|
-
const subQueryName = `${
|
|
1156
|
+
const subQueryName = `${parentAlias}$${relationField}`;
|
|
898
1157
|
let tbl = eb.selectFrom(() => {
|
|
899
|
-
let subQuery =
|
|
1158
|
+
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
1159
|
+
subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
|
|
900
1160
|
if (payload && typeof payload === "object") {
|
|
901
1161
|
if (payload.where) {
|
|
902
1162
|
subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
|
|
@@ -915,16 +1175,16 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
915
1175
|
if (m2m) {
|
|
916
1176
|
const parentIds = getIdFields(this.schema, model);
|
|
917
1177
|
const relationIds = getIdFields(this.schema, relationModel);
|
|
918
|
-
(0,
|
|
919
|
-
(0,
|
|
920
|
-
subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${
|
|
1178
|
+
(0, import_common_helpers3.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
1179
|
+
(0, import_common_helpers3.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
1180
|
+
subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
|
|
921
1181
|
} else {
|
|
922
1182
|
const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
|
|
923
1183
|
keyPairs.forEach(({ fk, pk }) => {
|
|
924
1184
|
if (ownedByModel) {
|
|
925
|
-
subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${
|
|
1185
|
+
subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentAlias}.${fk}`);
|
|
926
1186
|
} else {
|
|
927
|
-
subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${
|
|
1187
|
+
subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentAlias}.${pk}`);
|
|
928
1188
|
}
|
|
929
1189
|
});
|
|
930
1190
|
}
|
|
@@ -932,31 +1192,46 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
932
1192
|
});
|
|
933
1193
|
tbl = tbl.select(() => {
|
|
934
1194
|
const objArgs = [];
|
|
1195
|
+
const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
|
|
1196
|
+
if (descendantModels.length > 0) {
|
|
1197
|
+
objArgs.push(...descendantModels.map((subModel) => [
|
|
1198
|
+
import_kysely3.sql.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
|
|
1199
|
+
eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
|
|
1200
|
+
]).flatMap((v) => v));
|
|
1201
|
+
}
|
|
935
1202
|
if (payload === true || !payload.select) {
|
|
936
1203
|
objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
|
|
937
1204
|
import_kysely3.sql.lit(field),
|
|
938
|
-
|
|
1205
|
+
this.fieldRef(relationModel, field, eb)
|
|
939
1206
|
]).flatMap((v) => v));
|
|
940
1207
|
} else if (payload.select) {
|
|
941
1208
|
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
|
|
1209
|
+
if (field === "_count") {
|
|
1210
|
+
const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
|
|
945
1211
|
return [
|
|
946
1212
|
import_kysely3.sql.lit(field),
|
|
947
1213
|
subJson
|
|
948
1214
|
];
|
|
949
1215
|
} else {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1216
|
+
const fieldDef = requireField(this.schema, relationModel, field);
|
|
1217
|
+
if (fieldDef.relation) {
|
|
1218
|
+
const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
|
|
1219
|
+
return [
|
|
1220
|
+
import_kysely3.sql.lit(field),
|
|
1221
|
+
subJson
|
|
1222
|
+
];
|
|
1223
|
+
} else {
|
|
1224
|
+
return [
|
|
1225
|
+
import_kysely3.sql.lit(field),
|
|
1226
|
+
this.fieldRef(relationModel, field, eb)
|
|
1227
|
+
];
|
|
1228
|
+
}
|
|
954
1229
|
}
|
|
955
1230
|
}).flatMap((v) => v));
|
|
956
1231
|
}
|
|
957
1232
|
if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
|
|
958
1233
|
objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
|
|
959
|
-
const subJson = this.buildRelationJSON(relationModel, eb, field, `${
|
|
1234
|
+
const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
|
|
960
1235
|
return [
|
|
961
1236
|
import_kysely3.sql.lit(field),
|
|
962
1237
|
subJson
|
|
@@ -1006,93 +1281,17 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
1006
1281
|
buildArrayLiteralSQL(_values) {
|
|
1007
1282
|
throw new Error("SQLite does not support array literals");
|
|
1008
1283
|
}
|
|
1284
|
+
get supportInsertWithDefault() {
|
|
1285
|
+
return false;
|
|
1286
|
+
}
|
|
1009
1287
|
};
|
|
1010
1288
|
|
|
1011
1289
|
// src/client/crud/dialects/index.ts
|
|
1012
1290
|
function getCrudDialect(schema, options) {
|
|
1013
|
-
return (0,
|
|
1291
|
+
return (0, import_ts_pattern5.match)(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
|
|
1014
1292
|
}
|
|
1015
1293
|
__name(getCrudDialect, "getCrudDialect");
|
|
1016
1294
|
|
|
1017
|
-
// src/schema/expression.ts
|
|
1018
|
-
var ExpressionUtils = {
|
|
1019
|
-
literal: /* @__PURE__ */ __name((value) => {
|
|
1020
|
-
return {
|
|
1021
|
-
kind: "literal",
|
|
1022
|
-
value
|
|
1023
|
-
};
|
|
1024
|
-
}, "literal"),
|
|
1025
|
-
array: /* @__PURE__ */ __name((items) => {
|
|
1026
|
-
return {
|
|
1027
|
-
kind: "array",
|
|
1028
|
-
items
|
|
1029
|
-
};
|
|
1030
|
-
}, "array"),
|
|
1031
|
-
call: /* @__PURE__ */ __name((functionName, args) => {
|
|
1032
|
-
return {
|
|
1033
|
-
kind: "call",
|
|
1034
|
-
function: functionName,
|
|
1035
|
-
args
|
|
1036
|
-
};
|
|
1037
|
-
}, "call"),
|
|
1038
|
-
binary: /* @__PURE__ */ __name((left, op, right) => {
|
|
1039
|
-
return {
|
|
1040
|
-
kind: "binary",
|
|
1041
|
-
op,
|
|
1042
|
-
left,
|
|
1043
|
-
right
|
|
1044
|
-
};
|
|
1045
|
-
}, "binary"),
|
|
1046
|
-
unary: /* @__PURE__ */ __name((op, operand) => {
|
|
1047
|
-
return {
|
|
1048
|
-
kind: "unary",
|
|
1049
|
-
op,
|
|
1050
|
-
operand
|
|
1051
|
-
};
|
|
1052
|
-
}, "unary"),
|
|
1053
|
-
field: /* @__PURE__ */ __name((field) => {
|
|
1054
|
-
return {
|
|
1055
|
-
kind: "field",
|
|
1056
|
-
field
|
|
1057
|
-
};
|
|
1058
|
-
}, "field"),
|
|
1059
|
-
member: /* @__PURE__ */ __name((receiver, members) => {
|
|
1060
|
-
return {
|
|
1061
|
-
kind: "member",
|
|
1062
|
-
receiver,
|
|
1063
|
-
members
|
|
1064
|
-
};
|
|
1065
|
-
}, "member"),
|
|
1066
|
-
_this: /* @__PURE__ */ __name(() => {
|
|
1067
|
-
return {
|
|
1068
|
-
kind: "this"
|
|
1069
|
-
};
|
|
1070
|
-
}, "_this"),
|
|
1071
|
-
_null: /* @__PURE__ */ __name(() => {
|
|
1072
|
-
return {
|
|
1073
|
-
kind: "null"
|
|
1074
|
-
};
|
|
1075
|
-
}, "_null"),
|
|
1076
|
-
and: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
1077
|
-
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
|
|
1078
|
-
}, "and"),
|
|
1079
|
-
or: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
1080
|
-
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
|
|
1081
|
-
}, "or"),
|
|
1082
|
-
is: /* @__PURE__ */ __name((value, kind) => {
|
|
1083
|
-
return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
|
|
1084
|
-
}, "is"),
|
|
1085
|
-
isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
|
|
1086
|
-
isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
|
|
1087
|
-
isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
|
|
1088
|
-
isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
|
|
1089
|
-
isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
|
|
1090
|
-
isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
|
|
1091
|
-
isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
|
|
1092
|
-
isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
|
|
1093
|
-
isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
|
|
1094
|
-
};
|
|
1095
|
-
|
|
1096
1295
|
// src/utils/default-operation-node-visitor.ts
|
|
1097
1296
|
var import_kysely4 = require("kysely");
|
|
1098
1297
|
var DefaultOperationNodeVisitor = class extends import_kysely4.OperationNodeVisitor {
|
|
@@ -1412,19 +1611,19 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
|
|
|
1412
1611
|
};
|
|
1413
1612
|
|
|
1414
1613
|
// src/plugins/policy/expression-transformer.ts
|
|
1614
|
+
var import_common_helpers5 = require("@zenstackhq/common-helpers");
|
|
1415
1615
|
var import_kysely6 = require("kysely");
|
|
1416
|
-
var
|
|
1417
|
-
var import_ts_pattern6 = require("ts-pattern");
|
|
1616
|
+
var import_ts_pattern7 = require("ts-pattern");
|
|
1418
1617
|
|
|
1419
1618
|
// src/plugins/policy/expression-evaluator.ts
|
|
1420
|
-
var
|
|
1421
|
-
var
|
|
1619
|
+
var import_common_helpers4 = require("@zenstackhq/common-helpers");
|
|
1620
|
+
var import_ts_pattern6 = require("ts-pattern");
|
|
1422
1621
|
var ExpressionEvaluator = class {
|
|
1423
1622
|
static {
|
|
1424
1623
|
__name(this, "ExpressionEvaluator");
|
|
1425
1624
|
}
|
|
1426
1625
|
evaluate(expression, context) {
|
|
1427
|
-
const result = (0,
|
|
1626
|
+
const result = (0, import_ts_pattern6.match)(expression).when(ExpressionUtils.isArray, (expr2) => this.evaluateArray(expr2, context)).when(ExpressionUtils.isBinary, (expr2) => this.evaluateBinary(expr2, context)).when(ExpressionUtils.isField, (expr2) => this.evaluateField(expr2, context)).when(ExpressionUtils.isLiteral, (expr2) => this.evaluateLiteral(expr2)).when(ExpressionUtils.isMember, (expr2) => this.evaluateMember(expr2, context)).when(ExpressionUtils.isUnary, (expr2) => this.evaluateUnary(expr2, context)).when(ExpressionUtils.isCall, (expr2) => this.evaluateCall(expr2, context)).when(ExpressionUtils.isThis, () => context.thisValue).when(ExpressionUtils.isNull, () => null).exhaustive();
|
|
1428
1627
|
return result ?? null;
|
|
1429
1628
|
}
|
|
1430
1629
|
evaluateCall(expr2, context) {
|
|
@@ -1435,7 +1634,7 @@ var ExpressionEvaluator = class {
|
|
|
1435
1634
|
}
|
|
1436
1635
|
}
|
|
1437
1636
|
evaluateUnary(expr2, context) {
|
|
1438
|
-
return (0,
|
|
1637
|
+
return (0, import_ts_pattern6.match)(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
|
|
1439
1638
|
}
|
|
1440
1639
|
evaluateMember(expr2, context) {
|
|
1441
1640
|
let val = this.evaluate(expr2.receiver, context);
|
|
@@ -1459,21 +1658,21 @@ var ExpressionEvaluator = class {
|
|
|
1459
1658
|
}
|
|
1460
1659
|
const left = this.evaluate(expr2.left, context);
|
|
1461
1660
|
const right = this.evaluate(expr2.right, context);
|
|
1462
|
-
return (0,
|
|
1661
|
+
return (0, import_ts_pattern6.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
1662
|
const _right = right ?? [];
|
|
1464
|
-
(0,
|
|
1663
|
+
(0, import_common_helpers4.invariant)(Array.isArray(_right), 'expected array for "in" operator');
|
|
1465
1664
|
return _right.includes(left);
|
|
1466
1665
|
}).exhaustive();
|
|
1467
1666
|
}
|
|
1468
1667
|
evaluateCollectionPredicate(expr2, context) {
|
|
1469
1668
|
const op = expr2.op;
|
|
1470
|
-
(0,
|
|
1669
|
+
(0, import_common_helpers4.invariant)(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
|
|
1471
1670
|
const left = this.evaluate(expr2.left, context);
|
|
1472
1671
|
if (!left) {
|
|
1473
1672
|
return false;
|
|
1474
1673
|
}
|
|
1475
|
-
(0,
|
|
1476
|
-
return (0,
|
|
1674
|
+
(0, import_common_helpers4.invariant)(Array.isArray(left), "expected array");
|
|
1675
|
+
return (0, import_ts_pattern6.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
|
|
1477
1676
|
...context,
|
|
1478
1677
|
thisValue: item
|
|
1479
1678
|
}))).with("!", () => left.every((item) => this.evaluate(expr2.right, {
|
|
@@ -1489,11 +1688,11 @@ var ExpressionEvaluator = class {
|
|
|
1489
1688
|
// src/plugins/policy/utils.ts
|
|
1490
1689
|
var import_kysely5 = require("kysely");
|
|
1491
1690
|
function trueNode(dialect) {
|
|
1492
|
-
return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
|
|
1691
|
+
return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
|
|
1493
1692
|
}
|
|
1494
1693
|
__name(trueNode, "trueNode");
|
|
1495
1694
|
function falseNode(dialect) {
|
|
1496
|
-
return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
|
|
1695
|
+
return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
|
|
1497
1696
|
}
|
|
1498
1697
|
__name(falseNode, "falseNode");
|
|
1499
1698
|
function isTrueNode(node) {
|
|
@@ -1694,20 +1893,20 @@ var ExpressionTransformer = class {
|
|
|
1694
1893
|
return import_kysely6.BinaryOperationNode.create(left, this.transformOperator(op), right);
|
|
1695
1894
|
}
|
|
1696
1895
|
transformCollectionPredicate(expr2, context) {
|
|
1697
|
-
(0,
|
|
1896
|
+
(0, import_common_helpers5.invariant)(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
|
|
1698
1897
|
if (this.isAuthCall(expr2.left) || this.isAuthMember(expr2.left)) {
|
|
1699
1898
|
const value = new ExpressionEvaluator().evaluate(expr2, {
|
|
1700
1899
|
auth: this.auth
|
|
1701
1900
|
});
|
|
1702
1901
|
return this.transformValue(value, "Boolean");
|
|
1703
1902
|
}
|
|
1704
|
-
(0,
|
|
1903
|
+
(0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
|
|
1705
1904
|
let newContextModel;
|
|
1706
1905
|
if (ExpressionUtils.isField(expr2.left)) {
|
|
1707
1906
|
const fieldDef = requireField(this.schema, context.model, expr2.left.field);
|
|
1708
1907
|
newContextModel = fieldDef.type;
|
|
1709
1908
|
} else {
|
|
1710
|
-
(0,
|
|
1909
|
+
(0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.left.receiver));
|
|
1711
1910
|
const fieldDef = requireField(this.schema, context.model, expr2.left.receiver.field);
|
|
1712
1911
|
newContextModel = fieldDef.type;
|
|
1713
1912
|
for (const member of expr2.left.members) {
|
|
@@ -1727,7 +1926,7 @@ var ExpressionTransformer = class {
|
|
|
1727
1926
|
const count = import_kysely6.FunctionNode.create("count", [
|
|
1728
1927
|
import_kysely6.ValueNode.createImmediate(1)
|
|
1729
1928
|
]);
|
|
1730
|
-
const predicateResult = (0,
|
|
1929
|
+
const predicateResult = (0, import_ts_pattern7.match)(expr2.op).with("?", () => import_kysely6.BinaryOperationNode.create(count, import_kysely6.OperatorNode.create(">"), import_kysely6.ValueNode.createImmediate(0))).with("!", () => import_kysely6.BinaryOperationNode.create(count, import_kysely6.OperatorNode.create("="), import_kysely6.ValueNode.createImmediate(0))).with("^", () => import_kysely6.BinaryOperationNode.create(count, import_kysely6.OperatorNode.create("="), import_kysely6.ValueNode.createImmediate(0))).exhaustive();
|
|
1731
1930
|
return this.transform(expr2.left, {
|
|
1732
1931
|
...context,
|
|
1733
1932
|
memberSelect: import_kysely6.SelectionNode.create(import_kysely6.AliasNode.create(predicateResult, import_kysely6.IdentifierNode.create("$t"))),
|
|
@@ -1751,14 +1950,14 @@ var ExpressionTransformer = class {
|
|
|
1751
1950
|
}
|
|
1752
1951
|
}
|
|
1753
1952
|
transformValue(value, type) {
|
|
1754
|
-
return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type) ?? null);
|
|
1953
|
+
return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type, false) ?? null);
|
|
1755
1954
|
}
|
|
1756
1955
|
_unary(expr2, context) {
|
|
1757
|
-
(0,
|
|
1956
|
+
(0, import_common_helpers5.invariant)(expr2.op === "!", 'only "!" operator is supported');
|
|
1758
1957
|
return import_kysely6.BinaryOperationNode.create(this.transform(expr2.operand, context), this.transformOperator("!="), trueNode(this.dialect));
|
|
1759
1958
|
}
|
|
1760
1959
|
transformOperator(op) {
|
|
1761
|
-
const mappedOp = (0,
|
|
1960
|
+
const mappedOp = (0, import_ts_pattern7.match)(op).with("==", () => "=").otherwise(() => op);
|
|
1762
1961
|
return import_kysely6.OperatorNode.create(mappedOp);
|
|
1763
1962
|
}
|
|
1764
1963
|
_call(expr2, context) {
|
|
@@ -1797,10 +1996,10 @@ var ExpressionTransformer = class {
|
|
|
1797
1996
|
if (this.isAuthCall(expr2.receiver)) {
|
|
1798
1997
|
return this.valueMemberAccess(this.auth, expr2, this.authType);
|
|
1799
1998
|
}
|
|
1800
|
-
(0,
|
|
1999
|
+
(0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.receiver), "expect receiver to be field expression");
|
|
1801
2000
|
const { memberFilter, memberSelect, ...restContext } = context;
|
|
1802
2001
|
const receiver = this.transform(expr2.receiver, restContext);
|
|
1803
|
-
(0,
|
|
2002
|
+
(0, import_common_helpers5.invariant)(import_kysely6.SelectQueryNode.is(receiver), "expected receiver to be select query");
|
|
1804
2003
|
const receiverField = requireField(this.schema, context.model, expr2.receiver.field);
|
|
1805
2004
|
const memberFields = [];
|
|
1806
2005
|
let currType = receiverField.type;
|
|
@@ -1824,7 +2023,7 @@ var ExpressionTransformer = class {
|
|
|
1824
2023
|
thisEntity: void 0
|
|
1825
2024
|
});
|
|
1826
2025
|
if (currNode) {
|
|
1827
|
-
(0,
|
|
2026
|
+
(0, import_common_helpers5.invariant)(import_kysely6.SelectQueryNode.is(currNode), "expected select query node");
|
|
1828
2027
|
currNode = {
|
|
1829
2028
|
...relation,
|
|
1830
2029
|
selections: [
|
|
@@ -1841,8 +2040,8 @@ var ExpressionTransformer = class {
|
|
|
1841
2040
|
};
|
|
1842
2041
|
}
|
|
1843
2042
|
} else {
|
|
1844
|
-
(0,
|
|
1845
|
-
(0,
|
|
2043
|
+
(0, import_common_helpers5.invariant)(i === expr2.members.length - 1, "plain field access must be the last segment");
|
|
2044
|
+
(0, import_common_helpers5.invariant)(!currNode, "plain field access must be the last segment");
|
|
1846
2045
|
currNode = import_kysely6.ColumnNode.create(member);
|
|
1847
2046
|
}
|
|
1848
2047
|
}
|
|
@@ -1994,7 +2193,7 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
|
|
|
1994
2193
|
get kysely() {
|
|
1995
2194
|
return this.client.$qb;
|
|
1996
2195
|
}
|
|
1997
|
-
async handle(node, proceed
|
|
2196
|
+
async handle(node, proceed) {
|
|
1998
2197
|
if (!this.isCrudQueryNode(node)) {
|
|
1999
2198
|
throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
|
|
2000
2199
|
}
|
|
@@ -2014,27 +2213,20 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
|
|
|
2014
2213
|
if (!mutationRequiresTransaction && !node.returning) {
|
|
2015
2214
|
return proceed(this.transformNode(node));
|
|
2016
2215
|
}
|
|
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;
|
|
2216
|
+
if (import_kysely7.InsertQueryNode.is(node)) {
|
|
2217
|
+
await this.enforcePreCreatePolicy(node, proceed);
|
|
2218
|
+
}
|
|
2219
|
+
const transformedNode = this.transformNode(node);
|
|
2220
|
+
const result = await proceed(transformedNode);
|
|
2221
|
+
if (!this.onlyReturningId(node)) {
|
|
2222
|
+
const readBackResult = await this.processReadBack(node, result, proceed);
|
|
2223
|
+
if (readBackResult.rows.length !== result.rows.length) {
|
|
2224
|
+
throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
|
|
2032
2225
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2226
|
+
return readBackResult;
|
|
2227
|
+
} else {
|
|
2228
|
+
return result;
|
|
2036
2229
|
}
|
|
2037
|
-
return result;
|
|
2038
2230
|
}
|
|
2039
2231
|
onlyReturningId(node) {
|
|
2040
2232
|
if (!node.returning) {
|
|
@@ -2087,19 +2279,19 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
|
|
|
2087
2279
|
}
|
|
2088
2280
|
}
|
|
2089
2281
|
unwrapCreateValueRow(data, model, fields) {
|
|
2090
|
-
(0,
|
|
2282
|
+
(0, import_common_helpers6.invariant)(data.length === fields.length, "data length must match fields length");
|
|
2091
2283
|
const result = [];
|
|
2092
2284
|
for (let i = 0; i < data.length; i++) {
|
|
2093
2285
|
const item = data[i];
|
|
2094
2286
|
const fieldDef = requireField(this.client.$schema, model, fields[i]);
|
|
2095
2287
|
if (typeof item === "object" && item && "kind" in item) {
|
|
2096
|
-
(0,
|
|
2288
|
+
(0, import_common_helpers6.invariant)(item.kind === "ValueNode", "expecting a ValueNode");
|
|
2097
2289
|
result.push({
|
|
2098
|
-
node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
|
|
2290
|
+
node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
|
|
2099
2291
|
raw: item.value
|
|
2100
2292
|
});
|
|
2101
2293
|
} else {
|
|
2102
|
-
const value = this.dialect.transformPrimitive(item, fieldDef.type);
|
|
2294
|
+
const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
|
|
2103
2295
|
if (Array.isArray(value)) {
|
|
2104
2296
|
result.push({
|
|
2105
2297
|
node: import_kysely7.RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
|
|
@@ -2168,7 +2360,7 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
|
|
|
2168
2360
|
return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => import_kysely7.BinaryOperationNode.create(import_kysely7.ColumnNode.create(field), import_kysely7.OperatorNode.create("="), import_kysely7.ValueNode.create(row[field]))))));
|
|
2169
2361
|
}
|
|
2170
2362
|
getMutationModel(node) {
|
|
2171
|
-
const r = (0,
|
|
2363
|
+
const r = (0, import_ts_pattern8.match)(node).when(import_kysely7.InsertQueryNode.is, (node2) => getTableName(node2.into)).when(import_kysely7.UpdateQueryNode.is, (node2) => getTableName(node2.table)).when(import_kysely7.DeleteQueryNode.is, (node2) => {
|
|
2172
2364
|
if (node2.from.froms.length !== 1) {
|
|
2173
2365
|
throw new InternalError("Only one from table is supported for delete");
|
|
2174
2366
|
}
|
|
@@ -2301,8 +2493,8 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
|
|
|
2301
2493
|
const modelDef = requireModel(this.client.$schema, modelName);
|
|
2302
2494
|
const result = [];
|
|
2303
2495
|
const extractOperations = /* @__PURE__ */ __name((expr2) => {
|
|
2304
|
-
(0,
|
|
2305
|
-
(0,
|
|
2496
|
+
(0, import_common_helpers6.invariant)(ExpressionUtils.isLiteral(expr2), "expecting a literal");
|
|
2497
|
+
(0, import_common_helpers6.invariant)(typeof expr2.value === "string", "expecting a string literal");
|
|
2306
2498
|
return expr2.value.split(",").filter((v) => !!v).map((v) => v.trim());
|
|
2307
2499
|
}, "extractOperations");
|
|
2308
2500
|
if (modelDef.attributes) {
|
|
@@ -2330,9 +2522,18 @@ var PolicyPlugin = class {
|
|
|
2330
2522
|
get description() {
|
|
2331
2523
|
return "Enforces access policies defined in the schema.";
|
|
2332
2524
|
}
|
|
2333
|
-
onKyselyQuery({
|
|
2525
|
+
onKyselyQuery({
|
|
2526
|
+
query,
|
|
2527
|
+
client,
|
|
2528
|
+
proceed
|
|
2529
|
+
/*, transaction*/
|
|
2530
|
+
}) {
|
|
2334
2531
|
const handler = new PolicyHandler(client);
|
|
2335
|
-
return handler.handle(
|
|
2532
|
+
return handler.handle(
|
|
2533
|
+
query,
|
|
2534
|
+
proceed
|
|
2535
|
+
/*, transaction*/
|
|
2536
|
+
);
|
|
2336
2537
|
}
|
|
2337
2538
|
};
|
|
2338
2539
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -2340,4 +2541,4 @@ var PolicyPlugin = class {
|
|
|
2340
2541
|
PolicyPlugin,
|
|
2341
2542
|
RejectedByPolicyError
|
|
2342
2543
|
});
|
|
2343
|
-
//# sourceMappingURL=
|
|
2544
|
+
//# sourceMappingURL=index.cjs.map
|