@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
|
@@ -14,34 +14,130 @@ var RejectedByPolicyError = class extends Error {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// src/plugins/policy/policy-handler.ts
|
|
17
|
+
import { invariant as invariant6 } from "@zenstackhq/common-helpers";
|
|
17
18
|
import { AliasNode as AliasNode3, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode2, DeleteQueryNode, FromNode as FromNode2, IdentifierNode as IdentifierNode2, InsertQueryNode, OperationNodeTransformer, OperatorNode as OperatorNode3, PrimitiveValueListNode, RawNode, ReturningNode, SelectionNode as SelectionNode2, SelectQueryNode as SelectQueryNode2, TableNode as TableNode3, UpdateQueryNode, ValueNode as ValueNode3, ValuesNode, WhereNode as WhereNode2 } from "kysely";
|
|
18
|
-
import
|
|
19
|
-
import { match as match7 } from "ts-pattern";
|
|
19
|
+
import { match as match8 } from "ts-pattern";
|
|
20
20
|
|
|
21
21
|
// src/client/crud/dialects/index.ts
|
|
22
|
-
import { match as
|
|
22
|
+
import { match as match5 } from "ts-pattern";
|
|
23
23
|
|
|
24
24
|
// src/client/crud/dialects/postgresql.ts
|
|
25
|
+
import { invariant as invariant2 } from "@zenstackhq/common-helpers";
|
|
25
26
|
import { sql as sql2 } from "kysely";
|
|
26
|
-
import
|
|
27
|
-
|
|
27
|
+
import { match as match3 } from "ts-pattern";
|
|
28
|
+
|
|
29
|
+
// src/client/constants.ts
|
|
30
|
+
var DELEGATE_JOINED_FIELD_PREFIX = "$delegate$";
|
|
31
|
+
var LOGICAL_COMBINATORS = [
|
|
32
|
+
"AND",
|
|
33
|
+
"OR",
|
|
34
|
+
"NOT"
|
|
35
|
+
];
|
|
36
|
+
var AGGREGATE_OPERATORS = [
|
|
37
|
+
"_count",
|
|
38
|
+
"_sum",
|
|
39
|
+
"_avg",
|
|
40
|
+
"_min",
|
|
41
|
+
"_max"
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
// src/client/query-utils.ts
|
|
45
|
+
import { match } from "ts-pattern";
|
|
46
|
+
|
|
47
|
+
// src/schema/expression.ts
|
|
48
|
+
var ExpressionUtils = {
|
|
49
|
+
literal: /* @__PURE__ */ __name((value) => {
|
|
50
|
+
return {
|
|
51
|
+
kind: "literal",
|
|
52
|
+
value
|
|
53
|
+
};
|
|
54
|
+
}, "literal"),
|
|
55
|
+
array: /* @__PURE__ */ __name((items) => {
|
|
56
|
+
return {
|
|
57
|
+
kind: "array",
|
|
58
|
+
items
|
|
59
|
+
};
|
|
60
|
+
}, "array"),
|
|
61
|
+
call: /* @__PURE__ */ __name((functionName, args) => {
|
|
62
|
+
return {
|
|
63
|
+
kind: "call",
|
|
64
|
+
function: functionName,
|
|
65
|
+
args
|
|
66
|
+
};
|
|
67
|
+
}, "call"),
|
|
68
|
+
binary: /* @__PURE__ */ __name((left, op, right) => {
|
|
69
|
+
return {
|
|
70
|
+
kind: "binary",
|
|
71
|
+
op,
|
|
72
|
+
left,
|
|
73
|
+
right
|
|
74
|
+
};
|
|
75
|
+
}, "binary"),
|
|
76
|
+
unary: /* @__PURE__ */ __name((op, operand) => {
|
|
77
|
+
return {
|
|
78
|
+
kind: "unary",
|
|
79
|
+
op,
|
|
80
|
+
operand
|
|
81
|
+
};
|
|
82
|
+
}, "unary"),
|
|
83
|
+
field: /* @__PURE__ */ __name((field) => {
|
|
84
|
+
return {
|
|
85
|
+
kind: "field",
|
|
86
|
+
field
|
|
87
|
+
};
|
|
88
|
+
}, "field"),
|
|
89
|
+
member: /* @__PURE__ */ __name((receiver, members) => {
|
|
90
|
+
return {
|
|
91
|
+
kind: "member",
|
|
92
|
+
receiver,
|
|
93
|
+
members
|
|
94
|
+
};
|
|
95
|
+
}, "member"),
|
|
96
|
+
_this: /* @__PURE__ */ __name(() => {
|
|
97
|
+
return {
|
|
98
|
+
kind: "this"
|
|
99
|
+
};
|
|
100
|
+
}, "_this"),
|
|
101
|
+
_null: /* @__PURE__ */ __name(() => {
|
|
102
|
+
return {
|
|
103
|
+
kind: "null"
|
|
104
|
+
};
|
|
105
|
+
}, "_null"),
|
|
106
|
+
and: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
107
|
+
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
|
|
108
|
+
}, "and"),
|
|
109
|
+
or: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
110
|
+
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
|
|
111
|
+
}, "or"),
|
|
112
|
+
is: /* @__PURE__ */ __name((value, kind) => {
|
|
113
|
+
return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
|
|
114
|
+
}, "is"),
|
|
115
|
+
isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
|
|
116
|
+
isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
|
|
117
|
+
isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
|
|
118
|
+
isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
|
|
119
|
+
isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
|
|
120
|
+
isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
|
|
121
|
+
isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
|
|
122
|
+
isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
|
|
123
|
+
isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
|
|
124
|
+
};
|
|
28
125
|
|
|
29
126
|
// src/client/errors.ts
|
|
30
127
|
var QueryError = class extends Error {
|
|
31
128
|
static {
|
|
32
129
|
__name(this, "QueryError");
|
|
33
130
|
}
|
|
34
|
-
constructor(message) {
|
|
35
|
-
super(message
|
|
131
|
+
constructor(message, cause) {
|
|
132
|
+
super(message, {
|
|
133
|
+
cause
|
|
134
|
+
});
|
|
36
135
|
}
|
|
37
136
|
};
|
|
38
137
|
var InternalError = class extends Error {
|
|
39
138
|
static {
|
|
40
139
|
__name(this, "InternalError");
|
|
41
140
|
}
|
|
42
|
-
constructor(message) {
|
|
43
|
-
super(message);
|
|
44
|
-
}
|
|
45
141
|
};
|
|
46
142
|
|
|
47
143
|
// src/client/query-utils.ts
|
|
@@ -52,7 +148,7 @@ __name(getModel, "getModel");
|
|
|
52
148
|
function requireModel(schema, model) {
|
|
53
149
|
const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
|
|
54
150
|
if (!matchedName) {
|
|
55
|
-
throw new QueryError(`Model "${model}" not found`);
|
|
151
|
+
throw new QueryError(`Model "${model}" not found in schema`);
|
|
56
152
|
}
|
|
57
153
|
return schema.models[matchedName];
|
|
58
154
|
}
|
|
@@ -115,6 +211,16 @@ function getRelationForeignKeyFieldPairs(schema, model, relationField) {
|
|
|
115
211
|
}
|
|
116
212
|
}
|
|
117
213
|
__name(getRelationForeignKeyFieldPairs, "getRelationForeignKeyFieldPairs");
|
|
214
|
+
function isRelationField(schema, model, field) {
|
|
215
|
+
const fieldDef = getField(schema, model, field);
|
|
216
|
+
return !!fieldDef?.relation;
|
|
217
|
+
}
|
|
218
|
+
__name(isRelationField, "isRelationField");
|
|
219
|
+
function isInheritedField(schema, model, field) {
|
|
220
|
+
const fieldDef = getField(schema, model, field);
|
|
221
|
+
return !!fieldDef?.originModel;
|
|
222
|
+
}
|
|
223
|
+
__name(isInheritedField, "isInheritedField");
|
|
118
224
|
function getUniqueFields(schema, model) {
|
|
119
225
|
const modelDef = requireModel(schema, model);
|
|
120
226
|
const result = [];
|
|
@@ -151,7 +257,7 @@ function buildFieldRef(schema, model, field, options, eb, modelAlias) {
|
|
|
151
257
|
computer = computedFields?.[model]?.[field];
|
|
152
258
|
}
|
|
153
259
|
if (!computer) {
|
|
154
|
-
throw new QueryError(`Computed field "${field}" implementation not provided`);
|
|
260
|
+
throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
|
|
155
261
|
}
|
|
156
262
|
return computer(eb);
|
|
157
263
|
}
|
|
@@ -228,11 +334,28 @@ function flattenCompoundUniqueFilters(schema, model, filter) {
|
|
|
228
334
|
return result;
|
|
229
335
|
}
|
|
230
336
|
__name(flattenCompoundUniqueFilters, "flattenCompoundUniqueFilters");
|
|
337
|
+
function getDelegateDescendantModels(schema, model, collected = /* @__PURE__ */ new Set()) {
|
|
338
|
+
const subModels = Object.values(schema.models).filter((m) => m.baseModel === model);
|
|
339
|
+
subModels.forEach((def) => {
|
|
340
|
+
if (!collected.has(def)) {
|
|
341
|
+
collected.add(def);
|
|
342
|
+
getDelegateDescendantModels(schema, def.name, collected);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
return [
|
|
346
|
+
...collected
|
|
347
|
+
];
|
|
348
|
+
}
|
|
349
|
+
__name(getDelegateDescendantModels, "getDelegateDescendantModels");
|
|
350
|
+
function aggregate(eb, expr2, op) {
|
|
351
|
+
return 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();
|
|
352
|
+
}
|
|
353
|
+
__name(aggregate, "aggregate");
|
|
231
354
|
|
|
232
355
|
// src/client/crud/dialects/base.ts
|
|
233
|
-
import {
|
|
234
|
-
import
|
|
235
|
-
import { match, P } from "ts-pattern";
|
|
356
|
+
import { invariant, isPlainObject } from "@zenstackhq/common-helpers";
|
|
357
|
+
import { expressionBuilder, sql } from "kysely";
|
|
358
|
+
import { match as match2, P } from "ts-pattern";
|
|
236
359
|
|
|
237
360
|
// src/utils/enumerate.ts
|
|
238
361
|
function enumerate(x) {
|
|
@@ -249,7 +372,6 @@ function enumerate(x) {
|
|
|
249
372
|
__name(enumerate, "enumerate");
|
|
250
373
|
|
|
251
374
|
// src/client/crud/dialects/base.ts
|
|
252
|
-
import { isPlainObject } from "is-plain-object";
|
|
253
375
|
var BaseCrudDialect = class {
|
|
254
376
|
static {
|
|
255
377
|
__name(this, "BaseCrudDialect");
|
|
@@ -260,9 +382,20 @@ var BaseCrudDialect = class {
|
|
|
260
382
|
this.schema = schema;
|
|
261
383
|
this.options = options;
|
|
262
384
|
}
|
|
263
|
-
transformPrimitive(value, _type) {
|
|
385
|
+
transformPrimitive(value, _type, _forArrayField) {
|
|
264
386
|
return value;
|
|
265
387
|
}
|
|
388
|
+
// #region common query builders
|
|
389
|
+
buildSelectModel(eb, model) {
|
|
390
|
+
const modelDef = requireModel(this.schema, model);
|
|
391
|
+
let result = eb.selectFrom(model);
|
|
392
|
+
let joinBase = modelDef.baseModel;
|
|
393
|
+
while (joinBase) {
|
|
394
|
+
result = this.buildDelegateJoin(model, joinBase, result);
|
|
395
|
+
joinBase = requireModel(this.schema, joinBase).baseModel;
|
|
396
|
+
}
|
|
397
|
+
return result;
|
|
398
|
+
}
|
|
266
399
|
buildFilter(eb, model, modelAlias, where) {
|
|
267
400
|
if (where === true || where === void 0) {
|
|
268
401
|
return this.true(eb);
|
|
@@ -279,17 +412,20 @@ var BaseCrudDialect = class {
|
|
|
279
412
|
if (key.startsWith("$")) {
|
|
280
413
|
continue;
|
|
281
414
|
}
|
|
282
|
-
if (key
|
|
415
|
+
if (this.isLogicalCombinator(key)) {
|
|
283
416
|
result = this.and(eb, result, this.buildCompositeFilter(eb, model, modelAlias, key, payload));
|
|
284
417
|
continue;
|
|
285
418
|
}
|
|
286
419
|
const fieldDef = requireField(this.schema, model, key);
|
|
287
420
|
if (fieldDef.relation) {
|
|
288
421
|
result = this.and(eb, result, this.buildRelationFilter(eb, model, modelAlias, key, fieldDef, payload));
|
|
289
|
-
} else if (fieldDef.array) {
|
|
290
|
-
result = this.and(eb, result, this.buildArrayFilter(eb, model, modelAlias, key, fieldDef, payload));
|
|
291
422
|
} else {
|
|
292
|
-
|
|
423
|
+
const fieldRef = this.fieldRef(fieldDef.originModel ?? model, key, eb, fieldDef.originModel ?? modelAlias);
|
|
424
|
+
if (fieldDef.array) {
|
|
425
|
+
result = this.and(eb, result, this.buildArrayFilter(eb, fieldRef, fieldDef, payload));
|
|
426
|
+
} else {
|
|
427
|
+
result = this.and(eb, result, this.buildPrimitiveFilter(eb, fieldRef, fieldDef, payload));
|
|
428
|
+
}
|
|
293
429
|
}
|
|
294
430
|
}
|
|
295
431
|
if ("$expr" in _where && typeof _where["$expr"] === "function") {
|
|
@@ -297,8 +433,11 @@ var BaseCrudDialect = class {
|
|
|
297
433
|
}
|
|
298
434
|
return result;
|
|
299
435
|
}
|
|
436
|
+
isLogicalCombinator(key) {
|
|
437
|
+
return LOGICAL_COMBINATORS.includes(key);
|
|
438
|
+
}
|
|
300
439
|
buildCompositeFilter(eb, model, modelAlias, key, payload) {
|
|
301
|
-
return
|
|
440
|
+
return match2(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();
|
|
302
441
|
}
|
|
303
442
|
buildRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
|
|
304
443
|
if (!fieldDef.array) {
|
|
@@ -307,19 +446,26 @@ var BaseCrudDialect = class {
|
|
|
307
446
|
return this.buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload);
|
|
308
447
|
}
|
|
309
448
|
}
|
|
310
|
-
buildToOneRelationFilter(eb, model,
|
|
449
|
+
buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
|
|
311
450
|
if (payload === null) {
|
|
312
451
|
const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, model, field);
|
|
313
|
-
if (ownedByModel) {
|
|
314
|
-
return this.and(eb, ...keyPairs.map(({ fk }) => eb(sql.ref(`${
|
|
452
|
+
if (ownedByModel && !fieldDef.originModel) {
|
|
453
|
+
return this.and(eb, ...keyPairs.map(({ fk }) => eb(sql.ref(`${modelAlias}.${fk}`), "is", null)));
|
|
315
454
|
} else {
|
|
316
|
-
return this.buildToOneRelationFilter(eb, model,
|
|
455
|
+
return this.buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, {
|
|
317
456
|
is: null
|
|
318
457
|
});
|
|
319
458
|
}
|
|
320
459
|
}
|
|
321
|
-
const joinAlias = `${
|
|
322
|
-
const joinPairs = buildJoinPairs(
|
|
460
|
+
const joinAlias = `${modelAlias}$${field}`;
|
|
461
|
+
const joinPairs = buildJoinPairs(
|
|
462
|
+
this.schema,
|
|
463
|
+
model,
|
|
464
|
+
// if field is from a base, use the base model to join
|
|
465
|
+
fieldDef.originModel ?? modelAlias,
|
|
466
|
+
field,
|
|
467
|
+
joinAlias
|
|
468
|
+
);
|
|
323
469
|
const filterResultField = `${field}$filter`;
|
|
324
470
|
const joinSelect = eb.selectFrom(`${fieldDef.type} as ${joinAlias}`).where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql.ref(left), "=", sql.ref(right))))).select(() => eb.fn.count(eb.lit(1)).as(filterResultField));
|
|
325
471
|
const conditions = [];
|
|
@@ -380,30 +526,29 @@ var BaseCrudDialect = class {
|
|
|
380
526
|
}
|
|
381
527
|
switch (key) {
|
|
382
528
|
case "some": {
|
|
383
|
-
result = this.and(eb, result, eb(
|
|
529
|
+
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));
|
|
384
530
|
break;
|
|
385
531
|
}
|
|
386
532
|
case "every": {
|
|
387
|
-
result = this.and(eb, result, eb(
|
|
533
|
+
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));
|
|
388
534
|
break;
|
|
389
535
|
}
|
|
390
536
|
case "none": {
|
|
391
|
-
result = this.and(eb, result, eb(
|
|
537
|
+
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));
|
|
392
538
|
break;
|
|
393
539
|
}
|
|
394
540
|
}
|
|
395
541
|
}
|
|
396
542
|
return result;
|
|
397
543
|
}
|
|
398
|
-
buildArrayFilter(eb,
|
|
544
|
+
buildArrayFilter(eb, fieldRef, fieldDef, payload) {
|
|
399
545
|
const clauses = [];
|
|
400
546
|
const fieldType = fieldDef.type;
|
|
401
|
-
const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb, modelAlias);
|
|
402
547
|
for (const [key, _value] of Object.entries(payload)) {
|
|
403
548
|
if (_value === void 0) {
|
|
404
549
|
continue;
|
|
405
550
|
}
|
|
406
|
-
const value = this.transformPrimitive(_value, fieldType);
|
|
551
|
+
const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
|
|
407
552
|
switch (key) {
|
|
408
553
|
case "equals": {
|
|
409
554
|
clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
|
|
@@ -434,19 +579,23 @@ var BaseCrudDialect = class {
|
|
|
434
579
|
}
|
|
435
580
|
return this.and(eb, ...clauses);
|
|
436
581
|
}
|
|
437
|
-
buildPrimitiveFilter(eb,
|
|
582
|
+
buildPrimitiveFilter(eb, fieldRef, fieldDef, payload) {
|
|
438
583
|
if (payload === null) {
|
|
439
|
-
return eb(
|
|
584
|
+
return eb(fieldRef, "is", null);
|
|
440
585
|
}
|
|
441
586
|
if (isEnum(this.schema, fieldDef.type)) {
|
|
442
|
-
return this.buildEnumFilter(eb,
|
|
587
|
+
return this.buildEnumFilter(eb, fieldRef, fieldDef, payload);
|
|
443
588
|
}
|
|
444
|
-
return
|
|
589
|
+
return match2(fieldDef.type).with("String", () => this.buildStringFilter(eb, fieldRef, payload)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, fieldRef, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, fieldRef, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, fieldRef, payload)).with("Bytes", () => this.buildBytesFilter(eb, fieldRef, payload)).with("Json", () => {
|
|
590
|
+
throw new InternalError("JSON filters are not supported yet");
|
|
591
|
+
}).with("Unsupported", () => {
|
|
592
|
+
throw new QueryError(`Unsupported field cannot be used in filters`);
|
|
593
|
+
}).exhaustive();
|
|
445
594
|
}
|
|
446
595
|
buildLiteralFilter(eb, lhs, type, rhs) {
|
|
447
|
-
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type) : rhs);
|
|
596
|
+
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
|
|
448
597
|
}
|
|
449
|
-
buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
|
|
598
|
+
buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0, excludeKeys = []) {
|
|
450
599
|
if (payload === null || !isPlainObject(payload)) {
|
|
451
600
|
return {
|
|
452
601
|
conditions: [
|
|
@@ -461,8 +610,11 @@ var BaseCrudDialect = class {
|
|
|
461
610
|
if (onlyForKeys && !onlyForKeys.includes(op)) {
|
|
462
611
|
continue;
|
|
463
612
|
}
|
|
613
|
+
if (excludeKeys.includes(op)) {
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
464
616
|
const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
|
|
465
|
-
const condition =
|
|
617
|
+
const condition = match2(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
|
|
466
618
|
invariant(Array.isArray(rhs), "right hand side must be an array");
|
|
467
619
|
if (rhs.length === 0) {
|
|
468
620
|
return this.false(eb);
|
|
@@ -476,7 +628,11 @@ var BaseCrudDialect = class {
|
|
|
476
628
|
} else {
|
|
477
629
|
return eb.not(eb(lhs, "in", rhs));
|
|
478
630
|
}
|
|
479
|
-
}).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))).
|
|
631
|
+
}).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(P.union(...AGGREGATE_OPERATORS), (op2) => {
|
|
632
|
+
const innerResult = this.buildStandardFilter(eb, type, value, aggregate(eb, lhs, op2), getRhs, recurse, throwIfInvalid);
|
|
633
|
+
consumedKeys.push(...innerResult.consumedKeys);
|
|
634
|
+
return this.and(eb, ...innerResult.conditions);
|
|
635
|
+
}).otherwise(() => {
|
|
480
636
|
if (throwIfInvalid) {
|
|
481
637
|
throw new QueryError(`Invalid filter key: ${op}`);
|
|
482
638
|
} else {
|
|
@@ -493,24 +649,21 @@ var BaseCrudDialect = class {
|
|
|
493
649
|
consumedKeys
|
|
494
650
|
};
|
|
495
651
|
}
|
|
496
|
-
buildStringFilter(eb,
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
if (payload && typeof payload === "object" && "mode" in payload && payload.mode === "insensitive") {
|
|
501
|
-
insensitive = true;
|
|
502
|
-
fieldRef = eb.fn("lower", [
|
|
503
|
-
fieldRef
|
|
504
|
-
]);
|
|
652
|
+
buildStringFilter(eb, fieldRef, payload) {
|
|
653
|
+
let mode;
|
|
654
|
+
if (payload && typeof payload === "object" && "mode" in payload) {
|
|
655
|
+
mode = payload.mode;
|
|
505
656
|
}
|
|
506
|
-
const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload,
|
|
657
|
+
const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, mode === "insensitive" ? eb.fn("lower", [
|
|
658
|
+
fieldRef
|
|
659
|
+
]) : fieldRef, (value) => this.prepStringCasing(eb, value, mode), (value) => this.buildStringFilter(eb, fieldRef, value));
|
|
507
660
|
if (payload && typeof payload === "object") {
|
|
508
661
|
for (const [key, value] of Object.entries(payload)) {
|
|
509
662
|
if (key === "mode" || consumedKeys.includes(key)) {
|
|
510
663
|
continue;
|
|
511
664
|
}
|
|
512
|
-
const condition =
|
|
513
|
-
throw new
|
|
665
|
+
const condition = match2(key).with("contains", () => mode === "insensitive" ? eb(fieldRef, "ilike", sql.val(`%${value}%`)) : eb(fieldRef, "like", sql.val(`%${value}%`))).with("startsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", sql.val(`${value}%`)) : eb(fieldRef, "like", sql.val(`${value}%`))).with("endsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", sql.val(`%${value}`)) : eb(fieldRef, "like", sql.val(`%${value}`))).otherwise(() => {
|
|
666
|
+
throw new QueryError(`Invalid string filter key: ${key}`);
|
|
514
667
|
});
|
|
515
668
|
if (condition) {
|
|
516
669
|
conditions.push(condition);
|
|
@@ -519,34 +672,37 @@ var BaseCrudDialect = class {
|
|
|
519
672
|
}
|
|
520
673
|
return this.and(eb, ...conditions);
|
|
521
674
|
}
|
|
522
|
-
prepStringCasing(eb, value,
|
|
675
|
+
prepStringCasing(eb, value, mode) {
|
|
676
|
+
if (!mode || mode === "default") {
|
|
677
|
+
return value === null ? value : sql.val(value);
|
|
678
|
+
}
|
|
523
679
|
if (typeof value === "string") {
|
|
524
|
-
return
|
|
525
|
-
sql.
|
|
526
|
-
])
|
|
680
|
+
return eb.fn("lower", [
|
|
681
|
+
sql.val(value)
|
|
682
|
+
]);
|
|
527
683
|
} else if (Array.isArray(value)) {
|
|
528
|
-
return value.map((v) => this.prepStringCasing(eb, v,
|
|
684
|
+
return value.map((v) => this.prepStringCasing(eb, v, mode));
|
|
529
685
|
} else {
|
|
530
|
-
return value === null ? null : sql.
|
|
686
|
+
return value === null ? null : sql.val(value);
|
|
531
687
|
}
|
|
532
688
|
}
|
|
533
|
-
buildNumberFilter(eb,
|
|
534
|
-
const { conditions } = this.buildStandardFilter(eb, type, payload,
|
|
689
|
+
buildNumberFilter(eb, fieldRef, type, payload) {
|
|
690
|
+
const { conditions } = this.buildStandardFilter(eb, type, payload, fieldRef, (value) => this.transformPrimitive(value, type, false), (value) => this.buildNumberFilter(eb, fieldRef, type, value));
|
|
535
691
|
return this.and(eb, ...conditions);
|
|
536
692
|
}
|
|
537
|
-
buildBooleanFilter(eb,
|
|
538
|
-
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload,
|
|
693
|
+
buildBooleanFilter(eb, fieldRef, payload) {
|
|
694
|
+
const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, fieldRef, (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, fieldRef, value), true, [
|
|
539
695
|
"equals",
|
|
540
696
|
"not"
|
|
541
697
|
]);
|
|
542
698
|
return this.and(eb, ...conditions);
|
|
543
699
|
}
|
|
544
|
-
buildDateTimeFilter(eb,
|
|
545
|
-
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload,
|
|
700
|
+
buildDateTimeFilter(eb, fieldRef, payload) {
|
|
701
|
+
const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, fieldRef, (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, fieldRef, value), true);
|
|
546
702
|
return this.and(eb, ...conditions);
|
|
547
703
|
}
|
|
548
|
-
buildBytesFilter(eb,
|
|
549
|
-
const conditions = this.buildStandardFilter(eb, "Bytes", payload,
|
|
704
|
+
buildBytesFilter(eb, fieldRef, payload) {
|
|
705
|
+
const conditions = this.buildStandardFilter(eb, "Bytes", payload, fieldRef, (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, fieldRef, value), true, [
|
|
550
706
|
"equals",
|
|
551
707
|
"in",
|
|
552
708
|
"notIn",
|
|
@@ -554,8 +710,8 @@ var BaseCrudDialect = class {
|
|
|
554
710
|
]);
|
|
555
711
|
return this.and(eb, ...conditions.conditions);
|
|
556
712
|
}
|
|
557
|
-
buildEnumFilter(eb,
|
|
558
|
-
const conditions = this.buildStandardFilter(eb, "String", payload,
|
|
713
|
+
buildEnumFilter(eb, fieldRef, fieldDef, payload) {
|
|
714
|
+
const conditions = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => value, (value) => this.buildEnumFilter(eb, fieldRef, fieldDef, value), true, [
|
|
559
715
|
"equals",
|
|
560
716
|
"in",
|
|
561
717
|
"notIn",
|
|
@@ -587,9 +743,7 @@ var BaseCrudDialect = class {
|
|
|
587
743
|
invariant(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
|
|
588
744
|
for (const [k, v] of Object.entries(value)) {
|
|
589
745
|
invariant(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
|
|
590
|
-
result = result.orderBy((eb) => eb.
|
|
591
|
-
sql.ref(k)
|
|
592
|
-
]), sql.raw(this.negateSort(v, negated)));
|
|
746
|
+
result = result.orderBy((eb) => aggregate(eb, this.fieldRef(model, k, eb, modelAlias), field), sql.raw(this.negateSort(v, negated)));
|
|
593
747
|
}
|
|
594
748
|
continue;
|
|
595
749
|
}
|
|
@@ -598,7 +752,7 @@ var BaseCrudDialect = class {
|
|
|
598
752
|
invariant(value && typeof value === "object", 'invalid orderBy value for field "_count"');
|
|
599
753
|
for (const [k, v] of Object.entries(value)) {
|
|
600
754
|
invariant(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
|
|
601
|
-
result = result.orderBy((eb) => eb.fn.count(
|
|
755
|
+
result = result.orderBy((eb) => eb.fn.count(this.fieldRef(model, k, eb, modelAlias)), sql.raw(this.negateSort(v, negated)));
|
|
602
756
|
}
|
|
603
757
|
continue;
|
|
604
758
|
}
|
|
@@ -607,10 +761,11 @@ var BaseCrudDialect = class {
|
|
|
607
761
|
}
|
|
608
762
|
const fieldDef = requireField(this.schema, model, field);
|
|
609
763
|
if (!fieldDef.relation) {
|
|
764
|
+
const fieldRef = this.fieldRef(model, field, expressionBuilder(), modelAlias);
|
|
610
765
|
if (value === "asc" || value === "desc") {
|
|
611
|
-
result = result.orderBy(
|
|
766
|
+
result = result.orderBy(fieldRef, this.negateSort(value, negated));
|
|
612
767
|
} else if (value && typeof value === "object" && "nulls" in value && "sort" in value && (value.sort === "asc" || value.sort === "desc") && (value.nulls === "first" || value.nulls === "last")) {
|
|
613
|
-
result = result.orderBy(
|
|
768
|
+
result = result.orderBy(fieldRef, sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`));
|
|
614
769
|
}
|
|
615
770
|
} else {
|
|
616
771
|
const relationModel = fieldDef.type;
|
|
@@ -622,7 +777,7 @@ var BaseCrudDialect = class {
|
|
|
622
777
|
invariant(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
|
|
623
778
|
const sort = this.negateSort(value._count, negated);
|
|
624
779
|
result = result.orderBy((eb) => {
|
|
625
|
-
let subQuery =
|
|
780
|
+
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
626
781
|
const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, relationModel);
|
|
627
782
|
subQuery = subQuery.where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql.ref(left), "=", sql.ref(right)))));
|
|
628
783
|
subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
|
|
@@ -641,14 +796,90 @@ var BaseCrudDialect = class {
|
|
|
641
796
|
});
|
|
642
797
|
return result;
|
|
643
798
|
}
|
|
799
|
+
buildSelectAllFields(model, query, omit) {
|
|
800
|
+
const modelDef = requireModel(this.schema, model);
|
|
801
|
+
let result = query;
|
|
802
|
+
for (const field of Object.keys(modelDef.fields)) {
|
|
803
|
+
if (isRelationField(this.schema, model, field)) {
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
806
|
+
if (omit?.[field] === true) {
|
|
807
|
+
continue;
|
|
808
|
+
}
|
|
809
|
+
result = this.buildSelectField(result, model, model, field);
|
|
810
|
+
}
|
|
811
|
+
const descendants = getDelegateDescendantModels(this.schema, model);
|
|
812
|
+
for (const subModel of descendants) {
|
|
813
|
+
result = this.buildDelegateJoin(model, subModel.name, result);
|
|
814
|
+
result = result.select((eb) => {
|
|
815
|
+
const jsonObject = {};
|
|
816
|
+
for (const field of Object.keys(subModel.fields)) {
|
|
817
|
+
if (isRelationField(this.schema, subModel.name, field) || isInheritedField(this.schema, subModel.name, field)) {
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
jsonObject[field] = eb.ref(`${subModel.name}.${field}`);
|
|
821
|
+
}
|
|
822
|
+
return this.buildJsonObject(eb, jsonObject).as(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`);
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
return result;
|
|
826
|
+
}
|
|
827
|
+
buildSelectField(query, model, modelAlias, field) {
|
|
828
|
+
const fieldDef = requireField(this.schema, model, field);
|
|
829
|
+
if (fieldDef.computed) {
|
|
830
|
+
return query.select((eb) => this.fieldRef(model, field, eb, modelAlias).as(field));
|
|
831
|
+
} else if (!fieldDef.originModel) {
|
|
832
|
+
return query.select(sql.ref(`${modelAlias}.${field}`).as(field));
|
|
833
|
+
} else {
|
|
834
|
+
return this.buildSelectField(query, fieldDef.originModel, fieldDef.originModel, field);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
buildDelegateJoin(thisModel, otherModel, query) {
|
|
838
|
+
const idFields = getIdFields(this.schema, thisModel);
|
|
839
|
+
query = query.leftJoin(otherModel, (qb) => {
|
|
840
|
+
for (const idField of idFields) {
|
|
841
|
+
qb = qb.onRef(`${thisModel}.${idField}`, "=", `${otherModel}.${idField}`);
|
|
842
|
+
}
|
|
843
|
+
return qb;
|
|
844
|
+
});
|
|
845
|
+
return query;
|
|
846
|
+
}
|
|
847
|
+
buildCountJson(model, eb, parentAlias, payload) {
|
|
848
|
+
const modelDef = requireModel(this.schema, model);
|
|
849
|
+
const toManyRelations = Object.entries(modelDef.fields).filter(([, field]) => field.relation && field.array);
|
|
850
|
+
const selections = payload === true ? {
|
|
851
|
+
select: toManyRelations.reduce((acc, [field]) => {
|
|
852
|
+
acc[field] = true;
|
|
853
|
+
return acc;
|
|
854
|
+
}, {})
|
|
855
|
+
} : payload;
|
|
856
|
+
const jsonObject = {};
|
|
857
|
+
for (const [field, value] of Object.entries(selections.select)) {
|
|
858
|
+
const fieldDef = requireField(this.schema, model, field);
|
|
859
|
+
const fieldModel = fieldDef.type;
|
|
860
|
+
const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
|
|
861
|
+
let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
|
|
862
|
+
for (const [left, right] of joinPairs) {
|
|
863
|
+
fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
|
|
864
|
+
}
|
|
865
|
+
if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
|
|
866
|
+
const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
|
|
867
|
+
fieldCountQuery = fieldCountQuery.where(filter);
|
|
868
|
+
}
|
|
869
|
+
jsonObject[field] = fieldCountQuery;
|
|
870
|
+
}
|
|
871
|
+
return this.buildJsonObject(eb, jsonObject);
|
|
872
|
+
}
|
|
873
|
+
// #endregion
|
|
874
|
+
// #region utils
|
|
644
875
|
negateSort(sort, negated) {
|
|
645
876
|
return negated ? sort === "asc" ? "desc" : "asc" : sort;
|
|
646
877
|
}
|
|
647
878
|
true(eb) {
|
|
648
|
-
return eb.lit(this.transformPrimitive(true, "Boolean"));
|
|
879
|
+
return eb.lit(this.transformPrimitive(true, "Boolean", false));
|
|
649
880
|
}
|
|
650
881
|
false(eb) {
|
|
651
|
-
return eb.lit(this.transformPrimitive(false, "Boolean"));
|
|
882
|
+
return eb.lit(this.transformPrimitive(false, "Boolean", false));
|
|
652
883
|
}
|
|
653
884
|
isTrue(expression) {
|
|
654
885
|
const node = expression.toOperationNode();
|
|
@@ -687,6 +918,9 @@ var BaseCrudDialect = class {
|
|
|
687
918
|
not(eb, ...args) {
|
|
688
919
|
return eb.not(this.and(eb, ...args));
|
|
689
920
|
}
|
|
921
|
+
fieldRef(model, field, eb, modelAlias) {
|
|
922
|
+
return buildFieldRef(this.schema, model, field, this.options, eb, modelAlias);
|
|
923
|
+
}
|
|
690
924
|
};
|
|
691
925
|
|
|
692
926
|
// src/client/crud/dialects/postgresql.ts
|
|
@@ -697,14 +931,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
697
931
|
get provider() {
|
|
698
932
|
return "postgresql";
|
|
699
933
|
}
|
|
700
|
-
transformPrimitive(value, type) {
|
|
934
|
+
transformPrimitive(value, type, forArrayField) {
|
|
701
935
|
if (value === void 0) {
|
|
702
936
|
return value;
|
|
703
937
|
}
|
|
704
938
|
if (Array.isArray(value)) {
|
|
705
|
-
|
|
939
|
+
if (type === "Json" && !forArrayField) {
|
|
940
|
+
return JSON.stringify(value);
|
|
941
|
+
} else {
|
|
942
|
+
return value.map((v) => this.transformPrimitive(v, type, false));
|
|
943
|
+
}
|
|
706
944
|
} else {
|
|
707
|
-
return
|
|
945
|
+
return match3(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).with("Decimal", () => value !== null ? value.toString() : value).otherwise(() => value);
|
|
708
946
|
}
|
|
709
947
|
}
|
|
710
948
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
@@ -718,7 +956,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
718
956
|
const joinTableName = `${parentName}$${relationField}`;
|
|
719
957
|
let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
|
|
720
958
|
result = eb.selectFrom(() => {
|
|
721
|
-
let subQuery =
|
|
959
|
+
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
960
|
+
subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
|
|
722
961
|
if (payload && typeof payload === "object") {
|
|
723
962
|
if (payload.where) {
|
|
724
963
|
subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
|
|
@@ -762,34 +1001,57 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
762
1001
|
});
|
|
763
1002
|
return qb;
|
|
764
1003
|
}
|
|
765
|
-
buildRelationObjectArgs(relationModel, relationField, eb, payload,
|
|
1004
|
+
buildRelationObjectArgs(relationModel, relationField, eb, payload, parentAlias) {
|
|
766
1005
|
const relationModelDef = requireModel(this.schema, relationModel);
|
|
767
1006
|
const objArgs = [];
|
|
1007
|
+
const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
|
|
1008
|
+
if (descendantModels.length > 0) {
|
|
1009
|
+
objArgs.push(...descendantModels.map((subModel) => [
|
|
1010
|
+
sql2.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
|
|
1011
|
+
eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
|
|
1012
|
+
]).flatMap((v) => v));
|
|
1013
|
+
}
|
|
768
1014
|
if (payload === true || !payload.select) {
|
|
769
1015
|
objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
|
|
770
1016
|
sql2.lit(field),
|
|
771
|
-
|
|
1017
|
+
this.fieldRef(relationModel, field, eb)
|
|
772
1018
|
]).flatMap((v) => v));
|
|
773
1019
|
} else if (payload.select) {
|
|
774
|
-
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) =>
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
1020
|
+
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
|
|
1021
|
+
if (field === "_count") {
|
|
1022
|
+
const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
|
|
1023
|
+
return [
|
|
1024
|
+
sql2.lit(field),
|
|
1025
|
+
subJson
|
|
1026
|
+
];
|
|
1027
|
+
} else {
|
|
1028
|
+
const fieldDef = requireField(this.schema, relationModel, field);
|
|
1029
|
+
const fieldValue = fieldDef.relation ? eb.ref(`${parentAlias}$${relationField}$${field}.$j`) : this.fieldRef(relationModel, field, eb);
|
|
1030
|
+
return [
|
|
1031
|
+
sql2.lit(field),
|
|
1032
|
+
fieldValue
|
|
1033
|
+
];
|
|
1034
|
+
}
|
|
1035
|
+
}).flatMap((v) => v));
|
|
778
1036
|
}
|
|
779
1037
|
if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
|
|
780
1038
|
objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
|
|
781
1039
|
sql2.lit(field),
|
|
782
|
-
|
|
1040
|
+
// reference the synthesized JSON field
|
|
1041
|
+
eb.ref(`${parentAlias}$${relationField}$${field}.$j`)
|
|
783
1042
|
]).flatMap((v) => v));
|
|
784
1043
|
}
|
|
785
1044
|
return objArgs;
|
|
786
1045
|
}
|
|
787
|
-
buildRelationJoins(
|
|
1046
|
+
buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
|
|
788
1047
|
let result = qb;
|
|
789
|
-
if (typeof payload === "object"
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
1048
|
+
if (typeof payload === "object") {
|
|
1049
|
+
const selectInclude = payload.include ?? payload.select;
|
|
1050
|
+
if (selectInclude && typeof selectInclude === "object") {
|
|
1051
|
+
Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
|
|
1052
|
+
result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
793
1055
|
}
|
|
794
1056
|
return result;
|
|
795
1057
|
}
|
|
@@ -829,12 +1091,15 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
829
1091
|
return `ARRAY[${values.map((v) => typeof v === "string" ? `'${v}'` : v)}]`;
|
|
830
1092
|
}
|
|
831
1093
|
}
|
|
1094
|
+
get supportInsertWithDefault() {
|
|
1095
|
+
return true;
|
|
1096
|
+
}
|
|
832
1097
|
};
|
|
833
1098
|
|
|
834
1099
|
// src/client/crud/dialects/sqlite.ts
|
|
1100
|
+
import { invariant as invariant3 } from "@zenstackhq/common-helpers";
|
|
835
1101
|
import { sql as sql3 } from "kysely";
|
|
836
|
-
import
|
|
837
|
-
import { match as match3 } from "ts-pattern";
|
|
1102
|
+
import { match as match4 } from "ts-pattern";
|
|
838
1103
|
var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
839
1104
|
static {
|
|
840
1105
|
__name(this, "SqliteCrudDialect");
|
|
@@ -842,26 +1107,31 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
842
1107
|
get provider() {
|
|
843
1108
|
return "sqlite";
|
|
844
1109
|
}
|
|
845
|
-
transformPrimitive(value, type) {
|
|
1110
|
+
transformPrimitive(value, type, _forArrayField) {
|
|
846
1111
|
if (value === void 0) {
|
|
847
1112
|
return value;
|
|
848
1113
|
}
|
|
849
1114
|
if (Array.isArray(value)) {
|
|
850
|
-
return value.map((v) => this.transformPrimitive(v, type));
|
|
1115
|
+
return value.map((v) => this.transformPrimitive(v, type, false));
|
|
851
1116
|
} else {
|
|
852
|
-
|
|
1117
|
+
if (this.schema.typeDefs && type in this.schema.typeDefs) {
|
|
1118
|
+
return JSON.stringify(value);
|
|
1119
|
+
} else {
|
|
1120
|
+
return match4(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);
|
|
1121
|
+
}
|
|
853
1122
|
}
|
|
854
1123
|
}
|
|
855
1124
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
856
1125
|
return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
|
|
857
1126
|
}
|
|
858
|
-
buildRelationJSON(model, eb, relationField,
|
|
1127
|
+
buildRelationJSON(model, eb, relationField, parentAlias, payload) {
|
|
859
1128
|
const relationFieldDef = requireField(this.schema, model, relationField);
|
|
860
1129
|
const relationModel = relationFieldDef.type;
|
|
861
1130
|
const relationModelDef = requireModel(this.schema, relationModel);
|
|
862
|
-
const subQueryName = `${
|
|
1131
|
+
const subQueryName = `${parentAlias}$${relationField}`;
|
|
863
1132
|
let tbl = eb.selectFrom(() => {
|
|
864
|
-
let subQuery =
|
|
1133
|
+
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
1134
|
+
subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
|
|
865
1135
|
if (payload && typeof payload === "object") {
|
|
866
1136
|
if (payload.where) {
|
|
867
1137
|
subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
|
|
@@ -882,14 +1152,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
882
1152
|
const relationIds = getIdFields(this.schema, relationModel);
|
|
883
1153
|
invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
884
1154
|
invariant3(relationIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
885
|
-
subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${
|
|
1155
|
+
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}`)));
|
|
886
1156
|
} else {
|
|
887
1157
|
const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
|
|
888
1158
|
keyPairs.forEach(({ fk, pk }) => {
|
|
889
1159
|
if (ownedByModel) {
|
|
890
|
-
subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${
|
|
1160
|
+
subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentAlias}.${fk}`);
|
|
891
1161
|
} else {
|
|
892
|
-
subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${
|
|
1162
|
+
subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentAlias}.${pk}`);
|
|
893
1163
|
}
|
|
894
1164
|
});
|
|
895
1165
|
}
|
|
@@ -897,31 +1167,46 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
897
1167
|
});
|
|
898
1168
|
tbl = tbl.select(() => {
|
|
899
1169
|
const objArgs = [];
|
|
1170
|
+
const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
|
|
1171
|
+
if (descendantModels.length > 0) {
|
|
1172
|
+
objArgs.push(...descendantModels.map((subModel) => [
|
|
1173
|
+
sql3.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
|
|
1174
|
+
eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
|
|
1175
|
+
]).flatMap((v) => v));
|
|
1176
|
+
}
|
|
900
1177
|
if (payload === true || !payload.select) {
|
|
901
1178
|
objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
|
|
902
1179
|
sql3.lit(field),
|
|
903
|
-
|
|
1180
|
+
this.fieldRef(relationModel, field, eb)
|
|
904
1181
|
]).flatMap((v) => v));
|
|
905
1182
|
} else if (payload.select) {
|
|
906
1183
|
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
|
|
1184
|
+
if (field === "_count") {
|
|
1185
|
+
const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
|
|
910
1186
|
return [
|
|
911
1187
|
sql3.lit(field),
|
|
912
1188
|
subJson
|
|
913
1189
|
];
|
|
914
1190
|
} else {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1191
|
+
const fieldDef = requireField(this.schema, relationModel, field);
|
|
1192
|
+
if (fieldDef.relation) {
|
|
1193
|
+
const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
|
|
1194
|
+
return [
|
|
1195
|
+
sql3.lit(field),
|
|
1196
|
+
subJson
|
|
1197
|
+
];
|
|
1198
|
+
} else {
|
|
1199
|
+
return [
|
|
1200
|
+
sql3.lit(field),
|
|
1201
|
+
this.fieldRef(relationModel, field, eb)
|
|
1202
|
+
];
|
|
1203
|
+
}
|
|
919
1204
|
}
|
|
920
1205
|
}).flatMap((v) => v));
|
|
921
1206
|
}
|
|
922
1207
|
if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
|
|
923
1208
|
objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
|
|
924
|
-
const subJson = this.buildRelationJSON(relationModel, eb, field, `${
|
|
1209
|
+
const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
|
|
925
1210
|
return [
|
|
926
1211
|
sql3.lit(field),
|
|
927
1212
|
subJson
|
|
@@ -971,93 +1256,17 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
971
1256
|
buildArrayLiteralSQL(_values) {
|
|
972
1257
|
throw new Error("SQLite does not support array literals");
|
|
973
1258
|
}
|
|
1259
|
+
get supportInsertWithDefault() {
|
|
1260
|
+
return false;
|
|
1261
|
+
}
|
|
974
1262
|
};
|
|
975
1263
|
|
|
976
1264
|
// src/client/crud/dialects/index.ts
|
|
977
1265
|
function getCrudDialect(schema, options) {
|
|
978
|
-
return
|
|
1266
|
+
return match5(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
|
|
979
1267
|
}
|
|
980
1268
|
__name(getCrudDialect, "getCrudDialect");
|
|
981
1269
|
|
|
982
|
-
// src/schema/expression.ts
|
|
983
|
-
var ExpressionUtils = {
|
|
984
|
-
literal: /* @__PURE__ */ __name((value) => {
|
|
985
|
-
return {
|
|
986
|
-
kind: "literal",
|
|
987
|
-
value
|
|
988
|
-
};
|
|
989
|
-
}, "literal"),
|
|
990
|
-
array: /* @__PURE__ */ __name((items) => {
|
|
991
|
-
return {
|
|
992
|
-
kind: "array",
|
|
993
|
-
items
|
|
994
|
-
};
|
|
995
|
-
}, "array"),
|
|
996
|
-
call: /* @__PURE__ */ __name((functionName, args) => {
|
|
997
|
-
return {
|
|
998
|
-
kind: "call",
|
|
999
|
-
function: functionName,
|
|
1000
|
-
args
|
|
1001
|
-
};
|
|
1002
|
-
}, "call"),
|
|
1003
|
-
binary: /* @__PURE__ */ __name((left, op, right) => {
|
|
1004
|
-
return {
|
|
1005
|
-
kind: "binary",
|
|
1006
|
-
op,
|
|
1007
|
-
left,
|
|
1008
|
-
right
|
|
1009
|
-
};
|
|
1010
|
-
}, "binary"),
|
|
1011
|
-
unary: /* @__PURE__ */ __name((op, operand) => {
|
|
1012
|
-
return {
|
|
1013
|
-
kind: "unary",
|
|
1014
|
-
op,
|
|
1015
|
-
operand
|
|
1016
|
-
};
|
|
1017
|
-
}, "unary"),
|
|
1018
|
-
field: /* @__PURE__ */ __name((field) => {
|
|
1019
|
-
return {
|
|
1020
|
-
kind: "field",
|
|
1021
|
-
field
|
|
1022
|
-
};
|
|
1023
|
-
}, "field"),
|
|
1024
|
-
member: /* @__PURE__ */ __name((receiver, members) => {
|
|
1025
|
-
return {
|
|
1026
|
-
kind: "member",
|
|
1027
|
-
receiver,
|
|
1028
|
-
members
|
|
1029
|
-
};
|
|
1030
|
-
}, "member"),
|
|
1031
|
-
_this: /* @__PURE__ */ __name(() => {
|
|
1032
|
-
return {
|
|
1033
|
-
kind: "this"
|
|
1034
|
-
};
|
|
1035
|
-
}, "_this"),
|
|
1036
|
-
_null: /* @__PURE__ */ __name(() => {
|
|
1037
|
-
return {
|
|
1038
|
-
kind: "null"
|
|
1039
|
-
};
|
|
1040
|
-
}, "_null"),
|
|
1041
|
-
and: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
1042
|
-
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
|
|
1043
|
-
}, "and"),
|
|
1044
|
-
or: /* @__PURE__ */ __name((expr2, ...expressions) => {
|
|
1045
|
-
return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
|
|
1046
|
-
}, "or"),
|
|
1047
|
-
is: /* @__PURE__ */ __name((value, kind) => {
|
|
1048
|
-
return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
|
|
1049
|
-
}, "is"),
|
|
1050
|
-
isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
|
|
1051
|
-
isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
|
|
1052
|
-
isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
|
|
1053
|
-
isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
|
|
1054
|
-
isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
|
|
1055
|
-
isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
|
|
1056
|
-
isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
|
|
1057
|
-
isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
|
|
1058
|
-
isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
|
|
1059
|
-
};
|
|
1060
|
-
|
|
1061
1270
|
// src/utils/default-operation-node-visitor.ts
|
|
1062
1271
|
import { OperationNodeVisitor } from "kysely";
|
|
1063
1272
|
var DefaultOperationNodeVisitor = class extends OperationNodeVisitor {
|
|
@@ -1377,19 +1586,19 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
|
|
|
1377
1586
|
};
|
|
1378
1587
|
|
|
1379
1588
|
// src/plugins/policy/expression-transformer.ts
|
|
1380
|
-
import {
|
|
1381
|
-
import
|
|
1382
|
-
import { match as
|
|
1589
|
+
import { invariant as invariant5 } from "@zenstackhq/common-helpers";
|
|
1590
|
+
import { AliasNode as AliasNode2, BinaryOperationNode as BinaryOperationNode2, ColumnNode, expressionBuilder as expressionBuilder2, FromNode, FunctionNode as FunctionNode2, IdentifierNode, OperatorNode as OperatorNode2, ReferenceNode as ReferenceNode2, SelectionNode, SelectQueryNode, TableNode as TableNode2, ValueListNode, ValueNode as ValueNode2, WhereNode } from "kysely";
|
|
1591
|
+
import { match as match7 } from "ts-pattern";
|
|
1383
1592
|
|
|
1384
1593
|
// src/plugins/policy/expression-evaluator.ts
|
|
1385
|
-
import invariant4 from "
|
|
1386
|
-
import { match as
|
|
1594
|
+
import { invariant as invariant4 } from "@zenstackhq/common-helpers";
|
|
1595
|
+
import { match as match6 } from "ts-pattern";
|
|
1387
1596
|
var ExpressionEvaluator = class {
|
|
1388
1597
|
static {
|
|
1389
1598
|
__name(this, "ExpressionEvaluator");
|
|
1390
1599
|
}
|
|
1391
1600
|
evaluate(expression, context) {
|
|
1392
|
-
const result =
|
|
1601
|
+
const result = match6(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();
|
|
1393
1602
|
return result ?? null;
|
|
1394
1603
|
}
|
|
1395
1604
|
evaluateCall(expr2, context) {
|
|
@@ -1400,7 +1609,7 @@ var ExpressionEvaluator = class {
|
|
|
1400
1609
|
}
|
|
1401
1610
|
}
|
|
1402
1611
|
evaluateUnary(expr2, context) {
|
|
1403
|
-
return
|
|
1612
|
+
return match6(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
|
|
1404
1613
|
}
|
|
1405
1614
|
evaluateMember(expr2, context) {
|
|
1406
1615
|
let val = this.evaluate(expr2.receiver, context);
|
|
@@ -1424,7 +1633,7 @@ var ExpressionEvaluator = class {
|
|
|
1424
1633
|
}
|
|
1425
1634
|
const left = this.evaluate(expr2.left, context);
|
|
1426
1635
|
const right = this.evaluate(expr2.right, context);
|
|
1427
|
-
return
|
|
1636
|
+
return match6(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", () => {
|
|
1428
1637
|
const _right = right ?? [];
|
|
1429
1638
|
invariant4(Array.isArray(_right), 'expected array for "in" operator');
|
|
1430
1639
|
return _right.includes(left);
|
|
@@ -1438,7 +1647,7 @@ var ExpressionEvaluator = class {
|
|
|
1438
1647
|
return false;
|
|
1439
1648
|
}
|
|
1440
1649
|
invariant4(Array.isArray(left), "expected array");
|
|
1441
|
-
return
|
|
1650
|
+
return match6(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
|
|
1442
1651
|
...context,
|
|
1443
1652
|
thisValue: item
|
|
1444
1653
|
}))).with("!", () => left.every((item) => this.evaluate(expr2.right, {
|
|
@@ -1454,11 +1663,11 @@ var ExpressionEvaluator = class {
|
|
|
1454
1663
|
// src/plugins/policy/utils.ts
|
|
1455
1664
|
import { AliasNode, AndNode, BinaryOperationNode, FunctionNode, OperatorNode, OrNode, ParensNode, ReferenceNode, TableNode, UnaryOperationNode, ValueNode } from "kysely";
|
|
1456
1665
|
function trueNode(dialect) {
|
|
1457
|
-
return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
|
|
1666
|
+
return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
|
|
1458
1667
|
}
|
|
1459
1668
|
__name(trueNode, "trueNode");
|
|
1460
1669
|
function falseNode(dialect) {
|
|
1461
|
-
return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
|
|
1670
|
+
return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
|
|
1462
1671
|
}
|
|
1463
1672
|
__name(falseNode, "falseNode");
|
|
1464
1673
|
function isTrueNode(node) {
|
|
@@ -1692,7 +1901,7 @@ var ExpressionTransformer = class {
|
|
|
1692
1901
|
const count = FunctionNode2.create("count", [
|
|
1693
1902
|
ValueNode2.createImmediate(1)
|
|
1694
1903
|
]);
|
|
1695
|
-
const predicateResult =
|
|
1904
|
+
const predicateResult = match7(expr2.op).with("?", () => BinaryOperationNode2.create(count, OperatorNode2.create(">"), ValueNode2.createImmediate(0))).with("!", () => BinaryOperationNode2.create(count, OperatorNode2.create("="), ValueNode2.createImmediate(0))).with("^", () => BinaryOperationNode2.create(count, OperatorNode2.create("="), ValueNode2.createImmediate(0))).exhaustive();
|
|
1696
1905
|
return this.transform(expr2.left, {
|
|
1697
1906
|
...context,
|
|
1698
1907
|
memberSelect: SelectionNode.create(AliasNode2.create(predicateResult, IdentifierNode.create("$t"))),
|
|
@@ -1716,14 +1925,14 @@ var ExpressionTransformer = class {
|
|
|
1716
1925
|
}
|
|
1717
1926
|
}
|
|
1718
1927
|
transformValue(value, type) {
|
|
1719
|
-
return ValueNode2.create(this.dialect.transformPrimitive(value, type) ?? null);
|
|
1928
|
+
return ValueNode2.create(this.dialect.transformPrimitive(value, type, false) ?? null);
|
|
1720
1929
|
}
|
|
1721
1930
|
_unary(expr2, context) {
|
|
1722
1931
|
invariant5(expr2.op === "!", 'only "!" operator is supported');
|
|
1723
1932
|
return BinaryOperationNode2.create(this.transform(expr2.operand, context), this.transformOperator("!="), trueNode(this.dialect));
|
|
1724
1933
|
}
|
|
1725
1934
|
transformOperator(op) {
|
|
1726
|
-
const mappedOp =
|
|
1935
|
+
const mappedOp = match7(op).with("==", () => "=").otherwise(() => op);
|
|
1727
1936
|
return OperatorNode2.create(mappedOp);
|
|
1728
1937
|
}
|
|
1729
1938
|
_call(expr2, context) {
|
|
@@ -1735,7 +1944,7 @@ var ExpressionTransformer = class {
|
|
|
1735
1944
|
if (!func) {
|
|
1736
1945
|
throw new QueryError(`Function not implemented: ${expr2.function}`);
|
|
1737
1946
|
}
|
|
1738
|
-
const eb =
|
|
1947
|
+
const eb = expressionBuilder2();
|
|
1739
1948
|
return func(eb, (expr2.args ?? []).map((arg) => this.transformCallArg(eb, arg, context)), {
|
|
1740
1949
|
dialect: this.dialect,
|
|
1741
1950
|
model: context.model,
|
|
@@ -1959,7 +2168,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1959
2168
|
get kysely() {
|
|
1960
2169
|
return this.client.$qb;
|
|
1961
2170
|
}
|
|
1962
|
-
async handle(node, proceed
|
|
2171
|
+
async handle(node, proceed) {
|
|
1963
2172
|
if (!this.isCrudQueryNode(node)) {
|
|
1964
2173
|
throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
|
|
1965
2174
|
}
|
|
@@ -1979,27 +2188,20 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
1979
2188
|
if (!mutationRequiresTransaction && !node.returning) {
|
|
1980
2189
|
return proceed(this.transformNode(node));
|
|
1981
2190
|
}
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
const
|
|
1989
|
-
if (
|
|
1990
|
-
|
|
1991
|
-
if (readBackResult.rows.length !== result2.rows.length) {
|
|
1992
|
-
readBackError = true;
|
|
1993
|
-
}
|
|
1994
|
-
return readBackResult;
|
|
1995
|
-
} else {
|
|
1996
|
-
return result2;
|
|
2191
|
+
if (InsertQueryNode.is(node)) {
|
|
2192
|
+
await this.enforcePreCreatePolicy(node, proceed);
|
|
2193
|
+
}
|
|
2194
|
+
const transformedNode = this.transformNode(node);
|
|
2195
|
+
const result = await proceed(transformedNode);
|
|
2196
|
+
if (!this.onlyReturningId(node)) {
|
|
2197
|
+
const readBackResult = await this.processReadBack(node, result, proceed);
|
|
2198
|
+
if (readBackResult.rows.length !== result.rows.length) {
|
|
2199
|
+
throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
|
|
1997
2200
|
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2201
|
+
return readBackResult;
|
|
2202
|
+
} else {
|
|
2203
|
+
return result;
|
|
2001
2204
|
}
|
|
2002
|
-
return result;
|
|
2003
2205
|
}
|
|
2004
2206
|
onlyReturningId(node) {
|
|
2005
2207
|
if (!node.returning) {
|
|
@@ -2060,11 +2262,11 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2060
2262
|
if (typeof item === "object" && item && "kind" in item) {
|
|
2061
2263
|
invariant6(item.kind === "ValueNode", "expecting a ValueNode");
|
|
2062
2264
|
result.push({
|
|
2063
|
-
node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
|
|
2265
|
+
node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
|
|
2064
2266
|
raw: item.value
|
|
2065
2267
|
});
|
|
2066
2268
|
} else {
|
|
2067
|
-
const value = this.dialect.transformPrimitive(item, fieldDef.type);
|
|
2269
|
+
const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
|
|
2068
2270
|
if (Array.isArray(value)) {
|
|
2069
2271
|
result.push({
|
|
2070
2272
|
node: RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
|
|
@@ -2133,7 +2335,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
|
|
|
2133
2335
|
return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => BinaryOperationNode3.create(ColumnNode2.create(field), OperatorNode3.create("="), ValueNode3.create(row[field]))))));
|
|
2134
2336
|
}
|
|
2135
2337
|
getMutationModel(node) {
|
|
2136
|
-
const r =
|
|
2338
|
+
const r = match8(node).when(InsertQueryNode.is, (node2) => getTableName(node2.into)).when(UpdateQueryNode.is, (node2) => getTableName(node2.table)).when(DeleteQueryNode.is, (node2) => {
|
|
2137
2339
|
if (node2.from.froms.length !== 1) {
|
|
2138
2340
|
throw new InternalError("Only one from table is supported for delete");
|
|
2139
2341
|
}
|
|
@@ -2295,13 +2497,22 @@ var PolicyPlugin = class {
|
|
|
2295
2497
|
get description() {
|
|
2296
2498
|
return "Enforces access policies defined in the schema.";
|
|
2297
2499
|
}
|
|
2298
|
-
onKyselyQuery({
|
|
2500
|
+
onKyselyQuery({
|
|
2501
|
+
query,
|
|
2502
|
+
client,
|
|
2503
|
+
proceed
|
|
2504
|
+
/*, transaction*/
|
|
2505
|
+
}) {
|
|
2299
2506
|
const handler = new PolicyHandler(client);
|
|
2300
|
-
return handler.handle(
|
|
2507
|
+
return handler.handle(
|
|
2508
|
+
query,
|
|
2509
|
+
proceed
|
|
2510
|
+
/*, transaction*/
|
|
2511
|
+
);
|
|
2301
2512
|
}
|
|
2302
2513
|
};
|
|
2303
2514
|
export {
|
|
2304
2515
|
PolicyPlugin,
|
|
2305
2516
|
RejectedByPolicyError
|
|
2306
2517
|
};
|
|
2307
|
-
//# sourceMappingURL=
|
|
2518
|
+
//# sourceMappingURL=index.js.map
|