@zenstackhq/runtime 3.0.0-alpha.3 → 3.0.0-alpha.30

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.
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
7
  var __export = (target, all) => {
@@ -18,14 +16,6 @@ var __copyProps = (to, from, except, desc) => {
18
16
  }
19
17
  return to;
20
18
  };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
20
 
31
21
  // src/plugins/policy/index.ts
@@ -49,34 +39,130 @@ var RejectedByPolicyError = class extends Error {
49
39
  };
50
40
 
51
41
  // src/plugins/policy/policy-handler.ts
42
+ var import_common_helpers6 = require("@zenstackhq/common-helpers");
52
43
  var import_kysely7 = require("kysely");
53
- var import_tiny_invariant6 = __toESM(require("tiny-invariant"), 1);
54
- var import_ts_pattern7 = require("ts-pattern");
44
+ var import_ts_pattern8 = require("ts-pattern");
55
45
 
56
46
  // src/client/crud/dialects/index.ts
57
- var import_ts_pattern4 = require("ts-pattern");
47
+ var import_ts_pattern5 = require("ts-pattern");
58
48
 
59
49
  // src/client/crud/dialects/postgresql.ts
50
+ var import_common_helpers2 = require("@zenstackhq/common-helpers");
60
51
  var import_kysely2 = require("kysely");
61
- var import_tiny_invariant2 = __toESM(require("tiny-invariant"), 1);
62
- var import_ts_pattern2 = require("ts-pattern");
52
+ var import_ts_pattern3 = require("ts-pattern");
53
+
54
+ // src/client/constants.ts
55
+ var DELEGATE_JOINED_FIELD_PREFIX = "$delegate$";
56
+ var LOGICAL_COMBINATORS = [
57
+ "AND",
58
+ "OR",
59
+ "NOT"
60
+ ];
61
+ var AGGREGATE_OPERATORS = [
62
+ "_count",
63
+ "_sum",
64
+ "_avg",
65
+ "_min",
66
+ "_max"
67
+ ];
68
+
69
+ // src/client/query-utils.ts
70
+ var import_ts_pattern = require("ts-pattern");
71
+
72
+ // src/schema/expression.ts
73
+ var ExpressionUtils = {
74
+ literal: /* @__PURE__ */ __name((value) => {
75
+ return {
76
+ kind: "literal",
77
+ value
78
+ };
79
+ }, "literal"),
80
+ array: /* @__PURE__ */ __name((items) => {
81
+ return {
82
+ kind: "array",
83
+ items
84
+ };
85
+ }, "array"),
86
+ call: /* @__PURE__ */ __name((functionName, args) => {
87
+ return {
88
+ kind: "call",
89
+ function: functionName,
90
+ args
91
+ };
92
+ }, "call"),
93
+ binary: /* @__PURE__ */ __name((left, op, right) => {
94
+ return {
95
+ kind: "binary",
96
+ op,
97
+ left,
98
+ right
99
+ };
100
+ }, "binary"),
101
+ unary: /* @__PURE__ */ __name((op, operand) => {
102
+ return {
103
+ kind: "unary",
104
+ op,
105
+ operand
106
+ };
107
+ }, "unary"),
108
+ field: /* @__PURE__ */ __name((field) => {
109
+ return {
110
+ kind: "field",
111
+ field
112
+ };
113
+ }, "field"),
114
+ member: /* @__PURE__ */ __name((receiver, members) => {
115
+ return {
116
+ kind: "member",
117
+ receiver,
118
+ members
119
+ };
120
+ }, "member"),
121
+ _this: /* @__PURE__ */ __name(() => {
122
+ return {
123
+ kind: "this"
124
+ };
125
+ }, "_this"),
126
+ _null: /* @__PURE__ */ __name(() => {
127
+ return {
128
+ kind: "null"
129
+ };
130
+ }, "_null"),
131
+ and: /* @__PURE__ */ __name((expr2, ...expressions) => {
132
+ return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
133
+ }, "and"),
134
+ or: /* @__PURE__ */ __name((expr2, ...expressions) => {
135
+ return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
136
+ }, "or"),
137
+ is: /* @__PURE__ */ __name((value, kind) => {
138
+ return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
139
+ }, "is"),
140
+ isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
141
+ isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
142
+ isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
143
+ isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
144
+ isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
145
+ isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
146
+ isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
147
+ isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
148
+ isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
149
+ };
63
150
 
64
151
  // src/client/errors.ts
65
152
  var QueryError = class extends Error {
66
153
  static {
67
154
  __name(this, "QueryError");
68
155
  }
69
- constructor(message) {
70
- super(message);
156
+ constructor(message, cause) {
157
+ super(message, {
158
+ cause
159
+ });
71
160
  }
72
161
  };
73
162
  var InternalError = class extends Error {
74
163
  static {
75
164
  __name(this, "InternalError");
76
165
  }
77
- constructor(message) {
78
- super(message);
79
- }
80
166
  };
81
167
 
82
168
  // src/client/query-utils.ts
@@ -87,7 +173,7 @@ __name(getModel, "getModel");
87
173
  function requireModel(schema, model) {
88
174
  const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
89
175
  if (!matchedName) {
90
- throw new QueryError(`Model "${model}" not found`);
176
+ throw new QueryError(`Model "${model}" not found in schema`);
91
177
  }
92
178
  return schema.models[matchedName];
93
179
  }
@@ -150,6 +236,16 @@ function getRelationForeignKeyFieldPairs(schema, model, relationField) {
150
236
  }
151
237
  }
152
238
  __name(getRelationForeignKeyFieldPairs, "getRelationForeignKeyFieldPairs");
