@zenstackhq/runtime 3.0.0-alpha.2 → 3.0.0-alpha.20

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.
Files changed (43) hide show
  1. package/dist/{contract-DguafRNB.d.cts → contract-XFKcwhq7.d.cts} +970 -785
  2. package/dist/{contract-DguafRNB.d.ts → contract-XFKcwhq7.d.ts} +970 -785
  3. package/dist/{utils/pg-utils.cjs → helpers.cjs} +8 -16
  4. package/dist/helpers.cjs.map +1 -0
  5. package/dist/helpers.d.cts +1 -0
  6. package/dist/helpers.d.ts +1 -0
  7. package/dist/helpers.js +6 -0
  8. package/dist/helpers.js.map +1 -0
  9. package/dist/index.cjs +1774 -892
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +28 -6
  12. package/dist/index.d.ts +28 -6
  13. package/dist/index.js +1724 -847
  14. package/dist/index.js.map +1 -1
  15. package/dist/plugins/{policy.cjs → policy/index.cjs} +463 -266
  16. package/dist/plugins/policy/index.cjs.map +1 -0
  17. package/dist/plugins/{policy.d.ts → policy/index.d.cts} +2 -4
  18. package/dist/plugins/{policy.d.cts → policy/index.d.ts} +2 -4
  19. package/dist/plugins/{policy.js → policy/index.js} +435 -228
  20. package/dist/plugins/policy/index.js.map +1 -0
  21. package/dist/plugins/policy/plugin.zmodel +33 -0
  22. package/dist/schema.cjs.map +1 -1
  23. package/dist/schema.js.map +1 -1
  24. package/package.json +27 -49
  25. package/dist/client.cjs +0 -6094
  26. package/dist/client.cjs.map +0 -1
  27. package/dist/client.d.cts +0 -19
  28. package/dist/client.d.ts +0 -19
  29. package/dist/client.js +0 -6060
  30. package/dist/client.js.map +0 -1
  31. package/dist/plugins/policy.cjs.map +0 -1
  32. package/dist/plugins/policy.js.map +0 -1
  33. package/dist/utils/pg-utils.cjs.map +0 -1
  34. package/dist/utils/pg-utils.d.cts +0 -8
  35. package/dist/utils/pg-utils.d.ts +0 -8
  36. package/dist/utils/pg-utils.js +0 -16
  37. package/dist/utils/pg-utils.js.map +0 -1
  38. package/dist/utils/sqlite-utils.cjs +0 -55
  39. package/dist/utils/sqlite-utils.cjs.map +0 -1
  40. package/dist/utils/sqlite-utils.d.cts +0 -8
  41. package/dist/utils/sqlite-utils.d.ts +0 -8
  42. package/dist/utils/sqlite-utils.js +0 -22
  43. 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 invariant6 from "tiny-invariant";
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 match4 } from "ts-pattern";
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 invariant2 from "tiny-invariant";
27
- import { match as match2 } from "ts-pattern";
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
356
+ import { invariant, isPlainObject } from "@zenstackhq/common-helpers";
233
357
  import { sql } from "kysely";
234
- import invariant from "tiny-invariant";
235
- import { match, P } from "ts-pattern";
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 === "AND" || key === "OR" || key === "NOT") {
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
- result = this.and(eb, result, this.buildPrimitiveFilter(eb, model, modelAlias, key, fieldDef, payload));
423
+ const fieldRef = buildFieldRef(this.schema, fieldDef.originModel ?? model, key, this.options, 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 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();
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, table, field, fieldDef, payload) {
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(`${table}.${fk}`), "is", null)));
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, table, field, fieldDef, {
455
+ return this.buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, {
317
456
  is: null
318
457
  });
319
458
  }
320
459
  }
