@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.
@@ -16,32 +16,131 @@ var RejectedByPolicyError = class extends Error {
16
16
  // src/plugins/policy/policy-handler.ts
17
17
  import { invariant as invariant6 } from "@zenstackhq/common-helpers";
18
18
  import { AliasNode as AliasNode3, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode2, DeleteQueryNode, FromNode as FromNode2, IdentifierNode as IdentifierNode2, InsertQueryNode, OperationNodeTransformer, OperatorNode as OperatorNode3, PrimitiveValueListNode, RawNode, ReturningNode, SelectionNode as SelectionNode2, SelectQueryNode as SelectQueryNode2, TableNode as TableNode3, UpdateQueryNode, ValueNode as ValueNode3, ValuesNode, WhereNode as WhereNode2 } from "kysely";
19
- import { match as match7 } from "ts-pattern";
19
+ import { match as match8 } from "ts-pattern";
20
20
 
21
21
  // src/client/crud/dialects/index.ts
22
- import { match as match4 } from "ts-pattern";
22
+ import { match as match5 } from "ts-pattern";
23
23
 
24
24
  // src/client/crud/dialects/postgresql.ts
25
25
  import { invariant as invariant2 } from "@zenstackhq/common-helpers";
26
26
  import { sql as sql2 } from "kysely";
27
- import { match as match2 } from "ts-pattern";
27
+ import { match as match3 } from "ts-pattern";
28
+
29
+ // src/client/constants.ts
30
+ var DELEGATE_JOINED_FIELD_PREFIX = "$delegate$";
31
+ var LOGICAL_COMBINATORS = [
32
+ "AND",
33
+ "OR",
34
+ "NOT"
35
+ ];
36
+ var AGGREGATE_OPERATORS = [
37
+ "_count",
38
+ "_sum",
39
+ "_avg",
40
+ "_min",
41
+ "_max"
42
+ ];
43
+
44
+ // src/client/query-utils.ts
45
+ import { match } from "ts-pattern";
46
+
47
+ // src/schema/expression.ts
48
+ var ExpressionUtils = {
49
+ literal: /* @__PURE__ */ __name((value) => {
50
+ return {
51
+ kind: "literal",
52
+ value
53
+ };
54
+ }, "literal"),
55
+ array: /* @__PURE__ */ __name((items) => {
56
+ return {
57
+ kind: "array",
58
+ items
59
+ };
60
+ }, "array"),
61
+ call: /* @__PURE__ */ __name((functionName, args) => {
62
+ return {
63
+ kind: "call",
64
+ function: functionName,
65
+ args
66
+ };
67
+ }, "call"),
68
+ binary: /* @__PURE__ */ __name((left, op, right) => {
69
+ return {
70
+ kind: "binary",
71
+ op,
72
+ left,
73
+ right
74
+ };
75
+ }, "binary"),
76
+ unary: /* @__PURE__ */ __name((op, operand) => {
77
+ return {
78
+ kind: "unary",
79
+ op,
80
+ operand
81
+ };
82
+ }, "unary"),
83
+ field: /* @__PURE__ */ __name((field) => {
84
+ return {
85
+ kind: "field",
86
+ field
87
+ };
88
+ }, "field"),
89
+ member: /* @__PURE__ */ __name((receiver, members) => {
90
+ return {
91
+ kind: "member",
92
+ receiver,
93
+ members
94
+ };
95
+ }, "member"),
96
+ _this: /* @__PURE__ */ __name(() => {
97
+ return {
98
+ kind: "this"
99
+ };
100
+ }, "_this"),
101
+ _null: /* @__PURE__ */ __name(() => {
102
+ return {
103
+ kind: "null"
104
+ };
105
+ }, "_null"),
106
+ and: /* @__PURE__ */ __name((expr2, ...expressions) => {
107
+ return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
108
+ }, "and"),
109
+ or: /* @__PURE__ */ __name((expr2, ...expressions) => {
110
+ return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
111
+ }, "or"),
112
+ is: /* @__PURE__ */ __name((value, kind) => {
113
+ return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
114
+ }, "is"),
115
+ isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
116
+ isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
117
+ isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
118
+ isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
119
+ isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
120
+ isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
121
+ isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
122
+ isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
123
+ isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember"),
124
+ getLiteralValue: /* @__PURE__ */ __name((expr2) => {
125
+ return ExpressionUtils.isLiteral(expr2) ? expr2.value : void 0;
126
+ }, "getLiteralValue")
127
+ };
28
128
 
29
129
  // src/client/errors.ts
30
130
  var QueryError = class extends Error {
31
131
  static {
32
132
  __name(this, "QueryError");
33
133
  }
34
- constructor(message) {
35
- super(message);
134
+ constructor(message, cause) {
135
+ super(message, {
136
+ cause
137
+ });
36
138
  }
37
139
  };
38
140
  var InternalError = class extends Error {
39
141
  static {
40
142
  __name(this, "InternalError");
41
143
  }
42
- constructor(message) {
43
- super(message);
44
- }
45
144
  };
46
145
 
47
146
  // src/client/query-utils.ts
@@ -52,7 +151,7 @@ __name(getModel, "getModel");
52
151
  function requireModel(schema, model) {
53
152
  const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
54
153
  if (!matchedName) {
55
- throw new QueryError(`Model "${model}" not found`);
154
+ throw new QueryError(`Model "${model}" not found in schema`);
56
155
  }
57
156
  return schema.models[matchedName];
58
157
  }
@@ -115,6 +214,16 @@ function getRelationForeignKeyFieldPairs(schema, model, relationField) {
115
214
  }
116
215
  }
117
216
  __name(getRelationForeignKeyFieldPairs, "getRelationForeignKeyFieldPairs");
217
+ function isRelationField(schema, model, field) {
218
+ const fieldDef = getField(schema, model, field);
219
+ return !!fieldDef?.relation;
220
+ }
221
+ __name(isRelationField, "isRelationField");
222
+ function isInheritedField(schema, model, field) {
223
+ const fieldDef = getField(schema, model, field);
224
+ return !!fieldDef?.originModel;
225
+ }
226
+ __name(isInheritedField, "isInheritedField");
118
227
  function getUniqueFields(schema, model) {
119
228
  const modelDef = requireModel(schema, model);
120
229
  const result = [];
@@ -140,20 +249,25 @@ function getUniqueFields(schema, model) {
140
249
  return result;
141
250
  }
142
251
  __name(getUniqueFields, "getUniqueFields");
143
- function buildFieldRef(schema, model, field, options, eb, modelAlias) {
252
+ function buildFieldRef(schema, model, field, options, eb, modelAlias, inlineComputedField = true) {
144
253
  const fieldDef = requireField(schema, model, field);
145
254
  if (!fieldDef.computed) {
146
255
  return eb.ref(modelAlias ? `${modelAlias}.${field}` : field);
147
256
  } else {
257
+ if (!inlineComputedField) {
258
+ return eb.ref(modelAlias ? `${modelAlias}.${field}` : field);
259
+ }
148
260
  let computer;
149
261
  if ("computedFields" in options) {
150
262
  const computedFields = options.computedFields;
151
263
  computer = computedFields?.[model]?.[field];
152
264
  }
153
265
  if (!computer) {
154
- throw new QueryError(`Computed field "${field}" implementation not provided`);
266
+ throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
155
267
  }
156
- return computer(eb);
268
+ return computer(eb, {
269
+ currentModel: modelAlias
270
+ });
157
271
  }
158
272
  }
159
273
  __name(buildFieldRef, "buildFieldRef");
@@ -196,11 +310,33 @@ function getManyToManyRelation(schema, model, field) {
196
310
  model,
197
311
  fieldDef.type
198
312
  ].sort();
313
+ let orderedFK;
314
+ if (model !== fieldDef.type) {
315
+ orderedFK = sortedModelNames[0] === model ? [
316
+ "A",
317
+ "B"
318
+ ] : [
319
+ "B",
320
+ "A"
321
+ ];
322
+ } else {
323
+ const sortedFieldNames = [
324
+ field,
325
+ oppositeFieldDef.name
326
+ ].sort();
327
+ orderedFK = sortedFieldNames[0] === field ? [
328
+ "A",
329
+ "B"
330
+ ] : [
331
+ "B",
332
+ "A"
333
+ ];
334
+ }
199
335
  return {
200
- parentFkName: sortedModelNames[0] === model ? "A" : "B",
336
+ parentFkName: orderedFK[0],
201
337
  otherModel: fieldDef.type,
202
338
  otherField: fieldDef.relation.opposite,
203
- otherFkName: sortedModelNames[0] === fieldDef.type ? "A" : "B",
339
+ otherFkName: orderedFK[1],
204
340
  joinTable: fieldDef.relation.name ? `_${fieldDef.relation.name}` : `_${sortedModelNames[0]}To${sortedModelNames[1]}`
205
341
  };
206
342
  } else {
@@ -228,11 +364,38 @@ function flattenCompoundUniqueFilters(schema, model, filter) {
228
364
  return result;
229
365
  }
230
366
  __name(flattenCompoundUniqueFilters, "flattenCompoundUniqueFilters");
367
+ function ensureArray(value) {
368
+ if (Array.isArray(value)) {
369
+ return value;
370
+ } else {
371
+ return [
372
+ value
373
+ ];
374
+ }
375
+ }
376
+ __name(ensureArray, "ensureArray");
377
+ function getDelegateDescendantModels(schema, model, collected = /* @__PURE__ */ new Set()) {
378
+ const subModels = Object.values(schema.models).filter((m) => m.baseModel === model);
379
+ subModels.forEach((def) => {
380
+ if (!collected.has(def)) {
381
+ collected.add(def);
382
+ getDelegateDescendantModels(schema, def.name, collected);
383
+ }
384
+ });
385
+ return [
386
+ ...collected
387
+ ];
388
+ }
389
+ __name(getDelegateDescendantModels, "getDelegateDescendantModels");
390
+ function aggregate(eb, expr2, op) {
391
+ return match(op).with("_count", () => eb.fn.count(expr2)).with("_sum", () => eb.fn.sum(expr2)).with("_avg", () => eb.fn.avg(expr2)).with("_min", () => eb.fn.min(expr2)).with("_max", () => eb.fn.max(expr2)).exhaustive();
392
+ }
393
+ __name(aggregate, "aggregate");
231
394
 
232
395
  // src/client/crud/dialects/base.ts
233
396
  import { invariant, isPlainObject } from "@zenstackhq/common-helpers";
234
- import { sql } from "kysely";
235
- import { match, P } from "ts-pattern";
397
+ import { expressionBuilder, sql } from "kysely";
398
+ import { match as match2, P } from "ts-pattern";
236
399
 
237
400
  // src/utils/enumerate.ts
238
401
  function enumerate(x) {
@@ -259,9 +422,47 @@ var BaseCrudDialect = class {
259
422
  this.schema = schema;
260
423
  this.options = options;
261
424
  }
262
- transformPrimitive(value, _type) {
425
+ transformPrimitive(value, _type, _forArrayField) {
263
426
  return value;
264
427
  }
428
+ // #region common query builders
429
+ buildSelectModel(eb, model, modelAlias) {
430
+ const modelDef = requireModel(this.schema, model);
431
+ let result = eb.selectFrom(model === modelAlias ? model : `${model} as ${modelAlias}`);
432
+ let joinBase = modelDef.baseModel;
433
+ while (joinBase) {
434
+ result = this.buildDelegateJoin(model, modelAlias, joinBase, result);
435
+ joinBase = requireModel(this.schema, joinBase).baseModel;
436
+ }
437
+ return result;
438
+ }
439
+ buildFilterSortTake(model, args, query, modelAlias) {
440
+ let result = query;
441
+ if (args.where) {
442
+ result = result.where((eb) => this.buildFilter(eb, model, modelAlias, args?.where));
443
+ }
444
+ let negateOrderBy = false;
445
+ const skip = args.skip;
446
+ let take = args.take;
447
+ if (take !== void 0 && take < 0) {
448
+ negateOrderBy = true;
449
+ take = -take;
450
+ }
451
+ result = this.buildSkipTake(result, skip, take);
452
+ result = this.buildOrderBy(result, model, modelAlias, args.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
453
+ if ("distinct" in args && args.distinct) {
454
+ const distinct = ensureArray(args.distinct);
455
+ if (this.supportsDistinctOn) {
456
+ result = result.distinctOn(distinct.map((f) => sql.ref(`${modelAlias}.${f}`)));
457
+ } else {
458
+ throw new QueryError(`"distinct" is not supported by "${this.schema.provider.type}" provider`);
459
+ }
460
+ }
461
+ if (args.cursor) {
462
+ result = this.buildCursorFilter(model, result, args.cursor, args.orderBy, negateOrderBy, modelAlias);
463
+ }
464
+ return result;
465
+ }
265
466
  buildFilter(eb, model, modelAlias, where) {
266
467
  if (where === true || where === void 0) {
267
468
  return this.true(eb);
@@ -278,17 +479,20 @@ var BaseCrudDialect = class {
278
479
  if (key.startsWith("$")) {
279
480
  continue;
280
481
  }
281
- if (key === "AND" || key === "OR" || key === "NOT") {
482
+ if (this.isLogicalCombinator(key)) {
282
483
  result = this.and(eb, result, this.buildCompositeFilter(eb, model, modelAlias, key, payload));
283
484
  continue;
284
485
  }
285
486
  const fieldDef = requireField(this.schema, model, key);
286
487
  if (fieldDef.relation) {
287
488
  result = this.and(eb, result, this.buildRelationFilter(eb, model, modelAlias, key, fieldDef, payload));
288
- } else if (fieldDef.array) {
289
- result = this.and(eb, result, this.buildArrayFilter(eb, model, modelAlias, key, fieldDef, payload));
290
489
  } else {
291
- result = this.and(eb, result, this.buildPrimitiveFilter(eb, model, modelAlias, key, fieldDef, payload));
490
+ const fieldRef = this.fieldRef(fieldDef.originModel ?? model, key, eb, fieldDef.originModel ?? modelAlias);
491
+ if (fieldDef.array) {
492
+ result = this.and(eb, result, this.buildArrayFilter(eb, fieldRef, fieldDef, payload));
493
+ } else {
494
+ result = this.and(eb, result, this.buildPrimitiveFilter(eb, fieldRef, fieldDef, payload));
495
+ }
292
496
  }
293
497
  }
294
498
  if ("$expr" in _where && typeof _where["$expr"] === "function") {
@@ -296,8 +500,32 @@ var BaseCrudDialect = class {
296
500
  }
297
501
  return result;
298
502
  }
503
+ buildCursorFilter(model, query, cursor, orderBy, negateOrderBy, modelAlias) {
504
+ const _orderBy = orderBy ?? makeDefaultOrderBy(this.schema, model);
505
+ const orderByItems = ensureArray(_orderBy).flatMap((obj) => Object.entries(obj));
506
+ const eb = expressionBuilder();
507
+ const subQueryAlias = `${model}$cursor$sub`;
508
+ const cursorFilter = this.buildFilter(eb, model, subQueryAlias, cursor);
509
+ let result = query;
510
+ const filters = [];
511
+ for (let i = orderByItems.length - 1; i >= 0; i--) {
512
+ const andFilters = [];
513
+ for (let j = 0; j <= i; j++) {
514
+ const [field, order] = orderByItems[j];
515
+ const _order = negateOrderBy ? order === "asc" ? "desc" : "asc" : order;
516
+ const op = j === i ? _order === "asc" ? ">=" : "<=" : "=";
517
+ andFilters.push(eb(eb.ref(`${modelAlias}.${field}`), op, this.buildSelectModel(eb, model, subQueryAlias).select(`${subQueryAlias}.${field}`).where(cursorFilter)));
518
+ }
519
+ filters.push(eb.and(andFilters));
520
+ }
521
+ result = result.where((eb2) => eb2.or(filters));
522
+ return result;
523
+ }
524
+ isLogicalCombinator(key) {
525
+ return LOGICAL_COMBINATORS.includes(key);
526
+ }
299
527
  buildCompositeFilter(eb, model, modelAlias, key, payload) {
300
- return match(key).with("AND", () => this.and(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("OR", () => this.or(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("NOT", () => eb.not(this.buildCompositeFilter(eb, model, modelAlias, "AND", payload))).exhaustive();
528
+ return match2(key).with("AND", () => this.and(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("OR", () => this.or(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("NOT", () => eb.not(this.buildCompositeFilter(eb, model, modelAlias, "AND", payload))).exhaustive();
301
529
  }
302
530
  buildRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
303
531
  if (!fieldDef.array) {
@@ -306,19 +534,26 @@ var BaseCrudDialect = class {
306
534
  return this.buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload);
307
535
  }
308
536
  }
309
- buildToOneRelationFilter(eb, model, table, field, fieldDef, payload) {
537
+ buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
310
538
  if (payload === null) {
311
539
  const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, model, field);
312
- if (ownedByModel) {
313
- return this.and(eb, ...keyPairs.map(({ fk }) => eb(sql.ref(`${table}.${fk}`), "is", null)));
540
+ if (ownedByModel && !fieldDef.originModel) {
541
+ return this.and(eb, ...keyPairs.map(({ fk }) => eb(sql.ref(`${modelAlias}.${fk}`), "is", null)));
314
542
  } else {
315
- return this.buildToOneRelationFilter(eb, model, table, field, fieldDef, {
543
+ return this.buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, {
316
544
  is: null
317
545
  });
318
546
  }
319
547
  }
320
- const joinAlias = `${table}$${field}`;
321
- const joinPairs = buildJoinPairs(this.schema, model, table, field, joinAlias);
548
+ const joinAlias = `${modelAlias}$${field}`;
549
+ const joinPairs = buildJoinPairs(
550
+ this.schema,
551
+ model,
552
+ // if field is from a base, use the base model to join
553
+ fieldDef.originModel ?? modelAlias,
554
+ field,
555
+ joinAlias
556
+ );
322
557
  const filterResultField = `${field}$filter`;
323
558
  const joinSelect = eb.selectFrom(`${fieldDef.type} as ${joinAlias}`).where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql.ref(left), "=", sql.ref(right))))).select(() => eb.fn.count(eb.lit(1)).as(filterResultField));
324
559
  const conditions = [];
@@ -348,25 +583,26 @@ var BaseCrudDialect = class {
348
583
  }
349
584
  return this.and(eb, ...conditions);
350
585
  }
351
- buildToManyRelationFilter(eb, model, table, field, fieldDef, payload) {
586
+ buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
352
587
  if (payload === null) {
353
- return eb(sql.ref(`${table}.${field}`), "is", null);
588
+ return eb(sql.ref(`${modelAlias}.${field}`), "is", null);
354
589
  }
355
590
  const relationModel = fieldDef.type;
591
+ const relationFilterSelectAlias = `${modelAlias}$${field}$filter`;
356
592
  const buildPkFkWhereRefs = /* @__PURE__ */ __name((eb2) => {
357
593
  const m2m = getManyToManyRelation(this.schema, model, field);
358
594
  if (m2m) {
359
595
  const modelIdField = getIdFields(this.schema, model)[0];
360
596
  const relationIdField = getIdFields(this.schema, relationModel)[0];
361
- return eb2(sql.ref(`${relationModel}.${relationIdField}`), "in", eb2.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(sql.ref(`${m2m.joinTable}.${m2m.parentFkName}`), "=", sql.ref(`${table}.${modelIdField}`)));
597
+ return eb2(sql.ref(`${relationFilterSelectAlias}.${relationIdField}`), "in", eb2.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(sql.ref(`${m2m.joinTable}.${m2m.parentFkName}`), "=", sql.ref(`${modelAlias}.${modelIdField}`)));
362
598
  } else {
363
599
  const relationKeyPairs = getRelationForeignKeyFieldPairs(this.schema, model, field);
364
600
  let result2 = this.true(eb2);
365
601
  for (const { fk, pk } of relationKeyPairs.keyPairs) {
366
602
  if (relationKeyPairs.ownedByModel) {
367
- result2 = this.and(eb2, result2, eb2(sql.ref(`${table}.${fk}`), "=", sql.ref(`${relationModel}.${pk}`)));
603
+ result2 = this.and(eb2, result2, eb2(sql.ref(`${modelAlias}.${fk}`), "=", sql.ref(`${relationFilterSelectAlias}.${pk}`)));
368
604
  } else {
369
- result2 = this.and(eb2, result2, eb2(sql.ref(`${table}.${pk}`), "=", sql.ref(`${relationModel}.${fk}`)));
605
+ result2 = this.and(eb2, result2, eb2(sql.ref(`${modelAlias}.${pk}`), "=", sql.ref(`${relationFilterSelectAlias}.${fk}`)));
370
606
  }
371
607
  }
372
608
  return result2;
@@ -379,30 +615,29 @@ var BaseCrudDialect = class {
379
615
  }
380
616
  switch (key) {
381
617
  case "some": {
382
- 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));
618
+ 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));
383
619
  break;
384
620
  }
385
621
  case "every": {
386
- 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));
622
+ 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));
387
623
  break;
388
624
  }
389
625
  case "none": {
390
- 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));
626
+ 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));
391
627
  break;
392
628
  }
393
629
  }
394
630
  }
395
631
  return result;
396
632
  }
397
- buildArrayFilter(eb, model, modelAlias, field, fieldDef, payload) {
633
+ buildArrayFilter(eb, fieldRef, fieldDef, payload) {
398
634
  const clauses = [];
399
635
  const fieldType = fieldDef.type;
400
- const fieldRef = buildFieldRef(this.schema, model, field, this.options, eb, modelAlias);
401
636
  for (const [key, _value] of Object.entries(payload)) {
402
637
  if (_value === void 0) {
403
638
  continue;
404
639
  }
405
- const value = this.transformPrimitive(_value, fieldType);
640
+ const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
406
641
  switch (key) {
407
642
  case "equals": {
408
643
  clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
@@ -433,19 +668,23 @@ var BaseCrudDialect = class {
433
668
  }
434
669
  return this.and(eb, ...clauses);
435
670
  }
436
- buildPrimitiveFilter(eb, model, modelAlias, field, fieldDef, payload) {
671
+ buildPrimitiveFilter(eb, fieldRef, fieldDef, payload) {
437
672
  if (payload === null) {
438
- return eb(sql.ref(`${modelAlias}.${field}`), "is", null);
673
+ return eb(fieldRef, "is", null);
439
674
  }
440
675
  if (isEnum(this.schema, fieldDef.type)) {
441
- return this.buildEnumFilter(eb, modelAlias, field, fieldDef, payload);
676
+ return this.buildEnumFilter(eb, fieldRef, fieldDef, payload);
442
677
  }
443
- return match(fieldDef.type).with("String", () => this.buildStringFilter(eb, modelAlias, field, payload)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, model, modelAlias, field, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, modelAlias, field, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, modelAlias, field, payload)).with("Bytes", () => this.buildBytesFilter(eb, modelAlias, field, payload)).exhaustive();
678
+ return match2(fieldDef.type).with("String", () => this.buildStringFilter(eb, fieldRef, payload)).with(P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, fieldRef, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, fieldRef, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, fieldRef, payload)).with("Bytes", () => this.buildBytesFilter(eb, fieldRef, payload)).with("Json", () => {
679
+ throw new InternalError("JSON filters are not supported yet");
680
+ }).with("Unsupported", () => {
681
+ throw new QueryError(`Unsupported field cannot be used in filters`);
682
+ }).exhaustive();
444
683
  }
445
684
  buildLiteralFilter(eb, lhs, type, rhs) {
446
- return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type) : rhs);
685
+ return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
447
686
  }
448
- buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
687
+ buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0, excludeKeys = []) {
449
688
  if (payload === null || !isPlainObject(payload)) {
450
689
  return {
451
690
  conditions: [
@@ -460,8 +699,11 @@ var BaseCrudDialect = class {
460
699
  if (onlyForKeys && !onlyForKeys.includes(op)) {
461
700
  continue;
462
701
  }
702
+ if (excludeKeys.includes(op)) {
703
+ continue;
704
+ }
463
705
  const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
464
- const condition = match(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
706
+ const condition = match2(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
465
707
  invariant(Array.isArray(rhs), "right hand side must be an array");
466
708
  if (rhs.length === 0) {
467
709
  return this.false(eb);
@@ -475,7 +717,11 @@ var BaseCrudDialect = class {
475
717
  } else {
476
718
  return eb.not(eb(lhs, "in", rhs));
477
719
  }
478
- }).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(() => {
720
+ }).with("lt", () => eb(lhs, "<", rhs)).with("lte", () => eb(lhs, "<=", rhs)).with("gt", () => eb(lhs, ">", rhs)).with("gte", () => eb(lhs, ">=", rhs)).with("not", () => eb.not(recurse(value))).with(P.union(...AGGREGATE_OPERATORS), (op2) => {
721
+ const innerResult = this.buildStandardFilter(eb, type, value, aggregate(eb, lhs, op2), getRhs, recurse, throwIfInvalid);
722
+ consumedKeys.push(...innerResult.consumedKeys);
723
+ return this.and(eb, ...innerResult.conditions);
724
+ }).otherwise(() => {
479
725
  if (throwIfInvalid) {
480
726
  throw new QueryError(`Invalid filter key: ${op}`);
481
727
  } else {
@@ -492,24 +738,21 @@ var BaseCrudDialect = class {
492
738
  consumedKeys
493
739
  };
494
740
  }
495
- buildStringFilter(eb, table, field, payload) {
496
- const fieldDef = getField(this.schema, table, field);
497
- let fieldRef = fieldDef?.computed ? sql.ref(field) : sql.ref(`${table}.${field}`);
498
- let insensitive = false;
499
- if (payload && typeof payload === "object" && "mode" in payload && payload.mode === "insensitive") {
500
- insensitive = true;
501
- fieldRef = eb.fn("lower", [
502
- fieldRef
503
- ]);
741
+ buildStringFilter(eb, fieldRef, payload) {
742
+ let mode;
743
+ if (payload && typeof payload === "object" && "mode" in payload) {
744
+ mode = payload.mode;
504
745
  }
505
- const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => this.prepStringCasing(eb, value, insensitive), (value) => this.buildStringFilter(eb, table, field, value));
746
+ const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, mode === "insensitive" ? eb.fn("lower", [
747
+ fieldRef
748
+ ]) : fieldRef, (value) => this.prepStringCasing(eb, value, mode), (value) => this.buildStringFilter(eb, fieldRef, value));
506
749
  if (payload && typeof payload === "object") {
507
750
  for (const [key, value] of Object.entries(payload)) {
508
751
  if (key === "mode" || consumedKeys.includes(key)) {
509
752
  continue;
510
753
  }
511
- const condition = match(key).with("contains", () => insensitive ? eb(fieldRef, "ilike", sql.lit(`%${value}%`)) : eb(fieldRef, "like", sql.lit(`%${value}%`))).with("startsWith", () => insensitive ? eb(fieldRef, "ilike", sql.lit(`${value}%`)) : eb(fieldRef, "like", sql.lit(`${value}%`))).with("endsWith", () => insensitive ? eb(fieldRef, "ilike", sql.lit(`%${value}`)) : eb(fieldRef, "like", sql.lit(`%${value}`))).otherwise(() => {
512
- throw new Error(`Invalid string filter key: ${key}`);
754
+ const condition = match2(key).with("contains", () => mode === "insensitive" ? eb(fieldRef, "ilike", sql.val(`%${value}%`)) : eb(fieldRef, "like", sql.val(`%${value}%`))).with("startsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", sql.val(`${value}%`)) : eb(fieldRef, "like", sql.val(`${value}%`))).with("endsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", sql.val(`%${value}`)) : eb(fieldRef, "like", sql.val(`%${value}`))).otherwise(() => {
755
+ throw new QueryError(`Invalid string filter key: ${key}`);
513
756
  });
514
757
  if (condition) {
515
758
  conditions.push(condition);
@@ -518,34 +761,37 @@ var BaseCrudDialect = class {
518
761
  }
519
762
  return this.and(eb, ...conditions);
520
763
  }
521
- prepStringCasing(eb, value, toLower = true) {
764
+ prepStringCasing(eb, value, mode) {
765
+ if (!mode || mode === "default") {
766
+ return value === null ? value : sql.val(value);
767
+ }
522
768
  if (typeof value === "string") {
523
- return toLower ? eb.fn("lower", [
524
- sql.lit(value)
525
- ]) : sql.lit(value);
769
+ return eb.fn("lower", [
770
+ sql.val(value)
771
+ ]);
526
772
  } else if (Array.isArray(value)) {
527
- return value.map((v) => this.prepStringCasing(eb, v, toLower));
773
+ return value.map((v) => this.prepStringCasing(eb, v, mode));
528
774
  } else {
529
- return value === null ? null : sql.lit(value);
775
+ return value === null ? null : sql.val(value);
530
776
  }
531
777
  }
532
- buildNumberFilter(eb, model, table, field, type, payload) {
533
- 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));
778
+ buildNumberFilter(eb, fieldRef, type, payload) {
779
+ const { conditions } = this.buildStandardFilter(eb, type, payload, fieldRef, (value) => this.transformPrimitive(value, type, false), (value) => this.buildNumberFilter(eb, fieldRef, type, value));
534
780
  return this.and(eb, ...conditions);
535
781
  }
536
- buildBooleanFilter(eb, table, field, payload) {
537
- const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Boolean"), (value) => this.buildBooleanFilter(eb, table, field, value), true, [
782
+ buildBooleanFilter(eb, fieldRef, payload) {
783
+ const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, fieldRef, (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, fieldRef, value), true, [
538
784
  "equals",
539
785
  "not"
540
786
  ]);
541
787
  return this.and(eb, ...conditions);
542
788
  }
543
- buildDateTimeFilter(eb, table, field, payload) {
544
- const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "DateTime"), (value) => this.buildDateTimeFilter(eb, table, field, value), true);
789
+ buildDateTimeFilter(eb, fieldRef, payload) {
790
+ const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, fieldRef, (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, fieldRef, value), true);
545
791
  return this.and(eb, ...conditions);
546
792
  }
547
- buildBytesFilter(eb, table, field, payload) {
548
- const conditions = this.buildStandardFilter(eb, "Bytes", payload, sql.ref(`${table}.${field}`), (value) => this.transformPrimitive(value, "Bytes"), (value) => this.buildBytesFilter(eb, table, field, value), true, [
793
+ buildBytesFilter(eb, fieldRef, payload) {
794
+ const conditions = this.buildStandardFilter(eb, "Bytes", payload, fieldRef, (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, fieldRef, value), true, [
549
795
  "equals",
550
796
  "in",
551
797
  "notIn",
@@ -553,8 +799,8 @@ var BaseCrudDialect = class {
553
799
  ]);
554
800
  return this.and(eb, ...conditions.conditions);
555
801
  }
556
- buildEnumFilter(eb, table, field, fieldDef, payload) {
557
- const conditions = this.buildStandardFilter(eb, "String", payload, sql.ref(`${table}.${field}`), (value) => value, (value) => this.buildEnumFilter(eb, table, field, fieldDef, value), true, [
802
+ buildEnumFilter(eb, fieldRef, fieldDef, payload) {
803
+ const conditions = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => value, (value) => this.buildEnumFilter(eb, fieldRef, fieldDef, value), true, [
558
804
  "equals",
559
805
  "in",
560
806
  "notIn",
@@ -586,9 +832,7 @@ var BaseCrudDialect = class {
586
832
  invariant(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
587
833
  for (const [k, v] of Object.entries(value)) {
588
834
  invariant(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
589
- result = result.orderBy((eb) => eb.fn(field.slice(1), [
590
- sql.ref(k)
591
- ]), sql.raw(this.negateSort(v, negated)));
835
+ result = result.orderBy((eb) => aggregate(eb, this.fieldRef(model, k, eb, modelAlias), field), sql.raw(this.negateSort(v, negated)));
592
836
  }
593
837
  continue;
594
838
  }
@@ -597,7 +841,7 @@ var BaseCrudDialect = class {
597
841
  invariant(value && typeof value === "object", 'invalid orderBy value for field "_count"');
598
842
  for (const [k, v] of Object.entries(value)) {
599
843
  invariant(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
600
- result = result.orderBy((eb) => eb.fn.count(sql.ref(k)), sql.raw(this.negateSort(v, negated)));
844
+ result = result.orderBy((eb) => eb.fn.count(this.fieldRef(model, k, eb, modelAlias)), sql.raw(this.negateSort(v, negated)));
601
845
  }
602
846
  continue;
603
847
  }
@@ -606,10 +850,11 @@ var BaseCrudDialect = class {
606
850
  }
607
851
  const fieldDef = requireField(this.schema, model, field);
608
852
  if (!fieldDef.relation) {
853
+ const fieldRef = this.fieldRef(model, field, expressionBuilder(), modelAlias);
609
854
  if (value === "asc" || value === "desc") {
610
- result = result.orderBy(sql.ref(`${modelAlias}.${field}`), this.negateSort(value, negated));
855
+ result = result.orderBy(fieldRef, this.negateSort(value, negated));
611
856
  } else if (value && typeof value === "object" && "nulls" in value && "sort" in value && (value.sort === "asc" || value.sort === "desc") && (value.nulls === "first" || value.nulls === "last")) {
612
- result = result.orderBy(sql.ref(`${modelAlias}.${field}`), sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`));
857
+ result = result.orderBy(fieldRef, sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`));
613
858
  }
614
859
  } else {
615
860
  const relationModel = fieldDef.type;
@@ -621,8 +866,9 @@ var BaseCrudDialect = class {
621
866
  invariant(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
622
867
  const sort = this.negateSort(value._count, negated);
623
868
  result = result.orderBy((eb) => {
624
- let subQuery = eb.selectFrom(relationModel);
625
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, relationModel);
869
+ const subQueryAlias = `${modelAlias}$orderBy$${field}$count`;
870
+ let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
871
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
626
872
  subQuery = subQuery.where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql.ref(left), "=", sql.ref(right)))));
627
873
  subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
628
874
  return subQuery;
@@ -640,14 +886,100 @@ var BaseCrudDialect = class {
640
886
  });
641
887
  return result;
642
888
  }
889
+ buildSelectAllFields(model, query, omit, modelAlias) {
890
+ const modelDef = requireModel(this.schema, model);
891
+ let result = query;
892
+ for (const field of Object.keys(modelDef.fields)) {
893
+ if (isRelationField(this.schema, model, field)) {
894
+ continue;
895
+ }
896
+ if (omit?.[field] === true) {
897
+ continue;
898
+ }
899
+ result = this.buildSelectField(result, model, modelAlias, field);
900
+ }
901
+ const descendants = getDelegateDescendantModels(this.schema, model);
902
+ for (const subModel of descendants) {
903
+ result = this.buildDelegateJoin(model, modelAlias, subModel.name, result);
904
+ result = result.select((eb) => {
905
+ const jsonObject = {};
906
+ for (const field of Object.keys(subModel.fields)) {
907
+ if (isRelationField(this.schema, subModel.name, field) || isInheritedField(this.schema, subModel.name, field)) {
908
+ continue;
909
+ }
910
+ jsonObject[field] = eb.ref(`${subModel.name}.${field}`);
911
+ }
912
+ return this.buildJsonObject(eb, jsonObject).as(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`);
913
+ });
914
+ }
915
+ return result;
916
+ }
917
+ buildModelSelect(eb, model, subQueryAlias, payload, selectAllFields) {
918
+ let subQuery = this.buildSelectModel(eb, model, subQueryAlias);
919
+ if (selectAllFields) {
920
+ subQuery = this.buildSelectAllFields(model, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
921
+ }
922
+ if (payload && typeof payload === "object") {
923
+ subQuery = this.buildFilterSortTake(model, payload, subQuery, subQueryAlias);
924
+ }
925
+ return subQuery;
926
+ }
927
+ buildSelectField(query, model, modelAlias, field) {
928
+ const fieldDef = requireField(this.schema, model, field);
929
+ if (fieldDef.computed) {
930
+ return query.select((eb) => this.fieldRef(model, field, eb, modelAlias).as(field));
931
+ } else if (!fieldDef.originModel) {
932
+ return query.select(sql.ref(`${modelAlias}.${field}`).as(field));
933
+ } else {
934
+ return this.buildSelectField(query, fieldDef.originModel, fieldDef.originModel, field);
935
+ }
936
+ }
937
+ buildDelegateJoin(thisModel, thisModelAlias, otherModelAlias, query) {
938
+ const idFields = getIdFields(this.schema, thisModel);
939
+ query = query.leftJoin(otherModelAlias, (qb) => {
940
+ for (const idField of idFields) {
941
+ qb = qb.onRef(`${thisModelAlias}.${idField}`, "=", `${otherModelAlias}.${idField}`);
942
+ }
943
+ return qb;
944
+ });
945
+ return query;
946
+ }
947
+ buildCountJson(model, eb, parentAlias, payload) {
948
+ const modelDef = requireModel(this.schema, model);
949
+ const toManyRelations = Object.entries(modelDef.fields).filter(([, field]) => field.relation && field.array);
950
+ const selections = payload === true ? {
951
+ select: toManyRelations.reduce((acc, [field]) => {
952
+ acc[field] = true;
953
+ return acc;
954
+ }, {})
955
+ } : payload;
956
+ const jsonObject = {};
957
+ for (const [field, value] of Object.entries(selections.select)) {
958
+ const fieldDef = requireField(this.schema, model, field);
959
+ const fieldModel = fieldDef.type;
960
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
961
+ let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
962
+ for (const [left, right] of joinPairs) {
963
+ fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
964
+ }
965
+ if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
966
+ const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
967
+ fieldCountQuery = fieldCountQuery.where(filter);
968
+ }
969
+ jsonObject[field] = fieldCountQuery;
970
+ }
971
+ return this.buildJsonObject(eb, jsonObject);
972
+ }
973
+ // #endregion
974
+ // #region utils
643
975
  negateSort(sort, negated) {
644
976
  return negated ? sort === "asc" ? "desc" : "asc" : sort;
645
977
  }
646
978
  true(eb) {
647
- return eb.lit(this.transformPrimitive(true, "Boolean"));
979
+ return eb.lit(this.transformPrimitive(true, "Boolean", false));
648
980
  }
649
981
  false(eb) {
650
- return eb.lit(this.transformPrimitive(false, "Boolean"));
982
+ return eb.lit(this.transformPrimitive(false, "Boolean", false));
651
983
  }
652
984
  isTrue(expression) {
653
985
  const node = expression.toOperationNode();
@@ -686,6 +1018,21 @@ var BaseCrudDialect = class {
686
1018
  not(eb, ...args) {
687
1019
  return eb.not(this.and(eb, ...args));
688
1020
  }
1021
+ fieldRef(model, field, eb, modelAlias, inlineComputedField = true) {
1022
+ return buildFieldRef(this.schema, model, field, this.options, eb, modelAlias, inlineComputedField);
1023
+ }
1024
+ canJoinWithoutNestedSelect(modelDef, payload) {
1025
+ if (modelDef.computedFields) {
1026
+ return false;
1027
+ }
1028
+ if (modelDef.baseModel || modelDef.isDelegate) {
1029
+ return false;
1030
+ }
1031
+ if (typeof payload === "object" && (payload.orderBy || payload.skip !== void 0 || payload.take !== void 0 || payload.cursor || payload.distinct)) {
1032
+ return false;
1033
+ }
1034
+ return true;
1035
+ }
689
1036
  };
690
1037
 
691
1038
  // src/client/crud/dialects/postgresql.ts
@@ -696,99 +1043,123 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
696
1043
  get provider() {
697
1044
  return "postgresql";
698
1045
  }
699
- transformPrimitive(value, type) {
1046
+ transformPrimitive(value, type, forArrayField) {
700
1047
  if (value === void 0) {
701
1048
  return value;
702
1049
  }
703
1050
  if (Array.isArray(value)) {
704
- 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
+ }
705
1056
  } else {
706
- return match2(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).otherwise(() => value);
1057
+ return match3(type).with("DateTime", () => value instanceof Date ? value : typeof value === "string" ? new Date(value) : value).with("Decimal", () => value !== null ? value.toString() : value).otherwise(() => value);
707
1058
  }
708
1059
  }
709
1060
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
710
- const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload);
711
- return joinedQuery.select(`${parentAlias}$${relationField}.$j as ${relationField}`);
1061
+ const relationResultName = `${parentAlias}$${relationField}`;
1062
+ const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload, relationResultName);
1063
+ return joinedQuery.select(`${relationResultName}.$data as ${relationField}`);
712
1064
  }
713
- buildRelationJSON(model, qb, relationField, parentName, payload) {
1065
+ buildRelationJSON(model, qb, relationField, parentAlias, payload, resultName) {
714
1066
  const relationFieldDef = requireField(this.schema, model, relationField);
715
1067
  const relationModel = relationFieldDef.type;
716
1068
  return qb.leftJoinLateral((eb) => {
717
- const joinTableName = `${parentName}$${relationField}`;
718
- let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
719
- result = eb.selectFrom(() => {
720
- let subQuery = eb.selectFrom(`${relationModel}`).selectAll();
721
- if (payload && typeof payload === "object") {
722
- if (payload.where) {
723
- subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
724
- }
725
- const skip = payload.skip;
726
- let take = payload.take;
727
- let negateOrderBy = false;
728
- if (take !== void 0 && take < 0) {
729
- negateOrderBy = true;
730
- take = -take;
731
- }
732
- subQuery = this.buildSkipTake(subQuery, skip, take);
733
- subQuery = this.buildOrderBy(subQuery, relationModel, relationModel, payload.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
734
- }
735
- const m2m = getManyToManyRelation(this.schema, model, relationField);
736
- if (m2m) {
737
- const parentIds = getIdFields(this.schema, model);
738
- const relationIds = getIdFields(this.schema, relationModel);
739
- invariant2(parentIds.length === 1, "many-to-many relation must have exactly one id field");
740
- invariant2(relationIds.length === 1, "many-to-many relation must have exactly one id field");
741
- 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}`)));
742
- } else {
743
- const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, relationModel);
744
- subQuery = subQuery.where((eb2) => this.and(eb2, ...joinPairs.map(([left, right]) => eb2(sql2.ref(left), "=", sql2.ref(right)))));
745
- }
746
- return subQuery.as(joinTableName);
747
- });
748
- result = this.buildRelationObjectSelect(relationModel, relationField, relationFieldDef, result, payload, parentName);
749
- result = this.buildRelationJoins(relationModel, relationField, result, payload, parentName);
750
- return result.as(joinTableName);
1069
+ const relationSelectName = `${resultName}$sub`;
1070
+ const relationModelDef = requireModel(this.schema, relationModel);
1071
+ let tbl;
1072
+ if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1073
+ tbl = this.buildModelSelect(eb, relationModel, relationSelectName, payload, false);
1074
+ tbl = this.buildRelationJoinFilter(tbl, model, relationField, relationModel, relationSelectName, parentAlias);
1075
+ } else {
1076
+ tbl = eb.selectFrom(() => {
1077
+ let subQuery = this.buildModelSelect(eb, relationModel, `${relationSelectName}$t`, payload, true);
1078
+ subQuery = this.buildRelationJoinFilter(subQuery, model, relationField, relationModel, `${relationSelectName}$t`, parentAlias);
1079
+ return subQuery.as(relationSelectName);
1080
+ });
1081
+ }
1082
+ tbl = this.buildRelationObjectSelect(relationModel, relationSelectName, relationFieldDef, tbl, payload, resultName);
1083
+ tbl = this.buildRelationJoins(tbl, relationModel, relationSelectName, payload, resultName);
1084
+ return tbl.as(resultName);
751
1085
  }, (join) => join.onTrue());
752
1086
  }
753
- buildRelationObjectSelect(relationModel, relationField, relationFieldDef, qb, payload, parentName) {
1087
+ buildRelationJoinFilter(query, model, relationField, relationModel, relationModelAlias, parentAlias) {
1088
+ const m2m = getManyToManyRelation(this.schema, model, relationField);
1089
+ if (m2m) {
1090
+ const parentIds = getIdFields(this.schema, model);
1091
+ const relationIds = getIdFields(this.schema, relationModel);
1092
+ invariant2(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1093
+ invariant2(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1094
+ 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}`)));
1095
+ } else {
1096
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, relationField, relationModelAlias);
1097
+ query = query.where((eb) => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql2.ref(left), "=", sql2.ref(right)))));
1098
+ }
1099
+ return query;
1100
+ }
1101
+ buildRelationObjectSelect(relationModel, relationModelAlias, relationFieldDef, qb, payload, parentResultName) {
754
1102
  qb = qb.select((eb) => {
755
- const objArgs = this.buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName);
1103
+ const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName);
756
1104
  if (relationFieldDef.array) {
757
- return eb.fn.coalesce(sql2`jsonb_agg(jsonb_build_object(${sql2.join(objArgs)}))`, sql2`'[]'::jsonb`).as("$j");
1105
+ return eb.fn.coalesce(sql2`jsonb_agg(jsonb_build_object(${sql2.join(objArgs)}))`, sql2`'[]'::jsonb`).as("$data");
758
1106
  } else {
759
- return sql2`jsonb_build_object(${sql2.join(objArgs)})`.as("$j");
1107
+ return sql2`jsonb_build_object(${sql2.join(objArgs)})`.as("$data");
760
1108
  }
761
1109
  });
762
1110
  return qb;
763
1111
  }
764
- buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName) {
1112
+ buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName) {
765
1113
  const relationModelDef = requireModel(this.schema, relationModel);
766
1114
  const objArgs = [];
1115
+ const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1116
+ if (descendantModels.length > 0) {
1117
+ objArgs.push(...descendantModels.map((subModel) => [
1118
+ sql2.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1119
+ eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1120
+ ]).flatMap((v) => v));
1121
+ }
767
1122
  if (payload === true || !payload.select) {
768
1123
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
769
1124
  sql2.lit(field),
770
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
1125
+ this.fieldRef(relationModel, field, eb, relationModelAlias, false)
771
1126
  ]).flatMap((v) => v));
772
1127
  } else if (payload.select) {
773
- objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => [
774
- sql2.lit(field),
775
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
776
- ]).flatMap((v) => v));
1128
+ objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1129
+ if (field === "_count") {
1130
+ const subJson = this.buildCountJson(relationModel, eb, relationModelAlias, value);
1131
+ return [
1132
+ sql2.lit(field),
1133
+ subJson
1134
+ ];
1135
+ } else {
1136
+ const fieldDef = requireField(this.schema, relationModel, field);
1137
+ const fieldValue = fieldDef.relation ? eb.ref(`${parentResultName}$${field}.$data`) : this.fieldRef(relationModel, field, eb, relationModelAlias, false);
1138
+ return [
1139
+ sql2.lit(field),
1140
+ fieldValue
1141
+ ];
1142
+ }
1143
+ }).flatMap((v) => v));
777
1144
  }
778
1145
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
779
1146
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
780
1147
  sql2.lit(field),
781
- eb.ref(`${parentName}$${relationField}$${field}.$j`)
1148
+ // reference the synthesized JSON field
1149
+ eb.ref(`${parentResultName}$${field}.$data`)
782
1150
  ]).flatMap((v) => v));
783
1151
  }
784
1152
  return objArgs;
785
1153
  }
786
- buildRelationJoins(model, relationField, qb, payload, parentName) {
787
- let result = qb;
788
- if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
789
- Object.entries(payload.include).filter(([, value]) => value).forEach(([field, value]) => {
790
- result = this.buildRelationJSON(model, result, field, `${parentName}$${relationField}`, value);
791
- });
1154
+ buildRelationJoins(query, relationModel, relationModelAlias, payload, parentResultName) {
1155
+ let result = query;
1156
+ if (typeof payload === "object") {
1157
+ const selectInclude = payload.include ?? payload.select;
1158
+ if (selectInclude && typeof selectInclude === "object") {
1159
+ Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
1160
+ result = this.buildRelationJSON(relationModel, result, field, relationModelAlias, value, `${parentResultName}$${field}`);
1161
+ });
1162
+ }
792
1163
  }
793
1164
  return result;
794
1165
  }
@@ -828,12 +1199,15 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
828
1199
  return `ARRAY[${values.map((v) => typeof v === "string" ? `'${v}'` : v)}]`;
829
1200
  }
830
1201
  }
1202
+ get supportInsertWithDefault() {
1203
+ return true;
1204
+ }
831
1205
  };
832
1206
 
833
1207
  // src/client/crud/dialects/sqlite.ts
834
1208
  import { invariant as invariant3 } from "@zenstackhq/common-helpers";
835
1209
  import { sql as sql3 } from "kysely";
836
- import { match as match3 } from "ts-pattern";
1210
+ import { match as match4 } from "ts-pattern";
837
1211
  var SqliteCrudDialect = class extends BaseCrudDialect {
838
1212
  static {
839
1213
  __name(this, "SqliteCrudDialect");
@@ -841,86 +1215,82 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
841
1215
  get provider() {
842
1216
  return "sqlite";
843
1217
  }
844
- transformPrimitive(value, type) {
1218
+ transformPrimitive(value, type, _forArrayField) {
845
1219
  if (value === void 0) {
846
1220
  return value;
847
1221
  }
848
1222
  if (Array.isArray(value)) {
849
- return value.map((v) => this.transformPrimitive(v, type));
1223
+ return value.map((v) => this.transformPrimitive(v, type, false));
850
1224
  } else {
851
- return match3(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).otherwise(() => value);
1225
+ if (this.schema.typeDefs && type in this.schema.typeDefs) {
1226
+ return JSON.stringify(value);
1227
+ } else {
1228
+ return match4(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).with("Json", () => JSON.stringify(value)).otherwise(() => value);
1229
+ }
852
1230
  }
853
1231
  }
854
1232
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
855
1233
  return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
856
1234
  }
857
- buildRelationJSON(model, eb, relationField, parentName, payload) {
1235
+ buildRelationJSON(model, eb, relationField, parentAlias, payload) {
858
1236
  const relationFieldDef = requireField(this.schema, model, relationField);
859
1237
  const relationModel = relationFieldDef.type;
860
1238
  const relationModelDef = requireModel(this.schema, relationModel);
861
- const subQueryName = `${parentName}$${relationField}`;
862
- let tbl = eb.selectFrom(() => {
863
- let subQuery = eb.selectFrom(relationModel).selectAll();
864
- if (payload && typeof payload === "object") {
865
- if (payload.where) {
866
- subQuery = subQuery.where((eb2) => this.buildFilter(eb2, relationModel, relationModel, payload.where));
867
- }
868
- const skip = payload.skip;
869
- let take = payload.take;
870
- let negateOrderBy = false;
871
- if (take !== void 0 && take < 0) {
872
- negateOrderBy = true;
873
- take = -take;
874
- }
875
- subQuery = this.buildSkipTake(subQuery, skip, take);
876
- subQuery = this.buildOrderBy(subQuery, relationModel, relationModel, payload.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
877
- }
878
- const m2m = getManyToManyRelation(this.schema, model, relationField);
879
- if (m2m) {
880
- const parentIds = getIdFields(this.schema, model);
881
- const relationIds = getIdFields(this.schema, relationModel);
882
- invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
883
- invariant3(relationIds.length === 1, "many-to-many relation must have exactly one id field");
884
- 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}`)));
885
- } else {
886
- const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
887
- keyPairs.forEach(({ fk, pk }) => {
888
- if (ownedByModel) {
889
- subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentName}.${fk}`);
890
- } else {
891
- subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentName}.${pk}`);
892
- }
893
- });
894
- }
895
- return subQuery.as(subQueryName);
896
- });
1239
+ const subQueryName = `${parentAlias}$${relationField}`;
1240
+ let tbl;
1241
+ if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1242
+ tbl = this.buildModelSelect(eb, relationModel, subQueryName, payload, false);
1243
+ tbl = this.buildRelationJoinFilter(tbl, model, relationField, subQueryName, parentAlias);
1244
+ } else {
1245
+ tbl = eb.selectFrom(() => {
1246
+ const selectModelAlias = `${parentAlias}$${relationField}$sub`;
1247
+ let selectModelQuery = this.buildModelSelect(eb, relationModel, selectModelAlias, payload, true);
1248
+ selectModelQuery = this.buildRelationJoinFilter(selectModelQuery, model, relationField, selectModelAlias, parentAlias);
1249
+ return selectModelQuery.as(subQueryName);
1250
+ });
1251
+ }
897
1252
  tbl = tbl.select(() => {
898
1253
  const objArgs = [];
1254
+ const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1255
+ if (descendantModels.length > 0) {
1256
+ objArgs.push(...descendantModels.map((subModel) => [
1257
+ sql3.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1258
+ eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1259
+ ]).flatMap((v) => v));
1260
+ }
899
1261
  if (payload === true || !payload.select) {
900
1262
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
901
1263
  sql3.lit(field),
902
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
1264
+ this.fieldRef(relationModel, field, eb, subQueryName, false)
903
1265
  ]).flatMap((v) => v));
904
1266
  } else if (payload.select) {
905
1267
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
906
- const fieldDef = requireField(this.schema, relationModel, field);
907
- if (fieldDef.relation) {
908
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1268
+ if (field === "_count") {
1269
+ const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
909
1270
  return [
910
1271
  sql3.lit(field),
911
1272
  subJson
912
1273
  ];
913
1274
  } else {
914
- return [
915
- sql3.lit(field),
916
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
917
- ];
1275
+ const fieldDef = requireField(this.schema, relationModel, field);
1276
+ if (fieldDef.relation) {
1277
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
1278
+ return [
1279
+ sql3.lit(field),
1280
+ subJson
1281
+ ];
1282
+ } else {
1283
+ return [
1284
+ sql3.lit(field),
1285
+ this.fieldRef(relationModel, field, eb, subQueryName, false)
1286
+ ];
1287
+ }
918
1288
  }
919
1289
  }).flatMap((v) => v));
920
1290
  }
921
1291
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
922
1292
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
923
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1293
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
924
1294
  return [
925
1295
  sql3.lit(field),
926
1296
  subJson
@@ -928,13 +1298,35 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
928
1298
  }).flatMap((v) => v));
929
1299
  }
930
1300
  if (relationFieldDef.array) {
931
- return eb.fn.coalesce(sql3`json_group_array(json_object(${sql3.join(objArgs)}))`, sql3`json_array()`).as("$j");
1301
+ return eb.fn.coalesce(sql3`json_group_array(json_object(${sql3.join(objArgs)}))`, sql3`json_array()`).as("$data");
932
1302
  } else {
933
- return sql3`json_object(${sql3.join(objArgs)})`.as("data");
1303
+ return sql3`json_object(${sql3.join(objArgs)})`.as("$data");
934
1304
  }
935
1305
  });
936
1306
  return tbl;
937
1307
  }
1308
+ buildRelationJoinFilter(selectModelQuery, model, relationField, relationModelAlias, parentAlias) {
1309
+ const fieldDef = requireField(this.schema, model, relationField);
1310
+ const relationModel = fieldDef.type;
1311
+ const m2m = getManyToManyRelation(this.schema, model, relationField);
1312
+ if (m2m) {
1313
+ const parentIds = getIdFields(this.schema, model);
1314
+ const relationIds = getIdFields(this.schema, relationModel);
1315
+ invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1316
+ invariant3(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1317
+ 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}`)));
1318
+ } else {
1319
+ const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1320
+ keyPairs.forEach(({ fk, pk }) => {
1321
+ if (ownedByModel) {
1322
+ selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${pk}`, "=", `${parentAlias}.${fk}`);
1323
+ } else {
1324
+ selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${fk}`, "=", `${parentAlias}.${pk}`);
1325
+ }
1326
+ });
1327
+ }
1328
+ return selectModelQuery;
1329
+ }
938
1330
  buildSkipTake(query, skip, take) {
939
1331
  if (take !== void 0) {
940
1332
  query = query.limit(take);
@@ -970,93 +1362,17 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
970
1362
  buildArrayLiteralSQL(_values) {
971
1363
  throw new Error("SQLite does not support array literals");
972
1364
  }
1365
+ get supportInsertWithDefault() {
1366
+ return false;
1367
+ }
973
1368
  };
974
1369
 
975
1370
  // src/client/crud/dialects/index.ts
976
1371
  function getCrudDialect(schema, options) {
977
- return match4(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
1372
+ return match5(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
978
1373
  }
979
1374
  __name(getCrudDialect, "getCrudDialect");
980
1375
 
981
- // src/schema/expression.ts
982
- var ExpressionUtils = {
983
- literal: /* @__PURE__ */ __name((value) => {
984
- return {
985
- kind: "literal",
986
- value
987
- };
988
- }, "literal"),
989
- array: /* @__PURE__ */ __name((items) => {
990
- return {
991
- kind: "array",
992
- items
993
- };
994
- }, "array"),
995
- call: /* @__PURE__ */ __name((functionName, args) => {
996
- return {
997
- kind: "call",
998
- function: functionName,
999
- args
1000
- };
1001
- }, "call"),
1002
- binary: /* @__PURE__ */ __name((left, op, right) => {
1003
- return {
1004
- kind: "binary",
1005
- op,
1006
- left,
1007
- right
1008
- };
1009
- }, "binary"),
1010
- unary: /* @__PURE__ */ __name((op, operand) => {
1011
- return {
1012
- kind: "unary",
1013
- op,
1014
- operand
1015
- };
1016
- }, "unary"),
1017
- field: /* @__PURE__ */ __name((field) => {
1018
- return {
1019
- kind: "field",
1020
- field
1021
- };
1022
- }, "field"),
1023
- member: /* @__PURE__ */ __name((receiver, members) => {
1024
- return {
1025
- kind: "member",
1026
- receiver,
1027
- members
1028
- };
1029
- }, "member"),
1030
- _this: /* @__PURE__ */ __name(() => {
1031
- return {
1032
- kind: "this"
1033
- };
1034
- }, "_this"),
1035
- _null: /* @__PURE__ */ __name(() => {
1036
- return {
1037
- kind: "null"
1038
- };
1039
- }, "_null"),
1040
- and: /* @__PURE__ */ __name((expr2, ...expressions) => {
1041
- return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
1042
- }, "and"),
1043
- or: /* @__PURE__ */ __name((expr2, ...expressions) => {
1044
- return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
1045
- }, "or"),
1046
- is: /* @__PURE__ */ __name((value, kind) => {
1047
- return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
1048
- }, "is"),
1049
- isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
1050
- isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
1051
- isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
1052
- isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
1053
- isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
1054
- isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
1055
- isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
1056
- isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
1057
- isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
1058
- };
1059
-
1060
1376
  // src/utils/default-operation-node-visitor.ts
1061
1377
  import { OperationNodeVisitor } from "kysely";
1062
1378
  var DefaultOperationNodeVisitor = class extends OperationNodeVisitor {
@@ -1377,18 +1693,18 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
1377
1693
 
1378
1694
  // src/plugins/policy/expression-transformer.ts
1379
1695
  import { invariant as invariant5 } from "@zenstackhq/common-helpers";
1380
- import { AliasNode as AliasNode2, BinaryOperationNode as BinaryOperationNode2, ColumnNode, expressionBuilder, FromNode, FunctionNode as FunctionNode2, IdentifierNode, OperatorNode as OperatorNode2, ReferenceNode as ReferenceNode2, SelectionNode, SelectQueryNode, TableNode as TableNode2, ValueListNode, ValueNode as ValueNode2, WhereNode } from "kysely";
1381
- import { match as match6 } from "ts-pattern";
1696
+ import { AliasNode as AliasNode2, BinaryOperationNode as BinaryOperationNode2, ColumnNode, expressionBuilder as expressionBuilder2, FromNode, FunctionNode as FunctionNode2, IdentifierNode, OperatorNode as OperatorNode2, ReferenceNode as ReferenceNode2, SelectionNode, SelectQueryNode, TableNode as TableNode2, ValueListNode, ValueNode as ValueNode2, WhereNode } from "kysely";
1697
+ import { match as match7 } from "ts-pattern";
1382
1698
 
1383
1699
  // src/plugins/policy/expression-evaluator.ts
1384
1700
  import { invariant as invariant4 } from "@zenstackhq/common-helpers";
1385
- import { match as match5 } from "ts-pattern";
1701
+ import { match as match6 } from "ts-pattern";
1386
1702
  var ExpressionEvaluator = class {
1387
1703
  static {
1388
1704
  __name(this, "ExpressionEvaluator");
1389
1705
  }
1390
1706
  evaluate(expression, context) {
1391
- const result = match5(expression).when(ExpressionUtils.isArray, (expr2) => this.evaluateArray(expr2, context)).when(ExpressionUtils.isBinary, (expr2) => this.evaluateBinary(expr2, context)).when(ExpressionUtils.isField, (expr2) => this.evaluateField(expr2, context)).when(ExpressionUtils.isLiteral, (expr2) => this.evaluateLiteral(expr2)).when(ExpressionUtils.isMember, (expr2) => this.evaluateMember(expr2, context)).when(ExpressionUtils.isUnary, (expr2) => this.evaluateUnary(expr2, context)).when(ExpressionUtils.isCall, (expr2) => this.evaluateCall(expr2, context)).when(ExpressionUtils.isThis, () => context.thisValue).when(ExpressionUtils.isNull, () => null).exhaustive();
1707
+ const result = match6(expression).when(ExpressionUtils.isArray, (expr2) => this.evaluateArray(expr2, context)).when(ExpressionUtils.isBinary, (expr2) => this.evaluateBinary(expr2, context)).when(ExpressionUtils.isField, (expr2) => this.evaluateField(expr2, context)).when(ExpressionUtils.isLiteral, (expr2) => this.evaluateLiteral(expr2)).when(ExpressionUtils.isMember, (expr2) => this.evaluateMember(expr2, context)).when(ExpressionUtils.isUnary, (expr2) => this.evaluateUnary(expr2, context)).when(ExpressionUtils.isCall, (expr2) => this.evaluateCall(expr2, context)).when(ExpressionUtils.isThis, () => context.thisValue).when(ExpressionUtils.isNull, () => null).exhaustive();
1392
1708
  return result ?? null;
1393
1709
  }
1394
1710
  evaluateCall(expr2, context) {
@@ -1399,7 +1715,7 @@ var ExpressionEvaluator = class {
1399
1715
  }
1400
1716
  }
1401
1717
  evaluateUnary(expr2, context) {
1402
- return match5(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
1718
+ return match6(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
1403
1719
  }
1404
1720
  evaluateMember(expr2, context) {
1405
1721
  let val = this.evaluate(expr2.receiver, context);
@@ -1423,7 +1739,7 @@ var ExpressionEvaluator = class {
1423
1739
  }
1424
1740
  const left = this.evaluate(expr2.left, context);
1425
1741
  const right = this.evaluate(expr2.right, context);
1426
- return match5(expr2.op).with("==", () => left === right).with("!=", () => left !== right).with(">", () => left > right).with(">=", () => left >= right).with("<", () => left < right).with("<=", () => left <= right).with("&&", () => left && right).with("||", () => left || right).with("in", () => {
1742
+ return match6(expr2.op).with("==", () => left === right).with("!=", () => left !== right).with(">", () => left > right).with(">=", () => left >= right).with("<", () => left < right).with("<=", () => left <= right).with("&&", () => left && right).with("||", () => left || right).with("in", () => {
1427
1743
  const _right = right ?? [];
1428
1744
  invariant4(Array.isArray(_right), 'expected array for "in" operator');
1429
1745
  return _right.includes(left);
@@ -1437,7 +1753,7 @@ var ExpressionEvaluator = class {
1437
1753
  return false;
1438
1754
  }
1439
1755
  invariant4(Array.isArray(left), "expected array");
1440
- return match5(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1756
+ return match6(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1441
1757
  ...context,
1442
1758
  thisValue: item
1443
1759
  }))).with("!", () => left.every((item) => this.evaluate(expr2.right, {
@@ -1453,11 +1769,11 @@ var ExpressionEvaluator = class {
1453
1769
  // src/plugins/policy/utils.ts
1454
1770
  import { AliasNode, AndNode, BinaryOperationNode, FunctionNode, OperatorNode, OrNode, ParensNode, ReferenceNode, TableNode, UnaryOperationNode, ValueNode } from "kysely";
1455
1771
  function trueNode(dialect) {
1456
- return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean"));
1772
+ return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
1457
1773
  }
1458
1774
  __name(trueNode, "trueNode");
1459
1775
  function falseNode(dialect) {
1460
- return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean"));
1776
+ return ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
1461
1777
  }
1462
1778
  __name(falseNode, "falseNode");
1463
1779
  function isTrueNode(node) {
@@ -1691,7 +2007,7 @@ var ExpressionTransformer = class {
1691
2007
  const count = FunctionNode2.create("count", [
1692
2008
  ValueNode2.createImmediate(1)
1693
2009
  ]);
1694
- const predicateResult = match6(expr2.op).with("?", () => BinaryOperationNode2.create(count, OperatorNode2.create(">"), ValueNode2.createImmediate(0))).with("!", () => BinaryOperationNode2.create(count, OperatorNode2.create("="), ValueNode2.createImmediate(0))).with("^", () => BinaryOperationNode2.create(count, OperatorNode2.create("="), ValueNode2.createImmediate(0))).exhaustive();
2010
+ const predicateResult = match7(expr2.op).with("?", () => BinaryOperationNode2.create(count, OperatorNode2.create(">"), ValueNode2.createImmediate(0))).with("!", () => BinaryOperationNode2.create(count, OperatorNode2.create("="), ValueNode2.createImmediate(0))).with("^", () => BinaryOperationNode2.create(count, OperatorNode2.create("="), ValueNode2.createImmediate(0))).exhaustive();
1695
2011
  return this.transform(expr2.left, {
1696
2012
  ...context,
1697
2013
  memberSelect: SelectionNode.create(AliasNode2.create(predicateResult, IdentifierNode.create("$t"))),
@@ -1715,14 +2031,14 @@ var ExpressionTransformer = class {
1715
2031
  }
1716
2032
  }
1717
2033
  transformValue(value, type) {
1718
- return ValueNode2.create(this.dialect.transformPrimitive(value, type) ?? null);
2034
+ return ValueNode2.create(this.dialect.transformPrimitive(value, type, false) ?? null);
1719
2035
  }
1720
2036
  _unary(expr2, context) {
1721
2037
  invariant5(expr2.op === "!", 'only "!" operator is supported');
1722
2038
  return BinaryOperationNode2.create(this.transform(expr2.operand, context), this.transformOperator("!="), trueNode(this.dialect));
1723
2039
  }
1724
2040
  transformOperator(op) {
1725
- const mappedOp = match6(op).with("==", () => "=").otherwise(() => op);
2041
+ const mappedOp = match7(op).with("==", () => "=").otherwise(() => op);
1726
2042
  return OperatorNode2.create(mappedOp);
1727
2043
  }
1728
2044
  _call(expr2, context) {
@@ -1734,7 +2050,7 @@ var ExpressionTransformer = class {
1734
2050
  if (!func) {
1735
2051
  throw new QueryError(`Function not implemented: ${expr2.function}`);
1736
2052
  }
1737
- const eb = expressionBuilder();
2053
+ const eb = expressionBuilder2();
1738
2054
  return func(eb, (expr2.args ?? []).map((arg) => this.transformCallArg(eb, arg, context)), {
1739
2055
  dialect: this.dialect,
1740
2056
  model: context.model,
@@ -1958,7 +2274,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
1958
2274
  get kysely() {
1959
2275
  return this.client.$qb;
1960
2276
  }
1961
- async handle(node, proceed, transaction) {
2277
+ async handle(node, proceed) {
1962
2278
  if (!this.isCrudQueryNode(node)) {
1963
2279
  throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
1964
2280
  }
@@ -1978,27 +2294,20 @@ var PolicyHandler = class extends OperationNodeTransformer {
1978
2294
  if (!mutationRequiresTransaction && !node.returning) {
1979
2295
  return proceed(this.transformNode(node));
1980
2296
  }
1981
- let readBackError = false;
1982
- const result = await transaction(async (txProceed) => {
1983
- if (InsertQueryNode.is(node)) {
1984
- await this.enforcePreCreatePolicy(node, txProceed);
1985
- }
1986
- const transformedNode = this.transformNode(node);
1987
- const result2 = await txProceed(transformedNode);
1988
- if (!this.onlyReturningId(node)) {
1989
- const readBackResult = await this.processReadBack(node, result2, txProceed);
1990
- if (readBackResult.rows.length !== result2.rows.length) {
1991
- readBackError = true;
1992
- }
1993
- return readBackResult;
1994
- } else {
1995
- return result2;
2297
+ if (InsertQueryNode.is(node)) {
2298
+ await this.enforcePreCreatePolicy(node, proceed);
2299
+ }
2300
+ const transformedNode = this.transformNode(node);
2301
+ const result = await proceed(transformedNode);
2302
+ if (!this.onlyReturningId(node)) {
2303
+ const readBackResult = await this.processReadBack(node, result, proceed);
2304
+ if (readBackResult.rows.length !== result.rows.length) {
2305
+ throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
1996
2306
  }
1997
- });
1998
- if (readBackError) {
1999
- throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2307
+ return readBackResult;
2308
+ } else {
2309
+ return result;
2000
2310
  }
2001
- return result;
2002
2311
  }
2003
2312
  onlyReturningId(node) {
2004
2313
  if (!node.returning) {
@@ -2059,11 +2368,11 @@ var PolicyHandler = class extends OperationNodeTransformer {
2059
2368
  if (typeof item === "object" && item && "kind" in item) {
2060
2369
  invariant6(item.kind === "ValueNode", "expecting a ValueNode");
2061
2370
  result.push({
2062
- node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type)),
2371
+ node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
2063
2372
  raw: item.value
2064
2373
  });
2065
2374
  } else {
2066
- const value = this.dialect.transformPrimitive(item, fieldDef.type);
2375
+ const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
2067
2376
  if (Array.isArray(value)) {
2068
2377
  result.push({
2069
2378
  node: RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
@@ -2132,7 +2441,7 @@ var PolicyHandler = class extends OperationNodeTransformer {
2132
2441
  return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => BinaryOperationNode3.create(ColumnNode2.create(field), OperatorNode3.create("="), ValueNode3.create(row[field]))))));
2133
2442
  }
2134
2443
  getMutationModel(node) {
2135
- const r = match7(node).when(InsertQueryNode.is, (node2) => getTableName(node2.into)).when(UpdateQueryNode.is, (node2) => getTableName(node2.table)).when(DeleteQueryNode.is, (node2) => {
2444
+ const r = match8(node).when(InsertQueryNode.is, (node2) => getTableName(node2.into)).when(UpdateQueryNode.is, (node2) => getTableName(node2.table)).when(DeleteQueryNode.is, (node2) => {
2136
2445
  if (node2.from.froms.length !== 1) {
2137
2446
  throw new InternalError("Only one from table is supported for delete");
2138
2447
  }
@@ -2294,13 +2603,22 @@ var PolicyPlugin = class {
2294
2603
  get description() {
2295
2604
  return "Enforces access policies defined in the schema.";
2296
2605
  }
2297
- onKyselyQuery({ query, client, proceed, transaction }) {
2606
+ onKyselyQuery({
2607
+ query,
2608
+ client,
2609
+ proceed
2610
+ /*, transaction*/
2611
+ }) {
2298
2612
  const handler = new PolicyHandler(client);
2299
- return handler.handle(query, proceed, transaction);
2613
+ return handler.handle(
2614
+ query,
2615
+ proceed
2616
+ /*, transaction*/
2617
+ );
2300
2618
  }
2301
2619
  };
2302
2620
  export {
2303
2621
  PolicyPlugin,
2304
2622
  RejectedByPolicyError
2305
2623
  };
2306
- //# sourceMappingURL=policy.js.map
2624
+ //# sourceMappingURL=index.js.map