@zenstackhq/runtime 3.0.0-beta.3 → 3.0.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,13 +7,14 @@ var __export = (target, all) => {
7
7
 
8
8
  // src/client/client-impl.ts
9
9
  import { invariant as invariant15 } from "@zenstackhq/common-helpers";
10
- import { CompiledQuery, DefaultConnectionProvider, DefaultQueryExecutor as DefaultQueryExecutor2, Kysely, Log, sql as sql9, Transaction } from "kysely";
10
+ import { CompiledQuery, DefaultConnectionProvider, DefaultQueryExecutor as DefaultQueryExecutor2, Kysely, Log, sql as sql10, Transaction } from "kysely";
11
11
 
12
12
  // src/client/crud/operations/aggregate.ts
13
- import { sql as sql5 } from "kysely";
13
+ import { sql as sql6 } from "kysely";
14
14
  import { match as match10 } from "ts-pattern";
15
15
 
16
16
  // src/client/query-utils.ts
17
+ import { invariant } from "@zenstackhq/common-helpers";
17
18
  import { match } from "ts-pattern";
18
19
 
19
20
  // src/schema/expression.ts
@@ -81,6 +82,9 @@ var ExpressionUtils = {
81
82
  or: /* @__PURE__ */ __name((expr2, ...expressions) => {
82
83
  return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
83
84
  }, "or"),
85
+ not: /* @__PURE__ */ __name((expr2) => {
86
+ return ExpressionUtils.unary("!", expr2);
87
+ }, "not"),
84
88
  is: /* @__PURE__ */ __name((value, kind) => {
85
89
  return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
86
90
  }, "is"),
@@ -141,22 +145,26 @@ var NotFoundError = class extends Error {
141
145
  static {
142
146
  __name(this, "NotFoundError");
143
147
  }
144
- constructor(model) {
145
- super(`Entity not found for model "${model}"`);
148
+ constructor(model, details) {
149
+ super(`Entity not found for model "${model}"${details ? `: ${details}` : ""}`);
146
150
  }
147
151
  };
148
152
 
149
153
  // src/client/query-utils.ts
150
154
  function getModel(schema, model) {
151
- return schema.models[model];
155
+ return Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase());
152
156
  }
153
157
  __name(getModel, "getModel");
158
+ function getTypeDef(schema, type) {
159
+ return schema.typeDefs?.[type];
160
+ }
161
+ __name(getTypeDef, "getTypeDef");
154
162
  function requireModel(schema, model) {
155
- const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
156
- if (!matchedName) {
163
+ const modelDef = getModel(schema, model);
164
+ if (!modelDef) {
157
165
  throw new QueryError(`Model "${model}" not found in schema`);
158
166
  }
159
- return schema.models[matchedName];
167
+ return modelDef;
160
168
  }
161
169
  __name(requireModel, "requireModel");
162
170
  function getField(schema, model, field) {
@@ -164,19 +172,40 @@ function getField(schema, model, field) {
164
172
  return modelDef?.fields[field];
165
173
  }
166
174
  __name(getField, "getField");
167
- function requireField(schema, model, field) {
168
- const modelDef = requireModel(schema, model);
169
- if (!modelDef.fields[field]) {
170
- throw new QueryError(`Field "${field}" not found in model "${model}"`);
175
+ function requireField(schema, modelOrType, field) {
176
+ const modelDef = getModel(schema, modelOrType);
177
+ if (modelDef) {
178
+ if (!modelDef.fields[field]) {
179
+ throw new QueryError(`Field "${field}" not found in model "${modelOrType}"`);
180
+ } else {
181
+ return modelDef.fields[field];
182
+ }
171
183
  }
172
- return modelDef.fields[field];
184
+ const typeDef = getTypeDef(schema, modelOrType);
185
+ if (typeDef) {
186
+ if (!typeDef.fields[field]) {
187
+ throw new QueryError(`Field "${field}" not found in type "${modelOrType}"`);
188
+ } else {
189
+ return typeDef.fields[field];
190
+ }
191
+ }
192
+ throw new QueryError(`Model or type "${modelOrType}" not found in schema`);
173
193
  }
174
194
  __name(requireField, "requireField");
175
195
  function getIdFields(schema, model) {
176
- const modelDef = requireModel(schema, model);
196
+ const modelDef = getModel(schema, model);
177
197
  return modelDef?.idFields;
178
198
  }
179
199
  __name(getIdFields, "getIdFields");
200
+ function requireIdFields(schema, model) {
201
+ const modelDef = requireModel(schema, model);
202
+ const result = modelDef?.idFields;
203
+ if (!result) {
204
+ throw new InternalError(`Model "${model}" does not have ID field(s)`);
205
+ }
206
+ return result;
207
+ }
208
+ __name(requireIdFields, "requireIdFields");
180
209
  function getRelationForeignKeyFieldPairs(schema, model, relationField) {
181
210
  const fieldDef = requireField(schema, model, relationField);
182
211
  if (!fieldDef?.relation) {
@@ -290,7 +319,7 @@ function buildFieldRef(schema, model, field, options, eb, modelAlias, inlineComp
290
319
  throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
291
320
  }
292
321
  return computer(eb, {
293
- currentModel: modelAlias
322
+ modelAlias
294
323
  });
295
324
  }
296
325
  }
@@ -325,7 +354,7 @@ function buildJoinPairs(schema, model, modelAlias, relationField, relationModelA
325
354
  }
326
355
  __name(buildJoinPairs, "buildJoinPairs");
327
356
  function makeDefaultOrderBy(schema, model) {
328
- const idFields = getIdFields(schema, model);
357
+ const idFields = requireIdFields(schema, model);
329
358
  return idFields.map((f) => ({
330
359
  [f]: "asc"
331
360
  }));
@@ -364,11 +393,17 @@ function getManyToManyRelation(schema, model, field) {
364
393
  "A"
365
394
  ];
366
395
  }
396
+ const modelIdFields = requireIdFields(schema, model);
397
+ invariant(modelIdFields.length === 1, "Only single-field ID is supported for many-to-many relation");
398
+ const otherIdFields = requireIdFields(schema, fieldDef.type);
399
+ invariant(otherIdFields.length === 1, "Only single-field ID is supported for many-to-many relation");
367
400
  return {
368
401
  parentFkName: orderedFK[0],
402
+ parentPKName: modelIdFields[0],
369
403
  otherModel: fieldDef.type,
370
404
  otherField: fieldDef.relation.opposite,
371
405
  otherFkName: orderedFK[1],
406
+ otherPKName: otherIdFields[0],
372
407
  joinTable: fieldDef.relation.name ? `_${fieldDef.relation.name}` : `_${sortedModelNames[0]}To${sortedModelNames[1]}`
373
408
  };
374
409
  } else {
@@ -407,7 +442,7 @@ function ensureArray(value) {
407
442
  }
408
443
  __name(ensureArray, "ensureArray");
409
444
  function extractIdFields(entity, schema, model) {
410
- const idFields = getIdFields(schema, model);
445
+ const idFields = requireIdFields(schema, model);
411
446
  return extractFields(entity, idFields);
412
447
  }
413
448
  __name(extractIdFields, "extractIdFields");
@@ -444,35 +479,94 @@ __name(aggregate, "aggregate");
444
479
 
445
480
  // src/client/crud/operations/base.ts
446
481
  import { createId } from "@paralleldrive/cuid2";
447
- import { invariant as invariant7, isPlainObject as isPlainObject3 } from "@zenstackhq/common-helpers";
448
- import { expressionBuilder as expressionBuilder3, sql as sql4 } from "kysely";
482
+ import { invariant as invariant9, isPlainObject as isPlainObject3 } from "@zenstackhq/common-helpers";
483
+ import { expressionBuilder as expressionBuilder4, sql as sql5 } from "kysely";
449
484
  import { nanoid } from "nanoid";
450
485
  import { match as match9 } from "ts-pattern";
451
486
  import { ulid } from "ulid";
452
487
  import * as uuid from "uuid";
453
488
 
454
489
  // src/plugins/policy/errors.ts
490
+ var RejectedByPolicyReason = /* @__PURE__ */ function(RejectedByPolicyReason2) {
491
+ RejectedByPolicyReason2["NO_ACCESS"] = "no-access";
492
+ RejectedByPolicyReason2["CANNOT_READ_BACK"] = "cannot-read-back";
493
+ RejectedByPolicyReason2["OTHER"] = "other";
494
+ return RejectedByPolicyReason2;
495
+ }({});
455
496
  var RejectedByPolicyError = class extends Error {
456
497
  static {
457
498
  __name(this, "RejectedByPolicyError");
458
499
  }
459
500
  model;
460
501
  reason;
461
- constructor(model, reason) {
462
- super(reason ?? `Operation rejected by policy${model ? ": " + model : ""}`), this.model = model, this.reason = reason;
502
+ constructor(model, reason = "no-access", message) {
503
+ super(message ?? `Operation rejected by policy${model ? ": " + model : ""}`), this.model = model, this.reason = reason;
463
504
  }
464
505
  };
465
506
 
507
+ // src/plugins/policy/functions.ts
508
+ import { invariant as invariant8 } from "@zenstackhq/common-helpers";
509
+ import { ExpressionWrapper as ExpressionWrapper2, ValueNode as ValueNode4 } from "kysely";
510
+
511
+ // src/client/contract.ts
512
+ var TransactionIsolationLevel = /* @__PURE__ */ function(TransactionIsolationLevel2) {
513
+ TransactionIsolationLevel2["ReadUncommitted"] = "read uncommitted";
514
+ TransactionIsolationLevel2["ReadCommitted"] = "read committed";
515
+ TransactionIsolationLevel2["RepeatableRead"] = "repeatable read";
516
+ TransactionIsolationLevel2["Serializable"] = "serializable";
517
+ TransactionIsolationLevel2["Snapshot"] = "snapshot";
518
+ return TransactionIsolationLevel2;
519
+ }({});
520
+ var CRUD = [
521
+ "create",
522
+ "read",
523
+ "update",
524
+ "delete"
525
+ ];
526
+
527
+ // src/client/kysely-utils.ts
528
+ import { AliasNode, ColumnNode, ReferenceNode, TableNode } from "kysely";
529
+ function stripAlias(node) {
530
+ if (AliasNode.is(node)) {
531
+ return {
532
+ alias: node.alias,
533
+ node: node.node
534
+ };
535
+ } else {
536
+ return {
537
+ alias: void 0,
538
+ node
539
+ };
540
+ }
541
+ }
542
+ __name(stripAlias, "stripAlias");
543
+ function extractModelName(node) {
544
+ const { node: innerNode } = stripAlias(node);
545
+ return TableNode.is(innerNode) ? innerNode.table.identifier.name : void 0;
546
+ }
547
+ __name(extractModelName, "extractModelName");
548
+ function extractFieldName(node) {
549
+ if (ReferenceNode.is(node) && ColumnNode.is(node.column)) {
550
+ return node.column.column.name;
551
+ } else if (ColumnNode.is(node)) {
552
+ return node.column.name;
553
+ } else {
554
+ return void 0;
555
+ }
556
+ }
557
+ __name(extractFieldName, "extractFieldName");
558
+
466
559
  // src/plugins/policy/policy-handler.ts
467
- import { invariant as invariant6 } from "@zenstackhq/common-helpers";
468
- 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";
560
+ import { invariant as invariant7 } from "@zenstackhq/common-helpers";
561
+ import { AliasNode as AliasNode4, BinaryOperationNode as BinaryOperationNode3, ColumnNode as ColumnNode3, DeleteQueryNode, expressionBuilder as expressionBuilder3, ExpressionWrapper, FromNode as FromNode2, FunctionNode as FunctionNode3, IdentifierNode as IdentifierNode2, InsertQueryNode, OperationNodeTransformer, OperatorNode as OperatorNode3, ParensNode as ParensNode2, PrimitiveValueListNode, RawNode, ReturningNode, SelectionNode as SelectionNode2, SelectQueryNode as SelectQueryNode2, sql as sql4, TableNode as TableNode4, UpdateQueryNode, ValueListNode as ValueListNode2, ValueNode as ValueNode3, ValuesNode, WhereNode as WhereNode2 } from "kysely";
469
562
  import { match as match8 } from "ts-pattern";
470
563
 
471
564
  // src/client/crud/dialects/index.ts
472
565
  import { match as match5 } from "ts-pattern";
473
566
 
474
567
  // src/client/crud/dialects/postgresql.ts
475
- import { invariant as invariant2 } from "@zenstackhq/common-helpers";
568
+ import { invariant as invariant3 } from "@zenstackhq/common-helpers";
569
+ import Decimal from "decimal.js";
476
570
  import { sql as sql2 } from "kysely";
477
571
  import { match as match3 } from "ts-pattern";
478
572
 
@@ -497,8 +591,8 @@ var AGGREGATE_OPERATORS = [
497
591
  "_max"
498
592
  ];
499
593
 
500
- // src/client/crud/dialects/base.ts
501
- import { invariant, isPlainObject } from "@zenstackhq/common-helpers";
594
+ // src/client/crud/dialects/base-dialect.ts
595
+ import { invariant as invariant2, isPlainObject } from "@zenstackhq/common-helpers";
502
596
  import { expressionBuilder, sql } from "kysely";
503
597
  import { match as match2, P } from "ts-pattern";
504
598
 
@@ -516,7 +610,7 @@ function enumerate(x) {
516
610
  }
517
611
  __name(enumerate, "enumerate");
518
612
 
519
- // src/client/crud/dialects/base.ts
613
+ // src/client/crud/dialects/base-dialect.ts
520
614
  var BaseCrudDialect = class {
521
615
  static {
522
616
  __name(this, "BaseCrudDialect");
@@ -530,6 +624,9 @@ var BaseCrudDialect = class {
530
624
  transformPrimitive(value, _type, _forArrayField) {
531
625
  return value;
532
626
  }
627
+ transformOutput(value, _type) {
628
+ return value;
629
+ }
533
630
  // #region common query builders
534
631
  buildSelectModel(eb, model, modelAlias) {
535
632
  const modelDef = requireModel(this.schema, model);
@@ -697,9 +794,11 @@ var BaseCrudDialect = class {
697
794
  const buildPkFkWhereRefs = /* @__PURE__ */ __name((eb2) => {
698
795
  const m2m = getManyToManyRelation(this.schema, model, field);
699
796
  if (m2m) {
700
- const modelIdField = getIdFields(this.schema, model)[0];
701
- const relationIdField = getIdFields(this.schema, relationModel)[0];
702
- 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}`)));
797
+ const modelIdFields = requireIdFields(this.schema, model);
798
+ invariant2(modelIdFields.length === 1, "many-to-many relation must have exactly one id field");
799
+ const relationIdFields = requireIdFields(this.schema, relationModel);
800
+ invariant2(relationIdFields.length === 1, "many-to-many relation must have exactly one id field");
801
+ return eb2(sql.ref(`${relationFilterSelectAlias}.${relationIdFields[0]}`), "in", eb2.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(sql.ref(`${m2m.joinTable}.${m2m.parentFkName}`), "=", sql.ref(`${modelAlias}.${modelIdFields[0]}`)));
703
802
  } else {
704
803
  const relationKeyPairs = getRelationForeignKeyFieldPairs(this.schema, model, field);
705
804
  let result2 = this.true(eb2);
@@ -809,14 +908,14 @@ var BaseCrudDialect = class {
809
908
  }
810
909
  const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
811
910
  const condition = match2(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
812
- invariant(Array.isArray(rhs), "right hand side must be an array");
911
+ invariant2(Array.isArray(rhs), "right hand side must be an array");
813
912
  if (rhs.length === 0) {
814
913
  return this.false(eb);
815
914
  } else {
816
915
  return eb(lhs, "in", rhs);
817
916
  }
818
917
  }).with("notIn", () => {
819
- invariant(Array.isArray(rhs), "right hand side must be an array");
918
+ invariant2(Array.isArray(rhs), "right hand side must be an array");
820
919
  if (rhs.length === 0) {
821
920
  return this.true(eb);
822
921
  } else {
@@ -934,18 +1033,18 @@ var BaseCrudDialect = class {
934
1033
  "_min",
935
1034
  "_max"
936
1035
  ].includes(field)) {
937
- invariant(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
1036
+ invariant2(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
938
1037
  for (const [k, v] of Object.entries(value)) {
939
- invariant(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
1038
+ invariant2(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
940
1039
  result = result.orderBy((eb) => aggregate(eb, this.fieldRef(model, k, eb, modelAlias), field), sql.raw(this.negateSort(v, negated)));
941
1040
  }
942
1041
  continue;
943
1042
  }
944
1043
  switch (field) {
945
1044
  case "_count": {
946
- invariant(value && typeof value === "object", 'invalid orderBy value for field "_count"');
1045
+ invariant2(value && typeof value === "object", 'invalid orderBy value for field "_count"');
947
1046
  for (const [k, v] of Object.entries(value)) {
948
- invariant(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
1047
+ invariant2(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
949
1048
  result = result.orderBy((eb) => eb.fn.count(this.fieldRef(model, k, eb, modelAlias)), sql.raw(this.negateSort(v, negated)));
950
1049
  }
951
1050
  continue;
@@ -968,7 +1067,7 @@ var BaseCrudDialect = class {
968
1067
  throw new QueryError(`invalid orderBy value for field "${field}"`);
969
1068
  }
970
1069
  if ("_count" in value) {
971
- invariant(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
1070
+ invariant2(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
972
1071
  const sort = this.negateSort(value._count, negated);
973
1072
  result = result.orderBy((eb) => {
974
1073
  const subQueryAlias = `${modelAlias}$orderBy$${field}$count`;
@@ -1040,7 +1139,7 @@ var BaseCrudDialect = class {
1040
1139
  }
1041
1140
  }
1042
1141
  buildDelegateJoin(thisModel, thisModelAlias, otherModelAlias, query) {
1043
- const idFields = getIdFields(this.schema, thisModel);
1142
+ const idFields = requireIdFields(this.schema, thisModel);
1044
1143
  query = query.leftJoin(otherModelAlias, (qb) => {
1045
1144
  for (const idField of idFields) {
1046
1145
  qb = qb.onRef(`${thisModelAlias}.${idField}`, "=", `${otherModelAlias}.${idField}`);
@@ -1062,10 +1161,16 @@ var BaseCrudDialect = class {
1062
1161
  for (const [field, value] of Object.entries(selections.select)) {
1063
1162
  const fieldDef = requireField(this.schema, model, field);
1064
1163
  const fieldModel = fieldDef.type;
1065
- const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
1066
- let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
1067
- for (const [left, right] of joinPairs) {
1068
- fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
1164
+ let fieldCountQuery;
1165
+ const m2m = getManyToManyRelation(this.schema, model, field);
1166
+ if (m2m) {
1167
+ fieldCountQuery = eb.selectFrom(fieldModel).innerJoin(m2m.joinTable, (join) => join.onRef(`${m2m.joinTable}.${m2m.otherFkName}`, "=", `${fieldModel}.${m2m.otherPKName}`).onRef(`${m2m.joinTable}.${m2m.parentFkName}`, "=", `${parentAlias}.${m2m.parentPKName}`)).select(eb.fn.countAll().as(`_count$${field}`));
1168
+ } else {
1169
+ fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
1170
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
1171
+ for (const [left, right] of joinPairs) {
1172
+ fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
1173
+ }
1069
1174
  }
1070
1175
  if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
1071
1176
  const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
@@ -1145,6 +1250,9 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1145
1250
  static {
1146
1251
  __name(this, "PostgresCrudDialect");
1147
1252
  }
1253
+ constructor(schema, options) {
1254
+ super(schema, options);
1255
+ }
1148
1256
  get provider() {
1149
1257
  return "postgresql";
1150
1258
  }
@@ -1159,9 +1267,41 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1159
1267
  return value.map((v) => this.transformPrimitive(v, type, false));
1160
1268
  }
1161
1269
  } else {
1162
- 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);
1270
+ return match3(type).with("DateTime", () => value instanceof Date ? value.toISOString() : typeof value === "string" ? new Date(value).toISOString() : value).with("Decimal", () => value !== null ? value.toString() : value).otherwise(() => value);
1271
+ }
1272
+ }
1273
+ transformOutput(value, type) {
1274
+ if (value === null || value === void 0) {
1275
+ return value;
1276
+ }
1277
+ return match3(type).with("DateTime", () => this.transformOutputDate(value)).with("Bytes", () => this.transformOutputBytes(value)).with("BigInt", () => this.transformOutputBigInt(value)).with("Decimal", () => this.transformDecimal(value)).otherwise(() => super.transformOutput(value, type));
1278
+ }
1279
+ transformOutputBigInt(value) {
1280
+ if (typeof value === "bigint") {
1281
+ return value;
1282
+ }
1283
+ invariant3(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
1284
+ return BigInt(value);
1285
+ }
1286
+ transformDecimal(value) {
1287
+ if (value instanceof Decimal) {
1288
+ return value;
1289
+ }
1290
+ invariant3(typeof value === "string" || typeof value === "number" || value instanceof Decimal, `Expected string, number or Decimal, got ${typeof value}`);
1291
+ return new Decimal(value);
1292
+ }
1293
+ transformOutputDate(value) {
1294
+ if (typeof value === "string") {
1295
+ return new Date(value);
1296
+ } else if (value instanceof Date && this.options.fixPostgresTimezone !== false) {
1297
+ return new Date(value.getTime() - value.getTimezoneOffset() * 60 * 1e3);
1298
+ } else {
1299
+ return value;
1163
1300
  }
1164
1301
  }
1302
+ transformOutputBytes(value) {
1303
+ return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
1304
+ }
1165
1305
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
1166
1306
  const relationResultName = `${parentAlias}$${relationField}`;
1167
1307
  const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload, relationResultName);
@@ -1192,10 +1332,10 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1192
1332
  buildRelationJoinFilter(query, model, relationField, relationModel, relationModelAlias, parentAlias) {
1193
1333
  const m2m = getManyToManyRelation(this.schema, model, relationField);
1194
1334
  if (m2m) {
1195
- const parentIds = getIdFields(this.schema, model);
1196
- const relationIds = getIdFields(this.schema, relationModel);
1197
- invariant2(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1198
- invariant2(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1335
+ const parentIds = requireIdFields(this.schema, model);
1336
+ const relationIds = requireIdFields(this.schema, relationModel);
1337
+ invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1338
+ invariant3(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1199
1339
  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}`)));
1200
1340
  } else {
1201
1341
  const joinPairs = buildJoinPairs(this.schema, model, parentAlias, relationField, relationModelAlias);
@@ -1307,10 +1447,32 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1307
1447
  get supportInsertWithDefault() {
1308
1448
  return true;
1309
1449
  }
1450
+ getFieldSqlType(fieldDef) {
1451
+ if (fieldDef.relation) {
1452
+ throw new QueryError("Cannot get SQL type of a relation field");
1453
+ }
1454
+ let result;
1455
+ if (this.schema.enums?.[fieldDef.type]) {
1456
+ result = "text";
1457
+ } else {
1458
+ result = match3(fieldDef.type).with("String", () => "text").with("Boolean", () => "boolean").with("Int", () => "integer").with("BigInt", () => "bigint").with("Float", () => "double precision").with("Decimal", () => "decimal").with("DateTime", () => "timestamp").with("Bytes", () => "bytea").with("Json", () => "jsonb").otherwise(() => "text");
1459
+ }
1460
+ if (fieldDef.array) {
1461
+ result += "[]";
1462
+ }
1463
+ return result;
1464
+ }
1465
+ getStringCasingBehavior() {
1466
+ return {
1467
+ supportsILike: true,
1468
+ likeCaseSensitive: true
1469
+ };
1470
+ }
1310
1471
  };
1311
1472
 
1312
1473
  // src/client/crud/dialects/sqlite.ts
1313
- import { invariant as invariant3 } from "@zenstackhq/common-helpers";
1474
+ import { invariant as invariant4 } from "@zenstackhq/common-helpers";
1475
+ import Decimal2 from "decimal.js";
1314
1476
  import { sql as sql3 } from "kysely";
1315
1477
  import { match as match4 } from "ts-pattern";
1316
1478
  var SqliteCrudDialect = class extends BaseCrudDialect {
@@ -1330,9 +1492,57 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1330
1492
  if (this.schema.typeDefs && type in this.schema.typeDefs) {
1331
1493
  return JSON.stringify(value);
1332
1494
  } else {
1333
- 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);
1495
+ return match4(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : typeof value === "string" ? new Date(value).toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).with("Json", () => JSON.stringify(value)).otherwise(() => value);
1496
+ }
1497
+ }
1498
+ }
1499
+ transformOutput(value, type) {
1500
+ if (value === null || value === void 0) {
1501
+ return value;
1502
+ } else if (this.schema.typeDefs && type in this.schema.typeDefs) {
1503
+ return this.transformOutputJson(value);
1504
+ } else {
1505
+ return match4(type).with("Boolean", () => this.transformOutputBoolean(value)).with("DateTime", () => this.transformOutputDate(value)).with("Bytes", () => this.transformOutputBytes(value)).with("Decimal", () => this.transformOutputDecimal(value)).with("BigInt", () => this.transformOutputBigInt(value)).with("Json", () => this.transformOutputJson(value)).otherwise(() => super.transformOutput(value, type));
1506
+ }
1507
+ }
1508
+ transformOutputDecimal(value) {
1509
+ if (value instanceof Decimal2) {
1510
+ return value;
1511
+ }
1512
+ invariant4(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
1513
+ return new Decimal2(value);
1514
+ }
1515
+ transformOutputBigInt(value) {
1516
+ if (typeof value === "bigint") {
1517
+ return value;
1518
+ }
1519
+ invariant4(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
1520
+ return BigInt(value);
1521
+ }
1522
+ transformOutputBoolean(value) {
1523
+ return !!value;
1524
+ }
1525
+ transformOutputDate(value) {
1526
+ if (typeof value === "number") {
1527
+ return new Date(value);
1528
+ } else if (typeof value === "string") {
1529
+ return new Date(value);
1530
+ } else {
1531
+ return value;
1532
+ }
1533
+ }
1534
+ transformOutputBytes(value) {
1535
+ return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
1536
+ }
1537
+ transformOutputJson(value) {
1538
+ if (typeof value === "string") {
1539
+ try {
1540
+ return JSON.parse(value);
1541
+ } catch (e) {
1542
+ throw new QueryError("Invalid JSON returned", e);
1334
1543
  }
1335
1544
  }
1545
+ return value;
1336
1546
  }
1337
1547
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
1338
1548
  return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
@@ -1415,10 +1625,10 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1415
1625
  const relationModel = fieldDef.type;
1416
1626
  const m2m = getManyToManyRelation(this.schema, model, relationField);
1417
1627
  if (m2m) {
1418
- const parentIds = getIdFields(this.schema, model);
1419
- const relationIds = getIdFields(this.schema, relationModel);
1420
- invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1421
- invariant3(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1628
+ const parentIds = requireIdFields(this.schema, model);
1629
+ const relationIds = requireIdFields(this.schema, relationModel);
1630
+ invariant4(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1631
+ invariant4(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1422
1632
  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}`)));
1423
1633
  } else {
1424
1634
  const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
@@ -1470,6 +1680,24 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1470
1680
  get supportInsertWithDefault() {
1471
1681
  return false;
1472
1682
  }
1683
+ getFieldSqlType(fieldDef) {
1684
+ if (fieldDef.relation) {
1685
+ throw new QueryError("Cannot get SQL type of a relation field");
1686
+ }
1687
+ if (fieldDef.array) {
1688
+ throw new QueryError("SQLite does not support scalar list type");
1689
+ }
1690
+ if (this.schema.enums?.[fieldDef.type]) {
1691
+ return "text";
1692
+ }
1693
+ return match4(fieldDef.type).with("String", () => "text").with("Boolean", () => "integer").with("Int", () => "integer").with("BigInt", () => "integer").with("Float", () => "real").with("Decimal", () => "decimal").with("DateTime", () => "numeric").with("Bytes", () => "blob").with("Json", () => "jsonb").otherwise(() => "text");
1694
+ }
1695
+ getStringCasingBehavior() {
1696
+ return {
1697
+ supportsILike: false,
1698
+ likeCaseSensitive: false
1699
+ };
1700
+ }
1473
1701
  };
1474
1702
 
1475
1703
  // src/client/crud/dialects/index.ts
@@ -1797,12 +2025,12 @@ var ColumnCollector = class extends DefaultOperationNodeVisitor {
1797
2025
  };
1798
2026
 
1799
2027
  // src/plugins/policy/expression-transformer.ts
1800
- import { invariant as invariant5 } from "@zenstackhq/common-helpers";
1801
- 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";
2028
+ import { invariant as invariant6 } from "@zenstackhq/common-helpers";
2029
+ import { AliasNode as AliasNode3, BinaryOperationNode as BinaryOperationNode2, ColumnNode as ColumnNode2, expressionBuilder as expressionBuilder2, FromNode, FunctionNode as FunctionNode2, IdentifierNode, OperatorNode as OperatorNode2, ReferenceNode as ReferenceNode3, SelectionNode, SelectQueryNode, TableNode as TableNode3, ValueListNode, ValueNode as ValueNode2, WhereNode } from "kysely";
1802
2030
  import { match as match7 } from "ts-pattern";
1803
2031
 
1804
2032
  // src/plugins/policy/expression-evaluator.ts
1805
- import { invariant as invariant4 } from "@zenstackhq/common-helpers";
2033
+ import { invariant as invariant5 } from "@zenstackhq/common-helpers";
1806
2034
  import { match as match6 } from "ts-pattern";
1807
2035
  var ExpressionEvaluator = class {
1808
2036
  static {
@@ -1846,18 +2074,18 @@ var ExpressionEvaluator = class {
1846
2074
  const right = this.evaluate(expr2.right, context);
1847
2075
  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", () => {
1848
2076
  const _right = right ?? [];
1849
- invariant4(Array.isArray(_right), 'expected array for "in" operator');
2077
+ invariant5(Array.isArray(_right), 'expected array for "in" operator');
1850
2078
  return _right.includes(left);
1851
2079
  }).exhaustive();
1852
2080
  }
1853
2081
  evaluateCollectionPredicate(expr2, context) {
1854
2082
  const op = expr2.op;
1855
- invariant4(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
2083
+ invariant5(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
1856
2084
  const left = this.evaluate(expr2.left, context);
1857
2085
  if (!left) {
1858
2086
  return false;
1859
2087
  }
1860
- invariant4(Array.isArray(left), "expected array");
2088
+ invariant5(Array.isArray(left), "expected array");
1861
2089
  return match6(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
1862
2090
  ...context,
1863
2091
  thisValue: item
@@ -1872,7 +2100,7 @@ var ExpressionEvaluator = class {
1872
2100
  };
1873
2101
 
1874
2102
  // src/plugins/policy/utils.ts
1875
- import { AliasNode, AndNode, BinaryOperationNode, FunctionNode, OperatorNode, OrNode, ParensNode, ReferenceNode, TableNode, UnaryOperationNode, ValueNode } from "kysely";
2103
+ import { AliasNode as AliasNode2, AndNode, BinaryOperationNode, FunctionNode, OperatorNode, OrNode, ParensNode, ReferenceNode as ReferenceNode2, TableNode as TableNode2, UnaryOperationNode, ValueNode } from "kysely";
1876
2104
  function trueNode(dialect) {
1877
2105
  return ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
1878
2106
  }
@@ -1890,6 +2118,12 @@ function isFalseNode(node) {
1890
2118
  }
1891
2119
  __name(isFalseNode, "isFalseNode");
1892
2120
  function conjunction(dialect, nodes) {
2121
+ if (nodes.length === 0) {
2122
+ return trueNode(dialect);
2123
+ }
2124
+ if (nodes.length === 1) {
2125
+ return nodes[0];
2126
+ }
1893
2127
  if (nodes.some(isFalseNode)) {
1894
2128
  return falseNode(dialect);
1895
2129
  }
@@ -1897,10 +2131,16 @@ function conjunction(dialect, nodes) {
1897
2131
  if (items.length === 0) {
1898
2132
  return trueNode(dialect);
1899
2133
  }
1900
- return items.reduce((acc, node) => OrNode.is(node) ? AndNode.create(acc, ParensNode.create(node)) : AndNode.create(acc, node));
2134
+ return items.reduce((acc, node) => AndNode.create(wrapParensIf(acc, OrNode.is), wrapParensIf(node, OrNode.is)));
1901
2135
  }
1902
2136
  __name(conjunction, "conjunction");
1903
2137
  function disjunction(dialect, nodes) {
2138
+ if (nodes.length === 0) {
2139
+ return falseNode(dialect);
2140
+ }
2141
+ if (nodes.length === 1) {
2142
+ return nodes[0];
2143
+ }
1904
2144
  if (nodes.some(isTrueNode)) {
1905
2145
  return trueNode(dialect);
1906
2146
  }
@@ -1908,13 +2148,23 @@ function disjunction(dialect, nodes) {
1908
2148
  if (items.length === 0) {
1909
2149
  return falseNode(dialect);
1910
2150
  }
1911
- return items.reduce((acc, node) => AndNode.is(node) ? OrNode.create(acc, ParensNode.create(node)) : OrNode.create(acc, node));
2151
+ return items.reduce((acc, node) => OrNode.create(wrapParensIf(acc, AndNode.is), wrapParensIf(node, AndNode.is)));
1912
2152
  }
1913
2153
  __name(disjunction, "disjunction");
1914
- function logicalNot(node) {
1915
- return UnaryOperationNode.create(OperatorNode.create("not"), AndNode.is(node) || OrNode.is(node) ? ParensNode.create(node) : node);
2154
+ function logicalNot(dialect, node) {
2155
+ if (isTrueNode(node)) {
2156
+ return falseNode(dialect);
2157
+ }
2158
+ if (isFalseNode(node)) {
2159
+ return trueNode(dialect);
2160
+ }
2161
+ return UnaryOperationNode.create(OperatorNode.create("not"), wrapParensIf(node, (n) => AndNode.is(n) || OrNode.is(n)));
1916
2162
  }
1917
2163
  __name(logicalNot, "logicalNot");
2164
+ function wrapParensIf(node, predicate) {
2165
+ return predicate(node) ? ParensNode.create(node) : node;
2166
+ }
2167
+ __name(wrapParensIf, "wrapParensIf");
1918
2168
  function buildIsFalse(node, dialect) {
1919
2169
  if (isFalseNode(node)) {
1920
2170
  return trueNode(dialect);
@@ -1936,11 +2186,11 @@ function getTableName(node) {
1936
2186
  if (!node) {
1937
2187
  return node;
1938
2188
  }
1939
- if (TableNode.is(node)) {
2189
+ if (TableNode2.is(node)) {
1940
2190
  return node.table.identifier.name;
1941
- } else if (AliasNode.is(node)) {
2191
+ } else if (AliasNode2.is(node)) {
1942
2192
  return getTableName(node.node);
1943
- } else if (ReferenceNode.is(node) && node.table) {
2193
+ } else if (ReferenceNode2.is(node) && node.table) {
1944
2194
  return getTableName(node.table);
1945
2195
  }
1946
2196
  return void 0;
@@ -1973,16 +2223,21 @@ var ExpressionTransformer = class {
1973
2223
  static {
1974
2224
  __name(this, "ExpressionTransformer");
1975
2225
  }
1976
- schema;
1977
- clientOptions;
1978
- auth;
2226
+ client;
1979
2227
  dialect;
1980
- constructor(schema, clientOptions, auth) {
1981
- this.schema = schema;
1982
- this.clientOptions = clientOptions;
1983
- this.auth = auth;
2228
+ constructor(client) {
2229
+ this.client = client;
1984
2230
  this.dialect = getCrudDialect(this.schema, this.clientOptions);
1985
2231
  }
2232
+ get schema() {
2233
+ return this.client.$schema;
2234
+ }
2235
+ get clientOptions() {
2236
+ return this.client.$options;
2237
+ }
2238
+ get auth() {
2239
+ return this.client.$auth;
2240
+ }
1986
2241
  get authType() {
1987
2242
  if (!this.schema.authType) {
1988
2243
  throw new InternalError('Schema does not have an "authType" specified');
@@ -2005,11 +2260,7 @@ var ExpressionTransformer = class {
2005
2260
  _field(expr2, context) {
2006
2261
  const fieldDef = requireField(this.schema, context.model, expr2.field);
2007
2262
  if (!fieldDef.relation) {
2008
- if (context.thisEntity) {
2009
- return context.thisEntity[expr2.field];
2010
- } else {
2011
- return this.createColumnRef(expr2.field, context);
2012
- }
2263
+ return this.createColumnRef(expr2.field, context);
2013
2264
  } else {
2014
2265
  const { memberFilter, memberSelect, ...restContext } = context;
2015
2266
  const relation = this.transformRelationAccess(expr2.field, fieldDef.type, restContext);
@@ -2050,14 +2301,15 @@ var ExpressionTransformer = class {
2050
2301
  ]);
2051
2302
  }
2052
2303
  if (this.isAuthCall(expr2.left) || this.isAuthCall(expr2.right)) {
2053
- return this.transformAuthBinary(expr2);
2304
+ return this.transformAuthBinary(expr2, context);
2054
2305
  }
2055
2306
  const op = expr2.op;
2056
2307
  if (op === "?" || op === "!" || op === "^") {
2057
2308
  return this.transformCollectionPredicate(expr2, context);
2058
2309
  }
2059
- const left = this.transform(expr2.left, context);
2060
- const right = this.transform(expr2.right, context);
2310
+ const { normalizedLeft, normalizedRight } = this.normalizeBinaryOperationOperands(expr2, context);
2311
+ const left = this.transform(normalizedLeft, context);
2312
+ const right = this.transform(normalizedRight, context);
2061
2313
  if (op === "in") {
2062
2314
  if (this.isNullNode(left)) {
2063
2315
  return this.transformValue(false, "Boolean");
@@ -2072,29 +2324,65 @@ var ExpressionTransformer = class {
2072
2324
  }
2073
2325
  }
2074
2326
  if (this.isNullNode(right)) {
2075
- return expr2.op === "==" ? BinaryOperationNode2.create(left, OperatorNode2.create("is"), right) : BinaryOperationNode2.create(left, OperatorNode2.create("is not"), right);
2327
+ return this.transformNullCheck(left, expr2.op);
2076
2328
  } else if (this.isNullNode(left)) {
2077
- return expr2.op === "==" ? BinaryOperationNode2.create(right, OperatorNode2.create("is"), ValueNode2.createImmediate(null)) : BinaryOperationNode2.create(right, OperatorNode2.create("is not"), ValueNode2.createImmediate(null));
2329
+ return this.transformNullCheck(right, expr2.op);
2330
+ } else {
2331
+ return BinaryOperationNode2.create(left, this.transformOperator(op), right);
2332
+ }
2333
+ }
2334
+ transformNullCheck(expr2, operator) {
2335
+ invariant6(operator === "==" || operator === "!=", 'operator must be "==" or "!=" for null comparison');
2336
+ if (ValueNode2.is(expr2)) {
2337
+ if (expr2.value === null) {
2338
+ return operator === "==" ? trueNode(this.dialect) : falseNode(this.dialect);
2339
+ } else {
2340
+ return operator === "==" ? falseNode(this.dialect) : trueNode(this.dialect);
2341
+ }
2342
+ } else {
2343
+ return operator === "==" ? BinaryOperationNode2.create(expr2, OperatorNode2.create("is"), ValueNode2.createImmediate(null)) : BinaryOperationNode2.create(expr2, OperatorNode2.create("is not"), ValueNode2.createImmediate(null));
2344
+ }
2345
+ }
2346
+ normalizeBinaryOperationOperands(expr2, context) {
2347
+ let normalizedLeft = expr2.left;
2348
+ if (this.isRelationField(expr2.left, context.model)) {
2349
+ invariant6(ExpressionUtils.isNull(expr2.right), "only null comparison is supported for relation field");
2350
+ const leftRelDef = this.getFieldDefFromFieldRef(expr2.left, context.model);
2351
+ invariant6(leftRelDef, "failed to get relation field definition");
2352
+ const idFields = requireIdFields(this.schema, leftRelDef.type);
2353
+ normalizedLeft = this.makeOrAppendMember(normalizedLeft, idFields[0]);
2354
+ }
2355
+ let normalizedRight = expr2.right;
2356
+ if (this.isRelationField(expr2.right, context.model)) {
2357
+ invariant6(ExpressionUtils.isNull(expr2.left), "only null comparison is supported for relation field");
2358
+ const rightRelDef = this.getFieldDefFromFieldRef(expr2.right, context.model);
2359
+ invariant6(rightRelDef, "failed to get relation field definition");
2360
+ const idFields = requireIdFields(this.schema, rightRelDef.type);
2361
+ normalizedRight = this.makeOrAppendMember(normalizedRight, idFields[0]);
2078
2362
  }
2079
- return BinaryOperationNode2.create(left, this.transformOperator(op), right);
2363
+ return {
2364
+ normalizedLeft,
2365
+ normalizedRight
2366
+ };
2080
2367
  }
2081
2368
  transformCollectionPredicate(expr2, context) {
2082
- invariant5(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
2369
+ invariant6(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
2083
2370
  if (this.isAuthCall(expr2.left) || this.isAuthMember(expr2.left)) {
2084
2371
  const value = new ExpressionEvaluator().evaluate(expr2, {
2085
2372
  auth: this.auth
2086
2373
  });
2087
2374
  return this.transformValue(value, "Boolean");
2088
2375
  }
2089
- invariant5(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
2376
+ invariant6(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
2090
2377
  let newContextModel;
2091
- if (ExpressionUtils.isField(expr2.left)) {
2092
- const fieldDef = requireField(this.schema, context.model, expr2.left.field);
2378
+ const fieldDef = this.getFieldDefFromFieldRef(expr2.left, context.model);
2379
+ if (fieldDef) {
2380
+ invariant6(fieldDef.relation, `field is not a relation: ${JSON.stringify(expr2.left)}`);
2093
2381
  newContextModel = fieldDef.type;
2094
2382
  } else {
2095
- invariant5(ExpressionUtils.isField(expr2.left.receiver));
2096
- const fieldDef = requireField(this.schema, context.model, expr2.left.receiver.field);
2097
- newContextModel = fieldDef.type;
2383
+ invariant6(ExpressionUtils.isMember(expr2.left) && ExpressionUtils.isField(expr2.left.receiver), "left operand must be member access with field receiver");
2384
+ const fieldDef2 = requireField(this.schema, context.model, expr2.left.receiver.field);
2385
+ newContextModel = fieldDef2.type;
2098
2386
  for (const member of expr2.left.members) {
2099
2387
  const memberDef = requireField(this.schema, newContextModel, member);
2100
2388
  newContextModel = memberDef.type;
@@ -2103,11 +2391,10 @@ var ExpressionTransformer = class {
2103
2391
  let predicateFilter = this.transform(expr2.right, {
2104
2392
  ...context,
2105
2393
  model: newContextModel,
2106
- alias: void 0,
2107
- thisEntity: void 0
2394
+ alias: void 0
2108
2395
  });
2109
2396
  if (expr2.op === "!") {
2110
- predicateFilter = logicalNot(predicateFilter);
2397
+ predicateFilter = logicalNot(this.dialect, predicateFilter);
2111
2398
  }
2112
2399
  const count = FunctionNode2.create("count", [
2113
2400
  ValueNode2.createImmediate(1)
@@ -2115,32 +2402,66 @@ var ExpressionTransformer = class {
2115
2402
  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();
2116
2403
  return this.transform(expr2.left, {
2117
2404
  ...context,
2118
- memberSelect: SelectionNode.create(AliasNode2.create(predicateResult, IdentifierNode.create("$t"))),
2405
+ memberSelect: SelectionNode.create(AliasNode3.create(predicateResult, IdentifierNode.create("$t"))),
2119
2406
  memberFilter: predicateFilter
2120
2407
  });
2121
2408
  }
2122
- transformAuthBinary(expr2) {
2409
+ transformAuthBinary(expr2, context) {
2123
2410
  if (expr2.op !== "==" && expr2.op !== "!=") {
2124
- throw new Error(`Unsupported operator for auth call: ${expr2.op}`);
2411
+ throw new QueryError(`Unsupported operator for \`auth()\` in policy of model "${context.model}": ${expr2.op}`);
2125
2412
  }
2413
+ let authExpr;
2126
2414
  let other;
2127
2415
  if (this.isAuthCall(expr2.left)) {
2416
+ authExpr = expr2.left;
2128
2417
  other = expr2.right;
2129
2418
  } else {
2419
+ authExpr = expr2.right;
2130
2420
  other = expr2.left;
2131
2421
  }
2132
2422
  if (ExpressionUtils.isNull(other)) {
2133
2423
  return this.transformValue(expr2.op === "==" ? !this.auth : !!this.auth, "Boolean");
2134
2424
  } else {
2135
- throw new Error("Unsupported binary expression with `auth()`");
2425
+ const authModel = getModel(this.schema, this.authType);
2426
+ if (!authModel) {
2427
+ throw new QueryError(`Unsupported use of \`auth()\` in policy of model "${context.model}", comparing with \`auth()\` is only possible when auth type is a model`);
2428
+ }
2429
+ const idFields = Object.values(authModel.fields).filter((f) => f.id).map((f) => f.name);
2430
+ invariant6(idFields.length > 0, "auth type model must have at least one id field");
2431
+ const conditions = idFields.map((fieldName) => ExpressionUtils.binary(ExpressionUtils.member(authExpr, [
2432
+ fieldName
2433
+ ]), "==", this.makeOrAppendMember(other, fieldName)));
2434
+ let result = this.buildAnd(conditions);
2435
+ if (expr2.op === "!=") {
2436
+ result = this.buildLogicalNot(result);
2437
+ }
2438
+ return this.transform(result, context);
2439
+ }
2440
+ }
2441
+ makeOrAppendMember(other, fieldName) {
2442
+ if (ExpressionUtils.isMember(other)) {
2443
+ return ExpressionUtils.member(other.receiver, [
2444
+ ...other.members,
2445
+ fieldName
2446
+ ]);
2447
+ } else {
2448
+ return ExpressionUtils.member(other, [
2449
+ fieldName
2450
+ ]);
2136
2451
  }
2137
2452
  }
2138
2453
  transformValue(value, type) {
2139
- return ValueNode2.create(this.dialect.transformPrimitive(value, type, false) ?? null);
2454
+ if (value === true) {
2455
+ return trueNode(this.dialect);
2456
+ } else if (value === false) {
2457
+ return falseNode(this.dialect);
2458
+ } else {
2459
+ return ValueNode2.create(this.dialect.transformPrimitive(value, type, false) ?? null);
2460
+ }
2140
2461
  }
2141
2462
  _unary(expr2, context) {
2142
- invariant5(expr2.op === "!", 'only "!" operator is supported');
2143
- return BinaryOperationNode2.create(this.transform(expr2.operand, context), this.transformOperator("!="), trueNode(this.dialect));
2463
+ invariant6(expr2.op === "!", 'only "!" operator is supported');
2464
+ return logicalNot(this.dialect, this.transform(expr2.operand, context));
2144
2465
  }
2145
2466
  transformOperator(op) {
2146
2467
  const mappedOp = match7(op).with("==", () => "=").otherwise(() => op);
@@ -2151,23 +2472,37 @@ var ExpressionTransformer = class {
2151
2472
  return result.toOperationNode();
2152
2473
  }
2153
2474
  transformCall(expr2, context) {
2154
- const func = this.clientOptions.functions?.[expr2.function];
2475
+ const func = this.getFunctionImpl(expr2.function);
2155
2476
  if (!func) {
2156
2477
  throw new QueryError(`Function not implemented: ${expr2.function}`);
2157
2478
  }
2158
2479
  const eb = expressionBuilder2();
2159
2480
  return func(eb, (expr2.args ?? []).map((arg) => this.transformCallArg(eb, arg, context)), {
2481
+ client: this.client,
2160
2482
  dialect: this.dialect,
2161
2483
  model: context.model,
2484
+ modelAlias: context.alias ?? context.model,
2162
2485
  operation: context.operation
2163
2486
  });
2164
2487
  }
2488
+ getFunctionImpl(functionName) {
2489
+ let func = this.clientOptions.functions?.[functionName];
2490
+ if (!func) {
2491
+ for (const plugin of this.clientOptions.plugins ?? []) {
2492
+ if (plugin.functions?.[functionName]) {
2493
+ func = plugin.functions[functionName];
2494
+ break;
2495
+ }
2496
+ }
2497
+ }
2498
+ return func;
2499
+ }
2165
2500
  transformCallArg(eb, arg, context) {
2166
2501
  if (ExpressionUtils.isLiteral(arg)) {
2167
2502
  return eb.val(arg.value);
2168
2503
  }
2169
2504
  if (ExpressionUtils.isField(arg)) {
2170
- return context.thisEntityRaw ? eb.val(context.thisEntityRaw[arg.field]) : eb.ref(arg.field);
2505
+ return eb.ref(arg.field);
2171
2506
  }
2172
2507
  if (ExpressionUtils.isCall(arg)) {
2173
2508
  return this.transformCall(arg, context);
@@ -2182,14 +2517,32 @@ var ExpressionTransformer = class {
2182
2517
  if (this.isAuthCall(expr2.receiver)) {
2183
2518
  return this.valueMemberAccess(this.auth, expr2, this.authType);
2184
2519
  }
2185
- invariant5(ExpressionUtils.isField(expr2.receiver), "expect receiver to be field expression");
2520
+ invariant6(ExpressionUtils.isField(expr2.receiver) || ExpressionUtils.isThis(expr2.receiver), 'expect receiver to be field expression or "this"');
2521
+ let members = expr2.members;
2522
+ let receiver;
2186
2523
  const { memberFilter, memberSelect, ...restContext } = context;
2187
- const receiver = this.transform(expr2.receiver, restContext);
2188
- invariant5(SelectQueryNode.is(receiver), "expected receiver to be select query");
2189
- const receiverField = requireField(this.schema, context.model, expr2.receiver.field);
2524
+ if (ExpressionUtils.isThis(expr2.receiver)) {
2525
+ if (expr2.members.length === 1) {
2526
+ return this._field(ExpressionUtils.field(expr2.members[0]), context);
2527
+ } else {
2528
+ const firstMemberFieldDef = requireField(this.schema, context.model, expr2.members[0]);
2529
+ receiver = this.transformRelationAccess(expr2.members[0], firstMemberFieldDef.type, restContext);
2530
+ members = expr2.members.slice(1);
2531
+ }
2532
+ } else {
2533
+ receiver = this.transform(expr2.receiver, restContext);
2534
+ }
2535
+ invariant6(SelectQueryNode.is(receiver), "expected receiver to be select query");
2536
+ let startType;
2537
+ if (ExpressionUtils.isField(expr2.receiver)) {
2538
+ const receiverField = requireField(this.schema, context.model, expr2.receiver.field);
2539
+ startType = receiverField.type;
2540
+ } else {
2541
+ startType = context.model;
2542
+ }
2190
2543
  const memberFields = [];
2191
- let currType = receiverField.type;
2192
- for (const member of expr2.members) {
2544
+ let currType = startType;
2545
+ for (const member of members) {
2193
2546
  const fieldDef = requireField(this.schema, currType, member);
2194
2547
  memberFields.push({
2195
2548
  fieldDef,
@@ -2198,22 +2551,21 @@ var ExpressionTransformer = class {
2198
2551
  currType = fieldDef.type;
2199
2552
  }
2200
2553
  let currNode = void 0;
2201
- for (let i = expr2.members.length - 1; i >= 0; i--) {
2202
- const member = expr2.members[i];
2554
+ for (let i = members.length - 1; i >= 0; i--) {
2555
+ const member = members[i];
2203
2556
  const { fieldDef, fromModel } = memberFields[i];
2204
2557
  if (fieldDef.relation) {
2205
2558
  const relation = this.transformRelationAccess(member, fieldDef.type, {
2206
2559
  ...restContext,
2207
2560
  model: fromModel,
2208
- alias: void 0,
2209
- thisEntity: void 0
2561
+ alias: void 0
2210
2562
  });
2211
2563
  if (currNode) {
2212
- invariant5(SelectQueryNode.is(currNode), "expected select query node");
2564
+ invariant6(SelectQueryNode.is(currNode), "expected select query node");
2213
2565
  currNode = {
2214
2566
  ...relation,
2215
2567
  selections: [
2216
- SelectionNode.create(AliasNode2.create(currNode, IdentifierNode.create(expr2.members[i + 1])))
2568
+ SelectionNode.create(AliasNode3.create(currNode, IdentifierNode.create(members[i + 1])))
2217
2569
  ]
2218
2570
  };
2219
2571
  } else {
@@ -2226,15 +2578,15 @@ var ExpressionTransformer = class {
2226
2578
  };
2227
2579
  }
2228
2580
  } else {
2229
- invariant5(i === expr2.members.length - 1, "plain field access must be the last segment");
2230
- invariant5(!currNode, "plain field access must be the last segment");
2231
- currNode = ColumnNode.create(member);
2581
+ invariant6(i === members.length - 1, "plain field access must be the last segment");
2582
+ invariant6(!currNode, "plain field access must be the last segment");
2583
+ currNode = ColumnNode2.create(member);
2232
2584
  }
2233
2585
  }
2234
2586
  return {
2235
2587
  ...receiver,
2236
2588
  selections: [
2237
- SelectionNode.create(AliasNode2.create(currNode, IdentifierNode.create("$t")))
2589
+ SelectionNode.create(AliasNode3.create(currNode, IdentifierNode.create("$t")))
2238
2590
  ]
2239
2591
  };
2240
2592
  }
@@ -2251,40 +2603,33 @@ var ExpressionTransformer = class {
2251
2603
  return this.transformValue(fieldValue, fieldDef.type);
2252
2604
  }
2253
2605
  transformRelationAccess(field, relationModel, context) {
2606
+ const m2m = getManyToManyRelation(this.schema, context.model, field);
2607
+ if (m2m) {
2608
+ return this.transformManyToManyRelationAccess(m2m, context);
2609
+ }
2254
2610
  const fromModel = context.model;
2255
2611
  const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, fromModel, field);
2256
- if (context.thisEntity) {
2257
- let condition;
2258
- if (ownedByModel) {
2259
- condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(pk), TableNode2.create(relationModel)), OperatorNode2.create("="), context.thisEntity[fk])));
2260
- } else {
2261
- condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(fk), TableNode2.create(relationModel)), OperatorNode2.create("="), context.thisEntity[pk])));
2262
- }
2263
- return {
2264
- kind: "SelectQueryNode",
2265
- from: FromNode.create([
2266
- TableNode2.create(relationModel)
2267
- ]),
2268
- where: WhereNode.create(condition)
2269
- };
2612
+ let condition;
2613
+ if (ownedByModel) {
2614
+ condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode3.create(ColumnNode2.create(fk), TableNode3.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode3.create(ColumnNode2.create(pk), TableNode3.create(relationModel)))));
2270
2615
  } else {
2271
- let condition;
2272
- if (ownedByModel) {
2273
- condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(fk), TableNode2.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode2.create(ColumnNode.create(pk), TableNode2.create(relationModel)))));
2274
- } else {
2275
- condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode2.create(ColumnNode.create(pk), TableNode2.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode2.create(ColumnNode.create(fk), TableNode2.create(relationModel)))));
2276
- }
2277
- return {
2278
- kind: "SelectQueryNode",
2279
- from: FromNode.create([
2280
- TableNode2.create(relationModel)
2281
- ]),
2282
- where: WhereNode.create(condition)
2283
- };
2616
+ condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => BinaryOperationNode2.create(ReferenceNode3.create(ColumnNode2.create(pk), TableNode3.create(context.alias ?? fromModel)), OperatorNode2.create("="), ReferenceNode3.create(ColumnNode2.create(fk), TableNode3.create(relationModel)))));
2284
2617
  }
2618
+ return {
2619
+ kind: "SelectQueryNode",
2620
+ from: FromNode.create([
2621
+ TableNode3.create(relationModel)
2622
+ ]),
2623
+ where: WhereNode.create(condition)
2624
+ };
2625
+ }
2626
+ transformManyToManyRelationAccess(m2m, context) {
2627
+ const eb = expressionBuilder2();
2628
+ const relationQuery = eb.selectFrom(m2m.otherModel).innerJoin(m2m.joinTable, (join) => join.onRef(`${m2m.otherModel}.${m2m.otherPKName}`, "=", `${m2m.joinTable}.${m2m.otherFkName}`).onRef(`${m2m.joinTable}.${m2m.parentFkName}`, "=", `${context.alias ?? context.model}.${m2m.parentPKName}`));
2629
+ return relationQuery.toOperationNode();
2285
2630
  }
2286
2631
  createColumnRef(column, context) {
2287
- return ReferenceNode2.create(ColumnNode.create(column), TableNode2.create(context.alias ?? context.model));
2632
+ return ReferenceNode3.create(ColumnNode2.create(column), TableNode3.create(context.alias ?? context.model));
2288
2633
  }
2289
2634
  isAuthCall(value) {
2290
2635
  return ExpressionUtils.isCall(value) && value.function === "auth";
@@ -2295,6 +2640,31 @@ var ExpressionTransformer = class {
2295
2640
  isNullNode(node) {
2296
2641
  return ValueNode2.is(node) && node.value === null;
2297
2642
  }
2643
+ buildLogicalNot(result) {
2644
+ return ExpressionUtils.unary("!", result);
2645
+ }
2646
+ buildAnd(conditions) {
2647
+ if (conditions.length === 0) {
2648
+ return ExpressionUtils.literal(true);
2649
+ } else if (conditions.length === 1) {
2650
+ return conditions[0];
2651
+ } else {
2652
+ return conditions.reduce((acc, condition) => ExpressionUtils.binary(acc, "&&", condition));
2653
+ }
2654
+ }
2655
+ isRelationField(expr2, model) {
2656
+ const fieldDef = this.getFieldDefFromFieldRef(expr2, model);
2657
+ return !!fieldDef?.relation;
2658
+ }
2659
+ getFieldDefFromFieldRef(expr2, model) {
2660
+ if (ExpressionUtils.isField(expr2)) {
2661
+ return requireField(this.schema, model, expr2.field);
2662
+ } else if (ExpressionUtils.isMember(expr2) && expr2.members.length === 1 && ExpressionUtils.isThis(expr2.receiver)) {
2663
+ return requireField(this.schema, model, expr2.members[0]);
2664
+ } else {
2665
+ return void 0;
2666
+ }
2667
+ }
2298
2668
  };
2299
2669
  _ts_decorate([
2300
2670
  expr("literal"),
@@ -2381,103 +2751,288 @@ var PolicyHandler = class extends OperationNodeTransformer {
2381
2751
  }
2382
2752
  async handle(node, proceed) {
2383
2753
  if (!this.isCrudQueryNode(node)) {
2384
- throw new RejectedByPolicyError(void 0, "non-CRUD queries are not allowed");
2754
+ throw new RejectedByPolicyError(void 0, RejectedByPolicyReason.OTHER, "non-CRUD queries are not allowed");
2385
2755
  }
2386
2756
  if (!this.isMutationQueryNode(node)) {
2387
2757
  return proceed(this.transformNode(node));
2388
2758
  }
2389
- let mutationRequiresTransaction = false;
2390
- const mutationModel = this.getMutationModel(node);
2759
+ const { mutationModel } = this.getMutationModel(node);
2391
2760
  if (InsertQueryNode.is(node)) {
2392
- const constCondition = this.tryGetConstantPolicy(mutationModel, "create");
2393
- if (constCondition === false) {
2394
- throw new RejectedByPolicyError(mutationModel);
2395
- } else if (constCondition === void 0) {
2396
- mutationRequiresTransaction = true;
2761
+ const isManyToManyJoinTable = this.isManyToManyJoinTable(mutationModel);
2762
+ let needCheckPreCreate = true;
2763
+ if (!isManyToManyJoinTable) {
2764
+ const constCondition = this.tryGetConstantPolicy(mutationModel, "create");
2765
+ if (constCondition === true) {
2766
+ needCheckPreCreate = false;
2767
+ } else if (constCondition === false) {
2768
+ throw new RejectedByPolicyError(mutationModel);
2769
+ }
2770
+ }
2771
+ if (needCheckPreCreate) {
2772
+ await this.enforcePreCreatePolicy(node, mutationModel, isManyToManyJoinTable, proceed);
2397
2773
  }
2398
2774
  }
2399
- if (!mutationRequiresTransaction && !node.returning) {
2400
- return proceed(this.transformNode(node));
2401
- }
2402
- if (InsertQueryNode.is(node)) {
2403
- await this.enforcePreCreatePolicy(node, proceed);
2404
- }
2405
- const transformedNode = this.transformNode(node);
2406
- const result = await proceed(transformedNode);
2407
- if (!this.onlyReturningId(node)) {
2775
+ const result = await proceed(this.transformNode(node));
2776
+ if (!node.returning || this.onlyReturningId(node)) {
2777
+ return result;
2778
+ } else {
2408
2779
  const readBackResult = await this.processReadBack(node, result, proceed);
2409
2780
  if (readBackResult.rows.length !== result.rows.length) {
2410
- throw new RejectedByPolicyError(mutationModel, "result is not allowed to be read back");
2781
+ throw new RejectedByPolicyError(mutationModel, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
2411
2782
  }
2412
2783
  return readBackResult;
2413
- } else {
2784
+ }
2785
+ }
2786
+ // #region overrides
2787
+ transformSelectQuery(node) {
2788
+ let whereNode = this.transformNode(node.where);
2789
+ const policyFilter = this.createPolicyFilterForFrom(node.from);
2790
+ if (policyFilter) {
2791
+ whereNode = WhereNode2.create(whereNode?.where ? conjunction(this.dialect, [
2792
+ whereNode.where,
2793
+ policyFilter
2794
+ ]) : policyFilter);
2795
+ }
2796
+ const baseResult = super.transformSelectQuery({
2797
+ ...node,
2798
+ where: void 0
2799
+ });
2800
+ return {
2801
+ ...baseResult,
2802
+ where: whereNode
2803
+ };
2804
+ }
2805
+ transformJoin(node) {
2806
+ const table = this.extractTableName(node.table);
2807
+ if (!table) {
2808
+ return super.transformJoin(node);
2809
+ }
2810
+ const filter = this.buildPolicyFilter(table.model, table.alias, "read");
2811
+ const nestedSelect = {
2812
+ kind: "SelectQueryNode",
2813
+ from: FromNode2.create([
2814
+ node.table
2815
+ ]),
2816
+ selections: [
2817
+ SelectionNode2.createSelectAll()
2818
+ ],
2819
+ where: WhereNode2.create(filter)
2820
+ };
2821
+ return {
2822
+ ...node,
2823
+ table: AliasNode4.create(ParensNode2.create(nestedSelect), IdentifierNode2.create(table.alias ?? table.model))
2824
+ };
2825
+ }
2826
+ transformInsertQuery(node) {
2827
+ let onConflict = node.onConflict;
2828
+ if (onConflict?.updates) {
2829
+ const { mutationModel, alias } = this.getMutationModel(node);
2830
+ const filter = this.buildPolicyFilter(mutationModel, alias, "update");
2831
+ if (onConflict.updateWhere) {
2832
+ onConflict = {
2833
+ ...onConflict,
2834
+ updateWhere: WhereNode2.create(conjunction(this.dialect, [
2835
+ onConflict.updateWhere.where,
2836
+ filter
2837
+ ]))
2838
+ };
2839
+ } else {
2840
+ onConflict = {
2841
+ ...onConflict,
2842
+ updateWhere: WhereNode2.create(filter)
2843
+ };
2844
+ }
2845
+ }
2846
+ const processedNode = onConflict ? {
2847
+ ...node,
2848
+ onConflict
2849
+ } : node;
2850
+ const result = super.transformInsertQuery(processedNode);
2851
+ if (!node.returning) {
2414
2852
  return result;
2415
2853
  }
2854
+ if (this.onlyReturningId(node)) {
2855
+ return result;
2856
+ } else {
2857
+ const { mutationModel } = this.getMutationModel(node);
2858
+ const idFields = requireIdFields(this.client.$schema, mutationModel);
2859
+ return {
2860
+ ...result,
2861
+ returning: ReturningNode.create(idFields.map((field) => SelectionNode2.create(ColumnNode3.create(field))))
2862
+ };
2863
+ }
2864
+ }
2865
+ transformUpdateQuery(node) {
2866
+ const result = super.transformUpdateQuery(node);
2867
+ const { mutationModel, alias } = this.getMutationModel(node);
2868
+ let filter = this.buildPolicyFilter(mutationModel, alias, "update");
2869
+ if (node.from) {
2870
+ const joinFilter = this.createPolicyFilterForFrom(node.from);
2871
+ if (joinFilter) {
2872
+ filter = conjunction(this.dialect, [
2873
+ filter,
2874
+ joinFilter
2875
+ ]);
2876
+ }
2877
+ }
2878
+ return {
2879
+ ...result,
2880
+ where: WhereNode2.create(result.where ? conjunction(this.dialect, [
2881
+ result.where.where,
2882
+ filter
2883
+ ]) : filter)
2884
+ };
2885
+ }
2886
+ transformDeleteQuery(node) {
2887
+ const result = super.transformDeleteQuery(node);
2888
+ const { mutationModel, alias } = this.getMutationModel(node);
2889
+ let filter = this.buildPolicyFilter(mutationModel, alias, "delete");
2890
+ if (node.using) {
2891
+ const joinFilter = this.createPolicyFilterForTables(node.using.tables);
2892
+ if (joinFilter) {
2893
+ filter = conjunction(this.dialect, [
2894
+ filter,
2895
+ joinFilter
2896
+ ]);
2897
+ }
2898
+ }
2899
+ return {
2900
+ ...result,
2901
+ where: WhereNode2.create(result.where ? conjunction(this.dialect, [
2902
+ result.where.where,
2903
+ filter
2904
+ ]) : filter)
2905
+ };
2416
2906
  }
2907
+ // #endregion
2908
+ // #region helpers
2417
2909
  onlyReturningId(node) {
2418
2910
  if (!node.returning) {
2419
2911
  return true;
2420
2912
  }
2421
- const idFields = getIdFields(this.client.$schema, this.getMutationModel(node));
2913
+ const { mutationModel } = this.getMutationModel(node);
2914
+ const idFields = requireIdFields(this.client.$schema, mutationModel);
2422
2915
  const collector = new ColumnCollector();
2423
2916
  const selectedColumns = collector.collect(node.returning);
2424
2917
  return selectedColumns.every((c) => idFields.includes(c));
2425
2918
  }
2426
- async enforcePreCreatePolicy(node, proceed) {
2427
- if (!node.columns || !node.values) {
2428
- return;
2429
- }
2430
- const model = this.getMutationModel(node);
2431
- const fields = node.columns.map((c) => c.column.name);
2432
- const valueRows = this.unwrapCreateValueRows(node.values, model, fields);
2919
+ async enforcePreCreatePolicy(node, mutationModel, isManyToManyJoinTable, proceed) {
2920
+ const fields = node.columns?.map((c) => c.column.name) ?? [];
2921
+ const valueRows = node.values ? this.unwrapCreateValueRows(node.values, mutationModel, fields, isManyToManyJoinTable) : [
2922
+ []
2923
+ ];
2433
2924
  for (const values of valueRows) {
2434
- await this.enforcePreCreatePolicyForOne(model, fields, values.map((v) => v.node), values.map((v) => v.raw), proceed);
2925
+ if (isManyToManyJoinTable) {
2926
+ await this.enforcePreCreatePolicyForManyToManyJoinTable(mutationModel, fields, values.map((v) => v.node), proceed);
2927
+ } else {
2928
+ await this.enforcePreCreatePolicyForOne(mutationModel, fields, values.map((v) => v.node), proceed);
2929
+ }
2930
+ }
2931
+ }
2932
+ async enforcePreCreatePolicyForManyToManyJoinTable(tableName, fields, values, proceed) {
2933
+ const m2m = this.resolveManyToManyJoinTable(tableName);
2934
+ invariant7(m2m);
2935
+ invariant7(fields.includes("A") && fields.includes("B"), "many-to-many join table must have A and B fk fields");
2936
+ const aIndex = fields.indexOf("A");
2937
+ const aNode = values[aIndex];
2938
+ const bIndex = fields.indexOf("B");
2939
+ const bNode = values[bIndex];
2940
+ invariant7(ValueNode3.is(aNode) && ValueNode3.is(bNode), "A and B values must be ValueNode");
2941
+ const aValue = aNode.value;
2942
+ const bValue = bNode.value;
2943
+ invariant7(aValue !== null && aValue !== void 0, "A value cannot be null or undefined");
2944
+ invariant7(bValue !== null && bValue !== void 0, "B value cannot be null or undefined");
2945
+ const eb = expressionBuilder3();
2946
+ const filterA = this.buildPolicyFilter(m2m.firstModel, void 0, "update");
2947
+ const queryA = eb.selectFrom(m2m.firstModel).where(eb(eb.ref(`${m2m.firstModel}.${m2m.firstIdField}`), "=", aValue)).select(() => new ExpressionWrapper(filterA).as("$t"));
2948
+ const filterB = this.buildPolicyFilter(m2m.secondModel, void 0, "update");
2949
+ const queryB = eb.selectFrom(m2m.secondModel).where(eb(eb.ref(`${m2m.secondModel}.${m2m.secondIdField}`), "=", bValue)).select(() => new ExpressionWrapper(filterB).as("$t"));
2950
+ const queryNode = {
2951
+ kind: "SelectQueryNode",
2952
+ selections: [
2953
+ SelectionNode2.create(AliasNode4.create(queryA.toOperationNode(), IdentifierNode2.create("$conditionA"))),
2954
+ SelectionNode2.create(AliasNode4.create(queryB.toOperationNode(), IdentifierNode2.create("$conditionB")))
2955
+ ]
2956
+ };
2957
+ const result = await proceed(queryNode);
2958
+ if (!result.rows[0]?.$conditionA) {
2959
+ throw new RejectedByPolicyError(m2m.firstModel, RejectedByPolicyReason.CANNOT_READ_BACK, `many-to-many relation participant model "${m2m.firstModel}" not updatable`);
2960
+ }
2961
+ if (!result.rows[0]?.$conditionB) {
2962
+ throw new RejectedByPolicyError(m2m.secondModel, RejectedByPolicyReason.NO_ACCESS, `many-to-many relation participant model "${m2m.secondModel}" not updatable`);
2435
2963
  }
2436
2964
  }
2437
- async enforcePreCreatePolicyForOne(model, fields, values, valuesRaw, proceed) {
2438
- const thisEntity = {};
2439
- const thisEntityRaw = {};
2440
- for (let i = 0; i < fields.length; i++) {
2441
- thisEntity[fields[i]] = values[i];
2442
- thisEntityRaw[fields[i]] = valuesRaw[i];
2965
+ async enforcePreCreatePolicyForOne(model, fields, values, proceed) {
2966
+ const allFields = Object.entries(requireModel(this.client.$schema, model).fields).filter(([, def]) => !def.relation);
2967
+ const allValues = [];
2968
+ for (const [name, _def] of allFields) {
2969
+ const index = fields.indexOf(name);
2970
+ if (index >= 0) {
2971
+ allValues.push(values[index]);
2972
+ } else {
2973
+ allValues.push(ValueNode3.createImmediate(null));
2974
+ }
2443
2975
  }
2444
- const filter = this.buildPolicyFilter(model, void 0, "create", thisEntity, thisEntityRaw);
2976
+ const eb = expressionBuilder3();
2977
+ const constTable = {
2978
+ kind: "SelectQueryNode",
2979
+ from: FromNode2.create([
2980
+ AliasNode4.create(ParensNode2.create(ValuesNode.create([
2981
+ ValueListNode2.create(allValues)
2982
+ ])), IdentifierNode2.create("$t"))
2983
+ ]),
2984
+ selections: allFields.map(([name, def], index) => {
2985
+ const castedColumnRef = sql4`CAST(${eb.ref(`column${index + 1}`)} as ${sql4.raw(this.dialect.getFieldSqlType(def))})`.as(name);
2986
+ return SelectionNode2.create(castedColumnRef.toOperationNode());
2987
+ })
2988
+ };
2989
+ const filter = this.buildPolicyFilter(model, void 0, "create");
2445
2990
  const preCreateCheck = {
2446
2991
  kind: "SelectQueryNode",
2992
+ from: FromNode2.create([
2993
+ AliasNode4.create(constTable, IdentifierNode2.create(model))
2994
+ ]),
2447
2995
  selections: [
2448
- SelectionNode2.create(AliasNode3.create(filter, IdentifierNode2.create("$condition")))
2449
- ]
2996
+ SelectionNode2.create(AliasNode4.create(BinaryOperationNode3.create(FunctionNode3.create("COUNT", [
2997
+ ValueNode3.createImmediate(1)
2998
+ ]), OperatorNode3.create(">"), ValueNode3.createImmediate(0)), IdentifierNode2.create("$condition")))
2999
+ ],
3000
+ where: WhereNode2.create(filter)
2450
3001
  };
2451
3002
  const result = await proceed(preCreateCheck);
2452
3003
  if (!result.rows[0]?.$condition) {
2453
3004
  throw new RejectedByPolicyError(model);
2454
3005
  }
2455
3006
  }
2456
- unwrapCreateValueRows(node, model, fields) {
3007
+ unwrapCreateValueRows(node, model, fields, isManyToManyJoinTable) {
2457
3008
  if (ValuesNode.is(node)) {
2458
- return node.values.map((v) => this.unwrapCreateValueRow(v.values, model, fields));
3009
+ return node.values.map((v) => this.unwrapCreateValueRow(v.values, model, fields, isManyToManyJoinTable));
2459
3010
  } else if (PrimitiveValueListNode.is(node)) {
2460
3011
  return [
2461
- this.unwrapCreateValueRow(node.values, model, fields)
3012
+ this.unwrapCreateValueRow(node.values, model, fields, isManyToManyJoinTable)
2462
3013
  ];
2463
3014
  } else {
2464
3015
  throw new InternalError(`Unexpected node kind: ${node.kind} for unwrapping create values`);
2465
3016
  }
2466
3017
  }
2467
- unwrapCreateValueRow(data, model, fields) {
2468
- invariant6(data.length === fields.length, "data length must match fields length");
3018
+ unwrapCreateValueRow(data, model, fields, isImplicitManyToManyJoinTable) {
3019
+ invariant7(data.length === fields.length, "data length must match fields length");
2469
3020
  const result = [];
2470
3021
  for (let i = 0; i < data.length; i++) {
2471
3022
  const item = data[i];
2472
- const fieldDef = requireField(this.client.$schema, model, fields[i]);
2473
3023
  if (typeof item === "object" && item && "kind" in item) {
2474
- invariant6(item.kind === "ValueNode", "expecting a ValueNode");
3024
+ const fieldDef = requireField(this.client.$schema, model, fields[i]);
3025
+ invariant7(item.kind === "ValueNode", "expecting a ValueNode");
2475
3026
  result.push({
2476
3027
  node: ValueNode3.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
2477
3028
  raw: item.value
2478
3029
  });
2479
3030
  } else {
2480
- const value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
3031
+ let value = item;
3032
+ if (!isImplicitManyToManyJoinTable) {
3033
+ const fieldDef = requireField(this.client.$schema, model, fields[i]);
3034
+ value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
3035
+ }
2481
3036
  if (Array.isArray(value)) {
2482
3037
  result.push({
2483
3038
  node: RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
@@ -2521,16 +3076,13 @@ var PolicyHandler = class extends OperationNodeTransformer {
2521
3076
  if (!this.isMutationQueryNode(node) || !node.returning) {
2522
3077
  return result;
2523
3078
  }
2524
- const table = this.getMutationModel(node);
2525
- if (!table) {
2526
- throw new InternalError(`Unable to get table name for query node: ${node}`);
2527
- }
2528
- const idConditions = this.buildIdConditions(table, result.rows);
2529
- const policyFilter = this.buildPolicyFilter(table, void 0, "read");
3079
+ const { mutationModel } = this.getMutationModel(node);
3080
+ const idConditions = this.buildIdConditions(mutationModel, result.rows);
3081
+ const policyFilter = this.buildPolicyFilter(mutationModel, void 0, "read");
2530
3082
  const select = {
2531
3083
  kind: "SelectQueryNode",
2532
3084
  from: FromNode2.create([
2533
- TableNode3.create(table)
3085
+ TableNode4.create(mutationModel)
2534
3086
  ]),
2535
3087
  where: WhereNode2.create(conjunction(this.dialect, [
2536
3088
  idConditions,
@@ -2542,15 +3094,31 @@ var PolicyHandler = class extends OperationNodeTransformer {
2542
3094
  return selectResult;
2543
3095
  }
2544
3096
  buildIdConditions(table, rows) {
2545
- const idFields = getIdFields(this.client.$schema, table);
2546
- return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => BinaryOperationNode3.create(ColumnNode2.create(field), OperatorNode3.create("="), ValueNode3.create(row[field]))))));
3097
+ const idFields = requireIdFields(this.client.$schema, table);
3098
+ return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => BinaryOperationNode3.create(ColumnNode3.create(field), OperatorNode3.create("="), ValueNode3.create(row[field]))))));
2547
3099
  }
2548
3100
  getMutationModel(node) {
2549
- const r = match8(node).when(InsertQueryNode.is, (node2) => getTableName(node2.into)).when(UpdateQueryNode.is, (node2) => getTableName(node2.table)).when(DeleteQueryNode.is, (node2) => {
3101
+ const r = match8(node).when(InsertQueryNode.is, (node2) => ({
3102
+ mutationModel: getTableName(node2.into),
3103
+ alias: void 0
3104
+ })).when(UpdateQueryNode.is, (node2) => {
3105
+ if (!node2.table) {
3106
+ throw new QueryError("Update query must have a table");
3107
+ }
3108
+ const r2 = this.extractTableName(node2.table);
3109
+ return r2 ? {
3110
+ mutationModel: r2.model,
3111
+ alias: r2.alias
3112
+ } : void 0;
3113
+ }).when(DeleteQueryNode.is, (node2) => {
2550
3114
  if (node2.from.froms.length !== 1) {
2551
- throw new InternalError("Only one from table is supported for delete");
3115
+ throw new QueryError("Only one from table is supported for delete");
2552
3116
  }
2553
- return getTableName(node2.from.froms[0]);
3117
+ const r2 = this.extractTableName(node2.from.froms[0]);
3118
+ return r2 ? {
3119
+ mutationModel: r2.model,
3120
+ alias: r2.alias
3121
+ } : void 0;
2554
3122
  }).exhaustive();
2555
3123
  if (!r) {
2556
3124
  throw new InternalError(`Unable to get table name for query node: ${node}`);
@@ -2563,13 +3131,17 @@ var PolicyHandler = class extends OperationNodeTransformer {
2563
3131
  isMutationQueryNode(node) {
2564
3132
  return InsertQueryNode.is(node) || UpdateQueryNode.is(node) || DeleteQueryNode.is(node);
2565
3133
  }
2566
- buildPolicyFilter(model, alias, operation, thisEntity, thisEntityRaw) {
3134
+ buildPolicyFilter(model, alias, operation) {
3135
+ const m2mFilter = this.getModelPolicyFilterForManyToManyJoinTable(model, alias, operation);
3136
+ if (m2mFilter) {
3137
+ return m2mFilter;
3138
+ }
2567
3139
  const policies = this.getModelPolicies(model, operation);
2568
3140
  if (policies.length === 0) {
2569
3141
  return falseNode(this.dialect);
2570
3142
  }
2571
- const allows = policies.filter((policy) => policy.kind === "allow").map((policy) => this.transformPolicyCondition(model, alias, operation, policy, thisEntity, thisEntityRaw));
2572
- const denies = policies.filter((policy) => policy.kind === "deny").map((policy) => this.transformPolicyCondition(model, alias, operation, policy, thisEntity, thisEntityRaw));
3143
+ const allows = policies.filter((policy) => policy.kind === "allow").map((policy) => this.compilePolicyCondition(model, alias, operation, policy));
3144
+ const denies = policies.filter((policy) => policy.kind === "deny").map((policy) => this.compilePolicyCondition(model, alias, operation, policy));
2573
3145
  let combinedPolicy;
2574
3146
  if (allows.length === 0) {
2575
3147
  combinedPolicy = falseNode(this.dialect);
@@ -2577,110 +3149,67 @@ var PolicyHandler = class extends OperationNodeTransformer {
2577
3149
  combinedPolicy = disjunction(this.dialect, allows);
2578
3150
  if (denies.length !== 0) {
2579
3151
  const combinedDenies = conjunction(this.dialect, denies.map((d) => buildIsFalse(d, this.dialect)));
2580
- combinedPolicy = conjunction(this.dialect, [
2581
- combinedPolicy,
2582
- combinedDenies
2583
- ]);
2584
- }
2585
- }
2586
- return combinedPolicy;
2587
- }
2588
- transformSelectQuery(node) {
2589
- let whereNode = node.where;
2590
- node.from?.froms.forEach((from) => {
2591
- const extractResult = this.extractTableName(from);
2592
- if (extractResult) {
2593
- const { model, alias } = extractResult;
2594
- const filter = this.buildPolicyFilter(model, alias, "read");
2595
- whereNode = WhereNode2.create(whereNode?.where ? conjunction(this.dialect, [
2596
- whereNode.where,
2597
- filter
2598
- ]) : filter);
2599
- }
2600
- });
2601
- const baseResult = super.transformSelectQuery({
2602
- ...node,
2603
- where: void 0
2604
- });
2605
- return {
2606
- ...baseResult,
2607
- where: whereNode
2608
- };
2609
- }
2610
- transformInsertQuery(node) {
2611
- const result = super.transformInsertQuery(node);
2612
- if (!node.returning) {
2613
- return result;
2614
- }
2615
- if (this.onlyReturningId(node)) {
2616
- return result;
2617
- } else {
2618
- const idFields = getIdFields(this.client.$schema, this.getMutationModel(node));
2619
- return {
2620
- ...result,
2621
- returning: ReturningNode.create(idFields.map((field) => SelectionNode2.create(ColumnNode2.create(field))))
2622
- };
3152
+ combinedPolicy = conjunction(this.dialect, [
3153
+ combinedPolicy,
3154
+ combinedDenies
3155
+ ]);
3156
+ }
2623
3157
  }
3158
+ return combinedPolicy;
2624
3159
  }
2625
- transformUpdateQuery(node) {
2626
- const result = super.transformUpdateQuery(node);
2627
- const mutationModel = this.getMutationModel(node);
2628
- const filter = this.buildPolicyFilter(mutationModel, void 0, "update");
2629
- return {
2630
- ...result,
2631
- where: WhereNode2.create(result.where ? conjunction(this.dialect, [
2632
- result.where.where,
2633
- filter
2634
- ]) : filter)
2635
- };
2636
- }
2637
- transformDeleteQuery(node) {
2638
- const result = super.transformDeleteQuery(node);
2639
- const mutationModel = this.getMutationModel(node);
2640
- const filter = this.buildPolicyFilter(mutationModel, void 0, "delete");
2641
- return {
2642
- ...result,
2643
- where: WhereNode2.create(result.where ? conjunction(this.dialect, [
2644
- result.where.where,
2645
- filter
2646
- ]) : filter)
2647
- };
2648
- }
2649
- extractTableName(from) {
2650
- if (TableNode3.is(from)) {
3160
+ extractTableName(node) {
3161
+ if (TableNode4.is(node)) {
2651
3162
  return {
2652
- model: from.table.identifier.name
3163
+ model: node.table.identifier.name
2653
3164
  };
2654
3165
  }
2655
- if (AliasNode3.is(from)) {
2656
- const inner = this.extractTableName(from.node);
3166
+ if (AliasNode4.is(node)) {
3167
+ const inner = this.extractTableName(node.node);
2657
3168
  if (!inner) {
2658
3169
  return void 0;
2659
3170
  }
2660
3171
  return {
2661
3172
  model: inner.model,
2662
- alias: IdentifierNode2.is(from.alias) ? from.alias.name : void 0
3173
+ alias: IdentifierNode2.is(node.alias) ? node.alias.name : void 0
2663
3174
  };
2664
3175
  } else {
2665
3176
  return void 0;
2666
3177
  }
2667
3178
  }
2668
- transformPolicyCondition(model, alias, operation, policy, thisEntity, thisEntityRaw) {
2669
- return new ExpressionTransformer(this.client.$schema, this.client.$options, this.client.$auth).transform(policy.condition, {
3179
+ createPolicyFilterForFrom(node) {
3180
+ if (!node) {
3181
+ return void 0;
3182
+ }
3183
+ return this.createPolicyFilterForTables(node.froms);
3184
+ }
3185
+ createPolicyFilterForTables(tables) {
3186
+ return tables.reduce((acc, table) => {
3187
+ const extractResult = this.extractTableName(table);
3188
+ if (extractResult) {
3189
+ const { model, alias } = extractResult;
3190
+ const filter = this.buildPolicyFilter(model, alias, "read");
3191
+ return acc ? conjunction(this.dialect, [
3192
+ acc,
3193
+ filter
3194
+ ]) : filter;
3195
+ }
3196
+ return acc;
3197
+ }, void 0);
3198
+ }
3199
+ compilePolicyCondition(model, alias, operation, policy) {
3200
+ return new ExpressionTransformer(this.client).transform(policy.condition, {
2670
3201
  model,
2671
3202
  alias,
2672
3203
  operation,
2673
- thisEntity,
2674
- thisEntityRaw,
2675
3204
  auth: this.client.$auth
2676
3205
  });
2677
3206
  }
2678
- getModelPolicies(modelName, operation) {
2679
- const modelDef = requireModel(this.client.$schema, modelName);
3207
+ getModelPolicies(model, operation) {
3208
+ const modelDef = requireModel(this.client.$schema, model);
2680
3209
  const result = [];
2681
3210
  const extractOperations = /* @__PURE__ */ __name((expr2) => {
2682
- invariant6(ExpressionUtils.isLiteral(expr2), "expecting a literal");
2683
- invariant6(typeof expr2.value === "string", "expecting a string literal");
3211
+ invariant7(ExpressionUtils.isLiteral(expr2), "expecting a literal");
3212
+ invariant7(typeof expr2.value === "string", "expecting a string literal");
2684
3213
  return expr2.value.split(",").filter((v) => !!v).map((v) => v.trim());
2685
3214
  }, "extractOperations");
2686
3215
  if (modelDef.attributes) {
@@ -2692,8 +3221,84 @@ var PolicyHandler = class extends OperationNodeTransformer {
2692
3221
  }
2693
3222
  return result;
2694
3223
  }
3224
+ resolveManyToManyJoinTable(tableName) {
3225
+ for (const model of Object.values(this.client.$schema.models)) {
3226
+ for (const field of Object.values(model.fields)) {
3227
+ const m2m = getManyToManyRelation(this.client.$schema, model.name, field.name);
3228
+ if (m2m?.joinTable === tableName) {
3229
+ const sortedRecord = [
3230
+ {
3231
+ model: model.name,
3232
+ field: field.name
3233
+ },
3234
+ {
3235
+ model: m2m.otherModel,
3236
+ field: m2m.otherField
3237
+ }
3238
+ ].sort(this.manyToManySorter);
3239
+ const firstIdFields = requireIdFields(this.client.$schema, sortedRecord[0].model);
3240
+ const secondIdFields = requireIdFields(this.client.$schema, sortedRecord[1].model);
3241
+ invariant7(firstIdFields.length === 1 && secondIdFields.length === 1, "only single-field id is supported for implicit many-to-many join table");
3242
+ return {
3243
+ firstModel: sortedRecord[0].model,
3244
+ firstField: sortedRecord[0].field,
3245
+ firstIdField: firstIdFields[0],
3246
+ secondModel: sortedRecord[1].model,
3247
+ secondField: sortedRecord[1].field,
3248
+ secondIdField: secondIdFields[0]
3249
+ };
3250
+ }
3251
+ }
3252
+ }
3253
+ return void 0;
3254
+ }
3255
+ manyToManySorter(a, b) {
3256
+ return a.model !== b.model ? a.model.localeCompare(b.model) : a.field.localeCompare(b.field);
3257
+ }
3258
+ isManyToManyJoinTable(tableName) {
3259
+ return !!this.resolveManyToManyJoinTable(tableName);
3260
+ }
3261
+ getModelPolicyFilterForManyToManyJoinTable(tableName, alias, operation) {
3262
+ const m2m = this.resolveManyToManyJoinTable(tableName);
3263
+ if (!m2m) {
3264
+ return void 0;
3265
+ }
3266
+ const checkForOperation = operation === "read" ? "read" : "update";
3267
+ const eb = expressionBuilder3();
3268
+ const joinTable = alias ?? tableName;
3269
+ const aQuery = eb.selectFrom(m2m.firstModel).whereRef(`${m2m.firstModel}.${m2m.firstIdField}`, "=", `${joinTable}.A`).select(() => new ExpressionWrapper(this.buildPolicyFilter(m2m.firstModel, void 0, checkForOperation)).as("$conditionA"));
3270
+ const bQuery = eb.selectFrom(m2m.secondModel).whereRef(`${m2m.secondModel}.${m2m.secondIdField}`, "=", `${joinTable}.B`).select(() => new ExpressionWrapper(this.buildPolicyFilter(m2m.secondModel, void 0, checkForOperation)).as("$conditionB"));
3271
+ return eb.and([
3272
+ aQuery,
3273
+ bQuery
3274
+ ]).toOperationNode();
3275
+ }
2695
3276
  };
2696
3277
 
3278
+ // src/plugins/policy/functions.ts
3279
+ var check = /* @__PURE__ */ __name((eb, args, { client, model, modelAlias, operation }) => {
3280
+ invariant8(args.length === 1 || args.length === 2, '"check" function requires 1 or 2 arguments');
3281
+ const arg1Node = args[0].toOperationNode();
3282
+ const arg2Node = args.length === 2 ? args[1].toOperationNode() : void 0;
3283
+ if (arg2Node) {
3284
+ invariant8(ValueNode4.is(arg2Node) && typeof arg2Node.value === "string", '"operation" parameter must be a string literal when provided');
3285
+ invariant8(CRUD.includes(arg2Node.value), '"operation" parameter must be one of "create", "read", "update", "delete"');
3286
+ }
3287
+ const fieldName = extractFieldName(arg1Node);
3288
+ invariant8(fieldName, 'Failed to extract field name from the first argument of "check" function');
3289
+ const fieldDef = requireField(client.$schema, model, fieldName);
3290
+ invariant8(fieldDef.relation, `Field "${fieldName}" is not a relation field in model "${model}"`);
3291
+ invariant8(!fieldDef.array, `Field "${fieldName}" is a to-many relation, which is not supported by "check"`);
3292
+ const relationModel = fieldDef.type;
3293
+ const op = arg2Node ? arg2Node.value : operation;
3294
+ const policyHandler = new PolicyHandler(client);
3295
+ const joinPairs = buildJoinPairs(client.$schema, model, modelAlias, fieldName, relationModel);
3296
+ const joinCondition = joinPairs.length === 1 ? eb(eb.ref(joinPairs[0][0]), "=", eb.ref(joinPairs[0][1])) : eb.and(joinPairs.map(([left, right]) => eb(eb.ref(left), "=", eb.ref(right))));
3297
+ const policyCondition = policyHandler.buildPolicyFilter(relationModel, void 0, op);
3298
+ const result = eb.selectFrom(relationModel).where(joinCondition).select(new ExpressionWrapper2(policyCondition).as("$condition"));
3299
+ return result;
3300
+ }, "check");
3301
+
2697
3302
  // src/plugins/policy/plugin.ts
2698
3303
  var PolicyPlugin = class {
2699
3304
  static {
@@ -2708,6 +3313,11 @@ var PolicyPlugin = class {
2708
3313
  get description() {
2709
3314
  return "Enforces access policies defined in the schema.";
2710
3315
  }
3316
+ get functions() {
3317
+ return {
3318
+ check
3319
+ };
3320
+ }
2711
3321
  onKyselyQuery({
2712
3322
  query,
2713
3323
  client,
@@ -2743,16 +3353,6 @@ function clone(value) {
2743
3353
  }
2744
3354
  __name(clone, "clone");
2745
3355
 
2746
- // src/client/contract.ts
2747
- var TransactionIsolationLevel = /* @__PURE__ */ function(TransactionIsolationLevel2) {
2748
- TransactionIsolationLevel2["ReadUncommitted"] = "read uncommitted";
2749
- TransactionIsolationLevel2["ReadCommitted"] = "read committed";
2750
- TransactionIsolationLevel2["RepeatableRead"] = "repeatable read";
2751
- TransactionIsolationLevel2["Serializable"] = "serializable";
2752
- TransactionIsolationLevel2["Snapshot"] = "snapshot";
2753
- return TransactionIsolationLevel2;
2754
- }({});
2755
-
2756
3356
  // src/client/crud/operations/base.ts
2757
3357
  var BaseOperationHandler = class {
2758
3358
  static {
@@ -2797,7 +3397,7 @@ var BaseOperationHandler = class {
2797
3397
  return getField(this.schema, model, field);
2798
3398
  }
2799
3399
  async exists(kysely, model, filter) {
2800
- const idFields = getIdFields(this.schema, model);
3400
+ const idFields = requireIdFields(this.schema, model);
2801
3401
  const _filter = flattenCompoundUniqueFilters(this.schema, model, filter);
2802
3402
  const query = kysely.selectFrom(model).where((eb) => eb.and(_filter)).select(idFields.map((f) => kysely.dynamic.ref(f))).limit(1).modifyEnd(this.makeContextComment({
2803
3403
  model,
@@ -2806,7 +3406,7 @@ var BaseOperationHandler = class {
2806
3406
  return this.executeQueryTakeFirst(kysely, query, "exists");
2807
3407
  }
2808
3408
  async read(kysely, model, args) {
2809
- let query = this.dialect.buildSelectModel(expressionBuilder3(), model, model);
3409
+ let query = this.dialect.buildSelectModel(expressionBuilder4(), model, model);
2810
3410
  if (args) {
2811
3411
  query = this.dialect.buildFilterSortTake(model, args, query, model);
2812
3412
  }
@@ -2878,26 +3478,21 @@ var BaseOperationHandler = class {
2878
3478
  throw new QueryError(`Model "${this.model}" is a delegate and cannot be created directly.`);
2879
3479
  }
2880
3480
  let createFields = {};
2881
- let parentUpdateTask = void 0;
3481
+ let updateParent = void 0;
2882
3482
  let m2m = void 0;
2883
3483
  if (fromRelation) {
2884
3484
  m2m = getManyToManyRelation(this.schema, fromRelation.model, fromRelation.field);
2885
3485
  if (!m2m) {
2886
3486
  const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, fromRelation?.model ?? "", fromRelation?.field ?? "");
2887
3487
  if (!ownedByModel) {
2888
- const parentFkFields = this.buildFkAssignments(fromRelation.model, fromRelation.field, fromRelation.ids);
3488
+ const parentFkFields = await this.buildFkAssignments(kysely, fromRelation.model, fromRelation.field, fromRelation.ids);
2889
3489
  Object.assign(createFields, parentFkFields);
2890
3490
  } else {
2891
- parentUpdateTask = /* @__PURE__ */ __name((entity) => {
2892
- const query2 = kysely.updateTable(fromRelation.model).set(keyPairs.reduce((acc, { fk, pk }) => ({
2893
- ...acc,
2894
- [fk]: entity[pk]
2895
- }), {})).where((eb) => eb.and(fromRelation.ids)).modifyEnd(this.makeContextComment({
2896
- model: fromRelation.model,
2897
- operation: "update"
2898
- }));
2899
- return this.executeQuery(kysely, query2, "update");
2900
- }, "parentUpdateTask");
3491
+ updateParent = /* @__PURE__ */ __name((entity) => {
3492
+ for (const { fk, pk } of keyPairs) {
3493
+ fromRelation.parentUpdates[fk] = entity[pk];
3494
+ }
3495
+ }, "updateParent");
2901
3496
  }
2902
3497
  }
2903
3498
  }
@@ -2929,24 +3524,23 @@ var BaseOperationHandler = class {
2929
3524
  const baseCreateResult = await this.processBaseModelCreate(kysely, modelDef.baseModel, createFields, model);
2930
3525
  createFields = baseCreateResult.remainingFields;
2931
3526
  }
2932
- const updatedData = this.fillGeneratedValues(modelDef, createFields);
2933
- const idFields = getIdFields(this.schema, model);
3527
+ const updatedData = this.fillGeneratedAndDefaultValues(modelDef, createFields);
3528
+ const idFields = requireIdFields(this.schema, model);
2934
3529
  const query = kysely.insertInto(model).$if(Object.keys(updatedData).length === 0, (qb) => qb.defaultValues()).$if(Object.keys(updatedData).length > 0, (qb) => qb.values(updatedData)).returning(idFields).modifyEnd(this.makeContextComment({
2935
3530
  model,
2936
3531
  operation: "create"
2937
3532
  }));
2938
3533
  const createdEntity = await this.executeQueryTakeFirst(kysely, query, "create");
2939
3534
  if (Object.keys(postCreateRelations).length > 0) {
2940
- const relationPromises = Object.entries(postCreateRelations).map(([field, subPayload]) => {
2941
- return this.processNoneOwnedRelationForCreate(kysely, model, field, subPayload, createdEntity);
2942
- });
2943
- await Promise.all(relationPromises);
3535
+ for (const [field, subPayload] of Object.entries(postCreateRelations)) {
3536
+ await this.processNoneOwnedRelationForCreate(kysely, model, field, subPayload, createdEntity);
3537
+ }
2944
3538
  }
2945
3539
  if (fromRelation && m2m) {
2946
3540
  await this.handleManyToManyRelation(kysely, "connect", fromRelation.model, fromRelation.field, fromRelation.ids, m2m.otherModel, m2m.otherField, createdEntity, m2m.joinTable);
2947
3541
  }
2948
- if (parentUpdateTask) {
2949
- await parentUpdateTask(createdEntity);
3542
+ if (updateParent) {
3543
+ updateParent(createdEntity);
2950
3544
  }
2951
3545
  return createdEntity;
2952
3546
  }
@@ -2962,7 +3556,7 @@ var BaseOperationHandler = class {
2962
3556
  }
2963
3557
  });
2964
3558
  const discriminatorField = getDiscriminatorField(this.schema, model);
2965
- invariant7(discriminatorField, `Base model "${model}" must have a discriminator field`);
3559
+ invariant9(discriminatorField, `Base model "${model}" must have a discriminator field`);
2966
3560
  thisCreateFields[discriminatorField] = forModel;
2967
3561
  const baseEntity = await this.create(kysely, model, thisCreateFields, void 0, true);
2968
3562
  const idValues = extractIdFields(baseEntity, this.schema, model);
@@ -2972,14 +3566,24 @@ var BaseOperationHandler = class {
2972
3566
  remainingFields
2973
3567
  };
2974
3568
  }
2975
- buildFkAssignments(model, relationField, entity) {
3569
+ async buildFkAssignments(kysely, model, relationField, entity) {
2976
3570
  const parentFkFields = {};
2977
- invariant7(relationField, "parentField must be defined if parentModel is defined");
2978
- invariant7(entity, "parentEntity must be defined if parentModel is defined");
3571
+ invariant9(relationField, "parentField must be defined if parentModel is defined");
3572
+ invariant9(entity, "parentEntity must be defined if parentModel is defined");
2979
3573
  const { keyPairs } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
2980
3574
  for (const pair of keyPairs) {
2981
3575
  if (!(pair.pk in entity)) {
2982
- throw new QueryError(`Field "${pair.pk}" not found in parent created data`);
3576
+ const extraRead = await this.readUnique(kysely, model, {
3577
+ where: entity,
3578
+ select: {
3579
+ [pair.pk]: true
3580
+ }
3581
+ });
3582
+ if (!extraRead) {
3583
+ throw new QueryError(`Field "${pair.pk}" not found in parent created data`);
3584
+ } else {
3585
+ Object.assign(entity, extraRead);
3586
+ }
2983
3587
  }
2984
3588
  Object.assign(parentFkFields, {
2985
3589
  [pair.fk]: entity[pair.pk]
@@ -3000,15 +3604,15 @@ var BaseOperationHandler = class {
3000
3604
  entity: rightEntity
3001
3605
  }
3002
3606
  ].sort((a, b) => (
3003
- // the implement m2m join table's "A", "B" fk fields' order is determined
3607
+ // the implicit m2m join table's "A", "B" fk fields' order is determined
3004
3608
  // by model name's sort order, and when identical (for self-relations),
3005
3609
  // field name's sort order
3006
3610
  a.model !== b.model ? a.model.localeCompare(b.model) : a.field.localeCompare(b.field)
3007
3611
  ));
3008
- const firstIds = getIdFields(this.schema, sortedRecords[0].model);
3009
- const secondIds = getIdFields(this.schema, sortedRecords[1].model);
3010
- invariant7(firstIds.length === 1, "many-to-many relation must have exactly one id field");
3011
- invariant7(secondIds.length === 1, "many-to-many relation must have exactly one id field");
3612
+ const firstIds = requireIdFields(this.schema, sortedRecords[0].model);
3613
+ const secondIds = requireIdFields(this.schema, sortedRecords[1].model);
3614
+ invariant9(firstIds.length === 1, "many-to-many relation must have exactly one id field");
3615
+ invariant9(secondIds.length === 1, "many-to-many relation must have exactly one id field");
3012
3616
  if (action === "connect") {
3013
3617
  const result = await kysely.insertInto(joinTable).values({
3014
3618
  A: sortedRecords[0].entity[firstIds[0]],
@@ -3019,17 +3623,17 @@ var BaseOperationHandler = class {
3019
3623
  ]).doNothing()).execute();
3020
3624
  return result[0];
3021
3625
  } else {
3022
- const eb = expressionBuilder3();
3626
+ const eb = expressionBuilder4();
3023
3627
  const result = await kysely.deleteFrom(joinTable).where(eb(`${joinTable}.A`, "=", sortedRecords[0].entity[firstIds[0]])).where(eb(`${joinTable}.B`, "=", sortedRecords[1].entity[secondIds[0]])).execute();
3024
3628
  return result[0];
3025
3629
  }
3026
3630
  }
3027
3631
  resetManyToManyRelation(kysely, model, field, parentIds) {
3028
- invariant7(Object.keys(parentIds).length === 1, "parentIds must have exactly one field");
3632
+ invariant9(Object.keys(parentIds).length === 1, "parentIds must have exactly one field");
3029
3633
  const parentId = Object.values(parentIds)[0];
3030
3634
  const m2m = getManyToManyRelation(this.schema, model, field);
3031
- invariant7(m2m, "not a many-to-many relation");
3032
- const eb = expressionBuilder3();
3635
+ invariant9(m2m, "not a many-to-many relation");
3636
+ const eb = expressionBuilder4();
3033
3637
  return kysely.deleteFrom(m2m.joinTable).where(eb(`${m2m.joinTable}.${m2m.parentFkName}`, "=", parentId)).execute();
3034
3638
  }
3035
3639
  async processOwnedRelationForCreate(kysely, relationField, payload) {
@@ -3050,7 +3654,7 @@ var BaseOperationHandler = class {
3050
3654
  }
3051
3655
  case "connect": {
3052
3656
  const referencedPkFields = relationField.relation.references;
3053
- invariant7(referencedPkFields, "relation must have fields info");
3657
+ invariant9(referencedPkFields, "relation must have fields info");
3054
3658
  const extractedFks = extractFields(subPayload, referencedPkFields);
3055
3659
  if (Object.keys(extractedFks).length === referencedPkFields.length) {
3056
3660
  result = extractedFks;
@@ -3060,7 +3664,7 @@ var BaseOperationHandler = class {
3060
3664
  select: fieldsToSelectObject(referencedPkFields)
3061
3665
  });
3062
3666
  if (!relationEntity) {
3063
- throw new NotFoundError(`Could not find the entity for connect action`);
3667
+ throw new NotFoundError(relationModel, `Could not find the entity to connect for the relation "${relationField.name}"`);
3064
3668
  }
3065
3669
  result = relationEntity;
3066
3670
  }
@@ -3082,14 +3686,14 @@ var BaseOperationHandler = class {
3082
3686
  }
3083
3687
  return result;
3084
3688
  }
3085
- processNoneOwnedRelationForCreate(kysely, contextModel, relationFieldName, payload, parentEntity) {
3689
+ async processNoneOwnedRelationForCreate(kysely, contextModel, relationFieldName, payload, parentEntity) {
3086
3690
  const relationFieldDef = this.requireField(contextModel, relationFieldName);
3087
3691
  const relationModel = relationFieldDef.type;
3088
- const tasks = [];
3089
3692
  const fromRelationContext = {
3090
3693
  model: contextModel,
3091
3694
  field: relationFieldName,
3092
- ids: parentEntity
3695
+ ids: parentEntity,
3696
+ parentUpdates: {}
3093
3697
  };
3094
3698
  for (const [action, subPayload] of Object.entries(payload)) {
3095
3699
  if (!subPayload) {
@@ -3097,39 +3701,35 @@ var BaseOperationHandler = class {
3097
3701
  }
3098
3702
  switch (action) {
3099
3703
  case "create": {
3100
- tasks.push(...enumerate(subPayload).map((item) => this.create(kysely, relationModel, item, fromRelationContext)));
3704
+ for (const item of enumerate(subPayload)) {
3705
+ await this.create(kysely, relationModel, item, fromRelationContext);
3706
+ }
3101
3707
  break;
3102
3708
  }
3103
3709
  case "createMany": {
3104
- invariant7(relationFieldDef.array, "relation must be an array for createMany");
3105
- tasks.push(this.createMany(kysely, relationModel, subPayload, false, fromRelationContext));
3710
+ invariant9(relationFieldDef.array, "relation must be an array for createMany");
3711
+ await this.createMany(kysely, relationModel, subPayload, false, fromRelationContext);
3106
3712
  break;
3107
3713
  }
3108
3714
  case "connect": {
3109
- tasks.push(this.connectRelation(kysely, relationModel, subPayload, {
3110
- model: contextModel,
3111
- field: relationFieldName,
3112
- ids: parentEntity
3113
- }));
3715
+ await this.connectRelation(kysely, relationModel, subPayload, fromRelationContext);
3114
3716
  break;
3115
3717
  }
3116
3718
  case "connectOrCreate": {
3117
- tasks.push(...enumerate(subPayload).map((item) => this.exists(kysely, relationModel, item.where).then((found) => !found ? this.create(kysely, relationModel, item.create, {
3118
- model: contextModel,
3119
- field: relationFieldName,
3120
- ids: parentEntity
3121
- }) : this.connectRelation(kysely, relationModel, found, {
3122
- model: contextModel,
3123
- field: relationFieldName,
3124
- ids: parentEntity
3125
- }))));
3719
+ for (const item of enumerate(subPayload)) {
3720
+ const found = await this.exists(kysely, relationModel, item.where);
3721
+ if (!found) {
3722
+ await this.create(kysely, relationModel, item.create, fromRelationContext);
3723
+ } else {
3724
+ await this.connectRelation(kysely, relationModel, found, fromRelationContext);
3725
+ }
3726
+ }
3126
3727
  break;
3127
3728
  }
3128
3729
  default:
3129
3730
  throw new QueryError(`Invalid relation action: ${action}`);
3130
3731
  }
3131
3732
  }
3132
- return Promise.all(tasks);
3133
3733
  }
3134
3734
  async createMany(kysely, model, input, returnData, fromRelation) {
3135
3735
  if (!input.data || Array.isArray(input.data) && input.data.length === 0) {
@@ -3150,7 +3750,7 @@ var BaseOperationHandler = class {
3150
3750
  const newItem = {};
3151
3751
  for (const [name, value] of Object.entries(item)) {
3152
3752
  const fieldDef = this.requireField(model, name);
3153
- invariant7(!fieldDef.relation, "createMany does not support relations");
3753
+ invariant9(!fieldDef.relation, "createMany does not support relations");
3154
3754
  newItem[name] = this.dialect.transformPrimitive(value, fieldDef.type, !!fieldDef.array);
3155
3755
  }
3156
3756
  if (fromRelation) {
@@ -3158,7 +3758,7 @@ var BaseOperationHandler = class {
3158
3758
  newItem[fk] = fromRelation.ids[pk];
3159
3759
  }
3160
3760
  }
3161
- return this.fillGeneratedValues(modelDef, newItem);
3761
+ return this.fillGeneratedAndDefaultValues(modelDef, newItem);
3162
3762
  });
3163
3763
  if (!this.dialect.supportInsertWithDefault) {
3164
3764
  const allPassedFields = createData.reduce((acc, item) => {
@@ -3200,7 +3800,7 @@ var BaseOperationHandler = class {
3200
3800
  count: Number(result.numAffectedRows)
3201
3801
  };
3202
3802
  } else {
3203
- const idFields = getIdFields(this.schema, model);
3803
+ const idFields = requireIdFields(this.schema, model);
3204
3804
  const result = await query.returning(idFields).execute();
3205
3805
  return result;
3206
3806
  }
@@ -3209,7 +3809,7 @@ var BaseOperationHandler = class {
3209
3809
  const thisCreateRows = [];
3210
3810
  const remainingFieldRows = [];
3211
3811
  const discriminatorField = getDiscriminatorField(this.schema, model);
3212
- invariant7(discriminatorField, `Base model "${model}" must have a discriminator field`);
3812
+ invariant9(discriminatorField, `Base model "${model}" must have a discriminator field`);
3213
3813
  for (const createFields of createRows) {
3214
3814
  const thisCreateFields = {};
3215
3815
  const remainingFields = {};
@@ -3238,7 +3838,7 @@ var BaseOperationHandler = class {
3238
3838
  remainingFieldRows
3239
3839
  };
3240
3840
  }
3241
- fillGeneratedValues(modelDef, data) {
3841
+ fillGeneratedAndDefaultValues(modelDef, data) {
3242
3842
  const fields = modelDef.fields;
3243
3843
  const values = clone(data);
3244
3844
  for (const [field, fieldDef] of Object.entries(fields)) {
@@ -3253,6 +3853,16 @@ var BaseOperationHandler = class {
3253
3853
  }
3254
3854
  } else if (fields[field]?.updatedAt) {
3255
3855
  values[field] = this.dialect.transformPrimitive(/* @__PURE__ */ new Date(), "DateTime", false);
3856
+ } else if (fields[field]?.default !== void 0) {
3857
+ let value = fields[field].default;
3858
+ if (fieldDef.type === "Json") {
3859
+ if (fieldDef.array && Array.isArray(value)) {
3860
+ value = value.map((v) => typeof v === "string" ? JSON.parse(v) : v);
3861
+ } else if (typeof value === "string") {
3862
+ value = JSON.parse(value);
3863
+ }
3864
+ }
3865
+ values[field] = this.dialect.transformPrimitive(value, fields[field].type, !!fields[field].array);
3256
3866
  }
3257
3867
  }
3258
3868
  }
@@ -3295,7 +3905,7 @@ var BaseOperationHandler = class {
3295
3905
  }
3296
3906
  } else {
3297
3907
  const fromRelationFieldDef = this.requireField(fromRelation.model, fromRelation.field);
3298
- invariant7(fromRelationFieldDef.relation?.opposite);
3908
+ invariant9(fromRelationFieldDef.relation?.opposite);
3299
3909
  parentWhere[fromRelationFieldDef.relation.opposite] = {
3300
3910
  some: fromRelation.ids
3301
3911
  };
@@ -3353,10 +3963,7 @@ var BaseOperationHandler = class {
3353
3963
  throw new QueryError(`Relation update not allowed for field "${field}"`);
3354
3964
  }
3355
3965
  if (!thisEntity) {
3356
- thisEntity = await this.readUnique(kysely, model, {
3357
- where: combinedWhere,
3358
- select: this.makeIdSelect(model)
3359
- });
3966
+ thisEntity = await this.getEntityIds(kysely, model, combinedWhere);
3360
3967
  if (!thisEntity) {
3361
3968
  if (throwIfNotFound) {
3362
3969
  throw new NotFoundError(model);
@@ -3365,13 +3972,16 @@ var BaseOperationHandler = class {
3365
3972
  }
3366
3973
  }
3367
3974
  }
3368
- await this.processRelationUpdates(kysely, model, field, fieldDef, thisEntity, finalData[field], throwIfNotFound);
3975
+ const parentUpdates = await this.processRelationUpdates(kysely, model, field, fieldDef, thisEntity, finalData[field], throwIfNotFound);
3976
+ if (Object.keys(parentUpdates).length > 0) {
3977
+ Object.assign(updateFields, parentUpdates);
3978
+ }
3369
3979
  }
3370
3980
  }
3371
3981
  if (Object.keys(updateFields).length === 0) {
3372
3982
  return combinedWhere;
3373
3983
  } else {
3374
- const idFields = getIdFields(this.schema, model);
3984
+ const idFields = requireIdFields(this.schema, model);
3375
3985
  const query = kysely.updateTable(model).where((eb) => this.dialect.buildFilter(eb, model, model, combinedWhere)).set(updateFields).returning(idFields).modifyEnd(this.makeContextComment({
3376
3986
  model,
3377
3987
  operation: "update"
@@ -3416,7 +4026,7 @@ var BaseOperationHandler = class {
3416
4026
  if (!filter || typeof filter !== "object") {
3417
4027
  return false;
3418
4028
  }
3419
- const idFields = getIdFields(this.schema, model);
4029
+ const idFields = requireIdFields(this.schema, model);
3420
4030
  return idFields.length === Object.keys(filter).length && idFields.every((field) => field in filter);
3421
4031
  }
3422
4032
  async processBaseModelUpdate(kysely, model, where, updateFields, throwIfNotFound) {
@@ -3437,20 +4047,20 @@ var BaseOperationHandler = class {
3437
4047
  };
3438
4048
  }
3439
4049
  transformIncrementalUpdate(model, field, fieldDef, payload) {
3440
- invariant7(Object.keys(payload).length === 1, 'Only one of "set", "increment", "decrement", "multiply", or "divide" can be provided');
4050
+ invariant9(Object.keys(payload).length === 1, 'Only one of "set", "increment", "decrement", "multiply", or "divide" can be provided');
3441
4051
  const key = Object.keys(payload)[0];
3442
4052
  const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, false);
3443
- const eb = expressionBuilder3();
4053
+ const eb = expressionBuilder4();
3444
4054
  const fieldRef = this.dialect.fieldRef(model, field, eb);
3445
4055
  return match9(key).with("set", () => value).with("increment", () => eb(fieldRef, "+", value)).with("decrement", () => eb(fieldRef, "-", value)).with("multiply", () => eb(fieldRef, "*", value)).with("divide", () => eb(fieldRef, "/", value)).otherwise(() => {
3446
4056
  throw new InternalError(`Invalid incremental update operation: ${key}`);
3447
4057
  });
3448
4058
  }
3449
4059
  transformScalarListUpdate(model, field, fieldDef, payload) {
3450
- invariant7(Object.keys(payload).length === 1, 'Only one of "set", "push" can be provided');
4060
+ invariant9(Object.keys(payload).length === 1, 'Only one of "set", "push" can be provided');
3451
4061
  const key = Object.keys(payload)[0];
3452
4062
  const value = this.dialect.transformPrimitive(payload[key], fieldDef.type, true);
3453
- const eb = expressionBuilder3();
4063
+ const eb = expressionBuilder4();
3454
4064
  const fieldRef = this.dialect.fieldRef(model, field, eb);
3455
4065
  return match9(key).with("set", () => value).with("push", () => {
3456
4066
  return eb(fieldRef, "||", eb.val(ensureArray(value)));
@@ -3462,7 +4072,7 @@ var BaseOperationHandler = class {
3462
4072
  return NUMERIC_FIELD_TYPES.includes(fieldDef.type) && !fieldDef.array;
3463
4073
  }
3464
4074
  makeContextComment(_context) {
3465
- return sql4``;
4075
+ return sql5``;
3466
4076
  }
3467
4077
  async updateMany(kysely, model, where, data, limit, returnData, filterModel) {
3468
4078
  if (typeof data !== "object") {
@@ -3521,7 +4131,7 @@ var BaseOperationHandler = class {
3521
4131
  count: Number(result.numAffectedRows)
3522
4132
  };
3523
4133
  } else {
3524
- const idFields = getIdFields(this.schema, model);
4134
+ const idFields = requireIdFields(this.schema, model);
3525
4135
  const result = await query.returning(idFields).execute();
3526
4136
  return result;
3527
4137
  }
@@ -3544,82 +4154,87 @@ var BaseOperationHandler = class {
3544
4154
  };
3545
4155
  }
3546
4156
  buildIdFieldRefs(kysely, model) {
3547
- const idFields = getIdFields(this.schema, model);
4157
+ const idFields = requireIdFields(this.schema, model);
3548
4158
  return idFields.map((f) => kysely.dynamic.ref(`${model}.${f}`));
3549
4159
  }
3550
4160
  async processRelationUpdates(kysely, model, field, fieldDef, parentIds, args, throwIfNotFound) {
3551
- const tasks = [];
3552
4161
  const fieldModel = fieldDef.type;
3553
4162
  const fromRelationContext = {
3554
4163
  model,
3555
4164
  field,
3556
- ids: parentIds
4165
+ ids: parentIds,
4166
+ parentUpdates: {}
3557
4167
  };
3558
4168
  for (const [key, value] of Object.entries(args)) {
3559
4169
  switch (key) {
3560
4170
  case "create": {
3561
- invariant7(!Array.isArray(value) || fieldDef.array, "relation must be an array if create is an array");
3562
- tasks.push(...enumerate(value).map((item) => this.create(kysely, fieldModel, item, fromRelationContext)));
4171
+ invariant9(!Array.isArray(value) || fieldDef.array, "relation must be an array if create is an array");
4172
+ for (const item of enumerate(value)) {
4173
+ await this.create(kysely, fieldModel, item, fromRelationContext);
4174
+ }
3563
4175
  break;
3564
4176
  }
3565
4177
  case "createMany": {
3566
- invariant7(fieldDef.array, "relation must be an array for createMany");
3567
- tasks.push(this.createMany(kysely, fieldModel, value, false, fromRelationContext));
4178
+ invariant9(fieldDef.array, "relation must be an array for createMany");
4179
+ await this.createMany(kysely, fieldModel, value, false, fromRelationContext);
3568
4180
  break;
3569
4181
  }
3570
4182
  case "connect": {
3571
- tasks.push(this.connectRelation(kysely, fieldModel, value, fromRelationContext));
4183
+ await this.connectRelation(kysely, fieldModel, value, fromRelationContext);
3572
4184
  break;
3573
4185
  }
3574
4186
  case "connectOrCreate": {
3575
- tasks.push(this.connectOrCreateRelation(kysely, fieldModel, value, fromRelationContext));
4187
+ await this.connectOrCreateRelation(kysely, fieldModel, value, fromRelationContext);
3576
4188
  break;
3577
4189
  }
3578
4190
  case "disconnect": {
3579
- tasks.push(this.disconnectRelation(kysely, fieldModel, value, fromRelationContext));
4191
+ await this.disconnectRelation(kysely, fieldModel, value, fromRelationContext);
3580
4192
  break;
3581
4193
  }
3582
4194
  case "set": {
3583
- invariant7(fieldDef.array, "relation must be an array");
3584
- tasks.push(this.setRelation(kysely, fieldModel, value, fromRelationContext));
4195
+ invariant9(fieldDef.array, "relation must be an array");
4196
+ await this.setRelation(kysely, fieldModel, value, fromRelationContext);
3585
4197
  break;
3586
4198
  }
3587
4199
  case "update": {
3588
- tasks.push(...enumerate(value).map((item) => {
4200
+ for (const _item of enumerate(value)) {
4201
+ const item = _item;
3589
4202
  let where;
3590
4203
  let data;
3591
- if ("where" in item) {
4204
+ if ("data" in item && typeof item.data === "object") {
3592
4205
  where = item.where;
3593
4206
  data = item.data;
3594
4207
  } else {
3595
4208
  where = void 0;
3596
4209
  data = item;
3597
4210
  }
3598
- return this.update(kysely, fieldModel, where, data, fromRelationContext, true, throwIfNotFound);
3599
- }));
4211
+ await this.update(kysely, fieldModel, where, data, fromRelationContext, true, throwIfNotFound);
4212
+ }
3600
4213
  break;
3601
4214
  }
3602
4215
  case "upsert": {
3603
- tasks.push(...enumerate(value).map(async (item) => {
4216
+ for (const _item of enumerate(value)) {
4217
+ const item = _item;
3604
4218
  const updated = await this.update(kysely, fieldModel, item.where, item.update, fromRelationContext, true, false);
3605
- if (updated) {
3606
- return updated;
3607
- } else {
3608
- return this.create(kysely, fieldModel, item.create, fromRelationContext);
4219
+ if (!updated) {
4220
+ await this.create(kysely, fieldModel, item.create, fromRelationContext);
3609
4221
  }
3610
- }));
4222
+ }
3611
4223
  break;
3612
4224
  }
3613
4225
  case "updateMany": {
3614
- tasks.push(...enumerate(value).map((item) => this.update(kysely, fieldModel, item.where, item.data, fromRelationContext, false, false)));
4226
+ for (const _item of enumerate(value)) {
4227
+ const item = _item;
4228
+ await this.update(kysely, fieldModel, item.where, item.data, fromRelationContext, false, false);
4229
+ }
3615
4230
  break;
3616
4231
  }
3617
4232
  case "delete": {
3618
- tasks.push(this.deleteRelation(kysely, fieldModel, value, fromRelationContext, true));
4233
+ await this.deleteRelation(kysely, fieldModel, value, fromRelationContext, true);
3619
4234
  break;
3620
4235
  }
3621
4236
  case "deleteMany": {
3622
- tasks.push(this.deleteRelation(kysely, fieldModel, value, fromRelationContext, false));
4237
+ await this.deleteRelation(kysely, fieldModel, value, fromRelationContext, false);
3623
4238
  break;
3624
4239
  }
3625
4240
  default: {
@@ -3627,7 +4242,7 @@ var BaseOperationHandler = class {
3627
4242
  }
3628
4243
  }
3629
4244
  }
3630
- await Promise.all(tasks);
4245
+ return fromRelationContext.parentUpdates;
3631
4246
  }
3632
4247
  // #region relation manipulation
3633
4248
  async connectRelation(kysely, model, data, fromRelation) {
@@ -3637,37 +4252,35 @@ var BaseOperationHandler = class {
3637
4252
  }
3638
4253
  const m2m = getManyToManyRelation(this.schema, fromRelation.model, fromRelation.field);
3639
4254
  if (m2m) {
3640
- const actions = _data.map(async (d) => {
4255
+ const results = [];
4256
+ for (const d of _data) {
3641
4257
  const ids = await this.getEntityIds(kysely, model, d);
3642
- return this.handleManyToManyRelation(kysely, "connect", fromRelation.model, fromRelation.field, fromRelation.ids, m2m.otherModel, m2m.otherField, ids, m2m.joinTable);
3643
- });
3644
- const results = await Promise.all(actions);
4258
+ if (!ids) {
4259
+ throw new NotFoundError(model);
4260
+ }
4261
+ const r = await this.handleManyToManyRelation(kysely, "connect", fromRelation.model, fromRelation.field, fromRelation.ids, m2m.otherModel, m2m.otherField, ids, m2m.joinTable);
4262
+ results.push(r);
4263
+ }
3645
4264
  if (_data.length > results.filter((r) => !!r).length) {
3646
4265
  throw new NotFoundError(model);
3647
4266
  }
3648
4267
  } else {
3649
4268
  const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, fromRelation.model, fromRelation.field);
3650
- let updateResult;
3651
4269
  if (ownedByModel) {
3652
- invariant7(_data.length === 1, "only one entity can be connected");
4270
+ invariant9(_data.length === 1, "only one entity can be connected");
3653
4271
  const target = await this.readUnique(kysely, model, {
3654
4272
  where: _data[0]
3655
4273
  });
3656
4274
  if (!target) {
3657
4275
  throw new NotFoundError(model);
3658
4276
  }
3659
- const query = kysely.updateTable(fromRelation.model).where((eb) => eb.and(fromRelation.ids)).set(keyPairs.reduce((acc, { fk, pk }) => ({
3660
- ...acc,
3661
- [fk]: target[pk]
3662
- }), {})).modifyEnd(this.makeContextComment({
3663
- model: fromRelation.model,
3664
- operation: "update"
3665
- }));
3666
- updateResult = await this.executeQuery(kysely, query, "connect");
4277
+ for (const { fk, pk } of keyPairs) {
4278
+ fromRelation.parentUpdates[fk] = target[pk];
4279
+ }
3667
4280
  } else {
3668
4281
  const relationFieldDef = this.requireField(fromRelation.model, fromRelation.field);
3669
4282
  if (!relationFieldDef.array) {
3670
- const query2 = kysely.updateTable(model).where((eb) => eb.and(keyPairs.map(({ fk, pk }) => eb(sql4.ref(fk), "=", fromRelation.ids[pk])))).set(keyPairs.reduce((acc, { fk }) => ({
4283
+ const query2 = kysely.updateTable(model).where((eb) => eb.and(keyPairs.map(({ fk, pk }) => eb(sql5.ref(fk), "=", fromRelation.ids[pk])))).set(keyPairs.reduce((acc, { fk }) => ({
3671
4284
  ...acc,
3672
4285
  [fk]: null
3673
4286
  }), {})).modifyEnd(this.makeContextComment({
@@ -3683,10 +4296,10 @@ var BaseOperationHandler = class {
3683
4296
  model,
3684
4297
  operation: "update"
3685
4298
  }));
3686
- updateResult = await this.executeQuery(kysely, query, "connect");
3687
- }
3688
- if (_data.length > updateResult.numAffectedRows) {
3689
- throw new NotFoundError(model);
4299
+ const updateResult = await this.executeQuery(kysely, query, "connect");
4300
+ if (!updateResult.numAffectedRows || _data.length > updateResult.numAffectedRows) {
4301
+ throw new NotFoundError(model);
4302
+ }
3690
4303
  }
3691
4304
  }
3692
4305
  }
@@ -3695,16 +4308,16 @@ var BaseOperationHandler = class {
3695
4308
  if (_data.length === 0) {
3696
4309
  return;
3697
4310
  }
3698
- return Promise.all(_data.map(async ({ where, create }) => {
4311
+ for (const { where, create } of _data) {
3699
4312
  const existing = await this.exists(kysely, model, where);
3700
4313
  if (existing) {
3701
- return this.connectRelation(kysely, model, [
4314
+ await this.connectRelation(kysely, model, [
3702
4315
  where
3703
4316
  ], fromRelation);
3704
4317
  } else {
3705
- return this.create(kysely, model, create, fromRelation);
4318
+ await this.create(kysely, model, create, fromRelation);
3706
4319
  }
3707
- }));
4320
+ }
3708
4321
  }
3709
4322
  async disconnectRelation(kysely, model, data, fromRelation) {
3710
4323
  let disconnectConditions = [];
@@ -3727,33 +4340,51 @@ var BaseOperationHandler = class {
3727
4340
  }
3728
4341
  const m2m = getManyToManyRelation(this.schema, fromRelation.model, fromRelation.field);
3729
4342
  if (m2m) {
3730
- const actions = disconnectConditions.map(async (d) => {
4343
+ for (const d of disconnectConditions) {
3731
4344
  const ids = await this.getEntityIds(kysely, model, d);
3732
4345
  if (!ids) {
3733
4346
  return;
3734
4347
  }
3735
- return this.handleManyToManyRelation(kysely, "disconnect", fromRelation.model, fromRelation.field, fromRelation.ids, m2m.otherModel, m2m.otherField, ids, m2m.joinTable);
3736
- });
3737
- await Promise.all(actions);
4348
+ await this.handleManyToManyRelation(kysely, "disconnect", fromRelation.model, fromRelation.field, fromRelation.ids, m2m.otherModel, m2m.otherField, ids, m2m.joinTable);
4349
+ }
3738
4350
  } else {
3739
4351
  const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, fromRelation.model, fromRelation.field);
3740
- const eb = expressionBuilder3();
4352
+ const eb = expressionBuilder4();
3741
4353
  if (ownedByModel) {
3742
- invariant7(disconnectConditions.length === 1, "only one entity can be disconnected");
4354
+ invariant9(disconnectConditions.length === 1, "only one entity can be disconnected");
3743
4355
  const condition = disconnectConditions[0];
3744
- const query = kysely.updateTable(fromRelation.model).where(eb.and(fromRelation.ids)).$if(condition !== true, (qb) => qb.where(eb(
3745
- // @ts-ignore
3746
- eb.refTuple(...keyPairs.map(({ fk }) => fk)),
3747
- "in",
3748
- eb.selectFrom(model).select(keyPairs.map(({ pk }) => pk)).where(this.dialect.buildFilter(eb, model, model, condition))
3749
- ))).set(keyPairs.reduce((acc, { fk }) => ({
3750
- ...acc,
3751
- [fk]: null
3752
- }), {})).modifyEnd(this.makeContextComment({
3753
- model: fromRelation.model,
3754
- operation: "update"
3755
- }));
3756
- await this.executeQuery(kysely, query, "disconnect");
4356
+ if (condition === true) {
4357
+ for (const { fk } of keyPairs) {
4358
+ fromRelation.parentUpdates[fk] = null;
4359
+ }
4360
+ } else {
4361
+ const fromEntity = await this.readUnique(kysely, fromRelation.model, {
4362
+ where: fromRelation.ids,
4363
+ select: fieldsToSelectObject(keyPairs.map(({ fk }) => fk))
4364
+ });
4365
+ if (!fromEntity || keyPairs.some(({ fk }) => fromEntity[fk] == null)) {
4366
+ return;
4367
+ }
4368
+ const relationFilter = {
4369
+ AND: [
4370
+ condition,
4371
+ Object.fromEntries(keyPairs.map(({ fk, pk }) => [
4372
+ pk,
4373
+ fromEntity[fk]
4374
+ ]))
4375
+ ]
4376
+ };
4377
+ const targetExists = await this.read(kysely, model, {
4378
+ where: relationFilter,
4379
+ take: 1,
4380
+ select: this.makeIdSelect(model)
4381
+ });
4382
+ if (targetExists.length > 0) {
4383
+ for (const { fk } of keyPairs) {
4384
+ fromRelation.parentUpdates[fk] = null;
4385
+ }
4386
+ }
4387
+ }
3757
4388
  } else {
3758
4389
  const query = kysely.updateTable(model).where(eb.and([
3759
4390
  // fk filter
@@ -3779,11 +4410,14 @@ var BaseOperationHandler = class {
3779
4410
  const m2m = getManyToManyRelation(this.schema, fromRelation.model, fromRelation.field);
3780
4411
  if (m2m) {
3781
4412
  await this.resetManyToManyRelation(kysely, fromRelation.model, fromRelation.field, fromRelation.ids);
3782
- const actions = _data.map(async (d) => {
4413
+ const results = [];
4414
+ for (const d of _data) {
3783
4415
  const ids = await this.getEntityIds(kysely, model, d);
3784
- return this.handleManyToManyRelation(kysely, "connect", fromRelation.model, fromRelation.field, fromRelation.ids, m2m.otherModel, m2m.otherField, ids, m2m.joinTable);
3785
- });
3786
- const results = await Promise.all(actions);
4416
+ if (!ids) {
4417
+ throw new NotFoundError(model);
4418
+ }
4419
+ results.push(await this.handleManyToManyRelation(kysely, "connect", fromRelation.model, fromRelation.field, fromRelation.ids, m2m.otherModel, m2m.otherField, ids, m2m.joinTable));
4420
+ }
3787
4421
  if (_data.length > results.filter((r) => !!r).length) {
3788
4422
  throw new NotFoundError(model);
3789
4423
  }
@@ -3818,7 +4452,7 @@ var BaseOperationHandler = class {
3818
4452
  operation: "update"
3819
4453
  }));
3820
4454
  const r = await this.executeQuery(kysely, query2, "connect");
3821
- if (_data.length > r.numAffectedRows) {
4455
+ if (!r.numAffectedRows || _data.length > r.numAffectedRows) {
3822
4456
  throw new NotFoundError(model);
3823
4457
  }
3824
4458
  }
@@ -3844,10 +4478,12 @@ var BaseOperationHandler = class {
3844
4478
  expectedDeleteCount = deleteConditions.length;
3845
4479
  }
3846
4480
  let deleteResult;
4481
+ let deleteFromModel;
3847
4482
  const m2m = getManyToManyRelation(this.schema, fromRelation.model, fromRelation.field);
3848
4483
  if (m2m) {
4484
+ deleteFromModel = model;
3849
4485
  const fieldDef = this.requireField(fromRelation.model, fromRelation.field);
3850
- invariant7(fieldDef.relation?.opposite);
4486
+ invariant9(fieldDef.relation?.opposite);
3851
4487
  deleteResult = await this.delete(kysely, model, {
3852
4488
  AND: [
3853
4489
  {
@@ -3863,14 +4499,15 @@ var BaseOperationHandler = class {
3863
4499
  } else {
3864
4500
  const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, fromRelation.model, fromRelation.field);
3865
4501
  if (ownedByModel) {
4502
+ deleteFromModel = fromRelation.model;
3866
4503
  const fromEntity = await this.readUnique(kysely, fromRelation.model, {
3867
4504
  where: fromRelation.ids
3868
4505
  });
3869
4506
  if (!fromEntity) {
3870
- throw new NotFoundError(model);
4507
+ throw new NotFoundError(fromRelation.model);
3871
4508
  }
3872
4509
  const fieldDef = this.requireField(fromRelation.model, fromRelation.field);
3873
- invariant7(fieldDef.relation?.opposite);
4510
+ invariant9(fieldDef.relation?.opposite);
3874
4511
  deleteResult = await this.delete(kysely, model, {
3875
4512
  AND: [
3876
4513
  // filter for parent
@@ -3884,6 +4521,7 @@ var BaseOperationHandler = class {
3884
4521
  ]
3885
4522
  });
3886
4523
  } else {
4524
+ deleteFromModel = model;
3887
4525
  deleteResult = await this.delete(kysely, model, {
3888
4526
  AND: [
3889
4527
  Object.fromEntries(keyPairs.map(({ fk, pk }) => [
@@ -3898,7 +4536,7 @@ var BaseOperationHandler = class {
3898
4536
  }
3899
4537
  }
3900
4538
  if (throwForNotFound && expectedDeleteCount > deleteResult.count) {
3901
- throw new NotFoundError(model);
4539
+ throw new NotFoundError(deleteFromModel);
3902
4540
  }
3903
4541
  }
3904
4542
  normalizeRelationManipulationInput(model, data) {
@@ -3999,7 +4637,7 @@ var BaseOperationHandler = class {
3999
4637
  // reused the filter if it's a complete id filter (without extra fields)
4000
4638
  // otherwise, read the entity by the filter
4001
4639
  getEntityIds(kysely, model, uniqueFilter) {
4002
- const idFields = getIdFields(this.schema, model);
4640
+ const idFields = requireIdFields(this.schema, model);
4003
4641
  if (
4004
4642
  // all id fields are provided
4005
4643
  idFields.every((f) => f in uniqueFilter && uniqueFilter[f] !== void 0) && // no non-id filter exists
@@ -4101,7 +4739,7 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
4101
4739
  if (field === "_all") {
4102
4740
  query = query.select((eb) => eb.cast(eb.fn.countAll(), "integer").as(`_count._all`));
4103
4741
  } else {
4104
- query = query.select((eb) => eb.cast(eb.fn.count(sql5.ref(`$sub.${field}`)), "integer").as(`${key}.${field}`));
4742
+ query = query.select((eb) => eb.cast(eb.fn.count(sql6.ref(`$sub.${field}`)), "integer").as(`${key}.${field}`));
4105
4743
  }
4106
4744
  }
4107
4745
  });
@@ -4116,7 +4754,7 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
4116
4754
  if (val === true) {
4117
4755
  query = query.select((eb) => {
4118
4756
  const fn = match10(key).with("_sum", () => eb.fn.sum).with("_avg", () => eb.fn.avg).with("_max", () => eb.fn.max).with("_min", () => eb.fn.min).exhaustive();
4119
- return fn(sql5.ref(`$sub.${field}`)).as(`${key}.${field}`);
4757
+ return fn(sql6.ref(`$sub.${field}`)).as(`${key}.${field}`);
4120
4758
  });
4121
4759
  }
4122
4760
  });
@@ -4163,7 +4801,7 @@ var AggregateOperationHandler = class extends BaseOperationHandler {
4163
4801
  };
4164
4802
 
4165
4803
  // src/client/crud/operations/count.ts
4166
- import { sql as sql6 } from "kysely";
4804
+ import { sql as sql7 } from "kysely";
4167
4805
  var CountOperationHandler = class extends BaseOperationHandler {
4168
4806
  static {
4169
4807
  __name(this, "CountOperationHandler");
@@ -4187,7 +4825,7 @@ var CountOperationHandler = class extends BaseOperationHandler {
4187
4825
  return subQuery.as(subQueryName);
4188
4826
  });
4189
4827
  if (parsedArgs?.select && typeof parsedArgs.select === "object") {
4190
- query = query.select((eb) => Object.keys(parsedArgs.select).map((key) => key === "_all" ? eb.cast(eb.fn.countAll(), "integer").as("_all") : eb.cast(eb.fn.count(sql6.ref(`${subQueryName}.${key}`)), "integer").as(key)));
4828
+ query = query.select((eb) => Object.keys(parsedArgs.select).map((key) => key === "_all" ? eb.cast(eb.fn.countAll(), "integer").as("_all") : eb.cast(eb.fn.count(sql7.ref(`${subQueryName}.${key}`)), "integer").as(key)));
4191
4829
  const result = await this.executeQuery(this.kysely, query, "count");
4192
4830
  return result.rows[0];
4193
4831
  } else {
@@ -4223,7 +4861,7 @@ var CreateOperationHandler = class extends BaseOperationHandler {
4223
4861
  });
4224
4862
  });
4225
4863
  if (!result && this.hasPolicyEnabled) {
4226
- throw new RejectedByPolicyError(this.model, `result is not allowed to be read back`);
4864
+ throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, `result is not allowed to be read back`);
4227
4865
  }
4228
4866
  return result;
4229
4867
  }
@@ -4269,15 +4907,15 @@ var DeleteOperationHandler = class extends BaseOperationHandler {
4269
4907
  omit: args.omit,
4270
4908
  where: args.where
4271
4909
  });
4272
- if (!existing) {
4273
- throw new NotFoundError(this.model);
4274
- }
4275
4910
  await this.safeTransaction(async (tx) => {
4276
4911
  const result = await this.delete(tx, this.model, args.where);
4277
4912
  if (result.count === 0) {
4278
4913
  throw new NotFoundError(this.model);
4279
4914
  }
4280
4915
  });
4916
+ if (!existing && this.hasPolicyEnabled) {
4917
+ throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
4918
+ }
4281
4919
  return existing;
4282
4920
  }
4283
4921
  async runDeleteMany(args) {
@@ -4311,7 +4949,7 @@ var FindOperationHandler = class extends BaseOperationHandler {
4311
4949
  };
4312
4950
 
4313
4951
  // src/client/crud/operations/group-by.ts
4314
- import { expressionBuilder as expressionBuilder4 } from "kysely";
4952
+ import { expressionBuilder as expressionBuilder5 } from "kysely";
4315
4953
  import { match as match13 } from "ts-pattern";
4316
4954
  var GroupByOperationHandler = class extends BaseOperationHandler {
4317
4955
  static {
@@ -4333,7 +4971,7 @@ var GroupByOperationHandler = class extends BaseOperationHandler {
4333
4971
  subQuery = this.dialect.buildOrderBy(subQuery, this.model, this.model, void 0, skip !== void 0 || take !== void 0, negateOrderBy);
4334
4972
  return subQuery.as("$sub");
4335
4973
  });
4336
- const fieldRef = /* @__PURE__ */ __name((field) => this.dialect.fieldRef(this.model, field, expressionBuilder4(), "$sub"), "fieldRef");
4974
+ const fieldRef = /* @__PURE__ */ __name((field) => this.dialect.fieldRef(this.model, field, expressionBuilder5(), "$sub"), "fieldRef");
4337
4975
  const bys = typeof parsedArgs.by === "string" ? [
4338
4976
  parsedArgs.by
4339
4977
  ] : parsedArgs.by;
@@ -4448,7 +5086,7 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
4448
5086
  });
4449
5087
  if (!readBackResult) {
4450
5088
  if (this.hasPolicyEnabled) {
4451
- throw new RejectedByPolicyError(this.model, "result is not allowed to be read back");
5089
+ throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
4452
5090
  } else {
4453
5091
  return null;
4454
5092
  }
@@ -4465,16 +5103,24 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
4465
5103
  if (!args) {
4466
5104
  return [];
4467
5105
  }
4468
- return this.safeTransaction(async (tx) => {
4469
- const updateResult = await this.updateMany(tx, this.model, args.where, args.data, args.limit, true);
4470
- return this.read(tx, this.model, {
5106
+ const { readBackResult, updateResult } = await this.safeTransaction(async (tx) => {
5107
+ const updateResult2 = await this.updateMany(tx, this.model, args.where, args.data, args.limit, true);
5108
+ const readBackResult2 = await this.read(tx, this.model, {
4471
5109
  select: args.select,
4472
5110
  omit: args.omit,
4473
5111
  where: {
4474
- OR: updateResult.map((item) => getIdValues(this.schema, this.model, item))
5112
+ OR: updateResult2.map((item) => getIdValues(this.schema, this.model, item))
4475
5113
  }
4476
5114
  });
5115
+ return {
5116
+ readBackResult: readBackResult2,
5117
+ updateResult: updateResult2
5118
+ };
4477
5119
  });
5120
+ if (readBackResult.length < updateResult.length && this.hasPolicyEnabled) {
5121
+ throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
5122
+ }
5123
+ return readBackResult;
4478
5124
  }
4479
5125
  async runUpsert(args) {
4480
5126
  const result = await this.safeTransaction(async (tx) => {
@@ -4490,18 +5136,32 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
4490
5136
  });
4491
5137
  });
4492
5138
  if (!result && this.hasPolicyEnabled) {
4493
- throw new RejectedByPolicyError(this.model, "result is not allowed to be read back");
5139
+ throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
4494
5140
  }
4495
5141
  return result;
4496
5142
  }
4497
5143
  };
4498
5144
 
4499
5145
  // src/client/crud/validator.ts
4500
- import { invariant as invariant8 } from "@zenstackhq/common-helpers";
4501
- import Decimal from "decimal.js";
5146
+ import { invariant as invariant10 } from "@zenstackhq/common-helpers";
5147
+ import Decimal3 from "decimal.js";
4502
5148
  import stableStringify from "json-stable-stringify";
4503
5149
  import { match as match15, P as P2 } from "ts-pattern";
4504
5150
  import { z } from "zod";
5151
+
5152
+ // src/utils/zod-utils.ts
5153
+ import { fromError as fromError3 } from "zod-validation-error/v3";
5154
+ import { fromError as fromError4 } from "zod-validation-error/v4";
5155
+ function formatError(error) {
5156
+ if ("_zod" in error) {
5157
+ return fromError4(error).toString();
5158
+ } else {
5159
+ return fromError3(error).toString();
5160
+ }
5161
+ }
5162
+ __name(formatError, "formatError");
5163
+
5164
+ // src/client/crud/validator.ts
4505
5165
  var InputValidator = class {
4506
5166
  static {
4507
5167
  __name(this, "InputValidator");
@@ -4563,7 +5223,7 @@ var InputValidator = class {
4563
5223
  }
4564
5224
  const { error } = schema.safeParse(args);
4565
5225
  if (error) {
4566
- throw new InputValidationError(`Invalid ${operation} args: ${error.message}`, error);
5226
+ throw new InputValidationError(`Invalid ${operation} args: ${formatError(error)}`, error);
4567
5227
  }
4568
5228
  return args;
4569
5229
  }
@@ -4607,7 +5267,7 @@ var InputValidator = class {
4607
5267
  z.bigint()
4608
5268
  ])).with("Decimal", () => z.union([
4609
5269
  z.number(),
4610
- z.instanceof(Decimal),
5270
+ z.instanceof(Decimal3),
4611
5271
  z.string()
4612
5272
  ])).with("DateTime", () => z.union([
4613
5273
  z.date(),
@@ -4622,7 +5282,7 @@ var InputValidator = class {
4622
5282
  return schema;
4623
5283
  }
4624
5284
  const typeDef = this.schema.typeDefs?.[type];
4625
- invariant8(typeDef, `Type definition "${type}" not found in schema`);
5285
+ invariant10(typeDef, `Type definition "${type}" not found in schema`);
4626
5286
  schema = z.object(Object.fromEntries(Object.entries(typeDef.fields).map(([field, def]) => {
4627
5287
  let fieldSchema = this.makePrimitiveSchema(def.type);
4628
5288
  if (def.array) {
@@ -4640,10 +5300,7 @@ var InputValidator = class {
4640
5300
  return schema;
4641
5301
  }
4642
5302
  makeWhereSchema(model, unique, withoutRelationFields = false, withAggregations = false) {
4643
- const modelDef = getModel(this.schema, model);
4644
- if (!modelDef) {
4645
- throw new QueryError(`Model "${model}" not found in schema`);
4646
- }
5303
+ const modelDef = requireModel(this.schema, model);
4647
5304
  const fields = {};
4648
5305
  for (const field of Object.keys(modelDef.fields)) {
4649
5306
  const fieldDef = requireField(this.schema, model, field);
@@ -4693,7 +5350,7 @@ var InputValidator = class {
4693
5350
  for (const uniqueField of uniqueFields) {
4694
5351
  if ("defs" in uniqueField) {
4695
5352
  fields[uniqueField.name] = z.object(Object.fromEntries(Object.entries(uniqueField.defs).map(([key, def]) => {
4696
- invariant8(!def.relation, "unique field cannot be a relation");
5353
+ invariant10(!def.relation, "unique field cannot be a relation");
4697
5354
  let fieldSchema;
4698
5355
  const enumDef = getEnum(this.schema, def.type);
4699
5356
  if (enumDef) {
@@ -4899,9 +5556,16 @@ var InputValidator = class {
4899
5556
  fields[field] = z.boolean().optional();
4900
5557
  }
4901
5558
  }
5559
+ const _countSchema = this.makeCountSelectionSchema(modelDef);
5560
+ if (_countSchema) {
5561
+ fields["_count"] = _countSchema;
5562
+ }
5563
+ return z.strictObject(fields);
5564
+ }
5565
+ makeCountSelectionSchema(modelDef) {
4902
5566
  const toManyRelations = Object.values(modelDef.fields).filter((def) => def.relation && def.array);
4903
5567
  if (toManyRelations.length > 0) {
4904
- fields["_count"] = z.union([
5568
+ return z.union([
4905
5569
  z.literal(true),
4906
5570
  z.strictObject({
4907
5571
  select: z.strictObject(toManyRelations.reduce((acc, fieldDef) => ({
@@ -4915,8 +5579,9 @@ var InputValidator = class {
4915
5579
  }), {}))
4916
5580
  })
4917
5581
  ]).optional();
5582
+ } else {
5583
+ return void 0;
4918
5584
  }
4919
- return z.strictObject(fields);
4920
5585
  }
4921
5586
  makeRelationSelectIncludeSchema(fieldDef) {
4922
5587
  let objSchema = z.strictObject({
@@ -4963,6 +5628,10 @@ var InputValidator = class {
4963
5628
  fields[field] = this.makeRelationSelectIncludeSchema(fieldDef).optional();
4964
5629
  }
4965
5630
  }
5631
+ const _countSchema = this.makeCountSelectionSchema(modelDef);
5632
+ if (_countSchema) {
5633
+ fields["_count"] = _countSchema;
5634
+ }
4966
5635
  return z.strictObject(fields);
4967
5636
  }
4968
5637
  makeOrderBySchema(model, withRelation, WithAggregation) {
@@ -5029,13 +5698,15 @@ var InputValidator = class {
5029
5698
  // #region Create
5030
5699
  makeCreateSchema(model) {
5031
5700
  const dataSchema = this.makeCreateDataSchema(model, false);
5032
- const schema = z.strictObject({
5701
+ let schema = z.strictObject({
5033
5702
  data: dataSchema,
5034
5703
  select: this.makeSelectSchema(model).optional(),
5035
5704
  include: this.makeIncludeSchema(model).optional(),
5036
5705
  omit: this.makeOmitSchema(model).optional()
5037
5706
  });
5038
- return this.refineForSelectIncludeMutuallyExclusive(schema);
5707
+ schema = this.refineForSelectIncludeMutuallyExclusive(schema);
5708
+ schema = this.refineForSelectOmitMutuallyExclusive(schema);
5709
+ return schema;
5039
5710
  }
5040
5711
  makeCreateManySchema(model) {
5041
5712
  return this.makeCreateManyDataSchema(model, []).optional();
@@ -5160,11 +5831,11 @@ var InputValidator = class {
5160
5831
  fields["delete"] = this.makeDeleteRelationDataSchema(fieldType, array, true).optional();
5161
5832
  }
5162
5833
  fields["update"] = array ? this.orArray(z.strictObject({
5163
- where: this.makeWhereSchema(fieldType, true),
5834
+ where: this.makeWhereSchema(fieldType, true).optional(),
5164
5835
  data: this.makeUpdateDataSchema(fieldType, withoutFields)
5165
5836
  }), true).optional() : z.union([
5166
5837
  z.strictObject({
5167
- where: this.makeWhereSchema(fieldType, true),
5838
+ where: this.makeWhereSchema(fieldType, true).optional(),
5168
5839
  data: this.makeUpdateDataSchema(fieldType, withoutFields)
5169
5840
  }),
5170
5841
  this.makeUpdateDataSchema(fieldType, withoutFields)
@@ -5224,14 +5895,16 @@ var InputValidator = class {
5224
5895
  // #endregion
5225
5896
  // #region Update
5226
5897
  makeUpdateSchema(model) {
5227
- const schema = z.strictObject({
5898
+ let schema = z.strictObject({
5228
5899
  where: this.makeWhereSchema(model, true),
5229
5900
  data: this.makeUpdateDataSchema(model),
5230
5901
  select: this.makeSelectSchema(model).optional(),
5231
5902
  include: this.makeIncludeSchema(model).optional(),
5232
5903
  omit: this.makeOmitSchema(model).optional()
5233
5904
  });
5234
- return this.refineForSelectIncludeMutuallyExclusive(schema);
5905
+ schema = this.refineForSelectIncludeMutuallyExclusive(schema);
5906
+ schema = this.refineForSelectOmitMutuallyExclusive(schema);
5907
+ return schema;
5235
5908
  }
5236
5909
  makeUpdateManySchema(model) {
5237
5910
  return z.strictObject({
@@ -5242,14 +5915,15 @@ var InputValidator = class {
5242
5915
  }
5243
5916
  makeUpdateManyAndReturnSchema(model) {
5244
5917
  const base = this.makeUpdateManySchema(model);
5245
- const result = base.extend({
5918
+ let schema = base.extend({
5246
5919
  select: this.makeSelectSchema(model).optional(),
5247
5920
  omit: this.makeOmitSchema(model).optional()
5248
5921
  });
5249
- return this.refineForSelectOmitMutuallyExclusive(result);
5922
+ schema = this.refineForSelectOmitMutuallyExclusive(schema);
5923
+ return schema;
5250
5924
  }
5251
5925
  makeUpsertSchema(model) {
5252
- const schema = z.strictObject({
5926
+ let schema = z.strictObject({
5253
5927
  where: this.makeWhereSchema(model, true),
5254
5928
  create: this.makeCreateDataSchema(model, false),
5255
5929
  update: this.makeUpdateDataSchema(model),
@@ -5257,7 +5931,9 @@ var InputValidator = class {
5257
5931
  include: this.makeIncludeSchema(model).optional(),
5258
5932
  omit: this.makeOmitSchema(model).optional()
5259
5933
  });
5260
- return this.refineForSelectIncludeMutuallyExclusive(schema);
5934
+ schema = this.refineForSelectIncludeMutuallyExclusive(schema);
5935
+ schema = this.refineForSelectOmitMutuallyExclusive(schema);
5936
+ return schema;
5261
5937
  }
5262
5938
  makeUpdateDataSchema(model, withoutFields = [], withoutRelationFields = false) {
5263
5939
  const uncheckedVariantFields = {};
@@ -5334,12 +6010,14 @@ var InputValidator = class {
5334
6010
  // #endregion
5335
6011
  // #region Delete
5336
6012
  makeDeleteSchema(model) {
5337
- const schema = z.strictObject({
6013
+ let schema = z.strictObject({
5338
6014
  where: this.makeWhereSchema(model, true),
5339
6015
  select: this.makeSelectSchema(model).optional(),
5340
6016
  include: this.makeIncludeSchema(model).optional()
5341
6017
  });
5342
- return this.refineForSelectIncludeMutuallyExclusive(schema);
6018
+ schema = this.refineForSelectIncludeMutuallyExclusive(schema);
6019
+ schema = this.refineForSelectOmitMutuallyExclusive(schema);
6020
+ return schema;
5343
6021
  }
5344
6022
  makeDeleteManySchema(model) {
5345
6023
  return z.object({
@@ -5689,32 +6367,13 @@ function performanceNow() {
5689
6367
  __name(performanceNow, "performanceNow");
5690
6368
 
5691
6369
  // src/client/executor/zenstack-query-executor.ts
5692
- import { invariant as invariant11 } from "@zenstackhq/common-helpers";
5693
- import { AndNode as AndNode2, DefaultQueryExecutor, DeleteQueryNode as DeleteQueryNode2, InsertQueryNode as InsertQueryNode2, ReturningNode as ReturningNode2, SelectionNode as SelectionNode4, SingleConnectionProvider, TableNode as TableNode5, UpdateQueryNode as UpdateQueryNode2, WhereNode as WhereNode3 } from "kysely";
6370
+ import { invariant as invariant12 } from "@zenstackhq/common-helpers";
6371
+ import { AndNode as AndNode2, DefaultQueryExecutor, DeleteQueryNode as DeleteQueryNode2, InsertQueryNode as InsertQueryNode2, ReturningNode as ReturningNode2, SelectionNode as SelectionNode4, SingleConnectionProvider, TableNode as TableNode6, UpdateQueryNode as UpdateQueryNode2, WhereNode as WhereNode3 } from "kysely";
5694
6372
  import { match as match16 } from "ts-pattern";
5695
6373
 
5696
- // src/client/executor/kysely-utils.ts
5697
- import { invariant as invariant9 } from "@zenstackhq/common-helpers";
5698
- import { AliasNode as AliasNode4, IdentifierNode as IdentifierNode3 } from "kysely";
5699
- function stripAlias(node) {
5700
- if (AliasNode4.is(node)) {
5701
- invariant9(IdentifierNode3.is(node.alias), "Expected identifier as alias");
5702
- return {
5703
- alias: node.alias.name,
5704
- node: node.node
5705
- };
5706
- } else {
5707
- return {
5708
- alias: void 0,
5709
- node
5710
- };
5711
- }
5712
- }
5713
- __name(stripAlias, "stripAlias");
5714
-
5715
6374
  // src/client/executor/name-mapper.ts
5716
- import { invariant as invariant10 } from "@zenstackhq/common-helpers";
5717
- import { AliasNode as AliasNode5, ColumnNode as ColumnNode3, FromNode as FromNode3, IdentifierNode as IdentifierNode4, OperationNodeTransformer as OperationNodeTransformer2, ReferenceNode as ReferenceNode3, SelectAllNode, SelectionNode as SelectionNode3, TableNode as TableNode4 } from "kysely";
6375
+ import { invariant as invariant11 } from "@zenstackhq/common-helpers";
6376
+ import { AliasNode as AliasNode5, ColumnNode as ColumnNode4, FromNode as FromNode3, IdentifierNode as IdentifierNode3, OperationNodeTransformer as OperationNodeTransformer2, ReferenceNode as ReferenceNode4, SelectAllNode, SelectionNode as SelectionNode3, TableNode as TableNode5 } from "kysely";
5718
6377
  var QueryNameMapper = class extends OperationNodeTransformer2 {
5719
6378
  static {
5720
6379
  __name(this, "QueryNameMapper");
@@ -5783,7 +6442,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5783
6442
  };
5784
6443
  }
5785
6444
  transformReference(node) {
5786
- if (!ColumnNode3.is(node.column)) {
6445
+ if (!ColumnNode4.is(node.column)) {
5787
6446
  return super.transformReference(node);
5788
6447
  }
5789
6448
  const scope = this.resolveFieldFromScopes(node.column.column.name, node.table?.table.identifier.name);
@@ -5791,12 +6450,12 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5791
6450
  const mappedFieldName = this.mapFieldName(scope.model, node.column.column.name);
5792
6451
  let mappedTableName = node.table?.table.identifier.name;
5793
6452
  if (mappedTableName) {
5794
- if (scope.alias === mappedTableName) {
6453
+ if (scope.alias && IdentifierNode3.is(scope.alias) && scope.alias.name === mappedTableName) {
5795
6454
  } else if (scope.model === mappedTableName) {
5796
6455
  mappedTableName = this.mapTableName(scope.model);
5797
6456
  }
5798
6457
  }
5799
- return ReferenceNode3.create(ColumnNode3.create(mappedFieldName), mappedTableName ? TableNode4.create(mappedTableName) : void 0);
6458
+ return ReferenceNode4.create(ColumnNode4.create(mappedFieldName), mappedTableName ? TableNode5.create(mappedTableName) : void 0);
5800
6459
  } else {
5801
6460
  return super.transformReference(node);
5802
6461
  }
@@ -5807,14 +6466,14 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5807
6466
  return super.transformColumn(node);
5808
6467
  }
5809
6468
  const mappedName = this.mapFieldName(scope.model, node.column.name);
5810
- return ColumnNode3.create(mappedName);
6469
+ return ColumnNode4.create(mappedName);
5811
6470
  }
5812
6471
  transformUpdateQuery(node) {
5813
6472
  if (!node.table) {
5814
6473
  return super.transformUpdateQuery(node);
5815
6474
  }
5816
6475
  const { alias, node: innerTable } = stripAlias(node.table);
5817
- if (!innerTable || !TableNode4.is(innerTable)) {
6476
+ if (!innerTable || !TableNode5.is(innerTable)) {
5818
6477
  return super.transformUpdateQuery(node);
5819
6478
  }
5820
6479
  return this.withScope({
@@ -5832,14 +6491,14 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5832
6491
  const scopes = node.from.froms.map((node2) => {
5833
6492
  const { alias, node: innerNode } = stripAlias(node2);
5834
6493
  return {
5835
- model: this.extractModelName(innerNode),
6494
+ model: extractModelName(innerNode),
5836
6495
  alias,
5837
6496
  namesMapped: false
5838
6497
  };
5839
6498
  });
5840
6499
  const froms = node.from.froms.map((from) => {
5841
6500
  const { alias, node: innerNode } = stripAlias(from);
5842
- if (TableNode4.is(innerNode)) {
6501
+ if (TableNode5.is(innerNode)) {
5843
6502
  return this.wrapAlias(this.processTableRef(innerNode), alias);
5844
6503
  } else {
5845
6504
  return super.transformNode(from);
@@ -5864,15 +6523,15 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5864
6523
  } else {
5865
6524
  selections.push(super.transformSelection(selection));
5866
6525
  }
5867
- } else if (ReferenceNode3.is(selection.selection) || ColumnNode3.is(selection.selection)) {
6526
+ } else if (ReferenceNode4.is(selection.selection) || ColumnNode4.is(selection.selection)) {
5868
6527
  const transformed = this.transformNode(selection.selection);
5869
6528
  if (AliasNode5.is(transformed)) {
5870
6529
  selections.push(SelectionNode3.create(transformed));
5871
6530
  } else {
5872
- const origFieldName = this.extractFieldName(selection.selection);
5873
- const fieldName = this.extractFieldName(transformed);
6531
+ const origFieldName = extractFieldName(selection.selection);
6532
+ const fieldName = extractFieldName(transformed);
5874
6533
  if (fieldName !== origFieldName) {
5875
- selections.push(SelectionNode3.create(this.wrapAlias(transformed, origFieldName)));
6534
+ selections.push(SelectionNode3.create(this.wrapAlias(transformed, origFieldName ? IdentifierNode3.create(origFieldName) : void 0)));
5876
6535
  } else {
5877
6536
  selections.push(SelectionNode3.create(transformed));
5878
6537
  }
@@ -5888,7 +6547,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5888
6547
  const scope = this.scopes[i];
5889
6548
  if (qualifier) {
5890
6549
  if (scope.alias) {
5891
- if (scope.alias === qualifier) {
6550
+ if (scope.alias && IdentifierNode3.is(scope.alias) && scope.alias.name === qualifier) {
5892
6551
  return scope;
5893
6552
  } else {
5894
6553
  continue;
@@ -5934,16 +6593,16 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5934
6593
  }
5935
6594
  }
5936
6595
  wrapAlias(node, alias) {
5937
- return alias ? AliasNode5.create(node, IdentifierNode4.create(alias)) : node;
6596
+ return alias ? AliasNode5.create(node, alias) : node;
5938
6597
  }
5939
6598
  processTableRef(node) {
5940
6599
  if (!node) {
5941
6600
  return node;
5942
6601
  }
5943
- if (!TableNode4.is(node)) {
6602
+ if (!TableNode5.is(node)) {
5944
6603
  return super.transformNode(node);
5945
6604
  }
5946
- return TableNode4.create(this.mapTableName(node.table.identifier.name));
6605
+ return TableNode5.create(this.mapTableName(node.table.identifier.name));
5947
6606
  }
5948
6607
  getMappedName(def) {
5949
6608
  const mapAttr = def.attributes?.find((attr) => attr.name === "@@map" || attr.name === "@map");
@@ -5979,14 +6638,14 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5979
6638
  // convert a "from" node to a nested query if there are columns with name mapping
5980
6639
  processSelectTable(node) {
5981
6640
  const { alias, node: innerNode } = stripAlias(node);
5982
- if (innerNode && TableNode4.is(innerNode)) {
6641
+ if (innerNode && TableNode5.is(innerNode)) {
5983
6642
  const modelName = innerNode.table.identifier.name;
5984
6643
  const mappedName = this.mapTableName(modelName);
5985
- const finalAlias = alias ?? (mappedName !== modelName ? modelName : void 0);
6644
+ const finalAlias = alias ?? (mappedName !== modelName ? IdentifierNode3.create(modelName) : void 0);
5986
6645
  return {
5987
- node: this.wrapAlias(TableNode4.create(mappedName), finalAlias),
6646
+ node: this.wrapAlias(TableNode5.create(mappedName), finalAlias),
5988
6647
  scope: {
5989
- alias: alias ?? modelName,
6648
+ alias: alias ?? IdentifierNode3.create(modelName),
5990
6649
  model: modelName,
5991
6650
  namesMapped: !this.hasMappedColumns(modelName)
5992
6651
  }
@@ -6006,9 +6665,9 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
6006
6665
  const modelDef = requireModel(this.schema, model);
6007
6666
  return this.getModelFields(modelDef).map((fieldDef) => {
6008
6667
  const columnName = this.mapFieldName(model, fieldDef.name);
6009
- const columnRef = ReferenceNode3.create(ColumnNode3.create(columnName), alias ? TableNode4.create(alias) : void 0);
6668
+ const columnRef = ReferenceNode4.create(ColumnNode4.create(columnName), alias && IdentifierNode3.is(alias) ? TableNode5.create(alias.name) : void 0);
6010
6669
  if (columnName !== fieldDef.name) {
6011
- const aliased = AliasNode5.create(columnRef, IdentifierNode4.create(fieldDef.name));
6670
+ const aliased = AliasNode5.create(columnRef, IdentifierNode3.create(fieldDef.name));
6012
6671
  return SelectionNode3.create(aliased);
6013
6672
  } else {
6014
6673
  return SelectionNode3.create(columnRef);
@@ -6037,37 +6696,24 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
6037
6696
  processSelection(node) {
6038
6697
  let alias;
6039
6698
  if (!AliasNode5.is(node)) {
6040
- alias = this.extractFieldName(node);
6699
+ alias = extractFieldName(node);
6041
6700
  }
6042
6701
  const result = super.transformNode(node);
6043
- return this.wrapAlias(result, alias);
6702
+ return this.wrapAlias(result, alias ? IdentifierNode3.create(alias) : void 0);
6044
6703
  }
6045
6704
  processSelectAll(node) {
6046
6705
  const scope = this.scopes[this.scopes.length - 1];
6047
- invariant10(scope);
6706
+ invariant11(scope);
6048
6707
  if (!scope.model || !this.hasMappedColumns(scope.model)) {
6049
6708
  return super.transformSelectAll(node);
6050
6709
  }
6051
6710
  const modelDef = requireModel(this.schema, scope.model);
6052
6711
  return this.getModelFields(modelDef).map((fieldDef) => {
6053
6712
  const columnName = this.mapFieldName(modelDef.name, fieldDef.name);
6054
- const columnRef = ReferenceNode3.create(ColumnNode3.create(columnName));
6055
- return columnName !== fieldDef.name ? this.wrapAlias(columnRef, fieldDef.name) : columnRef;
6713
+ const columnRef = ReferenceNode4.create(ColumnNode4.create(columnName));
6714
+ return columnName !== fieldDef.name ? this.wrapAlias(columnRef, IdentifierNode3.create(fieldDef.name)) : columnRef;
6056
6715
  });
6057
6716
  }
6058
- extractModelName(node) {
6059
- const { node: innerNode } = stripAlias(node);
6060
- return TableNode4.is(innerNode) ? innerNode.table.identifier.name : void 0;
6061
- }
6062
- extractFieldName(node) {
6063
- if (ReferenceNode3.is(node) && ColumnNode3.is(node.column)) {
6064
- return node.column.column.name;
6065
- } else if (ColumnNode3.is(node)) {
6066
- return node.column.name;
6067
- } else {
6068
- return void 0;
6069
- }
6070
- }
6071
6717
  };
6072
6718
 
6073
6719
  // src/client/executor/zenstack-query-executor.ts
@@ -6114,7 +6760,6 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6114
6760
  const hookResult = await hook({
6115
6761
  client: this.client,
6116
6762
  schema: this.client.$schema,
6117
- kysely: this.kysely,
6118
6763
  query,
6119
6764
  proceed: _p
6120
6765
  });
@@ -6273,17 +6918,17 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6273
6918
  }
6274
6919
  getMutationModel(queryNode) {
6275
6920
  return match16(queryNode).when(InsertQueryNode2.is, (node) => {
6276
- invariant11(node.into, "InsertQueryNode must have an into clause");
6921
+ invariant12(node.into, "InsertQueryNode must have an into clause");
6277
6922
  return node.into.table.identifier.name;
6278
6923
  }).when(UpdateQueryNode2.is, (node) => {
6279
- invariant11(node.table, "UpdateQueryNode must have a table");
6924
+ invariant12(node.table, "UpdateQueryNode must have a table");
6280
6925
  const { node: tableNode } = stripAlias(node.table);
6281
- invariant11(TableNode5.is(tableNode), "UpdateQueryNode must use a TableNode");
6926
+ invariant12(TableNode6.is(tableNode), "UpdateQueryNode must use a TableNode");
6282
6927
  return tableNode.table.identifier.name;
6283
6928
  }).when(DeleteQueryNode2.is, (node) => {
6284
- invariant11(node.from.froms.length === 1, "Delete query must have exactly one from table");
6929
+ invariant12(node.from.froms.length === 1, "Delete query must have exactly one from table");
6285
6930
  const { node: tableNode } = stripAlias(node.from.froms[0]);
6286
- invariant11(TableNode5.is(tableNode), "DeleteQueryNode must use a TableNode");
6931
+ invariant12(TableNode6.is(tableNode), "DeleteQueryNode must use a TableNode");
6287
6932
  return tableNode.table.identifier.name;
6288
6933
  }).otherwise((node) => {
6289
6934
  throw new InternalError(`Invalid query node: ${node}`);
@@ -6381,53 +7026,58 @@ __export(functions_exports, {
6381
7026
  search: () => search,
6382
7027
  startsWith: () => startsWith
6383
7028
  });
6384
- import { invariant as invariant12, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
6385
- import { sql as sql7, ValueNode as ValueNode4 } from "kysely";
7029
+ import { invariant as invariant13, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
7030
+ import { sql as sql8, ValueNode as ValueNode5 } from "kysely";
6386
7031
  import { match as match17 } from "ts-pattern";
6387
- var contains = /* @__PURE__ */ __name((eb, args) => {
6388
- const [field, search2, caseInsensitive = false] = args;
6389
- if (!field) {
6390
- throw new Error('"field" parameter is required');
6391
- }
6392
- if (!search2) {
6393
- throw new Error('"search" parameter is required');
6394
- }
6395
- const searchExpr = eb.fn("CONCAT", [
6396
- sql7.lit("%"),
6397
- search2,
6398
- sql7.lit("%")
6399
- ]);
6400
- return eb(field, caseInsensitive ? "ilike" : "like", searchExpr);
6401
- }, "contains");
7032
+ var contains = /* @__PURE__ */ __name((eb, args, context) => textMatch(eb, args, context, "contains"), "contains");
6402
7033
  var search = /* @__PURE__ */ __name((_eb, _args) => {
6403
7034
  throw new Error(`"search" function is not implemented yet`);
6404
7035
  }, "search");
6405
- var startsWith = /* @__PURE__ */ __name((eb, args) => {
6406
- const [field, search2] = args;
6407
- if (!field) {
6408
- throw new Error('"field" parameter is required');
6409
- }
6410
- if (!search2) {
6411
- throw new Error('"search" parameter is required');
6412
- }
6413
- return eb(field, "like", eb.fn("CONCAT", [
6414
- search2,
6415
- sql7.lit("%")
6416
- ]));
6417
- }, "startsWith");
6418
- var endsWith = /* @__PURE__ */ __name((eb, args) => {
6419
- const [field, search2] = args;
7036
+ var startsWith = /* @__PURE__ */ __name((eb, args, context) => textMatch(eb, args, context, "startsWith"), "startsWith");
7037
+ var endsWith = /* @__PURE__ */ __name((eb, args, context) => textMatch(eb, args, context, "endsWith"), "endsWith");
7038
+ var textMatch = /* @__PURE__ */ __name((eb, args, { dialect }, method) => {
7039
+ const [field, search2, caseInsensitive = void 0] = args;
6420
7040
  if (!field) {
6421
7041
  throw new Error('"field" parameter is required');
6422
7042
  }
6423
7043
  if (!search2) {
6424
7044
  throw new Error('"search" parameter is required');
6425
7045
  }
6426
- return eb(field, "like", eb.fn("CONCAT", [
6427
- sql7.lit("%"),
6428
- search2
6429
- ]));
6430
- }, "endsWith");
7046
+ const casingBehavior = dialect.getStringCasingBehavior();
7047
+ const caseInsensitiveValue = readBoolean(caseInsensitive, false);
7048
+ let op;
7049
+ let fieldExpr = field;
7050
+ let searchExpr = search2;
7051
+ if (caseInsensitiveValue) {
7052
+ if (casingBehavior.supportsILike) {
7053
+ op = "ilike";
7054
+ } else {
7055
+ op = "like";
7056
+ if (casingBehavior.likeCaseSensitive === true) {
7057
+ fieldExpr = eb.fn("LOWER", [
7058
+ fieldExpr
7059
+ ]);
7060
+ searchExpr = eb.fn("LOWER", [
7061
+ searchExpr
7062
+ ]);
7063
+ }
7064
+ }
7065
+ } else {
7066
+ op = "like";
7067
+ }
7068
+ searchExpr = match17(method).with("contains", () => eb.fn("CONCAT", [
7069
+ sql8.lit("%"),
7070
+ sql8`CAST(${searchExpr} as text)`,
7071
+ sql8.lit("%")
7072
+ ])).with("startsWith", () => eb.fn("CONCAT", [
7073
+ sql8`CAST(${searchExpr} as text)`,
7074
+ sql8.lit("%")
7075
+ ])).with("endsWith", () => eb.fn("CONCAT", [
7076
+ sql8.lit("%"),
7077
+ sql8`CAST(${searchExpr} as text)`
7078
+ ])).exhaustive();
7079
+ return eb(fieldExpr, op, searchExpr);
7080
+ }, "textMatch");
6431
7081
  var has = /* @__PURE__ */ __name((eb, args) => {
6432
7082
  const [field, search2] = args;
6433
7083
  if (!field) {
@@ -6465,18 +7115,16 @@ var isEmpty = /* @__PURE__ */ __name((eb, args, { dialect }) => {
6465
7115
  if (!field) {
6466
7116
  throw new Error('"field" parameter is required');
6467
7117
  }
6468
- return eb(dialect.buildArrayLength(eb, field), "=", sql7.lit(0));
7118
+ return eb(dialect.buildArrayLength(eb, field), "=", sql8.lit(0));
6469
7119
  }, "isEmpty");
6470
- var now = /* @__PURE__ */ __name((eb, _args, { dialect }) => {
6471
- return match17(dialect.provider).with("postgresql", () => eb.fn("now")).with("sqlite", () => sql7.raw("CURRENT_TIMESTAMP")).exhaustive();
6472
- }, "now");
7120
+ var now = /* @__PURE__ */ __name(() => sql8.raw("CURRENT_TIMESTAMP"), "now");
6473
7121
  var currentModel = /* @__PURE__ */ __name((_eb, args, { model }) => {
6474
7122
  let result = model;
6475
7123
  const [casing] = args;
6476
7124
  if (casing) {
6477
7125
  result = processCasing(casing, result, model);
6478
7126
  }
6479
- return sql7.lit(result);
7127
+ return sql8.lit(result);
6480
7128
  }, "currentModel");
6481
7129
  var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
6482
7130
  let result = operation;
@@ -6484,21 +7132,30 @@ var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
6484
7132
  if (casing) {
6485
7133
  result = processCasing(casing, result, operation);
6486
7134
  }
6487
- return sql7.lit(result);
7135
+ return sql8.lit(result);
6488
7136
  }, "currentOperation");
6489
7137
  function processCasing(casing, result, model) {
6490
7138
  const opNode = casing.toOperationNode();
6491
- invariant12(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
7139
+ invariant13(ValueNode5.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
6492
7140
  result = match17(opNode.value).with("original", () => model).with("upper", () => result.toUpperCase()).with("lower", () => result.toLowerCase()).with("capitalize", () => upperCaseFirst(result)).with("uncapitalize", () => lowerCaseFirst(result)).otherwise(() => {
6493
7141
  throw new Error(`Invalid casing value: ${opNode.value}. Must be "original", "upper", "lower", "capitalize", or "uncapitalize".`);
6494
7142
  });
6495
7143
  return result;
6496
7144
  }
6497
7145
  __name(processCasing, "processCasing");
7146
+ function readBoolean(expr2, defaultValue) {
7147
+ if (expr2 === void 0) {
7148
+ return defaultValue;
7149
+ }
7150
+ const opNode = expr2.toOperationNode();
7151
+ invariant13(ValueNode5.is(opNode), "expression must be a literal value");
7152
+ return !!opNode.value;
7153
+ }
7154
+ __name(readBoolean, "readBoolean");
6498
7155
 
6499
7156
  // src/client/helpers/schema-db-pusher.ts
6500
- import { invariant as invariant13 } from "@zenstackhq/common-helpers";
6501
- import { sql as sql8 } from "kysely";
7157
+ import { invariant as invariant14 } from "@zenstackhq/common-helpers";
7158
+ import { sql as sql9 } from "kysely";
6502
7159
  import toposort from "toposort";
6503
7160
  import { match as match18 } from "ts-pattern";
6504
7161
  var SchemaDbPusher = class {
@@ -6519,7 +7176,8 @@ var SchemaDbPusher = class {
6519
7176
  await createEnum.execute();
6520
7177
  }
6521
7178
  }
6522
- const sortedModels = this.sortModels(this.schema.models);
7179
+ const models = Object.values(this.schema.models).filter((m) => !m.isView);
7180
+ const sortedModels = this.sortModels(models);
6523
7181
  for (const modelDef of sortedModels) {
6524
7182
  const createTable = this.createModelTable(tx, modelDef);
6525
7183
  await createTable.execute();
@@ -6528,7 +7186,7 @@ var SchemaDbPusher = class {
6528
7186
  }
6529
7187
  sortModels(models) {
6530
7188
  const graph = [];
6531
- for (const model of Object.values(models)) {
7189
+ for (const model of models) {
6532
7190
  let added = false;
6533
7191
  if (model.baseModel) {
6534
7192
  const baseDef = requireModel(this.schema, model.baseModel);
@@ -6613,7 +7271,7 @@ var SchemaDbPusher = class {
6613
7271
  }
6614
7272
  addUniqueConstraint(table, modelDef) {
6615
7273
  for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
6616
- invariant13(typeof value === "object", "expecting an object");
7274
+ invariant14(typeof value === "object", "expecting an object");
6617
7275
  if ("type" in value) {
6618
7276
  const fieldDef = modelDef.fields[key];
6619
7277
  if (fieldDef.unique) {
@@ -6636,7 +7294,7 @@ var SchemaDbPusher = class {
6636
7294
  if (fieldDef.default !== void 0) {
6637
7295
  if (typeof fieldDef.default === "object" && "kind" in fieldDef.default) {
6638
7296
  if (ExpressionUtils.isCall(fieldDef.default) && fieldDef.default.function === "now") {
6639
- col = col.defaultTo(sql8`CURRENT_TIMESTAMP`);
7297
+ col = col.defaultTo(sql9`CURRENT_TIMESTAMP`);
6640
7298
  }
6641
7299
  } else {
6642
7300
  col = col.defaultTo(fieldDef.default);
@@ -6656,7 +7314,7 @@ var SchemaDbPusher = class {
6656
7314
  }
6657
7315
  mapFieldType(fieldDef) {
6658
7316
  if (this.schema.enums?.[fieldDef.type]) {
6659
- return this.schema.provider.type === "postgresql" ? sql8.ref(fieldDef.type) : "text";
7317
+ return this.schema.provider.type === "postgresql" ? sql9.ref(fieldDef.type) : "text";
6660
7318
  }
6661
7319
  if (this.isAutoIncrement(fieldDef) && this.schema.provider.type === "postgresql") {
6662
7320
  return "serial";
@@ -6669,7 +7327,7 @@ var SchemaDbPusher = class {
6669
7327
  throw new Error(`Unsupported field type: ${type}`);
6670
7328
  });
6671
7329
  if (fieldDef.array) {
6672
- return sql8.raw(`${result}[]`);
7330
+ return sql9.raw(`${result}[]`);
6673
7331
  } else {
6674
7332
  return result;
6675
7333
  }
@@ -6681,7 +7339,7 @@ var SchemaDbPusher = class {
6681
7339
  return fieldDef.default && ExpressionUtils.isCall(fieldDef.default) && fieldDef.default.function === "autoincrement";
6682
7340
  }
6683
7341
  addForeignKeyConstraint(table, model, fieldName, fieldDef) {
6684
- invariant13(fieldDef.relation, "field must be a relation");
7342
+ invariant14(fieldDef.relation, "field must be a relation");
6685
7343
  if (!fieldDef.relation.fields || !fieldDef.relation.references) {
6686
7344
  return table;
6687
7345
  }
@@ -6738,16 +7396,15 @@ function valueToPromise(thing) {
6738
7396
  __name(valueToPromise, "valueToPromise");
6739
7397
 
6740
7398
  // src/client/result-processor.ts
6741
- import { invariant as invariant14 } from "@zenstackhq/common-helpers";
6742
- import Decimal2 from "decimal.js";
6743
- import { match as match19 } from "ts-pattern";
6744
7399
  var ResultProcessor = class {
6745
7400
  static {
6746
7401
  __name(this, "ResultProcessor");
6747
7402
  }
6748
7403
  schema;
6749
- constructor(schema) {
7404
+ dialect;
7405
+ constructor(schema, options) {
6750
7406
  this.schema = schema;
7407
+ this.dialect = getCrudDialect(schema, options);
6751
7408
  }
6752
7409
  processResult(data, model, args) {
6753
7410
  const result = this.doProcessResult(data, model);
@@ -6776,7 +7433,7 @@ var ResultProcessor = class {
6776
7433
  }
6777
7434
  if (key.startsWith(DELEGATE_JOINED_FIELD_PREFIX)) {
6778
7435
  if (value) {
6779
- const subRow = this.transformJson(value);
7436
+ const subRow = this.dialect.transformOutput(value, "Json");
6780
7437
  const subModel = key.slice(DELEGATE_JOINED_FIELD_PREFIX.length);
6781
7438
  const idValues = getIdValues(this.schema, subModel, subRow);
6782
7439
  if (Object.values(idValues).some((v) => v === null || v === void 0)) {
@@ -6810,10 +7467,10 @@ var ResultProcessor = class {
6810
7467
  processFieldValue(value, fieldDef) {
6811
7468
  const type = fieldDef.type;
6812
7469
  if (Array.isArray(value)) {
6813
- value.forEach((v, i) => value[i] = this.transformScalar(v, type));
7470
+ value.forEach((v, i) => value[i] = this.dialect.transformOutput(v, type));
6814
7471
  return value;
6815
7472
  } else {
6816
- return this.transformScalar(value, type);
7473
+ return this.dialect.transformOutput(value, type);
6817
7474
  }
6818
7475
  }
6819
7476
  processRelation(value, fieldDef) {
@@ -6827,42 +7484,6 @@ var ResultProcessor = class {
6827
7484
  }
6828
7485
  return this.doProcessResult(relationData, fieldDef.type);
6829
7486
  }
6830
- transformScalar(value, type) {
6831
- if (this.schema.typeDefs && type in this.schema.typeDefs) {
6832
- return this.transformJson(value);
6833
- } else {
6834
- return match19(type).with("Boolean", () => this.transformBoolean(value)).with("DateTime", () => this.transformDate(value)).with("Bytes", () => this.transformBytes(value)).with("Decimal", () => this.transformDecimal(value)).with("BigInt", () => this.transformBigInt(value)).with("Json", () => this.transformJson(value)).otherwise(() => value);
6835
- }
6836
- }
6837
- transformDecimal(value) {
6838
- if (value instanceof Decimal2) {
6839
- return value;
6840
- }
6841
- invariant14(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
6842
- return new Decimal2(value);
6843
- }
6844
- transformBigInt(value) {
6845
- if (typeof value === "bigint") {
6846
- return value;
6847
- }
6848
- invariant14(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
6849
- return BigInt(value);
6850
- }
6851
- transformBoolean(value) {
6852
- return !!value;
6853
- }
6854
- transformDate(value) {
6855
- if (typeof value === "number") {
6856
- return new Date(value);
6857
- } else if (typeof value === "string") {
6858
- return new Date(Date.parse(value));
6859
- } else {
6860
- return value;
6861
- }
6862
- }
6863
- transformBytes(value) {
6864
- return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
6865
- }
6866
7487
  fixReversedResult(data, model, args) {
6867
7488
  if (!data) {
6868
7489
  return;
@@ -6887,12 +7508,6 @@ var ResultProcessor = class {
6887
7508
  }
6888
7509
  }
6889
7510
  }
6890
- transformJson(value) {
6891
- return match19(this.schema.provider.type).with("sqlite", () => {
6892
- invariant14(typeof value === "string", "Expected string, got " + typeof value);
6893
- return JSON.parse(value);
6894
- }).otherwise(() => value);
6895
- }
6896
7511
  };
6897
7512
 
6898
7513
  // src/client/client-impl.ts
@@ -6915,7 +7530,7 @@ var ClientImpl = class _ClientImpl {
6915
7530
  this.schema = schema;
6916
7531
  this.options = options;
6917
7532
  this.$schema = schema;
6918
- this.$options = options ?? {};
7533
+ this.$options = options;
6919
7534
  this.$options.functions = {
6920
7535
  ...functions_exports,
6921
7536
  ...this.$options.functions
@@ -7082,7 +7697,7 @@ var ClientImpl = class _ClientImpl {
7082
7697
  }
7083
7698
  $executeRaw(query, ...values) {
7084
7699
  return createZenStackPromise(async () => {
7085
- const result = await sql9(query, ...values).execute(this.kysely);
7700
+ const result = await sql10(query, ...values).execute(this.kysely);
7086
7701
  return Number(result.numAffectedRows ?? 0);
7087
7702
  });
7088
7703
  }
@@ -7095,7 +7710,7 @@ var ClientImpl = class _ClientImpl {
7095
7710
  }
7096
7711
  $queryRaw(query, ...values) {
7097
7712
  return createZenStackPromise(async () => {
7098
- const result = await sql9(query, ...values).execute(this.kysely);
7713
+ const result = await sql10(query, ...values).execute(this.kysely);
7099
7714
  return result.rows;
7100
7715
  });
7101
7716
  }
@@ -7116,7 +7731,7 @@ var ClientImpl = class _ClientImpl {
7116
7731
  };
7117
7732
  function createClientProxy(client) {
7118
7733
  const inputValidator = new InputValidator(client.$schema);
7119
- const resultProcessor = new ResultProcessor(client.$schema);
7734
+ const resultProcessor = new ResultProcessor(client.$schema, client.$options);
7120
7735
  return new Proxy(client, {
7121
7736
  get: /* @__PURE__ */ __name((target, prop, receiver) => {
7122
7737
  if (typeof prop === "string" && prop.startsWith("$")) {
@@ -7234,7 +7849,7 @@ function definePlugin(plugin) {
7234
7849
  __name(definePlugin, "definePlugin");
7235
7850
 
7236
7851
  // src/client/index.ts
7237
- import { sql as sql10 } from "kysely";
7852
+ import { sql as sql11 } from "kysely";
7238
7853
  export {
7239
7854
  InputValidationError,
7240
7855
  InternalError,
@@ -7242,6 +7857,6 @@ export {
7242
7857
  QueryError,
7243
7858
  ZenStackClient,
7244
7859
  definePlugin,
7245
- sql10 as sql
7860
+ sql11 as sql
7246
7861
  };
7247
7862
  //# sourceMappingURL=index.js.map