@zenstackhq/runtime 3.0.0-alpha.31 → 3.0.0-alpha.33

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
@@ -6,8 +6,8 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // src/client/client-impl.ts
9
- import { invariant as invariant13 } from "@zenstackhq/common-helpers";
10
- import { CompiledQuery, DefaultConnectionProvider, DefaultQueryExecutor as DefaultQueryExecutor2, Kysely, Log, sql as sql9 } from "kysely";
9
+ import { invariant as invariant15 } from "@zenstackhq/common-helpers";
10
+ import { CompiledQuery, DefaultConnectionProvider, DefaultQueryExecutor as DefaultQueryExecutor2, Kysely, Log, sql as sql9, Transaction } from "kysely";
11
11
 
12
12
  // src/client/crud/operations/aggregate.ts
13
13
  import { sql as sql5 } from "kysely";
@@ -92,7 +92,10 @@ var ExpressionUtils = {
92
92
  isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
93
93
  isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
94
94
  isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
95
- isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
95
+ isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember"),
96
+ getLiteralValue: /* @__PURE__ */ __name((expr2) => {
97
+ return ExpressionUtils.isLiteral(expr2) ? expr2.value : void 0;
98
+ }, "getLiteralValue")
96
99
  };
97
100
 
98
101
  // src/utils/object-utils.ts
@@ -1016,6 +1019,16 @@ var BaseCrudDialect = class {
1016
1019
  }
1017
1020
  return result;
1018
1021
  }
1022
+ buildModelSelect(eb, model, subQueryAlias, payload, selectAllFields) {
1023
+ let subQuery = this.buildSelectModel(eb, model, subQueryAlias);
1024
+ if (selectAllFields) {
1025
+ subQuery = this.buildSelectAllFields(model, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
1026
+ }
1027
+ if (payload && typeof payload === "object") {
1028
+ subQuery = this.buildFilterSortTake(model, payload, subQuery, subQueryAlias);
1029
+ }
1030
+ return subQuery;
1031
+ }
1019
1032
  buildSelectField(query, model, modelAlias, field) {
1020
1033
  const fieldDef = requireField(this.schema, model, field);
1021
1034
  if (fieldDef.computed) {
@@ -1113,6 +1126,18 @@ var BaseCrudDialect = class {
1113
1126
  fieldRef(model, field, eb, modelAlias, inlineComputedField = true) {
1114
1127
  return buildFieldRef(this.schema, model, field, this.options, eb, modelAlias, inlineComputedField);
1115
1128
  }
1129
+ canJoinWithoutNestedSelect(modelDef, payload) {
1130
+ if (modelDef.computedFields) {
1131
+ return false;
1132
+ }
1133
+ if (modelDef.baseModel || modelDef.isDelegate) {
1134
+ return false;
1135
+ }
1136
+ if (typeof payload === "object" && (payload.orderBy || payload.skip !== void 0 || payload.take !== void 0 || payload.cursor || payload.distinct)) {
1137
+ return false;
1138
+ }
1139
+ return true;
1140
+ }
1116
1141
  };
1117
1142
 
1118
1143
  // src/client/crud/dialects/postgresql.ts
@@ -1138,52 +1163,58 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1138
1163
  }
1139
1164
  }
1140
1165
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
1141
- const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload);
1142
- return joinedQuery.select(`${parentAlias}$${relationField}.$j as ${relationField}`);
1166
+ const relationResultName = `${parentAlias}$${relationField}`;
1167
+ const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload, relationResultName);
1168
+ return joinedQuery.select(`${relationResultName}.$data as ${relationField}`);
1143
1169
  }