321
- const joinAlias = `${table}$${field}`;
322
- const joinPairs = buildJoinPairs(this.schema, model, table, field, joinAlias);
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(eb.selectFrom(relationModel).select((eb1) => eb1.fn.count(eb1.lit(1)).as("count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationModel, subPayload)), ">", 0));
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(eb.selectFrom(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));
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(eb.selectFrom(relationModel).select((eb1) => eb1.fn.count(eb1.lit(1)).as("count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationModel, subPayload)), "=", 0));
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, model, modelAlias, field, fieldDef, payload) {
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, model, modelAlias, field, fieldDef, payload) {
582
+ buildPrimitiveFilter(eb, fieldRef, fieldDef, payload) {
438
583
  if (payload === null) {
439
- return eb(sql.ref(`${modelAlias}.${field}`), "is", null);
584
+ return eb(fieldRef, "is", null);
440
585
  }
441
586
  if (isEnum(this.schema, fieldDef.type)) {
442
- return this.buildEnumFilter(eb, modelAlias, field, fieldDef, payload);
587
+ return this.buildEnumFilter(eb, fieldRef, fieldDef, payload);
443
588
  }
444
- return match(fieldDef.type).with("String", () => this.buildStringFilter(eb, modelAlias, field, payload)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, model, modelAlias, field, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, modelAlias, field, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, modelAlias, field, payload)).with("Bytes", () => this.buildBytesFilter(eb, modelAlias, field, payload)).exhaustive();
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 = match(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
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))).otherwise(() => {
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, table, field, payload) {
497
- const fieldDef = getField(this.schema, table, field);
498
- let fieldRef = fieldDef?.computed ? sql.ref(field) : sql.ref(`${table}.${field}`);
499
- let insensitive = false;
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, fieldRef, (value) => this.prepStringCasing(eb, value, insensitive), (value) => this.buildStringFilter(eb, table, field, value));
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 = match(key).with("contains", () => insensitive ? eb(fieldRef, "ilike", sql.lit(`%${value}%`)) : eb(fieldRef, "like", sql.lit(`%${value}%`))).with("startsWith", () => insensitive ? eb(fieldRef, "ilike", sql.lit(`${value}%`)) : eb(fieldRef, "like", sql.lit(`${value}%`))).with("endsWith", () => insensitive ? eb(fieldRef, "ilike", sql.lit(`%${value}`)) : eb(fieldRef, "like", sql.lit(`%${value}`))).otherwise(() => {
513
- throw new Error(`Invalid string filter key: ${key}`);
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, toLower = true) {
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 toLower ? eb.fn("lower", [
525
- sql.lit(value)
526
- ]) : sql.lit(value);
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, toLower));
684
+ return value.map((v) => this.prepStringCasing(eb, v, mode));
529
685
  } else {
530
- return value === null ? null : sql.lit(value);
686
+ return value === null ? null : sql.val(value);
531
687
  }
532
688
  }
533
- buildNumberFilter(eb, model, table, field, type, payload) {
534
- const { conditions } = this.buildStandardFilter(eb, type, payload, buildFieldRef(this.schema, model, field, this.options, eb), (value) => this.transformPrimitive(value, type), (value) => this.buildNumberFilter(eb, model, table, field, type, value));
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, table, field, payload) {
538
- const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Boolean"), (value) => this.buildBooleanFilter(eb, table, field, value), true, [
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, table, field, payload) {
545
- const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "DateTime"), (value) => this.buildDateTimeFilter(eb, table, field, value), true);
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, table, field, payload) {
549
- const conditions = this.buildStandardFilter(eb, "Bytes", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Bytes"), (value) => this.buildBytesFilter(eb, table, field, value), true, [
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, table, field, fieldDef, payload) {
558
- const conditions = this.buildStandardFilter(eb, "String", payload, sql.ref(`${table}.${field}`), (value) => value, (value) => this.buildEnumFilter(eb, table, field, fieldDef, value), true, [
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.fn(field.slice(1), [
591
- sql.ref(k)
592
- ]), sql.raw(this.negateSort(v, negated)));
746
+ result = result.orderBy((eb) => aggregate(eb, sql.ref(`${modelAlias}.${k}`), field), sql.raw(this.negateSort(v, negated)));
593
747
  }
594
748
  continue;
595
749
  }
@@ -622,7 +776,7 @@ var BaseCrudDialect = class {
622
776
  invariant(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
623
777
  const sort = this.negateSort(value._count, negated);
624
778
  result = result.orderBy((eb) => {
625
- let subQuery = eb.selectFrom(relationModel);
779
+ let subQuery = this.buildSelectModel(eb, relationModel);
626
780
  const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, relationModel);
627
781
  subQuery = subQuery.where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql.ref(left), "=", sql.ref(right)))));
628
782
  subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
@@ -641,14 +795,90 @@ var BaseCrudDialect = class {
641
795
  });
