@zenstackhq/runtime 3.0.0-alpha.8 → 3.0.0-beta.1

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.
@@ -41,32 +41,131 @@ var RejectedByPolicyError = class extends Error {
41
41
  // src/plugins/policy/policy-handler.ts
42
42
  var import_common_helpers6 = require("@zenstackhq/common-helpers");
43
43
  var import_kysely7 = require("kysely");
44
- var import_ts_pattern7 = require("ts-pattern");
44
+ var import_ts_pattern8 = require("ts-pattern");
45
45
 
46
46
  // src/client/crud/dialects/index.ts
47
- var import_ts_pattern4 = require("ts-pattern");
47
+ var import_ts_pattern5 = require("ts-pattern");
48
48
 
49
49
  // src/client/crud/dialects/postgresql.ts
50
50
  var import_common_helpers2 = require("@zenstackhq/common-helpers");
51
51
  var import_kysely2 = require("kysely");
52
- 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
+ getLiteralValue: /* @__PURE__ */ __name((expr2) => {
150
+ return ExpressionUtils.isLiteral(expr2) ? expr2.value : void 0;
151
+ }, "getLiteralValue")
152
+ };
53
153
 
54
154
  // src/client/errors.ts
55
155
  var QueryError = class extends Error {
56
156
  static {
57
157
  __name(this, "QueryError");
58
158
  }
59
- constructor(message) {
60
- super(message);
159
+ constructor(message, cause) {
160
+ super(message, {
161
+ cause
162
+ });
61
163
  }
62
164
  };
63
165
  var InternalError = class extends Error {
64
166
  static {
65
167
  __name(this, "InternalError");
66
168
  }
67
- constructor(message) {
68
- super(message);
69
- }
70
169
  };
71
170
 
72
171
  // src/client/query-utils.ts
@@ -77,7 +176,7 @@ __name(getModel, "getModel");
77
176
  function requireModel(schema, model) {
78
177
  const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
79
178
  if (!matchedName) {
80
- throw new QueryError(`Model "${model}" not found`);
179
+ throw new QueryError(`Model "${model}" not found in schema`);
81
180
  }
82
181
  return schema.models[matchedName];
83
182
  }
@@ -140,6 +239,16 @@ function getRelationForeignKeyFieldPairs(schema, model, relationField) {
140
239
  }
141
240
  }
142
241
  __name(getRelationForeignKeyFieldPairs, "getRelationForeignKeyFieldPairs");