1144
- buildRelationJSON(model, qb, relationField, parentName, payload) {
1170
+ buildRelationJSON(model, qb, relationField, parentAlias, payload, resultName) {
1145
1171
  const relationFieldDef = requireField(this.schema, model, relationField);
1146
1172
  const relationModel = relationFieldDef.type;
1147
1173
  return qb.leftJoinLateral((eb) => {
1148
- const joinTableName = `${parentName}$${relationField}`;
1149
- let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
1150
- const subQueryAlias = `${relationModel}$${relationField}$sub`;
1151
- result = eb.selectFrom(() => {
1152
- let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
1153
- subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
1154
- if (payload && typeof payload === "object") {
1155
- subQuery = this.buildFilterSortTake(relationModel, payload, subQuery, subQueryAlias);
1156
- }
1157
- const m2m = getManyToManyRelation(this.schema, model, relationField);
1158
- if (m2m) {
1159
- const parentIds = getIdFields(this.schema, model);
1160
- const relationIds = getIdFields(this.schema, relationModel);
1161
- invariant2(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1162
- invariant2(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1163
- subQuery = subQuery.where(eb(eb.ref(`${subQueryAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentName}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1164
- } else {
1165
- const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, subQueryAlias);
1166
- subQuery = subQuery.where((eb2) => this.and(eb2, ...joinPairs.map(([left, right]) => eb2(sql2.ref(left), "=", sql2.ref(right)))));
1167
- }
1168
- return subQuery.as(joinTableName);
1169
- });
1170
- result = this.buildRelationObjectSelect(relationModel, joinTableName, relationField, relationFieldDef, result, payload, parentName);
1171
- result = this.buildRelationJoins(relationModel, relationField, result, payload, parentName);
1172
- return result.as(joinTableName);
1174
+ const relationSelectName = `${resultName}$sub`;
1175
+ const relationModelDef = requireModel(this.schema, relationModel);
1176
+ let tbl;
1177
+ if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1178
+ tbl = this.buildModelSelect(eb, relationModel, relationSelectName, payload, false);
1179
+ tbl = this.buildRelationJoinFilter(tbl, model, relationField, relationModel, relationSelectName, parentAlias);
1180
+ } else {
1181
+ tbl = eb.selectFrom(() => {
1182
+ let subQuery = this.buildModelSelect(eb, relationModel, `${relationSelectName}$t`, payload, true);
1183
+ subQuery = this.buildRelationJoinFilter(subQuery, model, relationField, relationModel, `${relationSelectName}$t`, parentAlias);
1184
+ return subQuery.as(relationSelectName);
1185
+ });
1186
+ }
1187
+ tbl = this.buildRelationObjectSelect(relationModel, relationSelectName, relationFieldDef, tbl, payload, resultName);
1188
+ tbl = this.buildRelationJoins(tbl, relationModel, relationSelectName, payload, resultName);
1189
+ return tbl.as(resultName);
1173
1190
  }, (join) => join.onTrue());
1174
1191
  }
1175
- buildRelationObjectSelect(relationModel, relationModelAlias, relationField, relationFieldDef, qb, payload, parentName) {
1192
+ buildRelationJoinFilter(query, model, relationField, relationModel, relationModelAlias, parentAlias) {
1193
+ const m2m = getManyToManyRelation(this.schema, model, relationField);
1194
+ 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");
1199
+ 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
+ } else {
1201
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, relationField, relationModelAlias);
1202
+ query = query.where((eb) => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql2.ref(left), "=", sql2.ref(right)))));
1203
+ }
1204
+ return query;
1205
+ }
1206
+ buildRelationObjectSelect(relationModel, relationModelAlias, relationFieldDef, qb, payload, parentResultName) {
1176
1207
  qb = qb.select((eb) => {
1177
- const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, relationField, eb, payload, parentName);
1208
+ const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName);
1178
1209
  if (relationFieldDef.array) {
1179
- return eb.fn.coalesce(sql2`jsonb_agg(jsonb_build_object(${sql2.join(objArgs)}))`, sql2`'[]'::jsonb`).as("$j");
1210
+ return eb.fn.coalesce(sql2`jsonb_agg(jsonb_build_object(${sql2.join(objArgs)}))`, sql2`'[]'::jsonb`).as("$data");
1180
1211
  } else {
1181
- return sql2`jsonb_build_object(${sql2.join(objArgs)})`.as("$j");
1212
+ return sql2`jsonb_build_object(${sql2.join(objArgs)})`.as("$data");
1182
1213
  }
1183
1214
  });
1184
1215
  return qb;
1185
1216
  }
1186
- buildRelationObjectArgs(relationModel, relationModelAlias, relationField, eb, payload, parentAlias) {
1217
+ buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName) {
1187
1218
  const relationModelDef = requireModel(this.schema, relationModel);
1188
1219
  const objArgs = [];
1189
1220
  const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
@@ -1201,14 +1232,14 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1201
1232
  } else if (payload.select) {
1202
1233
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1203
1234
  if (field === "_count") {
1204
- const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
1235
+ const subJson = this.buildCountJson(relationModel, eb, relationModelAlias, value);
1205
1236
  return [
1206
1237
  sql2.lit(field),
1207
1238
  subJson
1208
1239
  ];
1209
1240
  } else {
1210
1241
  const fieldDef = requireField(this.schema, relationModel, field);
1211
- const fieldValue = fieldDef.relation ? eb.ref(`${parentAlias}$${relationField}$${field}.$j`) : this.fieldRef(relationModel, field, eb, void 0, false);
1242
+ const fieldValue = fieldDef.relation ? eb.ref(`${parentResultName}$${field}.$data`) : this.fieldRef(relationModel, field, eb, relationModelAlias, false);
1212
1243
  return [
1213
1244
  sql2.lit(field),
1214
1245
  fieldValue
@@ -1220,18 +1251,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1220
1251
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
1221
1252
  sql2.lit(field),
1222
1253
  // reference the synthesized JSON field
1223
- eb.ref(`${parentAlias}$${relationField}$${field}.$j`)
1254
+ eb.ref(`${parentResultName}$${field}.$data`)
1224
1255
  ]).flatMap((v) => v));
1225
1256
  }
1226
1257
  return objArgs;
1227
1258
  }
1228
- buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
1229
- let result = qb;
1259
+ buildRelationJoins(query, relationModel, relationModelAlias, payload, parentResultName) {
1260
+ let result = query;
1230
1261
  if (typeof payload === "object") {
1231
1262
  const selectInclude = payload.include ?? payload.select;
1232
1263
  if (selectInclude && typeof selectInclude === "object") {
1233
1264
  Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
1234
- result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
1265
+ result = this.buildRelationJSON(relationModel, result, field, relationModelAlias, value, `${parentResultName}$${field}`);
1235
1266
  });
1236
1267
  }
1237
1268
  }
@@ -1311,32 +1342,18 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1311
1342
  const relationModel = relationFieldDef.type;
1312
1343
  const relationModelDef = requireModel(this.schema, relationModel);
1313
1344
  const subQueryName = `${parentAlias}$${relationField}`;
1314
- let tbl = eb.selectFrom(() => {
1315
- const subQueryAlias = `${parentAlias}$${relationField}$sub`;
1316
- let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
1317
- subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
1318
- if (payload && typeof payload === "object") {
1319
- subQuery = this.buildFilterSortTake(relationModel, payload, subQuery, subQueryAlias);
1320
- }
1321
- const m2m = getManyToManyRelation(this.schema, model, relationField);
1322
- if (m2m) {
1323
- const parentIds = getIdFields(this.schema, model);
1324
- const relationIds = getIdFields(this.schema, relationModel);
1325
- invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1326
- invariant3(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1327
- subQuery = subQuery.where(eb(eb.ref(`${subQueryAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1328
- } else {
1329
- const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1330
- keyPairs.forEach(({ fk, pk }) => {
1331
- if (ownedByModel) {
1332
- subQuery = subQuery.whereRef(`${subQueryAlias}.${pk}`, "=", `${parentAlias}.${fk}`);
1333
- } else {
1334
- subQuery = subQuery.whereRef(`${subQueryAlias}.${fk}`, "=", `${parentAlias}.${pk}`);
1335
- }
1336
- });
1337
- }
1338
- return subQuery.as(subQueryName);
1339
- });
1345
+ let tbl;
1346
+ if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1347
+ tbl = this.buildModelSelect(eb, relationModel, subQueryName, payload, false);
1348
+ tbl = this.buildRelationJoinFilter(tbl, model, relationField, subQueryName, parentAlias);
1349
+ } else {
1350
+ tbl = eb.selectFrom(() => {
1351
+ const selectModelAlias = `${parentAlias}$${relationField}$sub`;
1352
+ let selectModelQuery = this.buildModelSelect(eb, relationModel, selectModelAlias, payload, true);
1353
+ selectModelQuery = this.buildRelationJoinFilter(selectModelQuery, model, relationField, selectModelAlias, parentAlias);
1354
+ return selectModelQuery.as(subQueryName);
1355
+ });
1356
+ }
1340
1357
  tbl = tbl.select(() => {
1341
1358
  const objArgs = [];
1342
1359
  const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
@@ -1349,7 +1366,7 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1349
1366
  if (payload === true || !payload.select) {
1350
1367
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
1351
1368
  sql3.lit(field),
1352
- this.fieldRef(relationModel, field, eb, void 0, false)
1369
+ this.fieldRef(relationModel, field, eb, subQueryName, false)
1353
1370
  ]).flatMap((v) => v));
1354
1371
  } else if (payload.select) {
1355
1372
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
@@ -1370,7 +1387,7 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1370
1387
  } else {
1371
1388
  return [
1372
1389
  sql3.lit(field),
1373
- this.fieldRef(relationModel, field, eb, void 0, false)
1390
+ this.fieldRef(relationModel, field, eb, subQueryName, false)
1374
1391
  ];
1375
1392
  }
1376
1393
  }
@@ -1386,13 +1403,35 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1386
1403
  }).flatMap((v) => v));
1387
1404
  }
1388
1405
  if (relationFieldDef.array) {
1389
- return eb.fn.coalesce(sql3`json_group_array(json_object(${sql3.join(objArgs)}))`, sql3`json_array()`).as("$j");
1406
+ return eb.fn.coalesce(sql3`json_group_array(json_object(${sql3.join(objArgs)}))`, sql3`json_array()`).as("$data");
1390
1407
  } else {
1391
- return sql3`json_object(${sql3.join(objArgs)})`.as("data");
1408
+ return sql3`json_object(${sql3.join(objArgs)})`.as("$data");
1392
1409
  }
1393
1410
  });
1394
1411
  return tbl;
1395
1412
  }