642
796
  return result;
643
797
  }
798
+ buildSelectAllFields(model, query, omit) {
799
+ const modelDef = requireModel(this.schema, model);
800
+ let result = query;
801
+ for (const field of Object.keys(modelDef.fields)) {
802
+ if (isRelationField(this.schema, model, field)) {
803
+ continue;
804
+ }
805
+ if (omit?.[field] === true) {
806
+ continue;
807
+ }
808
+ result = this.buildSelectField(result, model, model, field);
809
+ }
810
+ const descendants = getDelegateDescendantModels(this.schema, model);
811
+ for (const subModel of descendants) {
812
+ result = this.buildDelegateJoin(model, subModel.name, result);
813
+ result = result.select((eb) => {
814
+ const jsonObject = {};
815
+ for (const field of Object.keys(subModel.fields)) {
816
+ if (isRelationField(this.schema, subModel.name, field) || isInheritedField(this.schema, subModel.name, field)) {
817
+ continue;
818
+ }
819
+ jsonObject[field] = eb.ref(`${subModel.name}.${field}`);
820
+ }
821
+ return this.buildJsonObject(eb, jsonObject).as(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`);
822
+ });
823
+ }
824
+ return result;
825
+ }
826
+ buildSelectField(query, model, modelAlias, field) {
827
+ const fieldDef = requireField(this.schema, model, field);
828
+ if (fieldDef.computed) {
829
+ return query.select((eb) => buildFieldRef(this.schema, model, field, this.options, eb).as(field));
830
+ } else if (!fieldDef.originModel) {
831
+ return query.select(sql.ref(`${modelAlias}.${field}`).as(field));
832
+ } else {
833
+ return this.buildSelectField(query, fieldDef.originModel, fieldDef.originModel, field);
834
+ }
835
+ }
836
+ buildDelegateJoin(thisModel, otherModel, query) {
837
+ const idFields = getIdFields(this.schema, thisModel);
838
+ query = query.leftJoin(otherModel, (qb) => {
839
+ for (const idField of idFields) {
840
+ qb = qb.onRef(`${thisModel}.${idField}`, "=", `${otherModel}.${idField}`);
841
+ }
842
+ return qb;
843
+ });
844
+ return query;
845
+ }
846
+ buildCountJson(model, eb, parentAlias, payload) {
847
+ const modelDef = requireModel(this.schema, model);
848
+ const toManyRelations = Object.entries(modelDef.fields).filter(([, field]) => field.relation && field.array);
849
+ const selections = payload === true ? {
850
+ select: toManyRelations.reduce((acc, [field]) => {
851
+ acc[field] = true;
852
+ return acc;
853
+ }, {})
854
+ } : payload;
855
+ const jsonObject = {};
856
+ for (const [field, value] of Object.entries(selections.select)) {
857
+ const fieldDef = requireField(this.schema, model, field);
858
+ const fieldModel = fieldDef.type;
859
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
860
+ let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
861
+ for (const [left, right] of joinPairs) {
862
+ fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
863
+ }
864
+ if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
865
+ const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
866
+ fieldCountQuery = fieldCountQuery.where(filter);
867
+ }
868
+ jsonObject[field] = fieldCountQuery;
869
+ }
870
+ return this.buildJsonObject(eb, jsonObject);
871
+ }
872
+ // #endregion
873
+ // #region utils
644
874
  negateSort(sort, negated) {
645
875
  return negated ? sort === "asc" ? "desc" : "asc" : sort;
646
876
  }
647
877
  true(eb) {
648
- return eb.lit(this.transformPrimitive(true, "Boolean"));
878
+ return eb.lit(this.transformPrimitive(true, "Boolean", false));
649
879
  }
650
880
  false(eb) {
651
- return eb.lit(this.transformPrimitive(false, "Boolean"));
881
+ return eb.lit(this.transformPrimitive(false, "Boolean", false));
652
882
  }
653
883
  isTrue(expression) {
654
884
  const node = expression.toOperationNode();
@@ -697,14 +927,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
697
927
  get provider() {
698
928
  return "postgresql";
699
929
  }
700
- transformPrimitive(value, type) {
930
+ transformPrimitive(value, type, forArrayField) {
701
931
  if (value === void 0) {
702
932
  return value;
703
933
  }
704
934
  if (Array.isArray(value)) {
705
- return value.map((v) => this.transformPrimitive(v, type));
935
+ if (type === "Json" && !forArrayField) {
936
+ return JSON.stringify(value);
937
+ } else {
938
+ return value.map((v) => this.transformPrimitive(v, type, false));
939
+ }
706
940
  } else {
707
- return match2(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).otherwise(() => value);
941
+ 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
942
  }
709
943
  }
710
944
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
@@ -718,7 +952,8 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
718
952
  const joinTableName = `${parentName}$${relationField}`;
719
953
  let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
720
954
  result = eb.selectFrom(() => {
721
- let subQuery = eb.selectFrom(`${relationModel}`).selectAll();
955
+ let subQuery = this.buildSelectModel(eb, relationModel);
956
+ subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
722
957
  if (payload && typeof payload === "object") {
723
958
  if (payload.where) {
724
959
  subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
@@ -762,34 +997,57 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
762
997
  });
763
998
  return qb;
764
999
  }
765
- buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName) {
1000
+ buildRelationObjectArgs(relationModel, relationField, eb, payload, parentAlias) {
766
1001
  const relationModelDef = requireModel(this.schema, relationModel);
767
1002
  const objArgs = [];
1003
+ const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1004
+ if (descendantModels.length > 0) {
1005
+ objArgs.push(...descendantModels.map((subModel) => [
1006
+ sql2.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1007
+ eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1008
+ ]).flatMap((v) => v));
1009
+ }
768
1010
  if (payload === true || !payload.select) {
769
1011
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
770
1012
  sql2.lit(field),
771
1013
  buildFieldRef(this.schema, relationModel, field, this.options, eb)
772
1014
  ]).flatMap((v) => v));
773
1015
  } else if (payload.select) {
774
- objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => [
775
- sql2.lit(field),
776
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
777
- ]).flatMap((v) => v));
1016
+ objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1017
+ if (field === "_count") {
1018
+ const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
1019
+ return [
1020
+ sql2.lit(field),
1021
+ subJson
1022
+ ];
1023
+ } else {
1024
+ const fieldDef = requireField(this.schema, relationModel, field);
1025
+ const fieldValue = fieldDef.relation ? eb.ref(`${parentAlias}$${relationField}$${field}.$j`) : buildFieldRef(this.schema, relationModel, field, this.options, eb);
1026
+ return [
1027
+ sql2.lit(field),
1028
+ fieldValue
1029
+ ];
1030
+ }
1031
+ }).flatMap((v) => v));
778
1032
  }
779
1033
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
780
1034
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
781
1035
  sql2.lit(field),
782
- eb.ref(`${parentName}$${relationField}$${field}.$j`)
1036
+ // reference the synthesized JSON field
1037
+ eb.ref(`${parentAlias}$${relationField}$${field}.$j`)
783
1038
  ]).flatMap((v) => v));
784
1039
  }
785
1040
  return objArgs;
786
1041
  }
787
- buildRelationJoins(model, relationField, qb, payload, parentName) {
1042
+ buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
788
1043
  let result = qb;
789
- if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
790
- Object.entries(payload.include).filter(([, value]) => value).forEach(([field, value]) => {
791
- result = this.buildRelationJSON(model, result, field, `${parentName}$${relationField}`, value);
792
- });
1044
+ if (typeof payload === "object") {
1045
+ const selectInclude = payload.include ?? payload.select;
1046
+ if (selectInclude && typeof selectInclude === "object") {
1047
+ Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
1048
+ result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
1049
+ });
1050
+ }
793
1051
  }
794
1052
  return result;
795
1053
  }
@@ -829,12 +1087,15 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
829
1087
  return `ARRAY[${values.map((v) => typeof v === "string" ? `'${v}'` : v)}]`;
830
1088
  }
831
1089
  }
1090
+ get supportInsertWithDefault() {
1091
+ return true;
1092
+ }
832
1093
  };
833
1094
 
834
1095
  // src/client/crud/dialects/sqlite.ts
1096
+ import { invariant as invariant3 } from "@zenstackhq/common-helpers";
835
1097
  import { sql as sql3 } from "kysely";
836
- import invariant3 from "tiny-invariant";
837
- import { match as match3 } from "ts-pattern";
1098
+ import { match as match4 } from "ts-pattern";
838
1099
  var SqliteCrudDialect = class extends BaseCrudDialect {
839
1100
  static {
840
1101
  __name(this, "SqliteCrudDialect");
@@ -842,26 +1103,31 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
842
1103
  get provider() {
843
1104
  return "sqlite";
844
1105
  }
845
- transformPrimitive(value, type) {
1106
+ transformPrimitive(value, type, _forArrayField) {
846
1107
  if (value === void 0) {
847
1108
  return value;
848
1109
  }
849
1110
  if (Array.isArray(value)) {
850
- return value.map((v) => this.transformPrimitive(v, type));
1111
+ return value.map((v) => this.transformPrimitive(v, type, false));
851
1112
  } else {
852
- return match3(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).otherwise(() => value);
1113
+ if (this.schema.typeDefs && type in this.schema.typeDefs) {
1114
+ return JSON.stringify(value);
1115
+ } else {
1116
+ 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);
1117
+ }
853
1118
  }
854
1119
  }
855
1120
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
856
1121
  return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
857
1122
  }
858
- buildRelationJSON(model, eb, relationField, parentName, payload) {
1123
+ buildRelationJSON(model, eb, relationField, parentAlias, payload) {
859
1124
  const relationFieldDef = requireField(this.schema, model, relationField);
860
1125
  const relationModel = relationFieldDef.type;
861
1126
  const relationModelDef = requireModel(this.schema, relationModel);
862
- const subQueryName = `${parentName}$${relationField}`;
1127
+ const subQueryName = `${parentAlias}$${relationField}`;
863
1128
  let tbl = eb.selectFrom(() => {
864
- let subQuery = eb.selectFrom(relationModel).selectAll();
1129
+ let subQuery = this.buildSelectModel(eb, relationModel);
1130
+ subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
865
1131
  if (payload && typeof payload === "object") {
866
1132
  if (payload.where) {
867
1133
  subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
@@ -882,14 +1148,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
882
1148
  const relationIds = getIdFields(this.schema, relationModel);
883
1149
  invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
884
1150
  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(`${parentName}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1151
+ 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
1152
  } else {
887
1153
  const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
888
1154
  keyPairs.forEach(({ fk, pk }) => {
889
1155
  if (ownedByModel) {
890
- subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentName}.${fk}`);
1156
+ subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentAlias}.${fk}`);
891
1157
  } else {
892
- subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentName}.${pk}`);
1158
+ subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentAlias}.${pk}`);
893
1159
  }
894
1160
  });
895
1161
  }