239
+ function isRelationField(schema, model, field) {
240
+ const fieldDef = getField(schema, model, field);
241
+ return !!fieldDef?.relation;
242
+ }
243
+ __name(isRelationField, "isRelationField");
244
+ function isInheritedField(schema, model, field) {
245
+ const fieldDef = getField(schema, model, field);
246
+ return !!fieldDef?.originModel;
247
+ }
248
+ __name(isInheritedField, "isInheritedField");
153
249
  function getUniqueFields(schema, model) {
154
250
  const modelDef = requireModel(schema, model);
155
251
  const result = [];
@@ -175,20 +271,25 @@ function getUniqueFields(schema, model) {
175
271
  return result;
176
272
  }
177
273
  __name(getUniqueFields, "getUniqueFields");
178
- function buildFieldRef(schema, model, field, options, eb, modelAlias) {
274
+ function buildFieldRef(schema, model, field, options, eb, modelAlias, inlineComputedField = true) {
179
275
  const fieldDef = requireField(schema, model, field);
180
276
  if (!fieldDef.computed) {
181
277
  return eb.ref(modelAlias ? `${modelAlias}.${field}` : field);
182
278
  } else {
279
+ if (!inlineComputedField) {
280
+ return eb.ref(modelAlias ? `${modelAlias}.${field}` : field);
281
+ }
183
282
  let computer;
184
283
  if ("computedFields" in options) {
185
284
  const computedFields = options.computedFields;
186
285
  computer = computedFields?.[model]?.[field];
187
286
  }
188
287
  if (!computer) {
189
- throw new QueryError(`Computed field "${field}" implementation not provided`);
288
+ throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
190
289
  }
191
- return computer(eb);
290
+ return computer(eb, {
291
+ currentModel: modelAlias
292
+ });
192
293
  }
193
294
  }
194
295
  __name(buildFieldRef, "buildFieldRef");
@@ -231,11 +332,33 @@ function getManyToManyRelation(schema, model, field) {
231
332
  model,
232
333
  fieldDef.type
233
334
  ].sort();
335
+ let orderedFK;
336
+ if (model !== fieldDef.type) {
337
+ orderedFK = sortedModelNames[0] === model ? [
338
+ "A",
339
+ "B"
340
+ ] : [
341
+ "B",
342
+ "A"
343
+ ];
344
+ } else {
345
+ const sortedFieldNames = [
346
+ field,
347
+ oppositeFieldDef.name
348
+ ].sort();
349
+ orderedFK = sortedFieldNames[0] === field ? [
350
+ "A",
351
+ "B"
352
+ ] : [
353
+ "B",
354
+ "A"
355
+ ];
356
+ }
234
357
  return {
235
- parentFkName: sortedModelNames[0] === model ? "A" : "B",
358
+ parentFkName: orderedFK[0],
236
359
  otherModel: fieldDef.type,
237
360
  otherField: fieldDef.relation.opposite,
238
- otherFkName: sortedModelNames[0] === fieldDef.type ? "A" : "B",
361
+ otherFkName: orderedFK[1],
239
362
  joinTable: fieldDef.relation.name ? `_${fieldDef.relation.name}` : `_${sortedModelNames[0]}To${sortedModelNames[1]}`
240
363
  };
241
364
  } else {
@@ -263,11 +386,38 @@ function flattenCompoundUniqueFilters(schema, model, filter) {
263
386
  return result;
264
387
  }
265
388
  __name(flattenCompoundUniqueFilters, "flattenCompoundUniqueFilters");
389
+ function ensureArray(value) {
390
+ if (Array.isArray(value)) {
391
+ return value;
392
+ } else {
393
+ return [
394
+ value
395
+ ];
396
+ }
397
+ }
398
+ __name(ensureArray, "ensureArray");
399
+ function getDelegateDescendantModels(schema, model, collected = /* @__PURE__ */ new Set()) {
400
+ const subModels = Object.values(schema.models).filter((m) => m.baseModel === model);
401
+ subModels.forEach((def) => {
402
+ if (!collected.has(def)) {
403
+ collected.add(def);
404
+ getDelegateDescendantModels(schema, def.name, collected);
405
+ }
406
+ });
407
+ return [
408
+ ...collected
409
+ ];
410
+ }
411
+ __name(getDelegateDescendantModels, "getDelegateDescendantModels");
412
+ function aggregate(eb, expr2, op) {
413
+ return (0, import_ts_pattern.match)(op).with("_count", () => eb.fn.count(expr2)).with("_sum", () => eb.fn.sum(expr2)).with("_avg", () => eb.fn.avg(expr2)).with("_min", () => eb.fn.min(expr2)).with("_max", () => eb.fn.max(expr2)).exhaustive();
414
+ }
415
+ __name(aggregate, "aggregate");
266
416
 
267
417
  // src/client/crud/dialects/base.ts
418
+ var import_common_helpers = require("@zenstackhq/common-helpers");
268
419
  var import_kysely = require("kysely");
269
- var import_tiny_invariant = __toESM(require("tiny-invariant"), 1);
270
- var import_ts_pattern = require("ts-pattern");
420
+ var import_ts_pattern2 = require("ts-pattern");
271
421
 
272
422
  // src/utils/enumerate.ts
273
423
  function enumerate(x) {
@@ -284,7 +434,6 @@ function enumerate(x) {
284
434
  __name(enumerate, "enumerate");
285
435
 
286
436
  // src/client/crud/dialects/base.ts
287
- var import_is_plain_object = require("is-plain-object");
288
437
  var BaseCrudDialect = class {
289
438
  static {
290
439
  __name(this, "BaseCrudDialect");
@@ -295,9 +444,47 @@ var BaseCrudDialect = class {
295
444
  this.schema = schema;
296
445
  this.options = options;
297
446
  }
298
- transformPrimitive(value, _type) {
447
+ transformPrimitive(value, _type, _forArrayField) {
299
448
  return value;
300
449
  }
450
+ // #region common query builders
451
+ buildSelectModel(eb, model, modelAlias) {
452
+ const modelDef = requireModel(this.schema, model);
453
+ let result = eb.selectFrom(model === modelAlias ? model : `${model} as ${modelAlias}`);
454
+ let joinBase = modelDef.baseModel;
455
+ while (joinBase) {
456
+ result = this.buildDelegateJoin(model, modelAlias, joinBase, result);
457
+ joinBase = requireModel(this.schema, joinBase).baseModel;
458
+ }
459
+ return result;
460
+ }
461
+ buildFilterSortTake(model, args, query, modelAlias) {
462
+ let result = query;
463
+ if (args.where) {
464
+ result = result.where((eb) => this.buildFilter(eb, model, modelAlias, args?.where));
465
+ }
466
+ let negateOrderBy = false;
467
+ const skip = args.skip;
468
+ let take = args.take;
469
+ if (take !== void 0 && take < 0) {
470
+ negateOrderBy = true;
471
+ take = -take;
472
+ }
473
+ result = this.buildSkipTake(result, skip, take);
474
+ result = this.buildOrderBy(result, model, modelAlias, args.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
475
+ if ("distinct" in args && args.distinct) {
476
+ const distinct = ensureArray(args.distinct);
477
+ if (this.supportsDistinctOn) {
478
+ result = result.distinctOn(distinct.map((f) => import_kysely.sql.ref(`${modelAlias}.${f}`)));
479
+ } else {
480
+ throw new QueryError(`"distinct" is not supported by "${this.schema.provider.type}" provider`);
481
+ }
482
+ }
483
+ if (args.cursor) {
484
+ result = this.buildCursorFilter(model, result, args.cursor, args.orderBy, negateOrderBy, modelAlias);
485
+ }
486
+ return result;
487
+ }
301
488
  buildFilter(eb, model, modelAlias, where) {
302
489
  if (where === true || where === void 0) {
303
490
  return this.true(eb);
@@ -314,17 +501,20 @@ var BaseCrudDialect = class {
314
501
  if (key.startsWith("$")) {
315
502
  continue;
316
503
  }
317
- if (key === "AND" || key === "OR" || key === "NOT") {
504
+ if (this.isLogicalCombinator(key)) {
318
505
  result = this.and(eb, result, this.buildCompositeFilter(eb, model, modelAlias, key, payload));
319
506
  continue;
320
507
  }
321
508
  const fieldDef = requireField(this.schema, model, key);
322
509
  if (fieldDef.relation) {
323
510
  result = this.and(eb, result, this.buildRelationFilter(eb, model, modelAlias, key, fieldDef, payload));
324
- } else if (fieldDef.array) {
325
- result = this.and(eb, result, this.buildArrayFilter(eb, model, modelAlias, key, fieldDef, payload));
326
511
  } else {
327
- result = this.and(eb, result, this.buildPrimitiveFilter(eb, model, modelAlias, key, fieldDef, payload));
512
+ const fieldRef = this.fieldRef(fieldDef.originModel ?? model, key, eb, fieldDef.originModel ?? modelAlias);
513
+ if (fieldDef.array) {
514
+ result = this.and(eb, result, this.buildArrayFilter(eb, fieldRef, fieldDef, payload));
515
+ } else {
516
+ result = this.and(eb, result, this.buildPrimitiveFilter(eb, fieldRef, fieldDef, payload));
517
+ }
328
518
  }
329
519
  }
330
520
  if ("$expr" in _where && typeof _where["$expr"] === "function") {
@@ -332,8 +522,32 @@ var BaseCrudDialect = class {
332
522
  }
333
523
  return result;
334
524
  }
525
+ buildCursorFilter(model, query, cursor, orderBy, negateOrderBy, modelAlias) {
526
+ const _orderBy = orderBy ?? makeDefaultOrderBy(this.schema, model);
527
+ const orderByItems = ensureArray(_orderBy).flatMap((obj) => Object.entries(obj));
528
+ const eb = (0, import_kysely.expressionBuilder)();
529
+ const subQueryAlias = `${model}$cursor$sub`;
530
+ const cursorFilter = this.buildFilter(eb, model, subQueryAlias, cursor);
531
+ let result = query;
532
+ const filters = [];
533
+ for (let i = orderByItems.length - 1; i >= 0; i--) {
534
+ const andFilters = [];
535
+ for (let j = 0; j <= i; j++) {
536
+ const [field, order] = orderByItems[j];
537
+ const _order = negateOrderBy ? order === "asc" ? "desc" : "asc" : order;
538
+ const op = j === i ? _order === "asc" ? ">=" : "<=" : "=";
539
+ andFilters.push(eb(eb.ref(`${modelAlias}.${field}`), op, this.buildSelectModel(eb, model, subQueryAlias).select(`${subQueryAlias}.${field}`).where(cursorFilter)));
540
+ }
541
+ filters.push(eb.and(andFilters));
542
+ }
543
+ result = result.where((eb2) => eb2.or(filters));
544
+ return result;
545
+ }
546
+ isLogicalCombinator(key) {
547
+ return LOGICAL_COMBINATORS.includes(key);
548
+ }
335
549
  buildCompositeFilter(eb, model, modelAlias, key, payload) {
336
- return (0, import_ts_pattern.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();
550
+ return (0, import_ts_pattern2.match)(key).with("AND", () => this.and(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("OR", () => this.or(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("NOT", () => eb.not(this.buildCompositeFilter(eb, model, modelAlias, "AND", payload))).exhaustive();
337
551
  }
338
552
  buildRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
339
553
  if (!fieldDef.array) {
@@ -342,19 +556,26 @@ var BaseCrudDialect = class {
342
556
  return this.buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload);
343
557
  }
344
558
  }
345
- buildToOneRelationFilter(eb, model, table, field, fieldDef, payload) {
559
+ buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
346
560
  if (payload === null) {
347
561
  const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, model, field);
348
- if (ownedByModel) {
349
- return this.and(eb, ...keyPairs.map(({ fk }) => eb(import_kysely.sql.ref(`${table}.${fk}`), "is", null)));
562
+ if (ownedByModel && !fieldDef.originModel) {
563
+ return this.and(eb, ...keyPairs.map(({ fk }) => eb(import_kysely.sql.ref(`${modelAlias}.${fk}`), "is", null)));
350
564
  } else {
351
- return this.buildToOneRelationFilter(eb, model, table, field, fieldDef, {
565
+ return this.buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, {
352
566
  is: null
353
567
  });
354
568
  }
355
569
  }
356
- const joinAlias = `${table}$${field}`;
357
- const joinPairs = buildJoinPairs(this.schema, model, table, field, joinAlias);
570
+ const joinAlias = `${modelAlias}$${field}`;
571
+ const joinPairs = buildJoinPairs(
572
+ this.schema,
573
+ model,
574
+ // if field is from a base, use the base model to join
575
+ fieldDef.originModel ?? modelAlias,
576
+ field,
577
+ joinAlias
578
+ );
358
579
  const filterResultField = `${field}$filter`;
359
580
  const joinSelect = eb.selectFrom(`${fieldDef.type} as ${joinAlias}`).where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely.sql.ref(left), "=", import_kysely.sql.ref(right))))).select(() => eb.fn.count(eb.lit(1)).as(filterResultField));
360
581
  const conditions = [];
@@ -384,25 +605,26 @@ var BaseCrudDialect = class {
384
605
  }
385
606
  return this.and(eb, ...conditions);
386
607
  }
387
- buildToManyRelationFilter(eb, model, table, field, fieldDef, payload) {
608
+ buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
388
609
  if (payload === null) {
389
- return eb(import_kysely.sql.ref(`${table}.${field}`), "is", null);
610
+ return eb(import_kysely.sql.ref(`${modelAlias}.${field}`), "is", null);
390
611
  }
391
612
  const relationModel = fieldDef.type;
613
+ const relationFilterSelectAlias = `${modelAlias}$${field}$filter`;
392
614
  const buildPkFkWhereRefs = /* @__PURE__ */ __name((eb2) => {
393
615
  const m2m = getManyToManyRelation(this.schema, model, field);
394
616
  if (m2m) {
395
617
  const modelIdField = getIdFields(this.schema, model)[0];
396
618
  const relationIdField = getIdFields(this.schema, relationModel)[0];
397
- return eb2(import_kysely.sql.ref(`${relationModel}.${relationIdField}`), "in", eb2.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(import_kysely.sql.ref(`${m2m.joinTable}.${m2m.parentFkName}`), "=", import_kysely.sql.ref(`${table}.${modelIdField}`)));
619
+ return eb2(import_kysely.sql.ref(`${relationFilterSelectAlias}.${relationIdField}`), "in", eb2.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(import_kysely.sql.ref(`${m2m.joinTable}.${m2m.parentFkName}`), "=", import_kysely.sql.ref(`${modelAlias}.${modelIdField}`)));
398
620
  } else {
399
621
  const relationKeyPairs = getRelationForeignKeyFieldPairs(this.schema, model, field);
400
622
  let result2 = this.true(eb2);
401
623
  for (const { fk, pk } of relationKeyPairs.keyPairs) {
402
624
  if (relationKeyPairs.ownedByModel) {
403
- result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${table}.${fk}`), "=", import_kysely.sql.ref(`${relationModel}.${pk}`)));
625
+ result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${modelAlias}.${fk}`), "=", import_kysely.sql.ref(`${relationFilterSelectAlias}.${pk}`)));
404
626
  } else {
405
- result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${table}.${pk}`), "=", import_kysely.sql.ref(`${relationModel}.${fk}`)));
627
+ result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${modelAlias}.${pk}`), "=", import_kysely.sql.ref(`${relationFilterSelectAlias}.${fk}`)));
406
628
  }
407
629
  }
408
630
  return result2;
@@ -415,30 +637,29 @@ var BaseCrudDialect = class {
415
637
  }
416
638
  switch (key) {
417
639
  case "some": {
418
- 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));
640
+ result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel, relationFilterSelectAlias).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationFilterSelectAlias, subPayload)), ">", 0));
419
641
  break;
420
642
  }
421
643
  case "every": {
422
- 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));
644
+ result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel, relationFilterSelectAlias).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => eb1.not(this.buildFilter(eb1, relationModel, relationFilterSelectAlias, subPayload))), "=", 0));
423
645
  break;