242
+ function isRelationField(schema, model, field) {
243
+ const fieldDef = getField(schema, model, field);
244
+ return !!fieldDef?.relation;
245
+ }
246
+ __name(isRelationField, "isRelationField");
247
+ function isInheritedField(schema, model, field) {
248
+ const fieldDef = getField(schema, model, field);
249
+ return !!fieldDef?.originModel;
250
+ }
251
+ __name(isInheritedField, "isInheritedField");
143
252
  function getUniqueFields(schema, model) {
144
253
  const modelDef = requireModel(schema, model);
145
254
  const result = [];
@@ -165,20 +274,25 @@ function getUniqueFields(schema, model) {
165
274
  return result;
166
275
  }
167
276
  __name(getUniqueFields, "getUniqueFields");
168
- function buildFieldRef(schema, model, field, options, eb, modelAlias) {
277
+ function buildFieldRef(schema, model, field, options, eb, modelAlias, inlineComputedField = true) {
169
278
  const fieldDef = requireField(schema, model, field);
170
279
  if (!fieldDef.computed) {
171
280
  return eb.ref(modelAlias ? `${modelAlias}.${field}` : field);
172
281
  } else {
282
+ if (!inlineComputedField) {
283
+ return eb.ref(modelAlias ? `${modelAlias}.${field}` : field);
284
+ }
173
285
  let computer;
174
286
  if ("computedFields" in options) {
175
287
  const computedFields = options.computedFields;
176
288
  computer = computedFields?.[model]?.[field];
177
289
  }
178
290
  if (!computer) {
179
- throw new QueryError(`Computed field "${field}" implementation not provided`);
291
+ throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
180
292
  }
181
- return computer(eb);
293
+ return computer(eb, {
294
+ currentModel: modelAlias
295
+ });
182
296
  }
183
297
  }
184
298
  __name(buildFieldRef, "buildFieldRef");
@@ -221,11 +335,33 @@ function getManyToManyRelation(schema, model, field) {
221
335
  model,
222
336
  fieldDef.type
223
337
  ].sort();
338
+ let orderedFK;
339
+ if (model !== fieldDef.type) {
340
+ orderedFK = sortedModelNames[0] === model ? [
341
+ "A",
342
+ "B"
343
+ ] : [
344
+ "B",
345
+ "A"
346
+ ];
347
+ } else {
348
+ const sortedFieldNames = [
349
+ field,
350
+ oppositeFieldDef.name
351
+ ].sort();
352
+ orderedFK = sortedFieldNames[0] === field ? [
353
+ "A",
354
+ "B"
355
+ ] : [
356
+ "B",
357
+ "A"
358
+ ];
359
+ }
224
360
  return {
225
- parentFkName: sortedModelNames[0] === model ? "A" : "B",
361
+ parentFkName: orderedFK[0],
226
362
  otherModel: fieldDef.type,
227
363
  otherField: fieldDef.relation.opposite,
228
- otherFkName: sortedModelNames[0] === fieldDef.type ? "A" : "B",
364
+ otherFkName: orderedFK[1],
229
365
  joinTable: fieldDef.relation.name ? `_${fieldDef.relation.name}` : `_${sortedModelNames[0]}To${sortedModelNames[1]}`
230
366
  };
231
367
  } else {
@@ -253,11 +389,38 @@ function flattenCompoundUniqueFilters(schema, model, filter) {
253
389
  return result;
254
390
  }
255
391
  __name(flattenCompoundUniqueFilters, "flattenCompoundUniqueFilters");
392
+ function ensureArray(value) {
393
+ if (Array.isArray(value)) {
394
+ return value;
395
+ } else {
396
+ return [
397
+ value
398
+ ];
399
+ }
400
+ }
401
+ __name(ensureArray, "ensureArray");
402
+ function getDelegateDescendantModels(schema, model, collected = /* @__PURE__ */ new Set()) {
403
+ const subModels = Object.values(schema.models).filter((m) => m.baseModel === model);
404
+ subModels.forEach((def) => {
405
+ if (!collected.has(def)) {
406
+ collected.add(def);
407
+ getDelegateDescendantModels(schema, def.name, collected);
408
+ }
409
+ });
410
+ return [
411
+ ...collected
412
+ ];
413
+ }
414
+ __name(getDelegateDescendantModels, "getDelegateDescendantModels");
415
+ function aggregate(eb, expr2, op) {
416
+ 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();
417
+ }
418
+ __name(aggregate, "aggregate");
256
419
 
257
420
  // src/client/crud/dialects/base.ts
258
421
  var import_common_helpers = require("@zenstackhq/common-helpers");
259
422
  var import_kysely = require("kysely");
260
- var import_ts_pattern = require("ts-pattern");
423
+ var import_ts_pattern2 = require("ts-pattern");
261
424
 
262
425
  // src/utils/enumerate.ts
263
426
  function enumerate(x) {
@@ -284,9 +447,47 @@ var BaseCrudDialect = class {
284
447
  this.schema = schema;
285
448
  this.options = options;
286
449
  }
287
- transformPrimitive(value, _type) {
450
+ transformPrimitive(value, _type, _forArrayField) {
288
451
  return value;
289
452
  }
453
+ // #region common query builders
454
+ buildSelectModel(eb, model, modelAlias) {
455
+ const modelDef = requireModel(this.schema, model);
456
+ let result = eb.selectFrom(model === modelAlias ? model : `${model} as ${modelAlias}`);
457
+ let joinBase = modelDef.baseModel;
458
+ while (joinBase) {
459
+ result = this.buildDelegateJoin(model, modelAlias, joinBase, result);
460
+ joinBase = requireModel(this.schema, joinBase).baseModel;
461
+ }
462
+ return result;
463
+ }
464
+ buildFilterSortTake(model, args, query, modelAlias) {
465
+ let result = query;
466
+ if (args.where) {
467
+ result = result.where((eb) => this.buildFilter(eb, model, modelAlias, args?.where));
468
+ }
469
+ let negateOrderBy = false;
470
+ const skip = args.skip;
471
+ let take = args.take;
472
+ if (take !== void 0 && take < 0) {
473
+ negateOrderBy = true;
474
+ take = -take;
475
+ }
476
+ result = this.buildSkipTake(result, skip, take);
477
+ result = this.buildOrderBy(result, model, modelAlias, args.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
478
+ if ("distinct" in args && args.distinct) {
479
+ const distinct = ensureArray(args.distinct);
480
+ if (this.supportsDistinctOn) {
481
+ result = result.distinctOn(distinct.map((f) => import_kysely.sql.ref(`${modelAlias}.${f}`)));
482
+ } else {
483
+ throw new QueryError(`"distinct" is not supported by "${this.schema.provider.type}" provider`);
484
+ }
485
+ }
486
+ if (args.cursor) {
487
+ result = this.buildCursorFilter(model, result, args.cursor, args.orderBy, negateOrderBy, modelAlias);
488
+ }
489
+ return result;
490
+ }
290
491
  buildFilter(eb, model, modelAlias, where) {
291
492
  if (where === true || where === void 0) {
292
493
  return this.true(eb);
@@ -303,17 +504,20 @@ var BaseCrudDialect = class {
303
504
  if (key.startsWith("$")) {
304
505
  continue;
305
506
  }
306
- if (key === "AND" || key === "OR" || key === "NOT") {
507
+ if (this.isLogicalCombinator(key)) {
307
508
  result = this.and(eb, result, this.buildCompositeFilter(eb, model, modelAlias, key, payload));
308
509
  continue;
309
510
  }
310
511
  const fieldDef = requireField(this.schema, model, key);
311
512
  if (fieldDef.relation) {
312
513
  result = this.and(eb, result, this.buildRelationFilter(eb, model, modelAlias, key, fieldDef, payload));
313
- } else if (fieldDef.array) {
314
- result = this.and(eb, result, this.buildArrayFilter(eb, model, modelAlias, key, fieldDef, payload));
315
514
  } else {
316
- result = this.and(eb, result, this.buildPrimitiveFilter(eb, model, modelAlias, key, fieldDef, payload));
515
+ const fieldRef = this.fieldRef(fieldDef.originModel ?? model, key, eb, fieldDef.originModel ?? modelAlias);
516
+ if (fieldDef.array) {
517
+ result = this.and(eb, result, this.buildArrayFilter(eb, fieldRef, fieldDef, payload));
518
+ } else {
519
+ result = this.and(eb, result, this.buildPrimitiveFilter(eb, fieldRef, fieldDef, payload));
520
+ }
317
521
  }
318
522
  }
319
523
  if ("$expr" in _where && typeof _where["$expr"] === "function") {
@@ -321,8 +525,32 @@ var BaseCrudDialect = class {
321
525
  }
322
526
  return result;
323
527
  }
528
+ buildCursorFilter(model, query, cursor, orderBy, negateOrderBy, modelAlias) {
529
+ const _orderBy = orderBy ?? makeDefaultOrderBy(this.schema, model);
530
+ const orderByItems = ensureArray(_orderBy).flatMap((obj) => Object.entries(obj));
531
+ const eb = (0, import_kysely.expressionBuilder)();
532
+ const subQueryAlias = `${model}$cursor$sub`;
533
+ const cursorFilter = this.buildFilter(eb, model, subQueryAlias, cursor);
534
+ let result = query;
535
+ const filters = [];
536
+ for (let i = orderByItems.length - 1; i >= 0; i--) {
537
+ const andFilters = [];
538
+ for (let j = 0; j <= i; j++) {
539
+ const [field, order] = orderByItems[j];
540
+ const _order = negateOrderBy ? order === "asc" ? "desc" : "asc" : order;
541
+ const op = j === i ? _order === "asc" ? ">=" : "<=" : "=";
542
+ andFilters.push(eb(eb.ref(`${modelAlias}.${field}`), op, this.buildSelectModel(eb, model, subQueryAlias).select(`${subQueryAlias}.${field}`).where(cursorFilter)));
543
+ }
544
+ filters.push(eb.and(andFilters));
545
+ }
546
+ result = result.where((eb2) => eb2.or(filters));
547
+ return result;
548
+ }
549
+ isLogicalCombinator(key) {
550
+ return LOGICAL_COMBINATORS.includes(key);
551
+ }
324
552
  buildCompositeFilter(eb, model, modelAlias, key, payload) {
325
- 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();
553
+ 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();
326
554
  }
327
555
  buildRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
328
556
  if (!fieldDef.array) {
@@ -331,19 +559,26 @@ var BaseCrudDialect = class {
331
559
  return this.buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload);
332
560
  }
333
561
  }
334
- buildToOneRelationFilter(eb, model, table, field, fieldDef, payload) {
562
+ buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
335
563
  if (payload === null) {
336
564
  const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, model, field);
337
- if (ownedByModel) {
338
- return this.and(eb, ...keyPairs.map(({ fk }) => eb(import_kysely.sql.ref(`${table}.${fk}`), "is", null)));
565
+ if (ownedByModel && !fieldDef.originModel) {
566
+ return this.and(eb, ...keyPairs.map(({ fk }) => eb(import_kysely.sql.ref(`${modelAlias}.${fk}`), "is", null)));
339
567
  } else {
340
- return this.buildToOneRelationFilter(eb, model, table, field, fieldDef, {
568
+ return this.buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, {
341
569
  is: null
342
570
  });
343
571
  }
344
572
  }
345
- const joinAlias = `${table}$${field}`;
346
- const joinPairs = buildJoinPairs(this.schema, model, table, field, joinAlias);
573
+ const joinAlias = `${modelAlias}$${field}`;
574
+ const joinPairs = buildJoinPairs(
575
+ this.schema,
576
+ model,
577
+ // if field is from a base, use the base model to join
578
+ fieldDef.originModel ?? modelAlias,
579
+ field,
580
+ joinAlias
581
+ );
347
582
  const filterResultField = `${field}$filter`;
348
583
  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));
349
584
  const conditions = [];
@@ -373,25 +608,26 @@ var BaseCrudDialect = class {
373
608
  }
374
609
  return this.and(eb, ...conditions);
375
610
  }
376
- buildToManyRelationFilter(eb, model, table, field, fieldDef, payload) {
611
+ buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
377
612
  if (payload === null) {
378
- return eb(import_kysely.sql.ref(`${table}.${field}`), "is", null);
613
+ return eb(import_kysely.sql.ref(`${modelAlias}.${field}`), "is", null);
379
614
  }
380
615
  const relationModel = fieldDef.type;
616
+ const relationFilterSelectAlias = `${modelAlias}$${field}$filter`;
381
617
  const buildPkFkWhereRefs = /* @__PURE__ */ __name((eb2) => {
382
618
  const m2m = getManyToManyRelation(this.schema, model, field);
383
619
  if (m2m) {
384
620
  const modelIdField = getIdFields(this.schema, model)[0];
385
621
  const relationIdField = getIdFields(this.schema, relationModel)[0];
386
- 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}`)));
622
+ 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}`)));
387
623
  } else {
388
624
  const relationKeyPairs = getRelationForeignKeyFieldPairs(this.schema, model, field);
389
625
  let result2 = this.true(eb2);
390
626
  for (const { fk, pk } of relationKeyPairs.keyPairs) {
391
627
  if (relationKeyPairs.ownedByModel) {
392
- result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${table}.${fk}`), "=", import_kysely.sql.ref(`${relationModel}.${pk}`)));
628
+ result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${modelAlias}.${fk}`), "=", import_kysely.sql.ref(`${relationFilterSelectAlias}.${pk}`)));
393
629
  } else {
394
- result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${table}.${pk}`), "=", import_kysely.sql.ref(`${relationModel}.${fk}`)));
630
+ result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${modelAlias}.${pk}`), "=", import_kysely.sql.ref(`${relationFilterSelectAlias}.${fk}`)));
395
631
  }
396
632
  }