@@ -897,6 +1163,13 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
897
1163
  });
898
1164
  tbl = tbl.select(() => {
899
1165
  const objArgs = [];
1166
+ const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1167
+ if (descendantModels.length > 0) {
1168
+ objArgs.push(...descendantModels.map((subModel) => [
1169
+ sql3.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1170
+ eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1171
+ ]).flatMap((v) => v));
1172
+ }
900
1173
  if (payload === true || !payload.select) {
901
1174
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
902
1175
  sql3.lit(field),
@@ -904,24 +1177,32 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
904
1177
  ]).flatMap((v) => v));
905
1178
  } else if (payload.select) {
906
1179
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
907
- const fieldDef = requireField(this.schema, relationModel, field);
908
- if (fieldDef.relation) {
909
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1180
+ if (field === "_count") {
1181
+ const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
910
1182
  return [
911
1183
  sql3.lit(field),
912
1184
  subJson
913
1185
  ];
914
1186
  } else {
915
- return [
916
- sql3.lit(field),
917
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
918
- ];
1187
+ const fieldDef = requireField(this.schema, relationModel, field);
1188
+ if (fieldDef.relation) {
1189
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
1190
+ return [
1191
+ sql3.lit(field),
1192
+ subJson
1193
+ ];
1194
+ } else {
1195
+ return [
1196
+ sql3.lit(field),
1197
+ buildFieldRef(this.schema, relationModel, field, this.options, eb)
1198
+ ];
1199
+ }
919
1200
  }
920
1201
  }).flatMap((v) => v));