424
646
  }
425
647
  case "none": {
426
- 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));
648
+ result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel, relationFilterSelectAlias).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationFilterSelectAlias, subPayload)), "=", 0));
427
649
  break;
428
650
  }
429
651
  }
430
652
  }
431
653
  return result;
432
654
  }
433
- buildArrayFilter(eb, model, modelAlias, field, fieldDef, payload) {
655
+ buildArrayFilter(eb, fieldRef, fieldDef, payload) {
434
656
  const clauses = [];
435
657
  const fieldType = fieldDef.type;
436
- const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb, modelAlias);
437
658
  for (const [key, _value] of Object.entries(payload)) {
438
659
  if (_value === void 0) {
439
660
  continue;
440
661
  }
441
- const value = this.transformPrimitive(_value, fieldType);
662
+ const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
442
663
  switch (key) {
443
664
  case "equals": {
444
665
  clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
@@ -469,20 +690,24 @@ var BaseCrudDialect = class {
469
690
  }
470
691
  return this.and(eb, ...clauses);
471
692
  }
472
- buildPrimitiveFilter(eb, model, modelAlias, field, fieldDef, payload) {
693
+ buildPrimitiveFilter(eb, fieldRef, fieldDef, payload) {
473
694
  if (payload === null) {
474
- return eb(import_kysely.sql.ref(`${modelAlias}.${field}`), "is", null);
695
+ return eb(fieldRef, "is", null);
475
696
  }
476
697
  if (isEnum(this.schema, fieldDef.type)) {
477
- return this.buildEnumFilter(eb, modelAlias, field, fieldDef, payload);
698
+ return this.buildEnumFilter(eb, fieldRef, fieldDef, payload);
478
699
  }
479
- return (0, import_ts_pattern.match)(fieldDef.type).with("String", () => this.buildStringFilter(eb, modelAlias, field, payload)).with(import_ts_pattern.P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, model, modelAlias, field, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, modelAlias, field, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, modelAlias, field, payload)).with("Bytes", () => this.buildBytesFilter(eb, modelAlias, field, payload)).exhaustive();
700
+ return (0, import_ts_pattern2.match)(fieldDef.type).with("String", () => this.buildStringFilter(eb, fieldRef, payload)).with(import_ts_pattern2.P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, fieldRef, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, fieldRef, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, fieldRef, payload)).with("Bytes", () => this.buildBytesFilter(eb, fieldRef, payload)).with("Json", () => {
701
+ throw new InternalError("JSON filters are not supported yet");
702
+ }).with("Unsupported", () => {
703
+ throw new QueryError(`Unsupported field cannot be used in filters`);
704
+ }).exhaustive();
480
705
  }
481
706
  buildLiteralFilter(eb, lhs, type, rhs) {
482
- return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type) : rhs);
707
+ return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
483
708
  }