1413
+ buildRelationJoinFilter(selectModelQuery, model, relationField, relationModelAlias, parentAlias) {
1414
+ const fieldDef = requireField(this.schema, model, relationField);
1415
+ const relationModel = fieldDef.type;
1416
+ const m2m = getManyToManyRelation(this.schema, model, relationField);
1417
+ 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");
1422
+ 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
+ } else {
1424
+ const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1425
+ keyPairs.forEach(({ fk, pk }) => {
1426
+ if (ownedByModel) {
1427
+ selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${pk}`, "=", `${parentAlias}.${fk}`);
1428
+ } else {
1429
+ selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${fk}`, "=", `${parentAlias}.${pk}`);
1430
+ }
1431
+ });
1432
+ }
1433
+ return selectModelQuery;
1434
+ }
1396
1435
  buildSkipTake(query, skip, take) {
1397
1436
  if (take !== void 0) {
1398
1437
  query = query.limit(take);
@@ -2704,6 +2743,16 @@ function clone(value) {
2704
2743
  }
2705
2744
  __name(clone, "clone");
2706
2745
 
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
+
2707
2756
  // src/client/crud/operations/base.ts
2708
2757
  var BaseOperationHandler = class {
2709
2758
  static {
@@ -3942,7 +3991,7 @@ var BaseOperationHandler = class {
3942
3991
  return callback(this.kysely);
3943
3992
  } else {
3944
3993
  let txBuilder = this.kysely.transaction();
3945
- txBuilder = txBuilder.setIsolationLevel(isolationLevel ?? "repeatable read");
3994
+ txBuilder = txBuilder.setIsolationLevel(isolationLevel ?? TransactionIsolationLevel.RepeatableRead);
3946
3995
  return txBuilder.execute(callback);
3947
3996
  }
3948
3997
  }
@@ -5508,7 +5557,11 @@ var ZenStackDriver = class {
5508
5557
  this.#txConnections.delete(connection);
5509
5558
  if (callbacks) {
5510
5559
  for (const callback of callbacks) {
5511
- await callback();
5560
+ try {
5561
+ await callback();
5562
+ } catch (err) {
5563
+ console.error(`Error executing transaction commit callback: ${err}`);
5564
+ }
5512
5565
  }
5513
5566
  }
5514
5567
  return result;
@@ -5626,13 +5679,32 @@ function performanceNow() {
5626
5679
  __name(performanceNow, "performanceNow");
5627
5680
 
5628
5681
  // src/client/executor/zenstack-query-executor.ts
5629
- import { AndNode as AndNode2, DefaultQueryExecutor, DeleteQueryNode as DeleteQueryNode2, InsertQueryNode as InsertQueryNode2, ReturningNode as ReturningNode2, SelectionNode as SelectionNode4, UpdateQueryNode as UpdateQueryNode2, WhereNode as WhereNode3 } from "kysely";
5630
- import { nanoid as nanoid2 } from "nanoid";
5682
+ import { invariant as invariant11 } from "@zenstackhq/common-helpers";
5683
+ 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";
5631
5684
  import { match as match16 } from "ts-pattern";
5632
5685
 
5633
- // src/client/executor/name-mapper.ts
5686
+ // src/client/executor/kysely-utils.ts
5634
5687
  import { invariant as invariant9 } from "@zenstackhq/common-helpers";
5635
- import { AliasNode as AliasNode4, ColumnNode as ColumnNode3, FromNode as FromNode3, IdentifierNode as IdentifierNode3, OperationNodeTransformer as OperationNodeTransformer2, ReferenceNode as ReferenceNode3, SelectAllNode, SelectionNode as SelectionNode3, TableNode as TableNode4 } from "kysely";
5688
+ import { AliasNode as AliasNode4, IdentifierNode as IdentifierNode3 } from "kysely";
5689
+ function stripAlias(node) {
5690
+ if (AliasNode4.is(node)) {
5691
+ invariant9(IdentifierNode3.is(node.alias), "Expected identifier as alias");
5692
+ return {
5693
+ alias: node.alias.name,
5694
+ node: node.node
5695
+ };
5696
+ } else {
5697
+ return {
5698
+ alias: void 0,
5699
+ node
5700
+ };
5701
+ }
5702
+ }
5703
+ __name(stripAlias, "stripAlias");
5704
+
5705
+ // src/client/executor/name-mapper.ts
5706
+ import { invariant as invariant10 } from "@zenstackhq/common-helpers";
5707
+ 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";
5636
5708
  var QueryNameMapper = class extends OperationNodeTransformer2 {
5637
5709
  static {
5638
5710
  __name(this, "QueryNameMapper");
@@ -5640,7 +5712,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5640
5712
  schema;
5641
5713
  modelToTableMap = /* @__PURE__ */ new Map();
5642
5714
  fieldToColumnMap = /* @__PURE__ */ new Map();
5643
- modelScopes = [];
5715
+ scopes = [];
5644
5716
  constructor(schema) {
5645
5717
  super(), this.schema = schema;
5646
5718
  for (const [modelName, modelDef] of Object.entries(schema.models)) {
@@ -5661,12 +5733,23 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5661
5733
  if (!node.from?.froms) {
5662
5734
  return super.transformSelectQuery(node);
5663
5735
  }
5664
- const scopes = this.createScopesFromFroms(node.from, true);
5736
+ const processedFroms = node.from.froms.map((from) => this.processSelectTable(from));
5737
+ const processedJoins = (node.joins ?? []).map((join) => this.processSelectTable(join.table));
5738
+ const scopes = [
5739
+ ...processedFroms.map(({ scope }) => scope),
5740
+ ...processedJoins.map(({ scope }) => scope)
5741
+ ];
5665
5742
  return this.withScopes(scopes, () => {
5743
+ const joins = node.joins ? node.joins.map((join, i) => ({
5744
+ ...join,
5745
+ table: processedJoins[i].node,
5746
+ on: this.transformNode(join.on)
5747
+ })) : void 0;
5666
5748
  return {
5667
5749
  ...super.transformSelectQuery(node),
5668
- // convert "from" to nested query as needed
5669
- from: this.processFrom(node.from)
5750
+ from: FromNode3.create(processedFroms.map((f) => f.node)),
5751
+ joins,
5752
+ selections: this.processSelectQuerySelections(node)
5670
5753
  };
5671
5754
  });
5672
5755
  }
@@ -5689,27 +5772,13 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5689
5772
  selections: this.processSelections(node.selections)
5690
5773
  };
5691
5774
  }
5692
- transformJoin(node) {
5693
- const { alias, node: innerNode } = this.stripAlias(node.table);
5694
- if (TableNode4.is(innerNode)) {
5695
- const modelName = innerNode.table.identifier.name;
5696
- if (this.hasMappedColumns(modelName)) {
5697
- const select = this.createSelectAll(modelName);
5698
- return {
5699
- ...super.transformJoin(node),
5700
- table: this.wrapAlias(select, alias ?? modelName)
5701
- };
5702
- }
5703
- }
5704
- return super.transformJoin(node);
5705
- }
5706
5775
  transformReference(node) {
5707
5776
  if (!ColumnNode3.is(node.column)) {
5708
5777
  return super.transformReference(node);
5709
5778
  }
5710
- const { fieldDef, modelDef, scope } = this.resolveFieldFromScopes(node.column.column.name, node.table?.table.identifier.name);
5711
- if (fieldDef && !scope.namesMapped) {
5712
- const mappedFieldName = this.mapFieldName(modelDef.name, fieldDef.name);
5779
+ const scope = this.resolveFieldFromScopes(node.column.column.name, node.table?.table.identifier.name);
5780
+ if (scope && !scope.namesMapped && scope.model) {
5781
+ const mappedFieldName = this.mapFieldName(scope.model, node.column.column.name);
5713
5782
  let mappedTableName = node.table?.table.identifier.name;
5714
5783
  if (mappedTableName) {
5715
5784
  if (scope.alias === mappedTableName) {
@@ -5723,15 +5792,18 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5723
5792
  }
5724
5793
  }
5725
5794
  transformColumn(node) {
5726
- const { modelDef, fieldDef, scope } = this.resolveFieldFromScopes(node.column.name);
5727
- if (!fieldDef || scope.namesMapped) {
5795
+ const scope = this.resolveFieldFromScopes(node.column.name);
5796
+ if (!scope || scope.namesMapped || !scope.model) {
5728
5797
  return super.transformColumn(node);
5729
5798
  }
5730
- const mappedName = this.mapFieldName(modelDef.name, fieldDef.name);
5799
+ const mappedName = this.mapFieldName(scope.model, node.column.name);
5731
5800
  return ColumnNode3.create(mappedName);
5732
5801
  }
5733
5802
  transformUpdateQuery(node) {
5734
- const { alias, node: innerTable } = this.stripAlias(node.table);
5803
+ if (!node.table) {
5804
+ return super.transformUpdateQuery(node);
5805
+ }
5806
+ const { alias, node: innerTable } = stripAlias(node.table);
5735
5807
  if (!innerTable || !TableNode4.is(innerTable)) {
5736
5808
  return super.transformUpdateQuery(node);
5737
5809
  }
@@ -5747,9 +5819,16 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5747
5819
  });
5748
5820
  }
5749
5821
  transformDeleteQuery(node) {
5750
- const scopes = this.createScopesFromFroms(node.from, false);
5822
+ const scopes = node.from.froms.map((node2) => {
5823
+ const { alias, node: innerNode } = stripAlias(node2);
5824
+ return {
5825
+ model: this.extractModelName(innerNode),
5826
+ alias,
5827
+ namesMapped: false
5828
+ };
5829
+ });
5751
5830
  const froms = node.from.froms.map((from) => {
5752
- const { alias, node: innerNode } = this.stripAlias(from);
5831
+ const { alias, node: innerNode } = stripAlias(from);
5753
5832
  if (TableNode4.is(innerNode)) {
5754
5833
  return this.wrapAlias(this.processTableRef(innerNode), alias);
5755
5834
  } else {
@@ -5765,46 +5844,75 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5765
5844
  }
5766
5845
  // #endregion
5767
5846
  // #region utils
5847
+ processSelectQuerySelections(node) {
5848
+ const selections = [];
5849
+ for (const selection of node.selections ?? []) {
5850
+ if (SelectAllNode.is(selection.selection)) {
5851
+ const scope = this.scopes[this.scopes.length - 1];
5852
+ if (scope?.model && !scope.namesMapped) {
5853
+ selections.push(...this.createSelectAllFields(scope.model, scope.alias));
5854
+ } else {
5855
+ selections.push(super.transformSelection(selection));
5856
+ }
5857
+ } else if (ReferenceNode3.is(selection.selection) || ColumnNode3.is(selection.selection)) {
5858
+ const transformed = this.transformNode(selection.selection);
5859
+ if (AliasNode5.is(transformed)) {
5860
+ selections.push(SelectionNode3.create(transformed));
5861
+ } else {
5862
+ const origFieldName = this.extractFieldName(selection.selection);
5863
+ const fieldName = this.extractFieldName(transformed);
5864
+ if (fieldName !== origFieldName) {
5865
+ selections.push(SelectionNode3.create(this.wrapAlias(transformed, origFieldName)));
5866
+ } else {
5867
+ selections.push(SelectionNode3.create(transformed));
5868
+ }
5869
+ }
5870
+ } else {
5871
+ selections.push(super.transformSelection(selection));
5872
+ }
5873
+ }
5874
+ return selections;
5875
+ }
5768
5876
  resolveFieldFromScopes(name, qualifier) {
5769
- for (const scope of this.modelScopes.toReversed()) {
5877
+ for (let i = this.scopes.length - 1; i >= 0; i--) {
5878
+ const scope = this.scopes[i];
5770
5879
  if (qualifier) {
5771
5880
  if (scope.alias) {
5772
- if (qualifier !== scope.alias) {
5881
+ if (scope.alias === qualifier) {
5882
+ return scope;
5883
+ } else {
5773
5884
  continue;
5774
5885
  }
5775
- } else {
5776
- if (qualifier !== scope.model) {
5886
+ } else if (scope.model) {
5887
+ if (scope.model === qualifier) {
5888
+ return scope;
5889
+ } else {
5777
5890
  continue;
5778
5891
  }
5779
5892
  }
5780
- }
5781
- const modelDef = getModel(this.schema, scope.model);
5782
- if (!modelDef) {
5783
- continue;
5784
- }
5785
- if (modelDef.fields[name]) {
5786
- return {
5787
- modelDef,
5788
- fieldDef: modelDef.fields[name],
5789
- scope
5790
- };
5893
+ } else {
5894
+ if (scope.model) {
5895
+ const modelDef = getModel(this.schema, scope.model);
5896
+ if (!modelDef) {
5897
+ continue;
5898
+ }
5899
+ if (modelDef.fields[name]) {
5900
+ return scope;
5901
+ }
5902
+ }
5791
5903
  }
5792
5904
  }
5793
- return {
5794
- modelDef: void 0,
5795
- fieldDef: void 0,
5796
- scope: void 0
5797
- };
5905
+ return void 0;
5798
5906
  }
5799
5907
  pushScope(scope) {
5800
- this.modelScopes.push(scope);
5908
+ this.scopes.push(scope);
5801
5909
  }
5802
5910
  withScope(scope, fn) {
5803
5911
  this.pushScope(scope);
5804
5912
  try {
5805
5913
  return fn();
5806
5914
  } finally {
5807
- this.modelScopes.pop();
5915
+ this.scopes.pop();
5808
5916
  }
5809
5917
  }
5810
5918
  withScopes(scopes, fn) {
@@ -5812,17 +5920,11 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5812
5920
  try {
5813
5921
  return fn();
5814
5922
  } finally {
5815
- scopes.forEach(() => this.modelScopes.pop());
5923
+ scopes.forEach(() => this.scopes.pop());
5816
5924
  }
5817
5925
  }
5818
5926
  wrapAlias(node, alias) {
5819
- return alias ? AliasNode4.create(node, IdentifierNode3.create(alias)) : node;
5820
- }
5821
- ensureAlias(node, alias, fallbackName) {
5822
- if (!node) {
5823
- return node;
5824
- }
5825
- return alias ? AliasNode4.create(node, IdentifierNode3.create(alias)) : AliasNode4.create(node, IdentifierNode3.create(fallbackName));
5927
+ return alias ? AliasNode5.create(node, IdentifierNode4.create(alias)) : node;
5826
5928
  }
5827
5929
  processTableRef(node) {
5828
5930
  if (!node) {
@@ -5859,86 +5961,49 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5859
5961
  return tableName;
5860
5962
  }
5861
5963
  }
5862
- stripAlias(node) {
5863
- if (!node) {
5864
- return {
5865
- alias: void 0,
5866
- node
5867
- };
5868
- }
5869
- if (AliasNode4.is(node)) {
5870
- invariant9(IdentifierNode3.is(node.alias), "Expected identifier as alias");
5871
- return {
5872
- alias: node.alias.name,
5873
- node: node.node
5874
- };
5875
- }
5876
- return {
5877
- alias: void 0,
5878
- node
5879
- };
5880
- }
5881
5964
  hasMappedColumns(modelName) {
5882
5965
  return [
5883
5966
  ...this.fieldToColumnMap.keys()
5884
5967
  ].some((key) => key.startsWith(modelName + "."));
5885
5968
  }
5886
- createScopesFromFroms(node, namesMapped) {
5887
- if (!node) {
5888
- return [];
5889
- }
5890
- return node.froms.map((from) => {
5891
- const { alias, node: innerNode } = this.stripAlias(from);
5892
- if (innerNode && TableNode4.is(innerNode)) {
5893
- return {
5894
- model: innerNode.table.identifier.name,
5895
- alias,
5896
- namesMapped
5897
- };
5898
- } else {
5899
- return void 0;
5900
- }
5901
- }).filter((s) => !!s);
5902
- }
5903
5969
  // convert a "from" node to a nested query if there are columns with name mapping
5904
- processFrom(node) {
5905
- return {
5906
- ...super.transformFrom(node),
5907
- froms: node.froms.map((from) => {
5908
- const { alias, node: innerNode } = this.stripAlias(from);
5909
- if (!innerNode) {
5910
- return super.transformNode(from);
5911
- }
5912
- if (TableNode4.is(innerNode)) {
5913
- if (this.hasMappedColumns(innerNode.table.identifier.name)) {
5914
- const selectAll = this.createSelectAll(innerNode.table.identifier.name);
5915
- return this.ensureAlias(selectAll, alias, innerNode.table.identifier.name);
5916
- }
5970
+ processSelectTable(node) {
5971
+ const { alias, node: innerNode } = stripAlias(node);
5972
+ if (innerNode && TableNode4.is(innerNode)) {
5973
+ const modelName = innerNode.table.identifier.name;
5974
+ const mappedName = this.mapTableName(modelName);
5975
+ const finalAlias = alias ?? (mappedName !== modelName ? modelName : void 0);
5976
+ return {
5977
+ node: this.wrapAlias(TableNode4.create(mappedName), finalAlias),
5978
+ scope: {
5979
+ alias: alias ?? modelName,
5980
+ model: modelName,
5981
+ namesMapped: !this.hasMappedColumns(modelName)
5917
5982
  }
5918
- return this.transformNode(from);
5919
- })
5920
- };
5983
+ };
5984
+ } else {
5985
+ return {
5986
+ node: super.transformNode(node),
5987
+ scope: {
5988
+ alias,
5989
+ model: void 0,
5990
+ namesMapped: true
5991
+ }
5992
+ };
5993
+ }
5921
5994
  }
5922
- // create a `SelectQueryNode` for the given model with all columns mapped
5923
- createSelectAll(model) {
5995
+ createSelectAllFields(model, alias) {
5924
5996
  const modelDef = requireModel(this.schema, model);
5925
- const tableName = this.mapTableName(model);
5926
- return {
5927
- kind: "SelectQueryNode",
5928
- from: FromNode3.create([
5929
- TableNode4.create(tableName)
5930
- ]),
5931
- selections: this.getModelFields(modelDef).map((fieldDef) => {
5932
- const columnName = this.mapFieldName(model, fieldDef.name);
5933
- const columnRef = ReferenceNode3.create(ColumnNode3.create(columnName), TableNode4.create(tableName));
5934
- if (columnName !== fieldDef.name) {
5935
- const aliased = AliasNode4.create(columnRef, IdentifierNode3.create(fieldDef.name));
5936
- return SelectionNode3.create(aliased);
5937
- } else {
5938
- return SelectionNode3.create(columnRef);
5939
- }
5940
- })
5941
- };
5997
+ return this.getModelFields(modelDef).map((fieldDef) => {
5998
+ const columnName = this.mapFieldName(model, fieldDef.name);
5999
+ const columnRef = ReferenceNode3.create(ColumnNode3.create(columnName), alias ? TableNode4.create(alias) : void 0);
6000
+ if (columnName !== fieldDef.name) {
6001
+ const aliased = AliasNode5.create(columnRef, IdentifierNode4.create(fieldDef.name));
6002
+ return SelectionNode3.create(aliased);
6003
+ } else {
6004
+ return SelectionNode3.create(columnRef);
6005
+ }
6006
+ });
5942
6007
  }
5943
6008
  getModelFields(modelDef) {
5944
6009
  return Object.values(modelDef.fields).filter((f) => !f.relation && !f.computed && !f.originModel);
@@ -5961,25 +6026,29 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5961
6026
  }
5962
6027
  processSelection(node) {
5963
6028
  let alias;
5964
- if (!AliasNode4.is(node)) {
6029
+ if (!AliasNode5.is(node)) {
5965
6030
  alias = this.extractFieldName(node);
5966
6031
  }
5967
6032
  const result = super.transformNode(node);
5968
6033
  return this.wrapAlias(result, alias);
5969
6034
  }
5970
6035
  processSelectAll(node) {
5971
- const scope = this.modelScopes[this.modelScopes.length - 1];
5972
- invariant9(scope);
5973
- if (!this.hasMappedColumns(scope.model)) {
6036
+ const scope = this.scopes[this.scopes.length - 1];
6037
+ invariant10(scope);
6038
+ if (!scope.model || !this.hasMappedColumns(scope.model)) {
5974
6039
  return super.transformSelectAll(node);
5975
6040
  }
5976
6041
  const modelDef = requireModel(this.schema, scope.model);
5977
6042
  return this.getModelFields(modelDef).map((fieldDef) => {
5978
- const columnName = this.mapFieldName(scope.model, fieldDef.name);
6043
+ const columnName = this.mapFieldName(modelDef.name, fieldDef.name);
5979
6044
  const columnRef = ReferenceNode3.create(ColumnNode3.create(columnName));
5980
6045
  return columnName !== fieldDef.name ? this.wrapAlias(columnRef, fieldDef.name) : columnRef;
5981
6046
  });
5982
6047
  }
6048
+ extractModelName(node) {
6049
+ const { node: innerNode } = stripAlias(node);
6050
+ return TableNode4.is(innerNode) ? innerNode.table.identifier.name : void 0;
6051
+ }
5983
6052
  extractFieldName(node) {
5984
6053
  if (ReferenceNode3.is(node) && ColumnNode3.is(node.column)) {
5985
6054
  return node.column.column.name;
@@ -6000,9 +6069,10 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6000
6069
  driver;
6001
6070
  compiler;
6002
6071
  connectionProvider;
6072
+ suppressMutationHooks;
6003
6073
  nameMapper;
6004
- constructor(client, driver, compiler, adapter, connectionProvider, plugins = []) {
6005
- super(compiler, adapter, connectionProvider, plugins), this.client = client, this.driver = driver, this.compiler = compiler, this.connectionProvider = connectionProvider;
6074
+ constructor(client, driver, compiler, adapter, connectionProvider, plugins = [], suppressMutationHooks = false) {
6075
+ super(compiler, adapter, connectionProvider, plugins), this.client = client, this.driver = driver, this.compiler = compiler, this.connectionProvider = connectionProvider, this.suppressMutationHooks = suppressMutationHooks;
6006
6076
  this.nameMapper = new QueryNameMapper(client.$schema);
6007
6077
  }
6008
6078
  get kysely() {
@@ -6011,38 +6081,13 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6011
6081
  get options() {
6012
6082
  return this.client.$options;
6013
6083
  }
6014
- async executeQuery(compiledQuery, _queryId) {
6015
- let queryNode = compiledQuery.query;
6016
- let mutationInterceptionInfo;
6017
- if (this.isMutationNode(queryNode) && this.hasMutationHooks) {
6018
- mutationInterceptionInfo = await this.callMutationInterceptionFilters(queryNode);
6019
- }
6020
- const task = /* @__PURE__ */ __name(async () => {
6021
- if (this.isMutationNode(queryNode)) {
6022
- await this.callBeforeMutationHooks(queryNode, mutationInterceptionInfo);
6023
- }
6024
- const oldQueryNode = queryNode;
6025
- if ((InsertQueryNode2.is(queryNode) || UpdateQueryNode2.is(queryNode)) && mutationInterceptionInfo?.loadAfterMutationEntities) {
6026
- queryNode = {
6027
- ...queryNode,
6028
- returning: ReturningNode2.create([
6029
- SelectionNode4.createSelectAll()
6030
- ])
6031
- };
6032
- }
6033
- const queryParams = compiledQuery.$raw ? compiledQuery.parameters : void 0;
6034
- const result = await this.proceedQueryWithKyselyInterceptors(queryNode, queryParams);
6035
- if (this.isMutationNode(queryNode)) {
6036
- await this.callAfterMutationHooks(result.result, queryNode, mutationInterceptionInfo, result.connection);
6037
- }
6038
- if (oldQueryNode !== queryNode) {
6039
- }
6040
- return result.result;
6041
- }, "task");
6042
- return task();
6084
+ async executeQuery(compiledQuery, queryId) {
6085
+ const queryParams = compiledQuery.$raw ? compiledQuery.parameters : void 0;
6086
+ const result = await this.proceedQueryWithKyselyInterceptors(compiledQuery.query, queryParams, queryId.queryId);
6087
+ return result.result;
6043
6088
  }
6044
- proceedQueryWithKyselyInterceptors(queryNode, parameters) {
6045
- let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters), "proceed");
6089
+ async proceedQueryWithKyselyInterceptors(queryNode, parameters, queryId) {
6090
+ let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters, queryId), "proceed");
6046
6091
  const hooks = [];
6047
6092
  for (const plugin of this.client.$options.plugins ?? []) {
6048
6093
  if (plugin.onKyselyQuery) {
@@ -6052,10 +6097,8 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6052
6097
  for (const hook of hooks) {
6053
6098
  const _proceed = proceed;
6054
6099
  proceed = /* @__PURE__ */ __name(async (query) => {
6055
- let connection;
6056
6100
  const _p = /* @__PURE__ */ __name(async (q) => {
6057
6101
  const r = await _proceed(q);
6058
- connection = r.connection;
6059
6102
  return r.result;
6060
6103
  }, "_p");
6061
6104
  const hookResult = await hook({
@@ -6066,35 +6109,129 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6066
6109
  proceed: _p
6067
6110
  });
6068
6111
  return {
6069
- result: hookResult,
6070
- connection
6112
+ result: hookResult
6071
6113
  };
6072
6114
  }, "proceed");
6073
6115
  }
6074
- return proceed(queryNode);
6116
+ const result = await proceed(queryNode);
6117
+ return result;
6075
6118
  }
6076
- async proceedQuery(query, parameters) {
6077
- const finalQuery = this.nameMapper.transformNode(query);
6078
- let compiled = this.compileQuery(finalQuery);
6079
- if (parameters) {
6080
- compiled = {
6081
- ...compiled,
6082
- parameters
6083
- };
6084
- }
6119
+ getMutationInfo(queryNode) {
6120
+ const model = this.getMutationModel(queryNode);
6121
+ const { action, where } = match16(queryNode).when(InsertQueryNode2.is, () => ({
6122
+ action: "create",
6123
+ where: void 0
6124
+ })).when(UpdateQueryNode2.is, (node) => ({
6125
+ action: "update",
6126
+ where: node.where
6127
+ })).when(DeleteQueryNode2.is, (node) => ({
6128
+ action: "delete",
6129
+ where: node.where
6130
+ })).exhaustive();
6131
+ return {
6132
+ model,
6133
+ action,
6134
+ where
6135
+ };
6136
+ }
6137
+ async proceedQuery(query, parameters, queryId) {
6138
+ let compiled;
6085
6139
  try {
6086
6140
  return await this.provideConnection(async (connection) => {
6087
- const result = await connection.executeQuery(compiled);
6088
- return {
6089
- result,
6090
- connection
6091
- };
6141
+ if (this.suppressMutationHooks || !this.isMutationNode(query) || !this.hasEntityMutationPlugins) {
6142
+ const finalQuery2 = this.nameMapper.transformNode(query);
6143
+ compiled = this.compileQuery(finalQuery2);
6144
+ if (parameters) {
6145
+ compiled = {
6146
+ ...compiled,
6147
+ parameters
6148
+ };
6149
+ }
6150
+ const result = await connection.executeQuery(compiled);
6151
+ return {
6152
+ result
6153
+ };
6154
+ }
6155
+ if ((InsertQueryNode2.is(query) || UpdateQueryNode2.is(query)) && this.hasEntityMutationPluginsWithAfterMutationHooks) {
6156
+ query = {
6157
+ ...query,
6158
+ returning: ReturningNode2.create([
6159
+ SelectionNode4.createSelectAll()
6160
+ ])
6161
+ };
6162
+ }
6163
+ const finalQuery = this.nameMapper.transformNode(query);
6164
+ compiled = this.compileQuery(finalQuery);
6165
+ if (parameters) {
6166
+ compiled = {
6167
+ ...compiled,
6168
+ parameters
6169
+ };
6170
+ }
6171
+ const currentlyInTx = this.driver.isTransactionConnection(connection);
6172
+ const connectionClient = this.createClientForConnection(connection, currentlyInTx);
6173
+ const mutationInfo = this.getMutationInfo(finalQuery);
6174
+ let beforeMutationEntities;
6175
+ const loadBeforeMutationEntities = /* @__PURE__ */ __name(async () => {
6176
+ if (beforeMutationEntities === void 0 && (UpdateQueryNode2.is(query) || DeleteQueryNode2.is(query))) {
6177
+ beforeMutationEntities = await this.loadEntities(mutationInfo.model, mutationInfo.where, connection);
6178
+ }
6179
+ return beforeMutationEntities;
6180
+ }, "loadBeforeMutationEntities");
6181
+ await this.callBeforeMutationHooks(finalQuery, mutationInfo, loadBeforeMutationEntities, connectionClient, queryId);
6182
+ const shouldCreateTx = this.hasPluginRequestingAfterMutationWithinTransaction && !this.driver.isTransactionConnection(connection);
6183
+ if (!shouldCreateTx) {
6184
+ const result = await connection.executeQuery(compiled);
6185
+ if (!this.driver.isTransactionConnection(connection)) {
6186
+ await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "all", queryId);
6187
+ } else {
6188
+ await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "inTx", queryId);
6189
+ this.driver.registerTransactionCommitCallback(connection, () => this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "outTx", queryId));
6190
+ }
6191
+ return {
6192
+ result
6193
+ };
6194
+ } else {
6195
+ await this.driver.beginTransaction(connection, {
6196
+ isolationLevel: TransactionIsolationLevel.ReadCommitted
6197
+ });
6198
+ try {
6199
+ const result = await connection.executeQuery(compiled);
6200
+ await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "inTx", queryId);
6201
+ await this.driver.commitTransaction(connection);
6202
+ await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "outTx", queryId);
6203
+ return {
6204
+ result
6205
+ };
6206
+ } catch (err) {
6207
+ await this.driver.rollbackTransaction(connection);
6208
+ throw err;
6209
+ }
6210
+ }
6092
6211
  });
6093
6212
  } catch (err) {
6094
- const message = `Failed to execute query: ${err}, sql: ${compiled.sql}`;
6213
+ const message = `Failed to execute query: ${err}, sql: ${compiled?.sql}`;
6095
6214
  throw new QueryError(message, err);
6096
6215
  }
6097
6216
  }
6217
+ createClientForConnection(connection, inTx) {
6218
+ const innerExecutor = this.withConnectionProvider(new SingleConnectionProvider(connection));
6219
+ innerExecutor.suppressMutationHooks = true;
6220
+ const innerClient = this.client.withExecutor(innerExecutor);
6221
+ if (inTx) {
6222
+ innerClient.forceTransaction();
6223
+ }
6224
+ return innerClient;
6225
+ }
6226
+ get hasEntityMutationPlugins() {
6227
+ return (this.client.$options.plugins ?? []).some((plugin) => plugin.onEntityMutation);
6228
+ }
6229
+ get hasEntityMutationPluginsWithAfterMutationHooks() {
6230
+ return (this.client.$options.plugins ?? []).some((plugin) => plugin.onEntityMutation?.afterEntityMutation);
6231
+ }
6232
+ get hasPluginRequestingAfterMutationWithinTransaction() {
6233
+ return (this.client.$options.plugins ?? []).some((plugin) => plugin.onEntityMutation?.runAfterMutationWithinTransaction);
6234
+ }
6098
6235
  isMutationNode(queryNode) {
6099
6236
  return InsertQueryNode2.is(queryNode) || UpdateQueryNode2.is(queryNode) || DeleteQueryNode2.is(queryNode);
6100
6237
  }
@@ -6102,154 +6239,102 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6102
6239
  return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, [
6103
6240
  ...this.plugins,
6104
6241
  plugin
6105
- ]);
6242
+ ], this.suppressMutationHooks);
6106
6243
  }
6107
6244
  withPlugins(plugins) {
6108
6245
  return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, [
6109
6246
  ...this.plugins,
6110
6247
  ...plugins
6111
- ]);
6248
+ ], this.suppressMutationHooks);
6112
6249
  }
6113
6250
  withPluginAtFront(plugin) {
6114
6251
  return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, [
6115
6252
  plugin,
6116
6253
  ...this.plugins
6117
- ]);
6254
+ ], this.suppressMutationHooks);
6118
6255
  }
6119
6256
  withoutPlugins() {
6120
- return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, []);
6257
+ return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, [], this.suppressMutationHooks);
6121
6258
  }
6122
6259
  withConnectionProvider(connectionProvider) {
6123
- const newExecutor = new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider);
6260
+ const newExecutor = new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider, this.plugins, this.suppressMutationHooks);
6124
6261
  newExecutor.client = this.client.withExecutor(newExecutor);
6125
6262
  return newExecutor;
6126
6263
  }
6127
- get hasMutationHooks() {
6128
- return this.client.$options.plugins?.some((plugin) => !!plugin.onEntityMutation);
6129
- }
6130
6264
  getMutationModel(queryNode) {
6131
- return match16(queryNode).when(InsertQueryNode2.is, (node) => node.into.table.identifier.name).when(UpdateQueryNode2.is, (node) => node.table.table.identifier.name).when(DeleteQueryNode2.is, (node) => {
6132
- if (node.from.froms.length !== 1) {
6133
- throw new InternalError(`Delete query must have exactly one from table`);
6134
- }
6135
- return node.from.froms[0].table.identifier.name;
6265
+ return match16(queryNode).when(InsertQueryNode2.is, (node) => {
6266
+ invariant11(node.into, "InsertQueryNode must have an into clause");
6267
+ return node.into.table.identifier.name;
6268
+ }).when(UpdateQueryNode2.is, (node) => {
6269
+ invariant11(node.table, "UpdateQueryNode must have a table");
6270
+ const { node: tableNode } = stripAlias(node.table);
6271
+ invariant11(TableNode5.is(tableNode), "UpdateQueryNode must use a TableNode");
6272
+ return tableNode.table.identifier.name;
6273
+ }).when(DeleteQueryNode2.is, (node) => {
6274
+ invariant11(node.from.froms.length === 1, "Delete query must have exactly one from table");
6275
+ const { node: tableNode } = stripAlias(node.from.froms[0]);
6276
+ invariant11(TableNode5.is(tableNode), "DeleteQueryNode must use a TableNode");
6277
+ return tableNode.table.identifier.name;
6136
6278
  }).otherwise((node) => {
6137
6279
  throw new InternalError(`Invalid query node: ${node}`);
6138
6280
  });
6139
6281
  }
6140
- async callMutationInterceptionFilters(queryNode) {
6141
- const plugins = this.client.$options.plugins;
6142
- if (plugins) {
6143
- const mutationModel = this.getMutationModel(queryNode);
6144
- const result = {
6145
- intercept: false
6146
- };
6147
- const { action, where } = match16(queryNode).when(InsertQueryNode2.is, () => ({
6148
- action: "create",
6149
- where: void 0
6150
- })).when(UpdateQueryNode2.is, (node) => ({
6151
- action: "update",
6152
- where: node.where
6153
- })).when(DeleteQueryNode2.is, (node) => ({
6154
- action: "delete",
6155
- where: node.where
6156
- })).exhaustive();
6157
- for (const plugin of plugins) {
6158
- const onEntityMutation = plugin.onEntityMutation;
6159
- if (!onEntityMutation) {
6160
- continue;
6161
- }
6162
- if (!onEntityMutation.mutationInterceptionFilter) {
6163
- result.intercept = true;
6164
- } else {
6165
- const filterResult = await onEntityMutation.mutationInterceptionFilter({
6166
- model: mutationModel,
6167
- action,
6168
- queryNode
6169
- });
6170
- result.intercept ||= filterResult.intercept;
6171
- result.loadBeforeMutationEntities ||= filterResult.loadBeforeMutationEntities;
6172
- result.loadAfterMutationEntities ||= filterResult.loadAfterMutationEntities;
6173
- }
6174
- }
6175
- let beforeMutationEntities;
6176
- if (result.loadBeforeMutationEntities && (UpdateQueryNode2.is(queryNode) || DeleteQueryNode2.is(queryNode))) {
6177
- beforeMutationEntities = await this.loadEntities(mutationModel, where);
6178
- }
6179
- return {
6180
- ...result,
6181
- mutationModel,
6182
- action,
6183
- where,
6184
- beforeMutationEntities
6185
- };
6186
- } else {
6187
- return void 0;
6188
- }
6189
- }
6190
- async callBeforeMutationHooks(queryNode, mutationInterceptionInfo) {
6191
- if (!mutationInterceptionInfo?.intercept) {
6192
- return;
6193
- }
6282
+ async callBeforeMutationHooks(queryNode, mutationInfo, loadBeforeMutationEntities, client, queryId) {
6194
6283
  if (this.options.plugins) {
6195
- const mutationModel = this.getMutationModel(queryNode);
6196
6284
  for (const plugin of this.options.plugins) {
6197
6285
  const onEntityMutation = plugin.onEntityMutation;
6198
- if (onEntityMutation?.beforeEntityMutation) {
6199
- await onEntityMutation.beforeEntityMutation({
6200
- model: mutationModel,
6201
- action: mutationInterceptionInfo.action,
6202
- queryNode,
6203
- entities: mutationInterceptionInfo.beforeMutationEntities
6204
- });
6286
+ if (!onEntityMutation?.beforeEntityMutation) {
6287
+ continue;
6205
6288
  }
6289
+ await onEntityMutation.beforeEntityMutation({
6290
+ model: mutationInfo.model,
6291
+ action: mutationInfo.action,
6292
+ queryNode,
6293
+ loadBeforeMutationEntities,
6294
+ client,
6295
+ queryId
6296
+ });
6206
6297
  }
6207
6298
  }
6208
6299
  }
6209
- async callAfterMutationHooks(queryResult, queryNode, mutationInterceptionInfo, connection) {
6210
- if (!mutationInterceptionInfo?.intercept) {
6211
- return;
6212
- }
6300
+ async callAfterMutationHooks(queryResult, queryNode, mutationInfo, client, filterFor, queryId) {
6213
6301
  const hooks = [];
6214
6302
  for (const plugin of this.options.plugins ?? []) {
6215
6303
  const onEntityMutation = plugin.onEntityMutation;
6216
- if (onEntityMutation?.afterEntityMutation) {
6217
- hooks.push(onEntityMutation.afterEntityMutation.bind(plugin));
6304
+ if (!onEntityMutation?.afterEntityMutation) {
6305
+ continue;
6306
+ }
6307
+ if (filterFor === "inTx" && !onEntityMutation.runAfterMutationWithinTransaction) {
6308
+ continue;
6218
6309
  }
6310
+ if (filterFor === "outTx" && onEntityMutation.runAfterMutationWithinTransaction) {
6311
+ continue;
6312
+ }
6313
+ hooks.push(onEntityMutation.afterEntityMutation.bind(plugin));
6219
6314
  }
6220
6315
  if (hooks.length === 0) {
6221
6316
  return;
6222
6317
  }
6223
6318
  const mutationModel = this.getMutationModel(queryNode);
6224
- const inTransaction = this.driver.isTransactionConnection(connection);
6225
- for (const hook of hooks) {
6226
- let afterMutationEntities = void 0;
6227
- if (mutationInterceptionInfo.loadAfterMutationEntities) {
6228
- if (InsertQueryNode2.is(queryNode) || UpdateQueryNode2.is(queryNode)) {
6229
- afterMutationEntities = queryResult.rows;
6230
- }
6231
- }
6232
- const action = /* @__PURE__ */ __name(async () => {
6233
- try {
6234
- await hook({
6235
- model: mutationModel,
6236
- action: mutationInterceptionInfo.action,
6237
- queryNode,
6238
- beforeMutationEntities: mutationInterceptionInfo.beforeMutationEntities,
6239
- afterMutationEntities
6240
- });
6241
- } catch (err) {
6242
- console.error(`Error in afterEntityMutation hook for model "${mutationModel}": ${err}`);
6243
- }
6244
- }, "action");
6245
- if (inTransaction) {
6246
- this.driver.registerTransactionCommitCallback(connection, action);
6319
+ const loadAfterMutationEntities = /* @__PURE__ */ __name(async () => {
6320
+ if (mutationInfo.action === "delete") {
6321
+ return void 0;
6247
6322
  } else {
6248
- await action();
6323
+ return queryResult.rows;
6249
6324
  }
6325
+ }, "loadAfterMutationEntities");
6326
+ for (const hook of hooks) {
6327
+ await hook({
6328
+ model: mutationModel,
6329
+ action: mutationInfo.action,
6330
+ queryNode,
6331
+ loadAfterMutationEntities,
6332
+ client,
6333
+ queryId
6334
+ });
6250
6335
  }
6251
6336
  }
6252
- async loadEntities(model, where) {
6337
+ async loadEntities(model, where, connection) {
6253
6338
  const selectQuery = this.kysely.selectFrom(model).selectAll();
6254
6339
  let selectQueryNode = selectQuery.toOperationNode();
6255
6340
  selectQueryNode = {
@@ -6257,9 +6342,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6257
6342
  where: this.andNodes(selectQueryNode.where, where)
6258
6343
  };
6259
6344
  const compiled = this.compileQuery(selectQueryNode);
6260
- const result = await this.executeQuery(compiled, {
6261
- queryId: `zenstack-${nanoid2()}`
6262
- });
6345
+ const result = await connection.executeQuery(compiled);
6263
6346
  return result.rows;
6264
6347
  }
6265
6348
  andNodes(condition1, condition2) {
@@ -6288,7 +6371,7 @@ __export(functions_exports, {
6288
6371
  search: () => search,
6289
6372
  startsWith: () => startsWith
6290
6373
  });
6291
- import { invariant as invariant10, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
6374
+ import { invariant as invariant12, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
6292
6375
  import { sql as sql7, ValueNode as ValueNode4 } from "kysely";
6293
6376
  import { match as match17 } from "ts-pattern";
6294
6377
  var contains = /* @__PURE__ */ __name((eb, args) => {
@@ -6395,7 +6478,7 @@ var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
6395
6478
  }, "currentOperation");
6396
6479
  function processCasing(casing, result, model) {
6397
6480
  const opNode = casing.toOperationNode();
6398
- invariant10(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
6481
+ invariant12(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
6399
6482
  result = match17(opNode.value).with("original", () => model).with("upper", () => result.toUpperCase()).with("lower", () => result.toLowerCase()).with("capitalize", () => upperCaseFirst(result)).with("uncapitalize", () => lowerCaseFirst(result)).otherwise(() => {
6400
6483
  throw new Error(`Invalid casing value: ${opNode.value}. Must be "original", "upper", "lower", "capitalize", or "uncapitalize".`);
6401
6484
  });
@@ -6404,7 +6487,7 @@ function processCasing(casing, result, model) {
6404
6487
  __name(processCasing, "processCasing");
6405
6488
 
6406
6489
  // src/client/helpers/schema-db-pusher.ts
6407
- import { invariant as invariant11 } from "@zenstackhq/common-helpers";
6490
+ import { invariant as invariant13 } from "@zenstackhq/common-helpers";
6408
6491
  import { sql as sql8 } from "kysely";
6409
6492
  import toposort from "toposort";
6410
6493
  import { match as match18 } from "ts-pattern";
@@ -6465,7 +6548,7 @@ var SchemaDbPusher = class {
6465
6548
  return toposort(graph).reverse().filter((m) => !!m);
6466
6549
  }
6467
6550
  createModelTable(kysely, modelDef) {
6468
- let table = kysely.schema.createTable(modelDef.name).ifNotExists();
6551
+ let table = kysely.schema.createTable(this.getTableName(modelDef)).ifNotExists();
6469
6552
  for (const [fieldName, fieldDef] of Object.entries(modelDef.fields)) {
6470
6553
  if (fieldDef.originModel && !fieldDef.id) {
6471
6554
  continue;
@@ -6484,6 +6567,26 @@ var SchemaDbPusher = class {
6484
6567
  table = this.addUniqueConstraint(table, modelDef);
6485
6568
  return table;
6486
6569
  }
6570
+ getTableName(modelDef) {
6571
+ const mapAttr = modelDef.attributes?.find((a) => a.name === "@@map");
6572
+ if (mapAttr && mapAttr.args?.[0]) {
6573
+ const mappedName = ExpressionUtils.getLiteralValue(mapAttr.args[0].value);
6574
+ if (mappedName) {
6575
+ return mappedName;
6576
+ }
6577
+ }
6578
+ return modelDef.name;
6579
+ }
6580
+ getColumnName(fieldDef) {
6581
+ const mapAttr = fieldDef.attributes?.find((a) => a.name === "@map");
6582
+ if (mapAttr && mapAttr.args?.[0]) {
6583
+ const mappedName = ExpressionUtils.getLiteralValue(mapAttr.args[0].value);
6584
+ if (mappedName) {
6585
+ return mappedName;
6586
+ }
6587
+ }
6588
+ return fieldDef.name;
6589
+ }
6487
6590
  isComputedField(fieldDef) {
6488
6591
  return fieldDef.attributes?.some((a) => a.name === "@computed");
6489
6592
  }
@@ -6494,29 +6597,29 @@ var SchemaDbPusher = class {
6494
6597
  }
6495
6598
  }
6496
6599
  if (modelDef.idFields.length > 0) {
6497
- table = table.addPrimaryKeyConstraint(`pk_${modelDef.name}`, modelDef.idFields);
6600
+ table = table.addPrimaryKeyConstraint(`pk_${modelDef.name}`, modelDef.idFields.map((f) => this.getColumnName(modelDef.fields[f])));
6498
6601
  }
6499
6602
  return table;
6500
6603
  }
6501
6604
  addUniqueConstraint(table, modelDef) {
6502
6605
  for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
6503
- invariant11(typeof value === "object", "expecting an object");
6606
+ invariant13(typeof value === "object", "expecting an object");
6504
6607
  if ("type" in value) {
6505
6608
  const fieldDef = modelDef.fields[key];
6506
6609
  if (fieldDef.unique) {
6507
6610
  continue;
6508
6611
  }
6509
6612
  table = table.addUniqueConstraint(`unique_${modelDef.name}_${key}`, [
6510
- key
6613
+ this.getColumnName(fieldDef)
6511
6614
  ]);
6512
6615
  } else {
6513
- table = table.addUniqueConstraint(`unique_${modelDef.name}_${key}`, Object.keys(value));
6616
+ table = table.addUniqueConstraint(`unique_${modelDef.name}_${key}`, Object.keys(value).map((f) => this.getColumnName(modelDef.fields[f])));
6514
6617
  }
6515
6618
  }
6516
6619
  return table;
6517
6620
  }
6518
6621
  createModelField(table, fieldDef, modelDef) {
6519
- return table.addColumn(fieldDef.name, this.mapFieldType(fieldDef), (col) => {
6622
+ return table.addColumn(this.getColumnName(fieldDef), this.mapFieldType(fieldDef), (col) => {
6520
6623
  if (fieldDef.id && modelDef.idFields.length === 1) {
6521
6624
  col = col.primaryKey();
6522
6625
  }
@@ -6568,11 +6671,13 @@ var SchemaDbPusher = class {
6568
6671
  return fieldDef.default && ExpressionUtils.isCall(fieldDef.default) && fieldDef.default.function === "autoincrement";
6569
6672
  }
6570
6673
  addForeignKeyConstraint(table, model, fieldName, fieldDef) {
6571
- invariant11(fieldDef.relation, "field must be a relation");
6674
+ invariant13(fieldDef.relation, "field must be a relation");
6572
6675
  if (!fieldDef.relation.fields || !fieldDef.relation.references) {
6573
6676
  return table;
6574
6677
  }
6575
- table = table.addForeignKeyConstraint(`fk_${model}_${fieldName}`, fieldDef.relation.fields, fieldDef.type, fieldDef.relation.references, (cb) => {
6678
+ const modelDef = requireModel(this.schema, model);
6679
+ const relationModelDef = requireModel(this.schema, fieldDef.type);
6680
+ table = table.addForeignKeyConstraint(`fk_${model}_${fieldName}`, fieldDef.relation.fields.map((f) => this.getColumnName(modelDef.fields[f])), this.getTableName(relationModelDef), fieldDef.relation.references.map((f) => this.getColumnName(relationModelDef.fields[f])), (cb) => {
6576
6681
  if (fieldDef.relation?.onDelete) {
6577
6682
  cb = cb.onDelete(this.mapCascadeAction(fieldDef.relation.onDelete));
6578
6683
  }
@@ -6623,7 +6728,7 @@ function valueToPromise(thing) {
6623
6728
  __name(valueToPromise, "valueToPromise");
6624
6729
 
6625
6730
  // src/client/result-processor.ts
6626
- import { invariant as invariant12 } from "@zenstackhq/common-helpers";
6731
+ import { invariant as invariant14 } from "@zenstackhq/common-helpers";
6627
6732
  import Decimal2 from "decimal.js";
6628
6733
  import { match as match19 } from "ts-pattern";
6629
6734
  var ResultProcessor = class {
@@ -6723,14 +6828,14 @@ var ResultProcessor = class {
6723
6828
  if (value instanceof Decimal2) {
6724
6829
  return value;
6725
6830
  }
6726
- invariant12(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
6831
+ invariant14(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
6727
6832
  return new Decimal2(value);
6728
6833
  }
6729
6834
  transformBigInt(value) {
6730
6835
  if (typeof value === "bigint") {
6731
6836
  return value;
6732
6837
  }
6733
- invariant12(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
6838
+ invariant14(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
6734
6839
  return BigInt(value);
6735
6840
  }
6736
6841
  transformBoolean(value) {
@@ -6774,7 +6879,7 @@ var ResultProcessor = class {
6774
6879
  }
6775
6880
  transformJson(value) {
6776
6881
  return match19(this.schema.provider.type).with("sqlite", () => {
6777
- invariant12(typeof value === "string", "Expected string, got " + typeof value);
6882
+ invariant14(typeof value === "string", "Expected string, got " + typeof value);
6778
6883
  return JSON.parse(value);
6779
6884
  }).otherwise(() => value);
6780
6885
  }
@@ -6851,13 +6956,18 @@ var ClientImpl = class _ClientImpl {
6851
6956
  }
6852
6957
  // implementation
6853
6958
  async $transaction(input, options) {
6854
- invariant13(typeof input === "function" || Array.isArray(input) && input.every((p) => p.then && p.cb), "Invalid transaction input, expected a function or an array of ZenStackPromise");
6959
+ invariant15(typeof input === "function" || Array.isArray(input) && input.every((p) => p.then && p.cb), "Invalid transaction input, expected a function or an array of ZenStackPromise");
6855
6960
  if (typeof input === "function") {
6856
6961
  return this.interactiveTransaction(input, options);
6857
6962
  } else {
6858
6963
  return this.sequentialTransaction(input, options);
6859
6964
  }
6860
6965
  }
6966
+ forceTransaction() {
6967
+ if (!this.kysely.isTransaction) {
6968
+ this.kysely = new Transaction(this.kyselyProps);
6969
+ }
6970
+ }
6861
6971
  async interactiveTransaction(callback, options) {
6862
6972
  if (this.kysely.isTransaction) {
6863
6973
  return callback(this);