921
1202
  }
922
1203
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
923
1204
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
924
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1205
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
925
1206
  return [
926
1207
  sql3.lit(field),
927
1208
  subJson
@@ -971,93 +1252,17 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
971
1252
  buildArrayLiteralSQL(_values) {
972
1253
  throw new Error("SQLite does not support array literals");
973
1254
  }
1255
+ get supportInsertWithDefault() {
1256
+ return false;
1257
+ }
974
1258
  };
975
1259
 
976
1260
  // src/client/crud/dialects/index.ts
977
1261
  function getCrudDialect(schema, options) {
978
- return match4(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
1262
+ return match5(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
979
1263
  }
980
1264
  __name(getCrudDialect, "getCrudDialect");
981
1265
 
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
1266
  // src/utils/default-operation-node-visitor.ts
1062
1267
  import { OperationNodeVisitor } from "kysely";
1063
1268
  var DefaultOperationNodeVisitor = class extends OperationNodeVisitor {
@@ -1377,19 +1582,19 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
1377
1582
  };
1378
1583
 
1379
1584
  // src/plugins/policy/expression-transformer.ts
1585
+ import { invariant as invariant5 } from "@zenstackhq/common-helpers";
1380
1586
  import { AliasNode as AliasNode2, BinaryOperationNode as BinaryOperationNode2, ColumnNode, expressionBuilder, FromNode, FunctionNode as FunctionNode2, IdentifierNode, OperatorNode as OperatorNode2, ReferenceNode as ReferenceNode2, SelectionNode, SelectQueryNode, TableNode as TableNode2, ValueListNode, ValueNode as ValueNode2, WhereNode } from "kysely";
1381
- import invariant5 from "tiny-invariant";
1382
- import { match as match6 } from "ts-pattern";
1587
+ import { match as match7 } from "ts-pattern";
1383
1588
 
1384
1589
  // src/plugins/policy/expression-evaluator.ts
1385
- import invariant4 from "tiny-invariant";
1386
- import { match as match5 } from "ts-pattern";
1590
+ import { invariant as invariant4 } from "@zenstackhq/common-helpers";
1591
+ import { match as match6 } from "ts-pattern";
1387
1592
  var ExpressionEvaluator = class {
1388
1593
  static {
1389
1594
  __name(this, "ExpressionEvaluator");
1390
1595
  }
1391
1596
  evaluate(expression, context) {
1392
- const result = match5(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();
1597
+ 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
1598
  return result ?? null;
1394
1599
  }
1395
1600
  evaluateCall(expr2, context) {
@@ -1400,7 +1605,7 @@ var ExpressionEvaluator = class {
1400
1605
  }
1401
1606
  }
1402
1607
  evaluateUnary(expr2, context) {
1403
- return match5(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
1608
+ return match6(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
1404
1609
  }
1405
1610
  evaluateMember(expr2, context) {
1406
1611
  let val = this.evaluate(expr2.receiver, context);
@@ -1424,7 +1629,7 @@ var ExpressionEvaluator = class {
1424
1629
  }
1425
1630
  const left = this.evaluate(expr2.left, context);
1426
1631
  const right = this.evaluate(expr2.right, context);
1427
- return match5(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", () => {
1632
+ 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
1633
  const _right = right ?? [];
1429
1634
  invariant4(Array.isArray(_right), 'expected array for "in" operator');
1430
1635
  return _right.includes(left);
@@ -1438,7 +1643,7 @@ var ExpressionEvaluator = class {
1438
1643
  return false;
1439
1644
  }
1440
1645
  invariant4(Array.isArray(left), "expected array");
1441
- return match5(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1646
+ return match6(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1442
1647
  ...context,
1443
1648
  thisValue: item
1444
1649
  }))).with("!", () => left.every((item) => this.evaluate(expr2.right, {
@@ -1454,11 +1659,11 @@ var ExpressionEvaluator = class {
1454
1659
  // src/plugins/policy/utils.ts
1455
1660
  import { AliasNode, AndNode, BinaryOperationNode, FunctionNode, OperatorNode, OrNode, ParensNode, ReferenceNode, TableNode, UnaryOperationNode, ValueNode } from "kysely";
1456
1661
  function trueNode(dialect) {
1457
- return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
1662
+ return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
1458
1663
  }
1459
1664
  __name(trueNode, "trueNode");
1460
1665
  function falseNode(dialect) {
1461
- return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
1666
+ return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
1462
1667
  }
1463
1668
  __name(falseNode, "falseNode");
1464
1669
  function isTrueNode(node) {
@@ -1692,7 +1897,7 @@ var ExpressionTransformer = class {
1692
1897
  const count = FunctionNode2.create("count", [
1693
1898
  ValueNode2.createImmediate(1)
1694
1899
  ]);
1695
- const predicateResult = match6(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();
1900
+ 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
1901
  return this.transform(expr2.left, {
1697
1902
  ...context,
1698
1903
  memberSelect: SelectionNode.create(AliasNode2.create(predicateResult, IdentifierNode.create("$t"))),
@@ -1716,14 +1921,14 @@ var ExpressionTransformer = class {
1716
1921
  }
1717
1922
  }
1718
1923
  transformValue(value, type) {
1719
- return ValueNode2.create(this.dialect.transformPrimitive(value, type) ?? null);
1924
+ return ValueNode2.create(this.dialect.transformPrimitive(value, type, false) ?? null);
1720
1925
  }
1721
1926
  _unary(expr2, context) {
1722
1927
  invariant5(expr2.op === "!", 'only "!" operator is supported');
1723
1928
  return BinaryOperationNode2.create(this.transform(expr2.operand, context), this.transformOperator("!="), trueNode(this.dialect));
1724
1929
  }
1725
1930
  transformOperator(op) {
1726
- const mappedOp = match6(op).with("==", () => "=").otherwise(() => op);
1931
+ const mappedOp = match7(op).with("==", () => "=").otherwise(() => op);
1727
1932
  return OperatorNode2.create(mappedOp);
1728
1933
  }
1729
1934
  _call(expr2, context) {
@@ -1959,7 +2164,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
1959
2164
  get kysely() {
1960
2165
  return this.client.$qb;
1961
2166
  }
1962
- async handle(node, proceed, transaction) {
2167
+ async handle(node, proceed) {
1963
2168
  if (!this.isCrudQueryNode(node)) {
1964
2169
  throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
1965
2170
  }
@@ -1979,27 +2184,20 @@ var PolicyHandler = class extends OperationNodeTransformer {
1979
2184
  if (!mutationRequiresTransaction && !node.returning) {
1980
2185
  return proceed(this.transformNode(node));
1981
2186
  }
1982
- let readBackError = false;
1983
- const result = await transaction(async (txProceed) => {
1984
- if (InsertQueryNode.is(node)) {
1985
- await this.enforcePreCreatePolicy(node, txProceed);
1986
- }
1987
- const transformedNode = this.transformNode(node);
1988
- const result2 = await txProceed(transformedNode);
1989
- if (!this.onlyReturningId(node)) {
1990
- const readBackResult = await this.processReadBack(node, result2, txProceed);
1991
- if (readBackResult.rows.length !== result2.rows.length) {
1992
- readBackError = true;
1993
- }
1994
- return readBackResult;
1995
- } else {
1996
- return result2;
2187
+ if (InsertQueryNode.is(node)) {
2188
+ await this.enforcePreCreatePolicy(node, proceed);
2189
+ }
2190
+ const transformedNode = this.transformNode(node);
2191
+ const result = await proceed(transformedNode);
2192
+ if (!this.onlyReturningId(node)) {
2193
+ const readBackResult = await this.processReadBack(node, result, proceed);
2194
+ if (readBackResult.rows.length !== result.rows.length) {
2195
+ throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
1997
2196
  }
1998
- });
1999
- if (readBackError) {
2000
- throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2197
+ return readBackResult;
2198
+ } else {
2199
+ return result;
2001
2200
  }
2002
- return result;
2003
2201
  }
2004
2202
  onlyReturningId(node) {
2005
2203
  if (!node.returning) {
@@ -2060,11 +2258,11 @@ var PolicyHandler = class extends OperationNodeTransformer {
2060
2258
  if (typeof item === "object" && item && "kind" in item) {
2061
2259
  invariant6(item.kind === "ValueNode", "expecting a ValueNode");
2062
2260
  result.push({
2063
- node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
2261
+ node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
2064
2262
  raw: item.value
2065
2263
  });
2066
2264
  } else {
2067
- const value = this.dialect.transformPrimitive(item, fieldDef.type);
2265
+ const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
2068
2266
  if (Array.isArray(value)) {
2069
2267
  result.push({
2070
2268
  node: RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
@@ -2133,7 +2331,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
2133
2331
  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
2332
  }
2135
2333
  getMutationModel(node) {
2136
- const r = match7(node).when(InsertQueryNode.is, (node2) => getTableName(node2.into)).when(UpdateQueryNode.is, (node2) => getTableName(node2.table)).when(DeleteQueryNode.is, (node2) => {
2334
+ const r = match8(node).when(InsertQueryNode.is, (node2) => getTableName(node2.into)).when(UpdateQueryNode.is, (node2) => getTableName(node2.table)).when(DeleteQueryNode.is, (node2) => {
2137
2335
  if (node2.from.froms.length !== 1) {
2138
2336
  throw new InternalError("Only one from table is supported for delete");
2139
2337
  }
@@ -2295,13 +2493,22 @@ var PolicyPlugin = class {
2295
2493
  get description() {
2296
2494
  return "Enforces access policies defined in the schema.";
2297
2495
  }
2298
- onKyselyQuery({ query, client, proceed, transaction }) {
2496
+ onKyselyQuery({
2497
+ query,
2498
+ client,
2499
+ proceed
2500
+ /*, transaction*/
2501
+ }) {
2299
2502
  const handler = new PolicyHandler(client);
2300
- return handler.handle(query, proceed, transaction);
2503
+ return handler.handle(
2504
+ query,
2505
+ proceed
2506
+ /*, transaction*/
2507
+ );
2301
2508
  }
2302
2509
  };
2303
2510
  export {
2304
2511
  PolicyPlugin,
2305
2512
  RejectedByPolicyError
2306
2513
  };
2307
- //# sourceMappingURL=policy.js.map
2514
+ //# sourceMappingURL=index.js.map