397
633
  return result2;
@@ -404,30 +640,29 @@ var BaseCrudDialect = class {
404
640
  }
405
641
  switch (key) {
406
642
  case "some": {
407
- 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));
643
+ 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));
408
644
  break;
409
645
  }
410
646
  case "every": {
411
- 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));
647
+ 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));
412
648
  break;
413
649
  }
414
650
  case "none": {
415
- 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));
651
+ 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));
416
652
  break;
417
653
  }
418
654
  }
419
655
  }
420
656
  return result;
421
657
  }
422
- buildArrayFilter(eb, model, modelAlias, field, fieldDef, payload) {
658
+ buildArrayFilter(eb, fieldRef, fieldDef, payload) {
423
659
  const clauses = [];
424
660
  const fieldType = fieldDef.type;
425
- const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb, modelAlias);
426
661
  for (const [key, _value] of Object.entries(payload)) {
427
662
  if (_value === void 0) {
428
663
  continue;
429
664
  }
430
- const value = this.transformPrimitive(_value, fieldType);
665
+ const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
431
666
  switch (key) {
432
667
  case "equals": {
433
668
  clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
@@ -458,19 +693,23 @@ var BaseCrudDialect = class {
458
693
  }
459
694
  return this.and(eb, ...clauses);
460
695
  }
461
- buildPrimitiveFilter(eb, model, modelAlias, field, fieldDef, payload) {
696
+ buildPrimitiveFilter(eb, fieldRef, fieldDef, payload) {
462
697
  if (payload === null) {
463
- return eb(import_kysely.sql.ref(`${modelAlias}.${field}`), "is", null);
698
+ return eb(fieldRef, "is", null);
464
699
  }
465
700
  if (isEnum(this.schema, fieldDef.type)) {
466
- return this.buildEnumFilter(eb, modelAlias, field, fieldDef, payload);
701
+ return this.buildEnumFilter(eb, fieldRef, fieldDef, payload);
467
702
  }
468
- 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();
703
+ 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", () => {
704
+ throw new InternalError("JSON filters are not supported yet");
705
+ }).with("Unsupported", () => {
706
+ throw new QueryError(`Unsupported field cannot be used in filters`);
707
+ }).exhaustive();
469
708
  }
470
709
  buildLiteralFilter(eb, lhs, type, rhs) {
471
- return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type) : rhs);
710
+ return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
472
711
  }