484
- buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
485
- if (payload === null || !(0, import_is_plain_object.isPlainObject)(payload)) {
709
+ buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0, excludeKeys = []) {
710
+ if (payload === null || !(0, import_common_helpers.isPlainObject)(payload)) {
486
711
  return {
487
712
  conditions: [
488
713
  this.buildLiteralFilter(eb, lhs, type, payload)
@@ -496,22 +721,29 @@ var BaseCrudDialect = class {
496
721
  if (onlyForKeys && !onlyForKeys.includes(op)) {
497
722
  continue;
498
723
  }
724
+ if (excludeKeys.includes(op)) {
725
+ continue;
726
+ }
499
727
  const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
500
- const condition = (0, import_ts_pattern.match)(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
501
- (0, import_tiny_invariant.default)(Array.isArray(rhs), "right hand side must be an array");
728
+ const condition = (0, import_ts_pattern2.match)(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
729
+ (0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
502
730
  if (rhs.length === 0) {
503
731
  return this.false(eb);
504
732
  } else {
505
733
  return eb(lhs, "in", rhs);
506
734
  }
507
735
  }).with("notIn", () => {
508
- (0, import_tiny_invariant.default)(Array.isArray(rhs), "right hand side must be an array");
736
+ (0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
509
737
  if (rhs.length === 0) {
510
738
  return this.true(eb);
511
739
  } else {
512
740
  return eb.not(eb(lhs, "in", rhs));
513
741
  }
514
- }).with("lt", () => eb(lhs, "<", rhs)).with("lte", () => eb(lhs, "<=", rhs)).with("gt", () => eb(lhs, ">", rhs)).with("gte", () => eb(lhs, ">=", rhs)).with("not", () => eb.not(recurse(value))).otherwise(() => {
742
+ }).with("lt", () => eb(lhs, "<", rhs)).with("lte", () => eb(lhs, "<=", rhs)).with("gt", () => eb(lhs, ">", rhs)).with("gte", () => eb(lhs, ">=", rhs)).with("not", () => eb.not(recurse(value))).with(import_ts_pattern2.P.union(...AGGREGATE_OPERATORS), (op2) => {
743
+ const innerResult = this.buildStandardFilter(eb, type, value, aggregate(eb, lhs, op2), getRhs, recurse, throwIfInvalid);
744
+ consumedKeys.push(...innerResult.consumedKeys);
745
+ return this.and(eb, ...innerResult.conditions);
746
+ }).otherwise(() => {
515
747
  if (throwIfInvalid) {
516
748
  throw new QueryError(`Invalid filter key: ${op}`);
517
749
  } else {
@@ -528,24 +760,21 @@ var BaseCrudDialect = class {
528
760
  consumedKeys
529
761
  };
530
762
  }
531
- buildStringFilter(eb, table, field, payload) {
532
- const fieldDef = getField(this.schema, table, field);
533
- let fieldRef = fieldDef?.computed ? import_kysely.sql.ref(field) : import_kysely.sql.ref(`${table}.${field}`);
534
- let insensitive = false;
535
- if (payload && typeof payload === "object" && "mode" in payload && payload.mode === "insensitive") {
536
- insensitive = true;
537
- fieldRef = eb.fn("lower", [
538
- fieldRef
539
- ]);
763
+ buildStringFilter(eb, fieldRef, payload) {
764
+ let mode;
765
+ if (payload && typeof payload === "object" && "mode" in payload) {
766
+ mode = payload.mode;
540
767
  }
541
- const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => this.prepStringCasing(eb, value, insensitive), (value) => this.buildStringFilter(eb, table, field, value));
768
+ const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, mode === "insensitive" ? eb.fn("lower", [
769
+ fieldRef
770
+ ]) : fieldRef, (value) => this.prepStringCasing(eb, value, mode), (value) => this.buildStringFilter(eb, fieldRef, value));
542
771
  if (payload && typeof payload === "object") {
543
772
  for (const [key, value] of Object.entries(payload)) {
544
773
  if (key === "mode" || consumedKeys.includes(key)) {
545
774
  continue;
546
775
  }
547
- const condition = (0, import_ts_pattern.match)(key).with("contains", () => insensitive ? eb(fieldRef, "ilike", import_kysely.sql.lit(`%${value}%`)) : eb(fieldRef, "like", import_kysely.sql.lit(`%${value}%`))).with("startsWith", () => insensitive ? eb(fieldRef, "ilike", import_kysely.sql.lit(`${value}%`)) : eb(fieldRef, "like", import_kysely.sql.lit(`${value}%`))).with("endsWith", () => insensitive ? eb(fieldRef, "ilike", import_kysely.sql.lit(`%${value}`)) : eb(fieldRef, "like", import_kysely.sql.lit(`%${value}`))).otherwise(() => {
548
- throw new Error(`Invalid string filter key: ${key}`);
776
+ const condition = (0, import_ts_pattern2.match)(key).with("contains", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`%${value}%`)) : eb(fieldRef, "like", import_kysely.sql.val(`%${value}%`))).with("startsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`${value}%`)) : eb(fieldRef, "like", import_kysely.sql.val(`${value}%`))).with("endsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`%${value}`)) : eb(fieldRef, "like", import_kysely.sql.val(`%${value}`))).otherwise(() => {
777
+ throw new QueryError(`Invalid string filter key: ${key}`);
549
778
  });
550
779
  if (condition) {
551
780
  conditions.push(condition);
@@ -554,34 +783,37 @@ var BaseCrudDialect = class {
554
783
  }
555
784
  return this.and(eb, ...conditions);
556
785
  }
557
- prepStringCasing(eb, value, toLower = true) {
786
+ prepStringCasing(eb, value, mode) {
787
+ if (!mode || mode === "default") {
788
+ return value === null ? value : import_kysely.sql.val(value);
789
+ }
558
790
  if (typeof value === "string") {
559
- return toLower ? eb.fn("lower", [
560
- import_kysely.sql.lit(value)
561
- ]) : import_kysely.sql.lit(value);
791
+ return eb.fn("lower", [
792
+ import_kysely.sql.val(value)
793
+ ]);
562
794
  } else if (Array.isArray(value)) {
563
- return value.map((v) => this.prepStringCasing(eb, v, toLower));
795
+ return value.map((v) => this.prepStringCasing(eb, v, mode));
564
796
  } else {
565
- return value === null ? null : import_kysely.sql.lit(value);
797
+ return value === null ? null : import_kysely.sql.val(value);
566
798
  }
567
799
  }
568
- buildNumberFilter(eb, model, table, field, type, payload) {
569
- const { conditions } = this.buildStandardFilter(eb, type, payload, buildFieldRef(this.schema, model, field, this.options, eb), (value) => this.transformPrimitive(value, type), (value) => this.buildNumberFilter(eb, model, table, field, type, value));
800
+ buildNumberFilter(eb, fieldRef, type, payload) {
801
+ const { conditions } = this.buildStandardFilter(eb, type, payload, fieldRef, (value) => this.transformPrimitive(value, type, false), (value) => this.buildNumberFilter(eb, fieldRef, type, value));
570
802
  return this.and(eb, ...conditions);
571
803
  }
572
- buildBooleanFilter(eb, table, field, payload) {
573
- const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Boolean"), (value) => this.buildBooleanFilter(eb, table, field, value), true, [
804
+ buildBooleanFilter(eb, fieldRef, payload) {
805
+ const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, fieldRef, (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, fieldRef, value), true, [
574
806
  "equals",
575
807
  "not"
576
808
  ]);
577
809
  return this.and(eb, ...conditions);
578
810
  }
579
- buildDateTimeFilter(eb, table, field, payload) {
580
- const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "DateTime"), (value) => this.buildDateTimeFilter(eb, table, field, value), true);
811
+ buildDateTimeFilter(eb, fieldRef, payload) {
812
+ const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, fieldRef, (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, fieldRef, value), true);
581
813
  return this.and(eb, ...conditions);
582
814
  }
583
- buildBytesFilter(eb, table, field, payload) {
584
- const conditions = this.buildStandardFilter(eb, "Bytes", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Bytes"), (value) => this.buildBytesFilter(eb, table, field, value), true, [
815
+ buildBytesFilter(eb, fieldRef, payload) {
816
+ const conditions = this.buildStandardFilter(eb, "Bytes", payload, fieldRef, (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, fieldRef, value), true, [
585
817
  "equals",
586
818
  "in",
587
819
  "notIn",
@@ -589,8 +821,8 @@ var BaseCrudDialect = class {
589
821
  ]);
590
822
  return this.and(eb, ...conditions.conditions);
591
823
  }
592
- buildEnumFilter(eb, table, field, fieldDef, payload) {
593
- const conditions = this.buildStandardFilter(eb, "String", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => value, (value) => this.buildEnumFilter(eb, table, field, fieldDef, value), true, [
824
+ buildEnumFilter(eb, fieldRef, fieldDef, payload) {
825
+ const conditions = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => value, (value) => this.buildEnumFilter(eb, fieldRef, fieldDef, value), true, [
594
826
  "equals",
595
827
  "in",
596
828
  "notIn",
@@ -619,21 +851,19 @@ var BaseCrudDialect = class {
619
851
  "_min",
620
852
  "_max"
621
853
  ].includes(field)) {
622
- (0, import_tiny_invariant.default)(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
854
+ (0, import_common_helpers.invariant)(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
623
855
  for (const [k, v] of Object.entries(value)) {
624
- (0, import_tiny_invariant.default)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
625
- result = result.orderBy((eb) => eb.fn(field.slice(1), [
626
- import_kysely.sql.ref(k)
627
- ]), import_kysely.sql.raw(this.negateSort(v, negated)));
856
+ (0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
857
+ result = result.orderBy((eb) => aggregate(eb, this.fieldRef(model, k, eb, modelAlias), field), import_kysely.sql.raw(this.negateSort(v, negated)));
628
858
  }
629
859
  continue;
630
860
  }
631
861
  switch (field) {
632
862
  case "_count": {
633
- (0, import_tiny_invariant.default)(value && typeof value === "object", 'invalid orderBy value for field "_count"');
863
+ (0, import_common_helpers.invariant)(value && typeof value === "object", 'invalid orderBy value for field "_count"');
634
864
  for (const [k, v] of Object.entries(value)) {
635
- (0, import_tiny_invariant.default)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
636
- result = result.orderBy((eb) => eb.fn.count(import_kysely.sql.ref(k)), import_kysely.sql.raw(this.negateSort(v, negated)));
865
+ (0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
866
+ result = result.orderBy((eb) => eb.fn.count(this.fieldRef(model, k, eb, modelAlias)), import_kysely.sql.raw(this.negateSort(v, negated)));
637
867
  }
638
868
  continue;
639
869
  }
@@ -642,10 +872,11 @@ var BaseCrudDialect = class {
642
872
  }
643
873
  const fieldDef = requireField(this.schema, model, field);
644
874
  if (!fieldDef.relation) {
875
+ const fieldRef = this.fieldRef(model, field, (0, import_kysely.expressionBuilder)(), modelAlias);
645
876
  if (value === "asc" || value === "desc") {
646
- result = result.orderBy(import_kysely.sql.ref(`${modelAlias}.${field}`), this.negateSort(value, negated));
877
+ result = result.orderBy(fieldRef, this.negateSort(value, negated));
647
878
  } else if (value && typeof value === "object" && "nulls" in value && "sort" in value && (value.sort === "asc" || value.sort === "desc") && (value.nulls === "first" || value.nulls === "last")) {
648
- result = result.orderBy(import_kysely.sql.ref(`${modelAlias}.${field}`), import_kysely.sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`));
879
+ result = result.orderBy(fieldRef, import_kysely.sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`));
649
880
  }
650
881
  } else {
651
882
  const relationModel = fieldDef.type;
@@ -654,11 +885,12 @@ var BaseCrudDialect = class {
654
885
  throw new QueryError(`invalid orderBy value for field "${field}"`);
655
886
  }
656
887
  if ("_count" in value) {
657
- (0, import_tiny_invariant.default)(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
888
+ (0, import_common_helpers.invariant)(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
658
889
  const sort = this.negateSort(value._count, negated);
659
890
  result = result.orderBy((eb) => {
660
- let subQuery = eb.selectFrom(relationModel);
661
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, relationModel);
891
+ const subQueryAlias = `${modelAlias}$orderBy$${field}$count`;
892
+ let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
893
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
662
894
  subQuery = subQuery.where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely.sql.ref(left), "=", import_kysely.sql.ref(right)))));
663
895
  subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
664
896
  return subQuery;
@@ -676,14 +908,90 @@ var BaseCrudDialect = class {
676
908
  });
677
909
  return result;
678
910
  }
911
+ buildSelectAllFields(model, query, omit, modelAlias) {
912
+ const modelDef = requireModel(this.schema, model);
913
+ let result = query;
914
+ for (const field of Object.keys(modelDef.fields)) {
915
+ if (isRelationField(this.schema, model, field)) {
916
+ continue;
917
+ }
918
+ if (omit?.[field] === true) {
919
+ continue;
920
+ }
921
+ result = this.buildSelectField(result, model, modelAlias, field);
922
+ }
923
+ const descendants = getDelegateDescendantModels(this.schema, model);
924
+ for (const subModel of descendants) {
925
+ result = this.buildDelegateJoin(model, modelAlias, subModel.name, result);
926
+ result = result.select((eb) => {
927
+ const jsonObject = {};
928
+ for (const field of Object.keys(subModel.fields)) {
929
+ if (isRelationField(this.schema, subModel.name, field) || isInheritedField(this.schema, subModel.name, field)) {
930
+ continue;
931
+ }
932
+ jsonObject[field] = eb.ref(`${subModel.name}.${field}`);
933
+ }
934
+ return this.buildJsonObject(eb, jsonObject).as(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`);
935
+ });
936
+ }
937
+ return result;
938
+ }
939
+ buildSelectField(query, model, modelAlias, field) {
940
+ const fieldDef = requireField(this.schema, model, field);
941
+ if (fieldDef.computed) {
942
+ return query.select((eb) => this.fieldRef(model, field, eb, modelAlias).as(field));
943
+ } else if (!fieldDef.originModel) {
944
+ return query.select(import_kysely.sql.ref(`${modelAlias}.${field}`).as(field));
945
+ } else {
946
+ return this.buildSelectField(query, fieldDef.originModel, fieldDef.originModel, field);
947
+ }
948
+ }
949
+ buildDelegateJoin(thisModel, thisModelAlias, otherModelAlias, query) {
950
+ const idFields = getIdFields(this.schema, thisModel);
951
+ query = query.leftJoin(otherModelAlias, (qb) => {
952
+ for (const idField of idFields) {
953
+ qb = qb.onRef(`${thisModelAlias}.${idField}`, "=", `${otherModelAlias}.${idField}`);
954
+ }
955
+ return qb;
956
+ });
957
+ return query;
958
+ }
959
+ buildCountJson(model, eb, parentAlias, payload) {
960
+ const modelDef = requireModel(this.schema, model);
961
+ const toManyRelations = Object.entries(modelDef.fields).filter(([, field]) => field.relation && field.array);
962
+ const selections = payload === true ? {
963
+ select: toManyRelations.reduce((acc, [field]) => {
964
+ acc[field] = true;
965
+ return acc;
966
+ }, {})
967
+ } : payload;
968
+ const jsonObject = {};
969
+ for (const [field, value] of Object.entries(selections.select)) {
970
+ const fieldDef = requireField(this.schema, model, field);
971
+ const fieldModel = fieldDef.type;
972
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
973
+ let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
974
+ for (const [left, right] of joinPairs) {
975
+ fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
976
+ }
977
+ if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
978
+ const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
979
+ fieldCountQuery = fieldCountQuery.where(filter);
980
+ }
981
+ jsonObject[field] = fieldCountQuery;
982
+ }
983
+ return this.buildJsonObject(eb, jsonObject);
984
+ }
985
+ // #endregion
986
+ // #region utils
679
987
  negateSort(sort, negated) {
680
988
  return negated ? sort === "asc" ? "desc" : "asc" : sort;
681
989
  }
682
990
  true(eb) {
683
- return eb.lit(this.transformPrimitive(true, "Boolean"));
991
+ return eb.lit(this.transformPrimitive(true, "Boolean", false));
684
992
  }
685
993
  false(eb) {
686
- return eb.lit(this.transformPrimitive(false, "Boolean"));
994
+ return eb.lit(this.transformPrimitive(false, "Boolean", false));
687
995
  }
688
996
  isTrue(expression) {
689
997
  const node = expression.toOperationNode();
@@ -722,6 +1030,9 @@ var BaseCrudDialect = class {
722
1030
  not(eb, ...args) {
723
1031
  return eb.not(this.and(eb, ...args));
724
1032
  }
1033
+ fieldRef(model, field, eb, modelAlias, inlineComputedField = true) {
1034
+ return buildFieldRef(this.schema, model, field, this.options, eb, modelAlias, inlineComputedField);
1035
+ }
725
1036
  };
726
1037
 
727
1038
  // src/client/crud/dialects/postgresql.ts
@@ -732,14 +1043,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
732
1043
  get provider() {
733
1044
  return "postgresql";
734
1045
  }
735
- transformPrimitive(value, type) {
1046
+ transformPrimitive(value, type, forArrayField) {
736
1047
  if (value === void 0) {
737
1048
  return value;
738
1049
  }
739
1050
  if (Array.isArray(value)) {
740
- return value.map((v) => this.transformPrimitive(v, type));
1051
+ if (type === "Json" && !forArrayField) {
1052
+ return JSON.stringify(value);
1053
+ } else {
1054
+ return value.map((v) => this.transformPrimitive(v, type, false));
1055
+ }
741
1056
  } else {
742
- return (0, import_ts_pattern2.match)(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).otherwise(() => value);
1057
+ return (0, import_ts_pattern3.match)(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).with("Decimal", () => value !== null ? value.toString() : value).otherwise(() => value);
743
1058
  }
744
1059
  }
745
1060
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
@@ -752,43 +1067,34 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
752
1067
  return qb.leftJoinLateral((eb) => {
753
1068
  const joinTableName = `${parentName}$${relationField}`;
754
1069
  let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
1070
+ const subQueryAlias = `${relationModel}$${relationField}$sub`;
755
1071
  result = eb.selectFrom(() => {
756
- let subQuery = eb.selectFrom(`${relationModel}`).selectAll();
1072
+ let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
1073
+ subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
757
1074
  if (payload && typeof payload === "object") {
758
- if (payload.where) {
759
- subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
760
- }
761
- const skip = payload.skip;
762
- let take = payload.take;
763
- let negateOrderBy = false;
764
- if (take !== void 0 && take < 0) {
765
- negateOrderBy = true;
766
- take = -take;
767
- }
768
- subQuery = this.buildSkipTake(subQuery, skip, take);
769
- subQuery = this.buildOrderBy(subQuery, relationModel, relationModel, payload.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
1075
+ subQuery = this.buildFilterSortTake(relationModel, payload, subQuery, subQueryAlias);
770
1076
  }
771
1077
  const m2m = getManyToManyRelation(this.schema, model, relationField);
772
1078
  if (m2m) {
773
1079
  const parentIds = getIdFields(this.schema, model);
774
1080
  const relationIds = getIdFields(this.schema, relationModel);
775
- (0, import_tiny_invariant2.default)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
776
- (0, import_tiny_invariant2.default)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
777
- 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}`)));
1081
+ (0, import_common_helpers2.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1082
+ (0, import_common_helpers2.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1083
+ subQuery = subQuery.where(eb(eb.ref(`${subQueryAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentName}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
778
1084
  } else {
779
- const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, relationModel);
1085
+ const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, subQueryAlias);
780
1086
  subQuery = subQuery.where((eb2) => this.and(eb2, ...joinPairs.map(([left, right]) => eb2(import_kysely2.sql.ref(left), "=", import_kysely2.sql.ref(right)))));
781
1087
  }
782
1088
  return subQuery.as(joinTableName);
783
1089
  });
784
- result = this.buildRelationObjectSelect(relationModel, relationField, relationFieldDef, result, payload, parentName);
1090
+ result = this.buildRelationObjectSelect(relationModel, joinTableName, relationField, relationFieldDef, result, payload, parentName);
785
1091
  result = this.buildRelationJoins(relationModel, relationField, result, payload, parentName);
786
1092
  return result.as(joinTableName);
787
1093
  }, (join) => join.onTrue());
788
1094
  }
789
- buildRelationObjectSelect(relationModel, relationField, relationFieldDef, qb, payload, parentName) {
1095
+ buildRelationObjectSelect(relationModel, relationModelAlias, relationField, relationFieldDef, qb, payload, parentName) {
790
1096
  qb = qb.select((eb) => {
791
- const objArgs = this.buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName);
1097
+ const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, relationField, eb, payload, parentName);
792
1098
  if (relationFieldDef.array) {
793
1099
  return eb.fn.coalesce(import_kysely2.sql`jsonb_agg(jsonb_build_object(${import_kysely2.sql.join(objArgs)}))`, import_kysely2.sql`'[]'::jsonb`).as("$j");
794
1100
  } else {
@@ -797,34 +1103,57 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
797
1103
  });
798
1104
  return qb;
799
1105
  }
800
- buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName) {
1106
+ buildRelationObjectArgs(relationModel, relationModelAlias, relationField, eb, payload, parentAlias) {
801
1107
  const relationModelDef = requireModel(this.schema, relationModel);
802
1108
  const objArgs = [];
1109
+ const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1110
+ if (descendantModels.length > 0) {
1111
+ objArgs.push(...descendantModels.map((subModel) => [
1112
+ import_kysely2.sql.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1113
+ eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1114
+ ]).flatMap((v) => v));
1115
+ }
803
1116
  if (payload === true || !payload.select) {
804
1117
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
805
1118
  import_kysely2.sql.lit(field),
806
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
1119
+ this.fieldRef(relationModel, field, eb, relationModelAlias, false)
807
1120
  ]).flatMap((v) => v));
808
1121
  } else if (payload.select) {
809
- objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => [
810
- import_kysely2.sql.lit(field),
811
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
812
- ]).flatMap((v) => v));
1122
+ objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1123
+ if (field === "_count") {
1124
+ const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
1125
+ return [
1126
+ import_kysely2.sql.lit(field),
1127
+ subJson
1128
+ ];
1129
+ } else {
1130
+ const fieldDef = requireField(this.schema, relationModel, field);
1131
+ const fieldValue = fieldDef.relation ? eb.ref(`${parentAlias}$${relationField}$${field}.$j`) : this.fieldRef(relationModel, field, eb, void 0, false);
1132
+ return [
1133
+ import_kysely2.sql.lit(field),
1134
+ fieldValue
1135
+ ];
1136
+ }
1137
+ }).flatMap((v) => v));
813
1138
  }
814
1139
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
815
1140
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
816
1141
  import_kysely2.sql.lit(field),
817
- eb.ref(`${parentName}$${relationField}$${field}.$j`)
1142
+ // reference the synthesized JSON field
1143
+ eb.ref(`${parentAlias}$${relationField}$${field}.$j`)
818
1144
  ]).flatMap((v) => v));
819
1145
  }
820
1146
  return objArgs;
821
1147
  }
822
- buildRelationJoins(model, relationField, qb, payload, parentName) {
1148
+ buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
823
1149
  let result = qb;
824
- if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
825
- Object.entries(payload.include).filter(([, value]) => value).forEach(([field, value]) => {
826
- result = this.buildRelationJSON(model, result, field, `${parentName}$${relationField}`, value);
827
- });
1150
+ if (typeof payload === "object") {
1151
+ const selectInclude = payload.include ?? payload.select;
1152
+ if (selectInclude && typeof selectInclude === "object") {
1153
+ Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
1154
+ result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
1155
+ });
1156
+ }
828
1157
  }
829
1158
  return result;
830
1159
  }
@@ -864,12 +1193,15 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
864
1193
  return `ARRAY[${values.map((v) => typeof v === "string" ? `'${v}'` : v)}]`;
865
1194
  }
866
1195
  }
1196
+ get supportInsertWithDefault() {
1197
+ return true;
1198
+ }
867
1199
  };
868
1200
 
869
1201
  // src/client/crud/dialects/sqlite.ts
1202
+ var import_common_helpers3 = require("@zenstackhq/common-helpers");
870
1203
  var import_kysely3 = require("kysely");
871
- var import_tiny_invariant3 = __toESM(require("tiny-invariant"), 1);
872
- var import_ts_pattern3 = require("ts-pattern");
1204
+ var import_ts_pattern4 = require("ts-pattern");
873
1205
  var SqliteCrudDialect = class extends BaseCrudDialect {
874
1206
  static {
875
1207
  __name(this, "SqliteCrudDialect");
@@ -877,54 +1209,49 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
877
1209
  get provider() {
878
1210
  return "sqlite";
879
1211
  }
880
- transformPrimitive(value, type) {
1212
+ transformPrimitive(value, type, _forArrayField) {
881
1213
  if (value === void 0) {
882
1214
  return value;
883
1215
  }
884
1216
  if (Array.isArray(value)) {
885
- return value.map((v) => this.transformPrimitive(v, type));
1217
+ return value.map((v) => this.transformPrimitive(v, type, false));
886
1218
  } else {
887
- return (0, import_ts_pattern3.match)(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).otherwise(() => value);
1219
+ if (this.schema.typeDefs && type in this.schema.typeDefs) {
1220
+ return JSON.stringify(value);
1221
+ } else {
1222
+ return (0, import_ts_pattern4.match)(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).with("Json", () => JSON.stringify(value)).otherwise(() => value);
1223
+ }
888
1224
  }
889
1225
  }
890
1226
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
891
1227
  return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
892
1228
  }
893
- buildRelationJSON(model, eb, relationField, parentName, payload) {
1229
+ buildRelationJSON(model, eb, relationField, parentAlias, payload) {
894
1230
  const relationFieldDef = requireField(this.schema, model, relationField);
895
1231
  const relationModel = relationFieldDef.type;
896
1232
  const relationModelDef = requireModel(this.schema, relationModel);
897
- const subQueryName = `${parentName}$${relationField}`;
1233
+ const subQueryName = `${parentAlias}$${relationField}`;
898
1234
  let tbl = eb.selectFrom(() => {
899
- let subQuery = eb.selectFrom(relationModel).selectAll();
1235
+ const subQueryAlias = `${parentAlias}$${relationField}$sub`;
1236
+ let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
1237
+ subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
900
1238
  if (payload && typeof payload === "object") {
901
- if (payload.where) {
902
- subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
903
- }
904
- const skip = payload.skip;
905
- let take = payload.take;
906
- let negateOrderBy = false;
907
- if (take !== void 0 && take < 0) {
908
- negateOrderBy = true;
909
- take = -take;
910
- }
911
- subQuery = this.buildSkipTake(subQuery, skip, take);
912
- subQuery = this.buildOrderBy(subQuery, relationModel, relationModel, payload.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
1239
+ subQuery = this.buildFilterSortTake(relationModel, payload, subQuery, subQueryAlias);
913
1240
  }
914
1241
  const m2m = getManyToManyRelation(this.schema, model, relationField);
915
1242
  if (m2m) {
916
1243
  const parentIds = getIdFields(this.schema, model);
917
1244
  const relationIds = getIdFields(this.schema, relationModel);
918
- (0, import_tiny_invariant3.default)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
919
- (0, import_tiny_invariant3.default)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
920
- 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}`)));
1245
+ (0, import_common_helpers3.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1246
+ (0, import_common_helpers3.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1247
+ subQuery = subQuery.where(eb(eb.ref(`${subQueryAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
921
1248
  } else {
922
1249
  const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
923
1250
  keyPairs.forEach(({ fk, pk }) => {
924
1251
  if (ownedByModel) {
925
- subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentName}.${fk}`);
1252
+ subQuery = subQuery.whereRef(`${subQueryAlias}.${pk}`, "=", `${parentAlias}.${fk}`);
926
1253
  } else {
927
- subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentName}.${pk}`);
1254
+ subQuery = subQuery.whereRef(`${subQueryAlias}.${fk}`, "=", `${parentAlias}.${pk}`);
928
1255
  }
929
1256
  });
930
1257
  }
@@ -932,31 +1259,46 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
932
1259
  });
933
1260
  tbl = tbl.select(() => {
934
1261
  const objArgs = [];
1262
+ const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1263
+ if (descendantModels.length > 0) {
1264
+ objArgs.push(...descendantModels.map((subModel) => [
1265
+ import_kysely3.sql.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1266
+ eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1267
+ ]).flatMap((v) => v));
1268
+ }
935
1269
  if (payload === true || !payload.select) {
936
1270
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
937
1271
  import_kysely3.sql.lit(field),
938
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
1272
+ this.fieldRef(relationModel, field, eb, void 0, false)
939
1273
  ]).flatMap((v) => v));
940
1274
  } else if (payload.select) {
941
1275
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
942
- const fieldDef = requireField(this.schema, relationModel, field);
943
- if (fieldDef.relation) {
944
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1276
+ if (field === "_count") {
1277
+ const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
945
1278
  return [
946
1279
  import_kysely3.sql.lit(field),
947
1280
  subJson
948
1281
  ];
949
1282
  } else {
950
- return [
951
- import_kysely3.sql.lit(field),
952
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
953
- ];
1283
+ const fieldDef = requireField(this.schema, relationModel, field);
1284
+ if (fieldDef.relation) {
1285
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
1286
+ return [
1287
+ import_kysely3.sql.lit(field),
1288
+ subJson
1289
+ ];
1290
+ } else {
1291
+ return [
1292
+ import_kysely3.sql.lit(field),
1293
+ this.fieldRef(relationModel, field, eb, void 0, false)
1294
+ ];
1295
+ }
954
1296
  }
955
1297
  }).flatMap((v) => v));
956
1298
  }
957
1299
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
958
1300
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
959
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1301
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
960
1302
  return [
961
1303
  import_kysely3.sql.lit(field),
962
1304
  subJson
@@ -1006,93 +1348,17 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1006
1348
  buildArrayLiteralSQL(_values) {
1007
1349
  throw new Error("SQLite does not support array literals");
1008
1350
  }
1351
+ get supportInsertWithDefault() {
1352
+ return false;
1353
+ }
1009
1354
  };
1010
1355
 
1011
1356
  // src/client/crud/dialects/index.ts
1012
1357
  function getCrudDialect(schema, options) {
1013
- return (0, import_ts_pattern4.match)(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
1358
+ return (0, import_ts_pattern5.match)(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
1014
1359
  }
1015
1360
  __name(getCrudDialect, "getCrudDialect");
1016
1361
 
1017
- // src/schema/expression.ts
1018
- var ExpressionUtils = {
1019
- literal: /* @__PURE__ */ __name((value) => {
1020
- return {
1021
- kind: "literal",
1022
- value
1023
- };
1024
- }, "literal"),
1025
- array: /* @__PURE__ */ __name((items) => {
1026
- return {
1027
- kind: "array",
1028
- items
1029
- };
1030
- }, "array"),
1031
- call: /* @__PURE__ */ __name((functionName, args) => {
1032
- return {
1033
- kind: "call",
1034
- function: functionName,
1035
- args
1036
- };
1037
- }, "call"),
1038
- binary: /* @__PURE__ */ __name((left, op, right) => {
1039
- return {
1040
- kind: "binary",
1041
- op,
1042
- left,
1043
- right
1044
- };
1045
- }, "binary"),
1046
- unary: /* @__PURE__ */ __name((op, operand) => {
1047
- return {
1048
- kind: "unary",
1049
- op,
1050
- operand
1051
- };
1052
- }, "unary"),
1053
- field: /* @__PURE__ */ __name((field) => {
1054
- return {
1055
- kind: "field",
1056
- field
1057
- };
1058
- }, "field"),
1059
- member: /* @__PURE__ */ __name((receiver, members) => {
1060
- return {
1061
- kind: "member",
1062
- receiver,
1063
- members
1064
- };
1065
- }, "member"),
1066
- _this: /* @__PURE__ */ __name(() => {
1067
- return {
1068
- kind: "this"
1069
- };
1070
- }, "_this"),
1071
- _null: /* @__PURE__ */ __name(() => {
1072
- return {
1073
- kind: "null"
1074
- };
1075
- }, "_null"),
1076
- and: /* @__PURE__ */ __name((expr2, ...expressions) => {
1077
- return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
1078
- }, "and"),
1079
- or: /* @__PURE__ */ __name((expr2, ...expressions) => {
1080
- return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
1081
- }, "or"),
1082
- is: /* @__PURE__ */ __name((value, kind) => {
1083
- return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
1084
- }, "is"),
1085
- isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
1086
- isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
1087
- isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
1088
- isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
1089
- isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
1090
- isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
1091
- isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
1092
- isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
1093
- isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
1094
- };
1095
-
1096
1362
  // src/utils/default-operation-node-visitor.ts
1097
1363
  var import_kysely4 = require("kysely");
1098
1364
  var DefaultOperationNodeVisitor = class extends import_kysely4.OperationNodeVisitor {
@@ -1412,19 +1678,19 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
1412
1678
  };
1413
1679
 
1414
1680
  // src/plugins/policy/expression-transformer.ts
1681
+ var import_common_helpers5 = require("@zenstackhq/common-helpers");
1415
1682
  var import_kysely6 = require("kysely");
1416
- var import_tiny_invariant5 = __toESM(require("tiny-invariant"), 1);
1417
- var import_ts_pattern6 = require("ts-pattern");
1683
+ var import_ts_pattern7 = require("ts-pattern");
1418
1684
 
1419
1685
  // src/plugins/policy/expression-evaluator.ts
1420
- var import_tiny_invariant4 = __toESM(require("tiny-invariant"), 1);
1421
- var import_ts_pattern5 = require("ts-pattern");
1686
+ var import_common_helpers4 = require("@zenstackhq/common-helpers");
1687
+ var import_ts_pattern6 = require("ts-pattern");
1422
1688
  var ExpressionEvaluator = class {
1423
1689
  static {
1424
1690
  __name(this, "ExpressionEvaluator");
1425
1691
  }
1426
1692
  evaluate(expression, context) {
1427
- const result = (0, import_ts_pattern5.match)(expression).when(ExpressionUtils.isArray, (expr2) => this.evaluateArray(expr2, context)).when(ExpressionUtils.isBinary, (expr2) => this.evaluateBinary(expr2, context)).when(ExpressionUtils.isField, (expr2) => this.evaluateField(expr2, context)).when(ExpressionUtils.isLiteral, (expr2) => this.evaluateLiteral(expr2)).when(ExpressionUtils.isMember, (expr2) => this.evaluateMember(expr2, context)).when(ExpressionUtils.isUnary, (expr2) => this.evaluateUnary(expr2, context)).when(ExpressionUtils.isCall, (expr2) => this.evaluateCall(expr2, context)).when(ExpressionUtils.isThis, () => context.thisValue).when(ExpressionUtils.isNull, () => null).exhaustive();
1693
+ const result = (0, import_ts_pattern6.match)(expression).when(ExpressionUtils.isArray, (expr2) => this.evaluateArray(expr2, context)).when(ExpressionUtils.isBinary, (expr2) => this.evaluateBinary(expr2, context)).when(ExpressionUtils.isField, (expr2) => this.evaluateField(expr2, context)).when(ExpressionUtils.isLiteral, (expr2) => this.evaluateLiteral(expr2)).when(ExpressionUtils.isMember, (expr2) => this.evaluateMember(expr2, context)).when(ExpressionUtils.isUnary, (expr2) => this.evaluateUnary(expr2, context)).when(ExpressionUtils.isCall, (expr2) => this.evaluateCall(expr2, context)).when(ExpressionUtils.isThis, () => context.thisValue).when(ExpressionUtils.isNull, () => null).exhaustive();
1428
1694
  return result ?? null;
1429
1695
  }
1430
1696
  evaluateCall(expr2, context) {
@@ -1435,7 +1701,7 @@ var ExpressionEvaluator = class {
1435
1701
  }
1436
1702
  }
1437
1703
  evaluateUnary(expr2, context) {
1438
- return (0, import_ts_pattern5.match)(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
1704
+ return (0, import_ts_pattern6.match)(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
1439
1705
  }
1440
1706
  evaluateMember(expr2, context) {
1441
1707
  let val = this.evaluate(expr2.receiver, context);
@@ -1459,21 +1725,21 @@ var ExpressionEvaluator = class {
1459
1725
  }
1460
1726
  const left = this.evaluate(expr2.left, context);
1461
1727
  const right = this.evaluate(expr2.right, context);
1462
- return (0, import_ts_pattern5.match)(expr2.op).with("==", () => left === right).with("!=", () => left !== right).with(">", () => left > right).with(">=", () => left >= right).with("<", () => left < right).with("<=", () => left <= right).with("&&", () => left && right).with("||", () => left || right).with("in", () => {
1728
+ return (0, import_ts_pattern6.match)(expr2.op).with("==", () => left === right).with("!=", () => left !== right).with(">", () => left > right).with(">=", () => left >= right).with("<", () => left < right).with("<=", () => left <= right).with("&&", () => left && right).with("||", () => left || right).with("in", () => {
1463
1729
  const _right = right ?? [];
1464
- (0, import_tiny_invariant4.default)(Array.isArray(_right), 'expected array for "in" operator');
1730
+ (0, import_common_helpers4.invariant)(Array.isArray(_right), 'expected array for "in" operator');
1465
1731
  return _right.includes(left);
1466
1732
  }).exhaustive();
1467
1733
  }
1468
1734
  evaluateCollectionPredicate(expr2, context) {
1469
1735
  const op = expr2.op;
1470
- (0, import_tiny_invariant4.default)(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
1736
+ (0, import_common_helpers4.invariant)(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
1471
1737
  const left = this.evaluate(expr2.left, context);
1472
1738
  if (!left) {
1473
1739
  return false;
1474
1740
  }
1475
- (0, import_tiny_invariant4.default)(Array.isArray(left), "expected array");
1476
- return (0, import_ts_pattern5.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1741
+ (0, import_common_helpers4.invariant)(Array.isArray(left), "expected array");
1742
+ return (0, import_ts_pattern6.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1477
1743
  ...context,
1478
1744
  thisValue: item
1479
1745
  }))).with("!", () => left.every((item) => this.evaluate(expr2.right, {
@@ -1489,11 +1755,11 @@ var ExpressionEvaluator = class {
1489
1755
  // src/plugins/policy/utils.ts
1490
1756
  var import_kysely5 = require("kysely");
1491
1757
  function trueNode(dialect) {
1492
- return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
1758
+ return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
1493
1759
  }
1494
1760
  __name(trueNode, "trueNode");
1495
1761
  function falseNode(dialect) {
1496
- return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
1762
+ return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
1497
1763
  }
1498
1764
  __name(falseNode, "falseNode");
1499
1765
  function isTrueNode(node) {
@@ -1694,20 +1960,20 @@ var ExpressionTransformer = class {
1694
1960
  return import_kysely6.BinaryOperationNode.create(left, this.transformOperator(op), right);
1695
1961
  }
1696
1962
  transformCollectionPredicate(expr2, context) {
1697
- (0, import_tiny_invariant5.default)(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
1963
+ (0, import_common_helpers5.invariant)(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
1698
1964
  if (this.isAuthCall(expr2.left) || this.isAuthMember(expr2.left)) {
1699
1965
  const value = new ExpressionEvaluator().evaluate(expr2, {
1700
1966
  auth: this.auth
1701
1967
  });
1702
1968
  return this.transformValue(value, "Boolean");
1703
1969
  }
1704
- (0, import_tiny_invariant5.default)(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
1970
+ (0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
1705
1971
  let newContextModel;
1706
1972
  if (ExpressionUtils.isField(expr2.left)) {
1707
1973
  const fieldDef = requireField(this.schema, context.model, expr2.left.field);
1708
1974
  newContextModel = fieldDef.type;
1709
1975
  } else {
1710
- (0, import_tiny_invariant5.default)(ExpressionUtils.isField(expr2.left.receiver));
1976
+ (0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.left.receiver));
1711
1977
  const fieldDef = requireField(this.schema, context.model, expr2.left.receiver.field);
1712
1978
  newContextModel = fieldDef.type;
1713
1979
  for (const member of expr2.left.members) {
@@ -1727,7 +1993,7 @@ var ExpressionTransformer = class {
1727
1993
  const count = import_kysely6.FunctionNode.create("count", [
1728
1994
  import_kysely6.ValueNode.createImmediate(1)
1729
1995
  ]);
1730
- const predicateResult = (0, import_ts_pattern6.match)(expr2.op).with("?", () => import_kysely6.BinaryOperationNode.create(count, import_kysely6.OperatorNode.create(">"), import_kysely6.ValueNode.createImmediate(0))).with("!", () => import_kysely6.BinaryOperationNode.create(count, import_kysely6.OperatorNode.create("="), import_kysely6.ValueNode.createImmediate(0))).with("^", () => import_kysely6.BinaryOperationNode.create(count, import_kysely6.OperatorNode.create("="), import_kysely6.ValueNode.createImmediate(0))).exhaustive();
1996
+ const predicateResult = (0, import_ts_pattern7.match)(expr2.op).with("?", () => import_kysely6.BinaryOperationNode.create(count, import_kysely6.OperatorNode.create(">"), import_kysely6.ValueNode.createImmediate(0))).with("!", () => import_kysely6.BinaryOperationNode.create(count, import_kysely6.OperatorNode.create("="), import_kysely6.ValueNode.createImmediate(0))).with("^", () => import_kysely6.BinaryOperationNode.create(count, import_kysely6.OperatorNode.create("="), import_kysely6.ValueNode.createImmediate(0))).exhaustive();
1731
1997
  return this.transform(expr2.left, {
1732
1998
  ...context,
1733
1999
  memberSelect: import_kysely6.SelectionNode.create(import_kysely6.AliasNode.create(predicateResult, import_kysely6.IdentifierNode.create("$t"))),
@@ -1751,14 +2017,14 @@ var ExpressionTransformer = class {
1751
2017
  }
1752
2018
  }
1753
2019
  transformValue(value, type) {
1754
- return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type) ?? null);
2020
+ return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type, false) ?? null);
1755
2021
  }
1756
2022
  _unary(expr2, context) {
1757
- (0, import_tiny_invariant5.default)(expr2.op === "!", 'only "!" operator is supported');
2023
+ (0, import_common_helpers5.invariant)(expr2.op === "!", 'only "!" operator is supported');
1758
2024
  return import_kysely6.BinaryOperationNode.create(this.transform(expr2.operand, context), this.transformOperator("!="), trueNode(this.dialect));
1759
2025
  }
1760
2026
  transformOperator(op) {
1761
- const mappedOp = (0, import_ts_pattern6.match)(op).with("==", () => "=").otherwise(() => op);
2027
+ const mappedOp = (0, import_ts_pattern7.match)(op).with("==", () => "=").otherwise(() => op);
1762
2028
  return import_kysely6.OperatorNode.create(mappedOp);
1763
2029
  }
1764
2030
  _call(expr2, context) {
@@ -1797,10 +2063,10 @@ var ExpressionTransformer = class {
1797
2063
  if (this.isAuthCall(expr2.receiver)) {
1798
2064
  return this.valueMemberAccess(this.auth, expr2, this.authType);
1799
2065
  }
1800
- (0, import_tiny_invariant5.default)(ExpressionUtils.isField(expr2.receiver), "expect receiver to be field expression");
2066
+ (0, import_common_helpers5.invariant)(ExpressionUtils.isField(expr2.receiver), "expect receiver to be field expression");
1801
2067
  const { memberFilter, memberSelect, ...restContext } = context;
1802
2068
  const receiver = this.transform(expr2.receiver, restContext);
1803
- (0, import_tiny_invariant5.default)(import_kysely6.SelectQueryNode.is(receiver), "expected receiver to be select query");
2069
+ (0, import_common_helpers5.invariant)(import_kysely6.SelectQueryNode.is(receiver), "expected receiver to be select query");
1804
2070
  const receiverField = requireField(this.schema, context.model, expr2.receiver.field);
1805
2071
  const memberFields = [];
1806
2072
  let currType = receiverField.type;
@@ -1824,7 +2090,7 @@ var ExpressionTransformer = class {
1824
2090
  thisEntity: void 0
1825
2091
  });
1826
2092
  if (currNode) {
1827
- (0, import_tiny_invariant5.default)(import_kysely6.SelectQueryNode.is(currNode), "expected select query node");
2093
+ (0, import_common_helpers5.invariant)(import_kysely6.SelectQueryNode.is(currNode), "expected select query node");
1828
2094
  currNode = {
1829
2095
  ...relation,
1830
2096
  selections: [
@@ -1841,8 +2107,8 @@ var ExpressionTransformer = class {
1841
2107
  };
1842
2108
  }
1843
2109
  } else {
1844
- (0, import_tiny_invariant5.default)(i === expr2.members.length - 1, "plain field access must be the last segment");
1845
- (0, import_tiny_invariant5.default)(!currNode, "plain field access must be the last segment");
2110
+ (0, import_common_helpers5.invariant)(i === expr2.members.length - 1, "plain field access must be the last segment");
2111
+ (0, import_common_helpers5.invariant)(!currNode, "plain field access must be the last segment");
1846
2112
  currNode = import_kysely6.ColumnNode.create(member);
1847
2113
  }
1848
2114
  }
@@ -1994,7 +2260,7 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
1994
2260
  get kysely() {
1995
2261
  return this.client.$qb;
1996
2262
  }
1997
- async handle(node, proceed, transaction) {
2263
+ async handle(node, proceed) {
1998
2264
  if (!this.isCrudQueryNode(node)) {
1999
2265
  throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
2000
2266
  }
@@ -2014,27 +2280,20 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2014
2280
  if (!mutationRequiresTransaction && !node.returning) {
2015
2281
  return proceed(this.transformNode(node));
2016
2282
  }
2017
- let readBackError = false;
2018
- const result = await transaction(async (txProceed) => {
2019
- if (import_kysely7.InsertQueryNode.is(node)) {
2020
- await this.enforcePreCreatePolicy(node, txProceed);
2021
- }
2022
- const transformedNode = this.transformNode(node);
2023
- const result2 = await txProceed(transformedNode);
2024
- if (!this.onlyReturningId(node)) {
2025
- const readBackResult = await this.processReadBack(node, result2, txProceed);
2026
- if (readBackResult.rows.length !== result2.rows.length) {
2027
- readBackError = true;
2028
- }
2029
- return readBackResult;
2030
- } else {
2031
- return result2;
2283
+ if (import_kysely7.InsertQueryNode.is(node)) {
2284
+ await this.enforcePreCreatePolicy(node, proceed);
2285
+ }
2286
+ const transformedNode = this.transformNode(node);
2287
+ const result = await proceed(transformedNode);
2288
+ if (!this.onlyReturningId(node)) {
2289
+ const readBackResult = await this.processReadBack(node, result, proceed);
2290
+ if (readBackResult.rows.length !== result.rows.length) {
2291
+ throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2032
2292
  }
2033
- });
2034
- if (readBackError) {
2035
- throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2293
+ return readBackResult;
2294
+ } else {
2295
+ return result;
2036
2296
  }
2037
- return result;
2038
2297
  }
2039
2298
  onlyReturningId(node) {
2040
2299
  if (!node.returning) {
@@ -2087,19 +2346,19 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2087
2346
  }
2088
2347
  }
2089
2348
  unwrapCreateValueRow(data, model, fields) {
2090
- (0, import_tiny_invariant6.default)(data.length === fields.length, "data length must match fields length");
2349
+ (0, import_common_helpers6.invariant)(data.length === fields.length, "data length must match fields length");
2091
2350
  const result = [];
2092
2351
  for (let i = 0; i < data.length; i++) {
2093
2352
  const item = data[i];
2094
2353
  const fieldDef = requireField(this.client.$schema, model, fields[i]);
2095
2354
  if (typeof item === "object" && item && "kind" in item) {
2096
- (0, import_tiny_invariant6.default)(item.kind === "ValueNode", "expecting a ValueNode");
2355
+ (0, import_common_helpers6.invariant)(item.kind === "ValueNode", "expecting a ValueNode");
2097
2356
  result.push({
2098
- node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
2357
+ node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
2099
2358
  raw: item.value
2100
2359
  });
2101
2360
  } else {
2102
- const value = this.dialect.transformPrimitive(item, fieldDef.type);
2361
+ const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
2103
2362
  if (Array.isArray(value)) {
2104
2363
  result.push({
2105
2364
  node: import_kysely7.RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
@@ -2168,7 +2427,7 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2168
2427
  return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => import_kysely7.BinaryOperationNode.create(import_kysely7.ColumnNode.create(field), import_kysely7.OperatorNode.create("="), import_kysely7.ValueNode.create(row[field]))))));
2169
2428
  }
2170
2429
  getMutationModel(node) {
2171
- const r = (0, import_ts_pattern7.match)(node).when(import_kysely7.InsertQueryNode.is, (node2) => getTableName(node2.into)).when(import_kysely7.UpdateQueryNode.is, (node2) => getTableName(node2.table)).when(import_kysely7.DeleteQueryNode.is, (node2) => {
2430
+ const r = (0, import_ts_pattern8.match)(node).when(import_kysely7.InsertQueryNode.is, (node2) => getTableName(node2.into)).when(import_kysely7.UpdateQueryNode.is, (node2) => getTableName(node2.table)).when(import_kysely7.DeleteQueryNode.is, (node2) => {
2172
2431
  if (node2.from.froms.length !== 1) {
2173
2432
  throw new InternalError("Only one from table is supported for delete");
2174
2433
  }
@@ -2301,8 +2560,8 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2301
2560
  const modelDef = requireModel(this.client.$schema, modelName);
2302
2561
  const result = [];
2303
2562
  const extractOperations = /* @__PURE__ */ __name((expr2) => {
2304
- (0, import_tiny_invariant6.default)(ExpressionUtils.isLiteral(expr2), "expecting a literal");
2305
- (0, import_tiny_invariant6.default)(typeof expr2.value === "string", "expecting a string literal");
2563
+ (0, import_common_helpers6.invariant)(ExpressionUtils.isLiteral(expr2), "expecting a literal");
2564
+ (0, import_common_helpers6.invariant)(typeof expr2.value === "string", "expecting a string literal");
2306
2565
  return expr2.value.split(",").filter((v) => !!v).map((v) => v.trim());
2307
2566
  }, "extractOperations");
2308
2567
  if (modelDef.attributes) {
@@ -2330,9 +2589,18 @@ var PolicyPlugin = class {
2330
2589
  get description() {
2331
2590
  return "Enforces access policies defined in the schema.";
2332
2591
  }
2333
- onKyselyQuery({ query, client, proceed, transaction }) {
2592
+ onKyselyQuery({
2593
+ query,
2594
+ client,
2595
+ proceed
2596
+ /*, transaction*/
2597
+ }) {
2334
2598
  const handler = new PolicyHandler(client);
2335
- return handler.handle(query, proceed, transaction);
2599
+ return handler.handle(
2600
+ query,
2601
+ proceed
2602
+ /*, transaction*/
2603
+ );
2336
2604
  }
2337
2605
  };
2338
2606
  // Annotate the CommonJS export names for ESM import in node:
@@ -2340,4 +2608,4 @@ var PolicyPlugin = class {
2340
2608
  PolicyPlugin,
2341
2609
  RejectedByPolicyError
2342
2610
  });
2343
- //# sourceMappingURL=policy.cjs.map
2611
+ //# sourceMappingURL=index.cjs.map