473
- buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
712
+ buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0, excludeKeys = []) {
474
713
  if (payload === null || !(0, import_common_helpers.isPlainObject)(payload)) {
475
714
  return {
476
715
  conditions: [
@@ -485,8 +724,11 @@ var BaseCrudDialect = class {
485
724
  if (onlyForKeys && !onlyForKeys.includes(op)) {
486
725
  continue;
487
726
  }
727
+ if (excludeKeys.includes(op)) {
728
+ continue;
729
+ }
488
730
  const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
489
- const condition = (0, import_ts_pattern.match)(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
731
+ const condition = (0, import_ts_pattern2.match)(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
490
732
  (0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
491
733
  if (rhs.length === 0) {
492
734
  return this.false(eb);
@@ -500,7 +742,11 @@ var BaseCrudDialect = class {
500
742
  } else {
501
743
  return eb.not(eb(lhs, "in", rhs));
502
744
  }
503
- }).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(() => {
745
+ }).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) => {
746
+ const innerResult = this.buildStandardFilter(eb, type, value, aggregate(eb, lhs, op2), getRhs, recurse, throwIfInvalid);
747
+ consumedKeys.push(...innerResult.consumedKeys);
748
+ return this.and(eb, ...innerResult.conditions);
749
+ }).otherwise(() => {
504
750
  if (throwIfInvalid) {
505
751
  throw new QueryError(`Invalid filter key: ${op}`);
506
752
  } else {
@@ -517,24 +763,21 @@ var BaseCrudDialect = class {
517
763
  consumedKeys
518
764
  };
519
765
  }
520
- buildStringFilter(eb, table, field, payload) {
521
- const fieldDef = getField(this.schema, table, field);
522
- let fieldRef = fieldDef?.computed ? import_kysely.sql.ref(field) : import_kysely.sql.ref(`${table}.${field}`);
523
- let insensitive = false;
524
- if (payload && typeof payload === "object" && "mode" in payload && payload.mode === "insensitive") {
525
- insensitive = true;
526
- fieldRef = eb.fn("lower", [
527
- fieldRef
528
- ]);
766
+ buildStringFilter(eb, fieldRef, payload) {
767
+ let mode;
768
+ if (payload && typeof payload === "object" && "mode" in payload) {
769
+ mode = payload.mode;
529
770
  }
530
- const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => this.prepStringCasing(eb, value, insensitive), (value) => this.buildStringFilter(eb, table, field, value));
771
+ const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, mode === "insensitive" ? eb.fn("lower", [
772
+ fieldRef
773
+ ]) : fieldRef, (value) => this.prepStringCasing(eb, value, mode), (value) => this.buildStringFilter(eb, fieldRef, value));
531
774
  if (payload && typeof payload === "object") {
532
775
  for (const [key, value] of Object.entries(payload)) {
533
776
  if (key === "mode" || consumedKeys.includes(key)) {
534
777
  continue;
535
778
  }
536
- 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(() => {
537
- throw new Error(`Invalid string filter key: ${key}`);
779
+ 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(() => {
780
+ throw new QueryError(`Invalid string filter key: ${key}`);
538
781
  });
539
782
  if (condition) {
540
783
  conditions.push(condition);
@@ -543,34 +786,37 @@ var BaseCrudDialect = class {
543
786
  }
544
787
  return this.and(eb, ...conditions);
545
788
  }
546
- prepStringCasing(eb, value, toLower = true) {
789
+ prepStringCasing(eb, value, mode) {
790
+ if (!mode || mode === "default") {
791
+ return value === null ? value : import_kysely.sql.val(value);
792
+ }
547
793
  if (typeof value === "string") {
548
- return toLower ? eb.fn("lower", [
549
- import_kysely.sql.lit(value)
550
- ]) : import_kysely.sql.lit(value);
794
+ return eb.fn("lower", [
795
+ import_kysely.sql.val(value)
796
+ ]);
551
797
  } else if (Array.isArray(value)) {
552
- return value.map((v) => this.prepStringCasing(eb, v, toLower));
798
+ return value.map((v) => this.prepStringCasing(eb, v, mode));
553
799
  } else {
554
- return value === null ? null : import_kysely.sql.lit(value);
800
+ return value === null ? null : import_kysely.sql.val(value);
555
801
  }
556
802
  }
557
- buildNumberFilter(eb, model, table, field, type, payload) {
558
- 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));
803
+ buildNumberFilter(eb, fieldRef, type, payload) {
804
+ const { conditions } = this.buildStandardFilter(eb, type, payload, fieldRef, (value) => this.transformPrimitive(value, type, false), (value) => this.buildNumberFilter(eb, fieldRef, type, value));
559
805
  return this.and(eb, ...conditions);
560
806
  }
561
- buildBooleanFilter(eb, table, field, payload) {
562
- 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, [
807
+ buildBooleanFilter(eb, fieldRef, payload) {
808
+ const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, fieldRef, (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, fieldRef, value), true, [
563
809
  "equals",
564
810
  "not"
565
811
  ]);
566
812
  return this.and(eb, ...conditions);
567
813
  }
568
- buildDateTimeFilter(eb, table, field, payload) {
569
- 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);
814
+ buildDateTimeFilter(eb, fieldRef, payload) {
815
+ const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, fieldRef, (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, fieldRef, value), true);
570
816
  return this.and(eb, ...conditions);
571
817
  }
572
- buildBytesFilter(eb, table, field, payload) {
573
- 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, [
818
+ buildBytesFilter(eb, fieldRef, payload) {
819
+ const conditions = this.buildStandardFilter(eb, "Bytes", payload, fieldRef, (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, fieldRef, value), true, [
574
820
  "equals",
575
821
  "in",
576
822
  "notIn",
@@ -578,8 +824,8 @@ var BaseCrudDialect = class {
578
824
  ]);
579
825
  return this.and(eb, ...conditions.conditions);
580
826
  }
581
- buildEnumFilter(eb, table, field, fieldDef, payload) {
582
- const conditions = this.buildStandardFilter(eb, "String", payload, import_kysely.sql.ref(`${table}.${field}`), (value) => value, (value) => this.buildEnumFilter(eb, table, field, fieldDef, value), true, [
827
+ buildEnumFilter(eb, fieldRef, fieldDef, payload) {
828
+ const conditions = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => value, (value) => this.buildEnumFilter(eb, fieldRef, fieldDef, value), true, [
583
829
  "equals",
584
830
  "in",
585
831
  "notIn",
@@ -611,9 +857,7 @@ var BaseCrudDialect = class {
611
857
  (0, import_common_helpers.invariant)(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
612
858
  for (const [k, v] of Object.entries(value)) {
613
859
  (0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
614
- result = result.orderBy((eb) => eb.fn(field.slice(1), [
615
- import_kysely.sql.ref(k)
616
- ]), import_kysely.sql.raw(this.negateSort(v, negated)));
860
+ result = result.orderBy((eb) => aggregate(eb, this.fieldRef(model, k, eb, modelAlias), field), import_kysely.sql.raw(this.negateSort(v, negated)));
617
861
  }
618
862
  continue;
619
863
  }
@@ -622,7 +866,7 @@ var BaseCrudDialect = class {
622
866
  (0, import_common_helpers.invariant)(value && typeof value === "object", 'invalid orderBy value for field "_count"');
623
867
  for (const [k, v] of Object.entries(value)) {
624
868
  (0, import_common_helpers.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
625
- result = result.orderBy((eb) => eb.fn.count(import_kysely.sql.ref(k)), import_kysely.sql.raw(this.negateSort(v, negated)));
869
+ result = result.orderBy((eb) => eb.fn.count(this.fieldRef(model, k, eb, modelAlias)), import_kysely.sql.raw(this.negateSort(v, negated)));
626
870
  }
627
871
  continue;
628
872
  }
@@ -631,10 +875,11 @@ var BaseCrudDialect = class {
631
875
  }
632
876
  const fieldDef = requireField(this.schema, model, field);
633
877
  if (!fieldDef.relation) {
878
+ const fieldRef = this.fieldRef(model, field, (0, import_kysely.expressionBuilder)(), modelAlias);
634
879
  if (value === "asc" || value === "desc") {
635
- result = result.orderBy(import_kysely.sql.ref(`${modelAlias}.${field}`), this.negateSort(value, negated));
880
+ result = result.orderBy(fieldRef, this.negateSort(value, negated));
636
881
  } else if (value && typeof value === "object" && "nulls" in value && "sort" in value && (value.sort === "asc" || value.sort === "desc") && (value.nulls === "first" || value.nulls === "last")) {
637
- result = result.orderBy(import_kysely.sql.ref(`${modelAlias}.${field}`), import_kysely.sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`));
882
+ result = result.orderBy(fieldRef, import_kysely.sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`));
638
883
  }
639
884
  } else {
640
885
  const relationModel = fieldDef.type;
@@ -646,8 +891,9 @@ var BaseCrudDialect = class {
646
891
  (0, import_common_helpers.invariant)(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
647
892
  const sort = this.negateSort(value._count, negated);
648
893
  result = result.orderBy((eb) => {
649
- let subQuery = eb.selectFrom(relationModel);
650
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, relationModel);
894
+ const subQueryAlias = `${modelAlias}$orderBy$${field}$count`;
895
+ let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
896
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
651
897
  subQuery = subQuery.where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely.sql.ref(left), "=", import_kysely.sql.ref(right)))));
652
898
  subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
653
899
  return subQuery;
@@ -665,14 +911,100 @@ var BaseCrudDialect = class {
665
911
  });
666
912
  return result;
667
913
  }
914
+ buildSelectAllFields(model, query, omit, modelAlias) {
915
+ const modelDef = requireModel(this.schema, model);
916
+ let result = query;
917
+ for (const field of Object.keys(modelDef.fields)) {
918
+ if (isRelationField(this.schema, model, field)) {
919
+ continue;
920
+ }
921
+ if (omit?.[field] === true) {
922
+ continue;
923
+ }
924
+ result = this.buildSelectField(result, model, modelAlias, field);
925
+ }
926
+ const descendants = getDelegateDescendantModels(this.schema, model);
927
+ for (const subModel of descendants) {
928
+ result = this.buildDelegateJoin(model, modelAlias, subModel.name, result);
929
+ result = result.select((eb) => {
930
+ const jsonObject = {};
931
+ for (const field of Object.keys(subModel.fields)) {
932
+ if (isRelationField(this.schema, subModel.name, field) || isInheritedField(this.schema, subModel.name, field)) {
933
+ continue;
934
+ }
935
+ jsonObject[field] = eb.ref(`${subModel.name}.${field}`);
936
+ }
937
+ return this.buildJsonObject(eb, jsonObject).as(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`);
938
+ });
939
+ }
940
+ return result;
941
+ }
942
+ buildModelSelect(eb, model, subQueryAlias, payload, selectAllFields) {
943
+ let subQuery = this.buildSelectModel(eb, model, subQueryAlias);
944
+ if (selectAllFields) {
945
+ subQuery = this.buildSelectAllFields(model, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
946
+ }
947
+ if (payload && typeof payload === "object") {
948
+ subQuery = this.buildFilterSortTake(model, payload, subQuery, subQueryAlias);
949
+ }
950
+ return subQuery;
951
+ }
952
+ buildSelectField(query, model, modelAlias, field) {
953
+ const fieldDef = requireField(this.schema, model, field);
954
+ if (fieldDef.computed) {
955
+ return query.select((eb) => this.fieldRef(model, field, eb, modelAlias).as(field));
956
+ } else if (!fieldDef.originModel) {
957
+ return query.select(import_kysely.sql.ref(`${modelAlias}.${field}`).as(field));
958
+ } else {
959
+ return this.buildSelectField(query, fieldDef.originModel, fieldDef.originModel, field);
960
+ }
961
+ }
962
+ buildDelegateJoin(thisModel, thisModelAlias, otherModelAlias, query) {
963
+ const idFields = getIdFields(this.schema, thisModel);
964
+ query = query.leftJoin(otherModelAlias, (qb) => {
965
+ for (const idField of idFields) {
966
+ qb = qb.onRef(`${thisModelAlias}.${idField}`, "=", `${otherModelAlias}.${idField}`);
967
+ }
968
+ return qb;
969
+ });
970
+ return query;
971
+ }
972
+ buildCountJson(model, eb, parentAlias, payload) {
973
+ const modelDef = requireModel(this.schema, model);
974
+ const toManyRelations = Object.entries(modelDef.fields).filter(([, field]) => field.relation && field.array);
975
+ const selections = payload === true ? {
976
+ select: toManyRelations.reduce((acc, [field]) => {
977
+ acc[field] = true;
978
+ return acc;
979
+ }, {})
980
+ } : payload;
981
+ const jsonObject = {};
982
+ for (const [field, value] of Object.entries(selections.select)) {
983
+ const fieldDef = requireField(this.schema, model, field);
984
+ const fieldModel = fieldDef.type;
985
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
986
+ let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
987
+ for (const [left, right] of joinPairs) {
988
+ fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
989
+ }
990
+ if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
991
+ const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
992
+ fieldCountQuery = fieldCountQuery.where(filter);
993
+ }
994
+ jsonObject[field] = fieldCountQuery;
995
+ }
996
+ return this.buildJsonObject(eb, jsonObject);
997
+ }
998
+ // #endregion
999
+ // #region utils
668
1000
  negateSort(sort, negated) {
669
1001
  return negated ? sort === "asc" ? "desc" : "asc" : sort;
670
1002
  }
671
1003
  true(eb) {
672
- return eb.lit(this.transformPrimitive(true, "Boolean"));
1004
+ return eb.lit(this.transformPrimitive(true, "Boolean", false));
673
1005
  }
674
1006
  false(eb) {
675
- return eb.lit(this.transformPrimitive(false, "Boolean"));
1007
+ return eb.lit(this.transformPrimitive(false, "Boolean", false));
676
1008
  }
677
1009
  isTrue(expression) {
678
1010
  const node = expression.toOperationNode();
@@ -711,6 +1043,21 @@ var BaseCrudDialect = class {
711
1043
  not(eb, ...args) {
712
1044
  return eb.not(this.and(eb, ...args));
713
1045
  }
1046
+ fieldRef(model, field, eb, modelAlias, inlineComputedField = true) {
1047
+ return buildFieldRef(this.schema, model, field, this.options, eb, modelAlias, inlineComputedField);
1048
+ }
1049
+ canJoinWithoutNestedSelect(modelDef, payload) {
1050
+ if (modelDef.computedFields) {
1051
+ return false;
1052
+ }
1053
+ if (modelDef.baseModel || modelDef.isDelegate) {
1054
+ return false;
1055
+ }
1056
+ if (typeof payload === "object" && (payload.orderBy || payload.skip !== void 0 || payload.take !== void 0 || payload.cursor || payload.distinct)) {
1057
+ return false;
1058
+ }
1059
+ return true;
1060
+ }
714
1061
  };
715
1062
 
716
1063
  // src/client/crud/dialects/postgresql.ts
@@ -721,99 +1068,123 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
721
1068
  get provider() {
722
1069
  return "postgresql";
723
1070
  }
724
- transformPrimitive(value, type) {
1071
+ transformPrimitive(value, type, forArrayField) {
725
1072
  if (value === void 0) {
726
1073
  return value;
727
1074
  }
728
1075
  if (Array.isArray(value)) {
729
- return value.map((v) => this.transformPrimitive(v, type));
1076
+ if (type === "Json" && !forArrayField) {
1077
+ return JSON.stringify(value);
1078
+ } else {
1079
+ return value.map((v) => this.transformPrimitive(v, type, false));
1080
+ }
730
1081
  } else {
731
- return (0, import_ts_pattern2.match)(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).otherwise(() => value);
1082
+ 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);
732
1083
  }
733
1084
  }
734
1085
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
735
- const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload);
736
- return joinedQuery.select(`${parentAlias}$${relationField}.$j as ${relationField}`);
1086
+ const relationResultName = `${parentAlias}$${relationField}`;
1087
+ const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload, relationResultName);
1088
+ return joinedQuery.select(`${relationResultName}.$data as ${relationField}`);
737
1089
  }
738
- buildRelationJSON(model, qb, relationField, parentName, payload) {
1090
+ buildRelationJSON(model, qb, relationField, parentAlias, payload, resultName) {
739
1091
  const relationFieldDef = requireField(this.schema, model, relationField);
740
1092
  const relationModel = relationFieldDef.type;
741
1093
  return qb.leftJoinLateral((eb) => {
742
- const joinTableName = `${parentName}$${relationField}`;
743
- let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
744
- result = eb.selectFrom(() => {
745
- let subQuery = eb.selectFrom(`${relationModel}`).selectAll();
746
- if (payload && typeof payload === "object") {
747
- if (payload.where) {
748
- subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
749
- }
750
- const skip = payload.skip;
751
- let take = payload.take;
752
- let negateOrderBy = false;
753
- if (take !== void 0 && take < 0) {
754
- negateOrderBy = true;
755
- take = -take;
756
- }
757
- subQuery = this.buildSkipTake(subQuery, skip, take);
758
- subQuery = this.buildOrderBy(subQuery, relationModel, relationModel, payload.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
759
- }
760
- const m2m = getManyToManyRelation(this.schema, model, relationField);
761
- if (m2m) {
762
- const parentIds = getIdFields(this.schema, model);
763
- const relationIds = getIdFields(this.schema, relationModel);
764
- (0, import_common_helpers2.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
765
- (0, import_common_helpers2.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
766
- 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}`)));
767
- } else {
768
- const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, relationModel);
769
- subQuery = subQuery.where((eb2) => this.and(eb2, ...joinPairs.map(([left, right]) => eb2(import_kysely2.sql.ref(left), "=", import_kysely2.sql.ref(right)))));
770
- }
771
- return subQuery.as(joinTableName);
772
- });
773
- result = this.buildRelationObjectSelect(relationModel, relationField, relationFieldDef, result, payload, parentName);
774
- result = this.buildRelationJoins(relationModel, relationField, result, payload, parentName);
775
- return result.as(joinTableName);
1094
+ const relationSelectName = `${resultName}$sub`;
1095
+ const relationModelDef = requireModel(this.schema, relationModel);
1096
+ let tbl;
1097
+ if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1098
+ tbl = this.buildModelSelect(eb, relationModel, relationSelectName, payload, false);
1099
+ tbl = this.buildRelationJoinFilter(tbl, model, relationField, relationModel, relationSelectName, parentAlias);
1100
+ } else {
1101
+ tbl = eb.selectFrom(() => {
1102
+ let subQuery = this.buildModelSelect(eb, relationModel, `${relationSelectName}$t`, payload, true);
1103
+ subQuery = this.buildRelationJoinFilter(subQuery, model, relationField, relationModel, `${relationSelectName}$t`, parentAlias);
1104
+ return subQuery.as(relationSelectName);
1105
+ });
1106
+ }
1107
+ tbl = this.buildRelationObjectSelect(relationModel, relationSelectName, relationFieldDef, tbl, payload, resultName);
1108
+ tbl = this.buildRelationJoins(tbl, relationModel, relationSelectName, payload, resultName);
1109
+ return tbl.as(resultName);
776
1110
  }, (join) => join.onTrue());
777
1111
  }
778
- buildRelationObjectSelect(relationModel, relationField, relationFieldDef, qb, payload, parentName) {
1112
+ buildRelationJoinFilter(query, model, relationField, relationModel, relationModelAlias, parentAlias) {
1113
+ const m2m = getManyToManyRelation(this.schema, model, relationField);
1114
+ if (m2m) {
1115
+ const parentIds = getIdFields(this.schema, model);
1116
+ const relationIds = getIdFields(this.schema, relationModel);
1117
+ (0, import_common_helpers2.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1118
+ (0, import_common_helpers2.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1119
+ query = query.where((eb) => eb(eb.ref(`${relationModelAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1120
+ } else {
1121
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, relationField, relationModelAlias);
1122
+ query = query.where((eb) => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely2.sql.ref(left), "=", import_kysely2.sql.ref(right)))));
1123
+ }
1124
+ return query;
1125
+ }
1126
+ buildRelationObjectSelect(relationModel, relationModelAlias, relationFieldDef, qb, payload, parentResultName) {
779
1127
  qb = qb.select((eb) => {
780
- const objArgs = this.buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName);
1128
+ const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName);
781
1129
  if (relationFieldDef.array) {
782
- return eb.fn.coalesce(import_kysely2.sql`jsonb_agg(jsonb_build_object(${import_kysely2.sql.join(objArgs)}))`, import_kysely2.sql`'[]'::jsonb`).as("$j");
1130
+ return eb.fn.coalesce(import_kysely2.sql`jsonb_agg(jsonb_build_object(${import_kysely2.sql.join(objArgs)}))`, import_kysely2.sql`'[]'::jsonb`).as("$data");
783
1131
  } else {
784
- return import_kysely2.sql`jsonb_build_object(${import_kysely2.sql.join(objArgs)})`.as("$j");
1132
+ return import_kysely2.sql`jsonb_build_object(${import_kysely2.sql.join(objArgs)})`.as("$data");
785
1133
  }
786
1134
  });
787
1135
  return qb;
788
1136
  }
789
- buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName) {
1137
+ buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName) {
790
1138
  const relationModelDef = requireModel(this.schema, relationModel);
791
1139
  const objArgs = [];
1140
+ const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1141
+ if (descendantModels.length > 0) {
1142
+ objArgs.push(...descendantModels.map((subModel) => [
1143
+ import_kysely2.sql.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1144
+ eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1145
+ ]).flatMap((v) => v));
1146
+ }
792
1147
  if (payload === true || !payload.select) {
793
1148
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
794
1149
  import_kysely2.sql.lit(field),
795
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
1150
+ this.fieldRef(relationModel, field, eb, relationModelAlias, false)
796
1151
  ]).flatMap((v) => v));
797
1152
  } else if (payload.select) {
798
- objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => [
799
- import_kysely2.sql.lit(field),
800
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
801
- ]).flatMap((v) => v));
1153
+ objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1154
+ if (field === "_count") {
1155
+ const subJson = this.buildCountJson(relationModel, eb, relationModelAlias, value);
1156
+ return [
1157
+ import_kysely2.sql.lit(field),
1158
+ subJson
1159
+ ];
1160
+ } else {
1161
+ const fieldDef = requireField(this.schema, relationModel, field);
1162
+ const fieldValue = fieldDef.relation ? eb.ref(`${parentResultName}$${field}.$data`) : this.fieldRef(relationModel, field, eb, relationModelAlias, false);
1163
+ return [
1164
+ import_kysely2.sql.lit(field),
1165
+ fieldValue
1166
+ ];
1167
+ }
1168
+ }).flatMap((v) => v));
802
1169
  }
803
1170
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
804
1171
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
805
1172
  import_kysely2.sql.lit(field),
806
- eb.ref(`${parentName}$${relationField}$${field}.$j`)
1173
+ // reference the synthesized JSON field
1174
+ eb.ref(`${parentResultName}$${field}.$data`)
807
1175
  ]).flatMap((v) => v));
808
1176
  }
809
1177
  return objArgs;
810
1178
  }
811
- buildRelationJoins(model, relationField, qb, payload, parentName) {
812
- let result = qb;
813
- if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
814
- Object.entries(payload.include).filter(([, value]) => value).forEach(([field, value]) => {
815
- result = this.buildRelationJSON(model, result, field, `${parentName}$${relationField}`, value);
816
- });
1179
+ buildRelationJoins(query, relationModel, relationModelAlias, payload, parentResultName) {
1180
+ let result = query;
1181
+ if (typeof payload === "object") {
1182
+ const selectInclude = payload.include ?? payload.select;
1183
+ if (selectInclude && typeof selectInclude === "object") {
1184
+ Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
1185
+ result = this.buildRelationJSON(relationModel, result, field, relationModelAlias, value, `${parentResultName}$${field}`);
1186
+ });
1187
+ }
817
1188
  }
818
1189
  return result;
819
1190
  }
@@ -853,12 +1224,15 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
853
1224
  return `ARRAY[${values.map((v) => typeof v === "string" ? `'${v}'` : v)}]`;
854
1225
  }
855
1226
  }
1227
+ get supportInsertWithDefault() {
1228
+ return true;
1229
+ }
856
1230
  };
857
1231
 
858
1232
  // src/client/crud/dialects/sqlite.ts
859
1233
  var import_common_helpers3 = require("@zenstackhq/common-helpers");
860
1234
  var import_kysely3 = require("kysely");
861
- var import_ts_pattern3 = require("ts-pattern");
1235
+ var import_ts_pattern4 = require("ts-pattern");
862
1236
  var SqliteCrudDialect = class extends BaseCrudDialect {
863
1237
  static {
864
1238
  __name(this, "SqliteCrudDialect");
@@ -866,86 +1240,82 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
866
1240
  get provider() {
867
1241
  return "sqlite";
868
1242
  }
869
- transformPrimitive(value, type) {
1243
+ transformPrimitive(value, type, _forArrayField) {
870
1244
  if (value === void 0) {
871
1245
  return value;
872
1246
  }
873
1247
  if (Array.isArray(value)) {
874
- return value.map((v) => this.transformPrimitive(v, type));
1248
+ return value.map((v) => this.transformPrimitive(v, type, false));
875
1249
  } else {
876
- 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);
1250
+ if (this.schema.typeDefs && type in this.schema.typeDefs) {
1251
+ return JSON.stringify(value);
1252
+ } else {
1253
+ 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);
1254
+ }
877
1255
  }
878
1256
  }
879
1257
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
880
1258
  return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
881
1259
  }
882
- buildRelationJSON(model, eb, relationField, parentName, payload) {
1260
+ buildRelationJSON(model, eb, relationField, parentAlias, payload) {
883
1261
  const relationFieldDef = requireField(this.schema, model, relationField);
884
1262
  const relationModel = relationFieldDef.type;
885
1263
  const relationModelDef = requireModel(this.schema, relationModel);
886
- const subQueryName = `${parentName}$${relationField}`;
887
- let tbl = eb.selectFrom(() => {
888
- let subQuery = eb.selectFrom(relationModel).selectAll();
889
- if (payload && typeof payload === "object") {
890
- if (payload.where) {
891
- subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
892
- }
893
- const skip = payload.skip;
894
- let take = payload.take;
895
- let negateOrderBy = false;
896
- if (take !== void 0 && take < 0) {
897
- negateOrderBy = true;
898
- take = -take;
899
- }
900
- subQuery = this.buildSkipTake(subQuery, skip, take);
901
- subQuery = this.buildOrderBy(subQuery, relationModel, relationModel, payload.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
902
- }
903
- const m2m = getManyToManyRelation(this.schema, model, relationField);
904
- if (m2m) {
905
- const parentIds = getIdFields(this.schema, model);
906
- const relationIds = getIdFields(this.schema, relationModel);
907
- (0, import_common_helpers3.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
908
- (0, import_common_helpers3.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
909
- 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}`)));
910
- } else {
911
- const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
912
- keyPairs.forEach(({ fk, pk }) => {
913
- if (ownedByModel) {
914
- subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentName}.${fk}`);
915
- } else {
916
- subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentName}.${pk}`);
917
- }
918
- });
919
- }
920
- return subQuery.as(subQueryName);
921
- });
1264
+ const subQueryName = `${parentAlias}$${relationField}`;
1265
+ let tbl;
1266
+ if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1267
+ tbl = this.buildModelSelect(eb, relationModel, subQueryName, payload, false);
1268
+ tbl = this.buildRelationJoinFilter(tbl, model, relationField, subQueryName, parentAlias);
1269
+ } else {
1270
+ tbl = eb.selectFrom(() => {
1271
+ const selectModelAlias = `${parentAlias}$${relationField}$sub`;
1272
+ let selectModelQuery = this.buildModelSelect(eb, relationModel, selectModelAlias, payload, true);
1273
+ selectModelQuery = this.buildRelationJoinFilter(selectModelQuery, model, relationField, selectModelAlias, parentAlias);
1274
+ return selectModelQuery.as(subQueryName);
1275
+ });
1276
+ }
922
1277
  tbl = tbl.select(() => {
923
1278
  const objArgs = [];
1279
+ const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1280
+ if (descendantModels.length > 0) {
1281
+ objArgs.push(...descendantModels.map((subModel) => [
1282
+ import_kysely3.sql.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1283
+ eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1284
+ ]).flatMap((v) => v));
1285
+ }
924
1286
  if (payload === true || !payload.select) {
925
1287
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
926
1288
  import_kysely3.sql.lit(field),
927
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
1289
+ this.fieldRef(relationModel, field, eb, subQueryName, false)
928
1290
  ]).flatMap((v) => v));
929
1291
  } else if (payload.select) {
930
1292
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
931
- const fieldDef = requireField(this.schema, relationModel, field);
932
- if (fieldDef.relation) {
933
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1293
+ if (field === "_count") {
1294
+ const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
934
1295
  return [
935
1296
  import_kysely3.sql.lit(field),
936
1297
  subJson
937
1298
  ];
938
1299
  } else {
939
- return [
940
- import_kysely3.sql.lit(field),
941
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
942
- ];
1300
+ const fieldDef = requireField(this.schema, relationModel, field);
1301
+ if (fieldDef.relation) {
1302
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
1303
+ return [
1304
+ import_kysely3.sql.lit(field),
1305
+ subJson
1306
+ ];
1307
+ } else {
1308
+ return [
1309
+ import_kysely3.sql.lit(field),
1310
+ this.fieldRef(relationModel, field, eb, subQueryName, false)
1311
+ ];
1312
+ }
943
1313
  }
944
1314
  }).flatMap((v) => v));
945
1315
  }
946
1316
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
947
1317
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
948
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1318
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
949
1319
  return [
950
1320
  import_kysely3.sql.lit(field),
951
1321
  subJson
@@ -953,13 +1323,35 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
953
1323
  }).flatMap((v) => v));
954
1324
  }
955
1325
  if (relationFieldDef.array) {
956
- return eb.fn.coalesce(import_kysely3.sql`json_group_array(json_object(${import_kysely3.sql.join(objArgs)}))`, import_kysely3.sql`json_array()`).as("$j");
1326
+ return eb.fn.coalesce(import_kysely3.sql`json_group_array(json_object(${import_kysely3.sql.join(objArgs)}))`, import_kysely3.sql`json_array()`).as("$data");
957
1327
  } else {
958
- return import_kysely3.sql`json_object(${import_kysely3.sql.join(objArgs)})`.as("data");
1328
+ return import_kysely3.sql`json_object(${import_kysely3.sql.join(objArgs)})`.as("$data");
959
1329
  }
960
1330
  });
961
1331
  return tbl;
962
1332
  }
1333
+ buildRelationJoinFilter(selectModelQuery, model, relationField, relationModelAlias, parentAlias) {
1334
+ const fieldDef = requireField(this.schema, model, relationField);
1335
+ const relationModel = fieldDef.type;
1336
+ const m2m = getManyToManyRelation(this.schema, model, relationField);
1337
+ if (m2m) {
1338
+ const parentIds = getIdFields(this.schema, model);
1339
+ const relationIds = getIdFields(this.schema, relationModel);
1340
+ (0, import_common_helpers3.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1341
+ (0, import_common_helpers3.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1342
+ selectModelQuery = selectModelQuery.where((eb) => eb(eb.ref(`${relationModelAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1343
+ } else {
1344
+ const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1345
+ keyPairs.forEach(({ fk, pk }) => {
1346
+ if (ownedByModel) {
1347
+ selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${pk}`, "=", `${parentAlias}.${fk}`);
1348
+ } else {
1349
+ selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${fk}`, "=", `${parentAlias}.${pk}`);
1350
+ }
1351
+ });
1352
+ }
1353
+ return selectModelQuery;
1354
+ }
963
1355
  buildSkipTake(query, skip, take) {
964
1356
  if (take !== void 0) {
965
1357
  query = query.limit(take);
@@ -995,93 +1387,17 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
995
1387
  buildArrayLiteralSQL(_values) {
996
1388
  throw new Error("SQLite does not support array literals");
997
1389
  }
1390
+ get supportInsertWithDefault() {
1391
+ return false;
1392
+ }
998
1393
  };
999
1394
 
1000
1395
  // src/client/crud/dialects/index.ts
1001
1396
  function getCrudDialect(schema, options) {
1002
- return (0, import_ts_pattern4.match)(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
1397
+ return (0, import_ts_pattern5.match)(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
1003
1398
  }
1004
1399
  __name(getCrudDialect, "getCrudDialect");
1005
1400
 
1006
- // src/schema/expression.ts
1007
- var ExpressionUtils = {
1008
- literal: /* @__PURE__ */ __name((value) => {
1009
- return {
1010
- kind: "literal",
1011
- value
1012
- };
1013
- }, "literal"),
1014
- array: /* @__PURE__ */ __name((items) => {
1015
- return {
1016
- kind: "array",
1017
- items
1018
- };
1019
- }, "array"),
1020
- call: /* @__PURE__ */ __name((functionName, args) => {
1021
- return {
1022
- kind: "call",
1023
- function: functionName,
1024
- args
1025
- };
1026
- }, "call"),
1027
- binary: /* @__PURE__ */ __name((left, op, right) => {
1028
- return {
1029
- kind: "binary",
1030
- op,
1031
- left,
1032
- right
1033
- };
1034
- }, "binary"),
1035
- unary: /* @__PURE__ */ __name((op, operand) => {
1036
- return {
1037
- kind: "unary",
1038
- op,
1039
- operand
1040
- };
1041
- }, "unary"),
1042
- field: /* @__PURE__ */ __name((field) => {
1043
- return {
1044
- kind: "field",
1045
- field
1046
- };
1047
- }, "field"),
1048
- member: /* @__PURE__ */ __name((receiver, members) => {
1049
- return {
1050
- kind: "member",
1051
- receiver,
1052
- members
1053
- };
1054
- }, "member"),
1055
- _this: /* @__PURE__ */ __name(() => {
1056
- return {
1057
- kind: "this"
1058
- };
1059
- }, "_this"),
1060
- _null: /* @__PURE__ */ __name(() => {
1061
- return {
1062
- kind: "null"
1063
- };
1064
- }, "_null"),
1065
- and: /* @__PURE__ */ __name((expr2, ...expressions) => {
1066
- return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
1067
- }, "and"),
1068
- or: /* @__PURE__ */ __name((expr2, ...expressions) => {
1069
- return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
1070
- }, "or"),
1071
- is: /* @__PURE__ */ __name((value, kind) => {
1072
- return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
1073
- }, "is"),
1074
- isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
1075
- isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
1076
- isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
1077
- isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
1078
- isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
1079
- isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
1080
- isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
1081
- isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
1082
- isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
1083
- };
1084
-
1085
1401
  // src/utils/default-operation-node-visitor.ts
1086
1402
  var import_kysely4 = require("kysely");
1087
1403
  var DefaultOperationNodeVisitor = class extends import_kysely4.OperationNodeVisitor {
@@ -1403,17 +1719,17 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
1403
1719
  // src/plugins/policy/expression-transformer.ts
1404
1720
  var import_common_helpers5 = require("@zenstackhq/common-helpers");
1405
1721
  var import_kysely6 = require("kysely");
1406
- var import_ts_pattern6 = require("ts-pattern");
1722
+ var import_ts_pattern7 = require("ts-pattern");
1407
1723
 
1408
1724
  // src/plugins/policy/expression-evaluator.ts
1409
1725
  var import_common_helpers4 = require("@zenstackhq/common-helpers");
1410
- var import_ts_pattern5 = require("ts-pattern");
1726
+ var import_ts_pattern6 = require("ts-pattern");
1411
1727
  var ExpressionEvaluator = class {
1412
1728
  static {
1413
1729
  __name(this, "ExpressionEvaluator");
1414
1730
  }
1415
1731
  evaluate(expression, context) {
1416
- 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();
1732
+ 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();
1417
1733
  return result ?? null;
1418
1734
  }
1419
1735
  evaluateCall(expr2, context) {
@@ -1424,7 +1740,7 @@ var ExpressionEvaluator = class {
1424
1740
  }
1425
1741
  }
1426
1742
  evaluateUnary(expr2, context) {
1427
- return (0, import_ts_pattern5.match)(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
1743
+ return (0, import_ts_pattern6.match)(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
1428
1744
  }
1429
1745
  evaluateMember(expr2, context) {
1430
1746
  let val = this.evaluate(expr2.receiver, context);
@@ -1448,7 +1764,7 @@ var ExpressionEvaluator = class {
1448
1764
  }
1449
1765
  const left = this.evaluate(expr2.left, context);
1450
1766
  const right = this.evaluate(expr2.right, context);
1451
- 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", () => {
1767
+ 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", () => {
1452
1768
  const _right = right ?? [];
1453
1769
  (0, import_common_helpers4.invariant)(Array.isArray(_right), 'expected array for "in" operator');
1454
1770
  return _right.includes(left);
@@ -1462,7 +1778,7 @@ var ExpressionEvaluator = class {
1462
1778
  return false;
1463
1779
  }
1464
1780
  (0, import_common_helpers4.invariant)(Array.isArray(left), "expected array");
1465
- return (0, import_ts_pattern5.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1781
+ return (0, import_ts_pattern6.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1466
1782
  ...context,
1467
1783
  thisValue: item
1468
1784
  }))).with("!", () => left.every((item) => this.evaluate(expr2.right, {
@@ -1478,11 +1794,11 @@ var ExpressionEvaluator = class {
1478
1794
  // src/plugins/policy/utils.ts
1479
1795
  var import_kysely5 = require("kysely");
1480
1796
  function trueNode(dialect) {
1481
- return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
1797
+ return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
1482
1798
  }
1483
1799
  __name(trueNode, "trueNode");
1484
1800
  function falseNode(dialect) {
1485
- return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
1801
+ return import_kysely5.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
1486
1802
  }
1487
1803
  __name(falseNode, "falseNode");
1488
1804
  function isTrueNode(node) {
@@ -1716,7 +2032,7 @@ var ExpressionTransformer = class {
1716
2032
  const count = import_kysely6.FunctionNode.create("count", [
1717
2033
  import_kysely6.ValueNode.createImmediate(1)
1718
2034
  ]);
1719
- 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();
2035
+ 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();
1720
2036
  return this.transform(expr2.left, {
1721
2037
  ...context,
1722
2038
  memberSelect: import_kysely6.SelectionNode.create(import_kysely6.AliasNode.create(predicateResult, import_kysely6.IdentifierNode.create("$t"))),
@@ -1740,14 +2056,14 @@ var ExpressionTransformer = class {
1740
2056
  }
1741
2057
  }
1742
2058
  transformValue(value, type) {
1743
- return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type) ?? null);
2059
+ return import_kysely6.ValueNode.create(this.dialect.transformPrimitive(value, type, false) ?? null);
1744
2060
  }
1745
2061
  _unary(expr2, context) {
1746
2062
  (0, import_common_helpers5.invariant)(expr2.op === "!", 'only "!" operator is supported');
1747
2063
  return import_kysely6.BinaryOperationNode.create(this.transform(expr2.operand, context), this.transformOperator("!="), trueNode(this.dialect));
1748
2064
  }
1749
2065
  transformOperator(op) {
1750
- const mappedOp = (0, import_ts_pattern6.match)(op).with("==", () => "=").otherwise(() => op);
2066
+ const mappedOp = (0, import_ts_pattern7.match)(op).with("==", () => "=").otherwise(() => op);
1751
2067
  return import_kysely6.OperatorNode.create(mappedOp);
1752
2068
  }
1753
2069
  _call(expr2, context) {
@@ -1983,7 +2299,7 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
1983
2299
  get kysely() {
1984
2300
  return this.client.$qb;
1985
2301
  }
1986
- async handle(node, proceed, transaction) {
2302
+ async handle(node, proceed) {
1987
2303
  if (!this.isCrudQueryNode(node)) {
1988
2304
  throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
1989
2305
  }
@@ -2003,27 +2319,20 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2003
2319
  if (!mutationRequiresTransaction && !node.returning) {
2004
2320
  return proceed(this.transformNode(node));
2005
2321
  }
2006
- let readBackError = false;
2007
- const result = await transaction(async (txProceed) => {
2008
- if (import_kysely7.InsertQueryNode.is(node)) {
2009
- await this.enforcePreCreatePolicy(node, txProceed);
2010
- }
2011
- const transformedNode = this.transformNode(node);
2012
- const result2 = await txProceed(transformedNode);
2013
- if (!this.onlyReturningId(node)) {
2014
- const readBackResult = await this.processReadBack(node, result2, txProceed);
2015
- if (readBackResult.rows.length !== result2.rows.length) {
2016
- readBackError = true;
2017
- }
2018
- return readBackResult;
2019
- } else {
2020
- return result2;
2322
+ if (import_kysely7.InsertQueryNode.is(node)) {
2323
+ await this.enforcePreCreatePolicy(node, proceed);
2324
+ }
2325
+ const transformedNode = this.transformNode(node);
2326
+ const result = await proceed(transformedNode);
2327
+ if (!this.onlyReturningId(node)) {
2328
+ const readBackResult = await this.processReadBack(node, result, proceed);
2329
+ if (readBackResult.rows.length !== result.rows.length) {
2330
+ throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2021
2331
  }
2022
- });
2023
- if (readBackError) {
2024
- throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2332
+ return readBackResult;
2333
+ } else {
2334
+ return result;
2025
2335
  }
2026
- return result;
2027
2336
  }
2028
2337
  onlyReturningId(node) {
2029
2338
  if (!node.returning) {
@@ -2084,11 +2393,11 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2084
2393
  if (typeof item === "object" && item && "kind" in item) {
2085
2394
  (0, import_common_helpers6.invariant)(item.kind === "ValueNode", "expecting a ValueNode");
2086
2395
  result.push({
2087
- node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
2396
+ node: import_kysely7.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
2088
2397
  raw: item.value
2089
2398
  });
2090
2399
  } else {
2091
- const value = this.dialect.transformPrimitive(item, fieldDef.type);
2400
+ const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
2092
2401
  if (Array.isArray(value)) {
2093
2402
  result.push({
2094
2403
  node: import_kysely7.RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
@@ -2157,7 +2466,7 @@ var PolicyHandler = class extends import_kysely7.OperationNodeTransformer {
2157
2466
  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]))))));
2158
2467
  }
2159
2468
  getMutationModel(node) {
2160
- 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) => {
2469
+ 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) => {
2161
2470
  if (node2.from.froms.length !== 1) {
2162
2471
  throw new InternalError("Only one from table is supported for delete");
2163
2472
  }
@@ -2319,9 +2628,18 @@ var PolicyPlugin = class {
2319
2628
  get description() {
2320
2629
  return "Enforces access policies defined in the schema.";
2321
2630
  }
2322
- onKyselyQuery({ query, client, proceed, transaction }) {
2631
+ onKyselyQuery({
2632
+ query,
2633
+ client,
2634
+ proceed
2635
+ /*, transaction*/
2636
+ }) {
2323
2637
  const handler = new PolicyHandler(client);
2324
- return handler.handle(query, proceed, transaction);
2638
+ return handler.handle(
2639
+ query,
2640
+ proceed
2641
+ /*, transaction*/
2642
+ );
2325
2643
  }
2326
2644
  };
2327
2645
  // Annotate the CommonJS export names for ESM import in node:
@@ -2329,4 +2647,4 @@ var PolicyPlugin = class {
2329
2647
  PolicyPlugin,
2330
2648
  RejectedByPolicyError
2331
2649
  });
2332
- //# sourceMappingURL=policy.cjs.map
2650
+ //# sourceMappingURL=index.cjs.map