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

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";
@@ -2704,6 +2704,16 @@ function clone(value) {
2704
2704
  }
2705
2705
  __name(clone, "clone");
2706
2706
 
2707
+ // src/client/contract.ts
2708
+ var TransactionIsolationLevel = /* @__PURE__ */ function(TransactionIsolationLevel2) {
2709
+ TransactionIsolationLevel2["ReadUncommitted"] = "read uncommitted";
2710
+ TransactionIsolationLevel2["ReadCommitted"] = "read committed";
2711
+ TransactionIsolationLevel2["RepeatableRead"] = "repeatable read";
2712
+ TransactionIsolationLevel2["Serializable"] = "serializable";
2713
+ TransactionIsolationLevel2["Snapshot"] = "snapshot";
2714
+ return TransactionIsolationLevel2;
2715
+ }({});
2716
+
2707
2717
  // src/client/crud/operations/base.ts
2708
2718
  var BaseOperationHandler = class {
2709
2719
  static {
@@ -3942,7 +3952,7 @@ var BaseOperationHandler = class {
3942
3952
  return callback(this.kysely);
3943
3953
  } else {
3944
3954
  let txBuilder = this.kysely.transaction();
3945
- txBuilder = txBuilder.setIsolationLevel(isolationLevel ?? "repeatable read");
3955
+ txBuilder = txBuilder.setIsolationLevel(isolationLevel ?? TransactionIsolationLevel.RepeatableRead);
3946
3956
  return txBuilder.execute(callback);
3947
3957
  }
3948
3958
  }
@@ -5508,7 +5518,11 @@ var ZenStackDriver = class {
5508
5518
  this.#txConnections.delete(connection);
5509
5519
  if (callbacks) {
5510
5520
  for (const callback of callbacks) {
5511
- await callback();
5521
+ try {
5522
+ await callback();
5523
+ } catch (err) {
5524
+ console.error(`Error executing transaction commit callback: ${err}`);
5525
+ }
5512
5526
  }
5513
5527
  }
5514
5528
  return result;
@@ -5626,13 +5640,32 @@ function performanceNow() {
5626
5640
  __name(performanceNow, "performanceNow");
5627
5641
 
5628
5642
  // 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";
5643
+ import { invariant as invariant11 } from "@zenstackhq/common-helpers";
5644
+ 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
5645
  import { match as match16 } from "ts-pattern";
5632
5646
 
5633
- // src/client/executor/name-mapper.ts
5647
+ // src/client/executor/kysely-utils.ts
5634
5648
  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";
5649
+ import { AliasNode as AliasNode4, IdentifierNode as IdentifierNode3 } from "kysely";
5650
+ function stripAlias(node) {
5651
+ if (AliasNode4.is(node)) {
5652
+ invariant9(IdentifierNode3.is(node.alias), "Expected identifier as alias");
5653
+ return {
5654
+ alias: node.alias.name,
5655
+ node: node.node
5656
+ };
5657
+ } else {
5658
+ return {
5659
+ alias: void 0,
5660
+ node
5661
+ };
5662
+ }
5663
+ }
5664
+ __name(stripAlias, "stripAlias");
5665
+
5666
+ // src/client/executor/name-mapper.ts
5667
+ import { invariant as invariant10 } from "@zenstackhq/common-helpers";
5668
+ 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
5669
  var QueryNameMapper = class extends OperationNodeTransformer2 {
5637
5670
  static {
5638
5671
  __name(this, "QueryNameMapper");
@@ -5690,7 +5723,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5690
5723
  };
5691
5724
  }
5692
5725
  transformJoin(node) {
5693
- const { alias, node: innerNode } = this.stripAlias(node.table);
5726
+ const { alias, node: innerNode } = stripAlias(node.table);
5694
5727
  if (TableNode4.is(innerNode)) {
5695
5728
  const modelName = innerNode.table.identifier.name;
5696
5729
  if (this.hasMappedColumns(modelName)) {
@@ -5731,7 +5764,10 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5731
5764
  return ColumnNode3.create(mappedName);
5732
5765
  }
5733
5766
  transformUpdateQuery(node) {
5734
- const { alias, node: innerTable } = this.stripAlias(node.table);
5767
+ if (!node.table) {
5768
+ return super.transformUpdateQuery(node);
5769
+ }
5770
+ const { alias, node: innerTable } = stripAlias(node.table);
5735
5771
  if (!innerTable || !TableNode4.is(innerTable)) {
5736
5772
  return super.transformUpdateQuery(node);
5737
5773
  }
@@ -5749,7 +5785,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5749
5785
  transformDeleteQuery(node) {
5750
5786
  const scopes = this.createScopesFromFroms(node.from, false);
5751
5787
  const froms = node.from.froms.map((from) => {
5752
- const { alias, node: innerNode } = this.stripAlias(from);
5788
+ const { alias, node: innerNode } = stripAlias(from);
5753
5789
  if (TableNode4.is(innerNode)) {
5754
5790
  return this.wrapAlias(this.processTableRef(innerNode), alias);
5755
5791
  } else {
@@ -5816,13 +5852,13 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5816
5852
  }
5817
5853
  }
5818
5854
  wrapAlias(node, alias) {
5819
- return alias ? AliasNode4.create(node, IdentifierNode3.create(alias)) : node;
5855
+ return alias ? AliasNode5.create(node, IdentifierNode4.create(alias)) : node;
5820
5856
  }
5821
5857
  ensureAlias(node, alias, fallbackName) {
5822
5858
  if (!node) {
5823
5859
  return node;
5824
5860
  }
5825
- return alias ? AliasNode4.create(node, IdentifierNode3.create(alias)) : AliasNode4.create(node, IdentifierNode3.create(fallbackName));
5861
+ return alias ? AliasNode5.create(node, IdentifierNode4.create(alias)) : AliasNode5.create(node, IdentifierNode4.create(fallbackName));
5826
5862
  }
5827
5863
  processTableRef(node) {
5828
5864
  if (!node) {
@@ -5859,25 +5895,6 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5859
5895
  return tableName;
5860
5896
  }
5861
5897
  }
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
5898
  hasMappedColumns(modelName) {
5882
5899
  return [
5883
5900
  ...this.fieldToColumnMap.keys()
@@ -5888,7 +5905,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5888
5905
  return [];
5889
5906
  }
5890
5907
  return node.froms.map((from) => {
5891
- const { alias, node: innerNode } = this.stripAlias(from);
5908
+ const { alias, node: innerNode } = stripAlias(from);
5892
5909
  if (innerNode && TableNode4.is(innerNode)) {
5893
5910
  return {
5894
5911
  model: innerNode.table.identifier.name,
@@ -5905,7 +5922,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5905
5922
  return {
5906
5923
  ...super.transformFrom(node),
5907
5924
  froms: node.froms.map((from) => {
5908
- const { alias, node: innerNode } = this.stripAlias(from);
5925
+ const { alias, node: innerNode } = stripAlias(from);
5909
5926
  if (!innerNode) {
5910
5927
  return super.transformNode(from);
5911
5928
  }
@@ -5932,7 +5949,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5932
5949
  const columnName = this.mapFieldName(model, fieldDef.name);
5933
5950
  const columnRef = ReferenceNode3.create(ColumnNode3.create(columnName), TableNode4.create(tableName));
5934
5951
  if (columnName !== fieldDef.name) {
5935
- const aliased = AliasNode4.create(columnRef, IdentifierNode3.create(fieldDef.name));
5952
+ const aliased = AliasNode5.create(columnRef, IdentifierNode4.create(fieldDef.name));
5936
5953
  return SelectionNode3.create(aliased);
5937
5954
  } else {
5938
5955
  return SelectionNode3.create(columnRef);
@@ -5961,7 +5978,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5961
5978
  }
5962
5979
  processSelection(node) {
5963
5980
  let alias;
5964
- if (!AliasNode4.is(node)) {
5981
+ if (!AliasNode5.is(node)) {
5965
5982
  alias = this.extractFieldName(node);
5966
5983
  }
5967
5984
  const result = super.transformNode(node);
@@ -5969,7 +5986,7 @@ var QueryNameMapper = class extends OperationNodeTransformer2 {
5969
5986
  }
5970
5987
  processSelectAll(node) {
5971
5988
  const scope = this.modelScopes[this.modelScopes.length - 1];
5972
- invariant9(scope);
5989
+ invariant10(scope);
5973
5990
  if (!this.hasMappedColumns(scope.model)) {
5974
5991
  return super.transformSelectAll(node);
5975
5992
  }
@@ -6000,9 +6017,10 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6000
6017
  driver;
6001
6018
  compiler;
6002
6019
  connectionProvider;
6020
+ suppressMutationHooks;
6003
6021
  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;
6022
+ constructor(client, driver, compiler, adapter, connectionProvider, plugins = [], suppressMutationHooks = false) {
6023
+ super(compiler, adapter, connectionProvider, plugins), this.client = client, this.driver = driver, this.compiler = compiler, this.connectionProvider = connectionProvider, this.suppressMutationHooks = suppressMutationHooks;
6006
6024
  this.nameMapper = new QueryNameMapper(client.$schema);
6007
6025
  }
6008
6026
  get kysely() {
@@ -6011,38 +6029,13 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6011
6029
  get options() {
6012
6030
  return this.client.$options;
6013
6031
  }
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();
6032
+ async executeQuery(compiledQuery, queryId) {
6033
+ const queryParams = compiledQuery.$raw ? compiledQuery.parameters : void 0;
6034
+ const result = await this.proceedQueryWithKyselyInterceptors(compiledQuery.query, queryParams, queryId.queryId);
6035
+ return result.result;
6043
6036
  }
6044
- proceedQueryWithKyselyInterceptors(queryNode, parameters) {
6045
- let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters), "proceed");
6037
+ async proceedQueryWithKyselyInterceptors(queryNode, parameters, queryId) {
6038
+ let proceed = /* @__PURE__ */ __name((q) => this.proceedQuery(q, parameters, queryId), "proceed");
6046
6039
  const hooks = [];
6047
6040
  for (const plugin of this.client.$options.plugins ?? []) {
6048
6041
  if (plugin.onKyselyQuery) {
@@ -6052,10 +6045,8 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6052
6045
  for (const hook of hooks) {
6053
6046
  const _proceed = proceed;
6054
6047
  proceed = /* @__PURE__ */ __name(async (query) => {
6055
- let connection;
6056
6048
  const _p = /* @__PURE__ */ __name(async (q) => {
6057
6049
  const r = await _proceed(q);
6058
- connection = r.connection;
6059
6050
  return r.result;
6060
6051
  }, "_p");
6061
6052
  const hookResult = await hook({
@@ -6066,35 +6057,129 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6066
6057
  proceed: _p
6067
6058
  });
6068
6059
  return {
6069
- result: hookResult,
6070
- connection
6060
+ result: hookResult
6071
6061
  };
6072
6062
  }, "proceed");
6073
6063
  }
6074
- return proceed(queryNode);
6064
+ const result = await proceed(queryNode);
6065
+ return result;
6075
6066
  }
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
- }
6067
+ getMutationInfo(queryNode) {
6068
+ const model = this.getMutationModel(queryNode);
6069
+ const { action, where } = match16(queryNode).when(InsertQueryNode2.is, () => ({
6070
+ action: "create",
6071
+ where: void 0
6072
+ })).when(UpdateQueryNode2.is, (node) => ({
6073
+ action: "update",
6074
+ where: node.where
6075
+ })).when(DeleteQueryNode2.is, (node) => ({
6076
+ action: "delete",
6077
+ where: node.where
6078
+ })).exhaustive();
6079
+ return {
6080
+ model,
6081
+ action,
6082
+ where
6083
+ };
6084
+ }
6085
+ async proceedQuery(query, parameters, queryId) {
6086
+ let compiled;
6085
6087
  try {
6086
6088
  return await this.provideConnection(async (connection) => {
6087
- const result = await connection.executeQuery(compiled);
6088
- return {
6089
- result,
6090
- connection
6091
- };
6089
+ if (this.suppressMutationHooks || !this.isMutationNode(query) || !this.hasEntityMutationPlugins) {
6090
+ const finalQuery2 = this.nameMapper.transformNode(query);
6091
+ compiled = this.compileQuery(finalQuery2);
6092
+ if (parameters) {
6093
+ compiled = {
6094
+ ...compiled,
6095
+ parameters
6096
+ };
6097
+ }
6098
+ const result = await connection.executeQuery(compiled);
6099
+ return {
6100
+ result
6101
+ };
6102
+ }
6103
+ if ((InsertQueryNode2.is(query) || UpdateQueryNode2.is(query)) && this.hasEntityMutationPluginsWithAfterMutationHooks) {
6104
+ query = {
6105
+ ...query,
6106
+ returning: ReturningNode2.create([
6107
+ SelectionNode4.createSelectAll()
6108
+ ])
6109
+ };
6110
+ }
6111
+ const finalQuery = this.nameMapper.transformNode(query);
6112
+ compiled = this.compileQuery(finalQuery);
6113
+ if (parameters) {
6114
+ compiled = {
6115
+ ...compiled,
6116
+ parameters
6117
+ };
6118
+ }
6119
+ const currentlyInTx = this.driver.isTransactionConnection(connection);
6120
+ const connectionClient = this.createClientForConnection(connection, currentlyInTx);
6121
+ const mutationInfo = this.getMutationInfo(finalQuery);
6122
+ let beforeMutationEntities;
6123
+ const loadBeforeMutationEntities = /* @__PURE__ */ __name(async () => {
6124
+ if (beforeMutationEntities === void 0 && (UpdateQueryNode2.is(query) || DeleteQueryNode2.is(query))) {
6125
+ beforeMutationEntities = await this.loadEntities(mutationInfo.model, mutationInfo.where, connection);
6126
+ }
6127
+ return beforeMutationEntities;
6128
+ }, "loadBeforeMutationEntities");
6129
+ await this.callBeforeMutationHooks(finalQuery, mutationInfo, loadBeforeMutationEntities, connectionClient, queryId);
6130
+ const shouldCreateTx = this.hasPluginRequestingAfterMutationWithinTransaction && !this.driver.isTransactionConnection(connection);
6131
+ if (!shouldCreateTx) {
6132
+ const result = await connection.executeQuery(compiled);
6133
+ if (!this.driver.isTransactionConnection(connection)) {
6134
+ await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "all", queryId);
6135
+ } else {
6136
+ await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "inTx", queryId);
6137
+ this.driver.registerTransactionCommitCallback(connection, () => this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "outTx", queryId));
6138
+ }
6139
+ return {
6140
+ result
6141
+ };
6142
+ } else {
6143
+ await this.driver.beginTransaction(connection, {
6144
+ isolationLevel: TransactionIsolationLevel.ReadCommitted
6145
+ });
6146
+ try {
6147
+ const result = await connection.executeQuery(compiled);
6148
+ await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "inTx", queryId);
6149
+ await this.driver.commitTransaction(connection);
6150
+ await this.callAfterMutationHooks(result, finalQuery, mutationInfo, connectionClient, "outTx", queryId);
6151
+ return {
6152
+ result
6153
+ };
6154
+ } catch (err) {
6155
+ await this.driver.rollbackTransaction(connection);
6156
+ throw err;
6157
+ }
6158
+ }
6092
6159
  });
6093
6160
  } catch (err) {
6094
- const message = `Failed to execute query: ${err}, sql: ${compiled.sql}`;
6161
+ const message = `Failed to execute query: ${err}, sql: ${compiled?.sql}`;
6095
6162
  throw new QueryError(message, err);
6096
6163
  }
6097
6164
  }
6165
+ createClientForConnection(connection, inTx) {
6166
+ const innerExecutor = this.withConnectionProvider(new SingleConnectionProvider(connection));
6167
+ innerExecutor.suppressMutationHooks = true;
6168
+ const innerClient = this.client.withExecutor(innerExecutor);
6169
+ if (inTx) {
6170
+ innerClient.forceTransaction();
6171
+ }
6172
+ return innerClient;
6173
+ }
6174
+ get hasEntityMutationPlugins() {
6175
+ return (this.client.$options.plugins ?? []).some((plugin) => plugin.onEntityMutation);
6176
+ }
6177
+ get hasEntityMutationPluginsWithAfterMutationHooks() {
6178
+ return (this.client.$options.plugins ?? []).some((plugin) => plugin.onEntityMutation?.afterEntityMutation);
6179
+ }
6180
+ get hasPluginRequestingAfterMutationWithinTransaction() {
6181
+ return (this.client.$options.plugins ?? []).some((plugin) => plugin.onEntityMutation?.runAfterMutationWithinTransaction);
6182
+ }
6098
6183
  isMutationNode(queryNode) {
6099
6184
  return InsertQueryNode2.is(queryNode) || UpdateQueryNode2.is(queryNode) || DeleteQueryNode2.is(queryNode);
6100
6185
  }
@@ -6102,154 +6187,102 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6102
6187
  return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, [
6103
6188
  ...this.plugins,
6104
6189
  plugin
6105
- ]);
6190
+ ], this.suppressMutationHooks);
6106
6191
  }
6107
6192
  withPlugins(plugins) {
6108
6193
  return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, [
6109
6194
  ...this.plugins,
6110
6195
  ...plugins
6111
- ]);
6196
+ ], this.suppressMutationHooks);
6112
6197
  }
6113
6198
  withPluginAtFront(plugin) {
6114
6199
  return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, [
6115
6200
  plugin,
6116
6201
  ...this.plugins
6117
- ]);
6202
+ ], this.suppressMutationHooks);
6118
6203
  }
6119
6204
  withoutPlugins() {
6120
- return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, []);
6205
+ return new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, this.connectionProvider, [], this.suppressMutationHooks);
6121
6206
  }
6122
6207
  withConnectionProvider(connectionProvider) {
6123
- const newExecutor = new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider);
6208
+ const newExecutor = new _ZenStackQueryExecutor(this.client, this.driver, this.compiler, this.adapter, connectionProvider, this.plugins, this.suppressMutationHooks);
6124
6209
  newExecutor.client = this.client.withExecutor(newExecutor);
6125
6210
  return newExecutor;
6126
6211
  }
6127
- get hasMutationHooks() {
6128
- return this.client.$options.plugins?.some((plugin) => !!plugin.onEntityMutation);
6129
- }
6130
6212
  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;
6213
+ return match16(queryNode).when(InsertQueryNode2.is, (node) => {
6214
+ invariant11(node.into, "InsertQueryNode must have an into clause");
6215
+ return node.into.table.identifier.name;
6216
+ }).when(UpdateQueryNode2.is, (node) => {
6217
+ invariant11(node.table, "UpdateQueryNode must have a table");
6218
+ const { node: tableNode } = stripAlias(node.table);
6219
+ invariant11(TableNode5.is(tableNode), "UpdateQueryNode must use a TableNode");
6220
+ return tableNode.table.identifier.name;
6221
+ }).when(DeleteQueryNode2.is, (node) => {
6222
+ invariant11(node.from.froms.length === 1, "Delete query must have exactly one from table");
6223
+ const { node: tableNode } = stripAlias(node.from.froms[0]);
6224
+ invariant11(TableNode5.is(tableNode), "DeleteQueryNode must use a TableNode");
6225
+ return tableNode.table.identifier.name;
6136
6226
  }).otherwise((node) => {
6137
6227
  throw new InternalError(`Invalid query node: ${node}`);
6138
6228
  });
6139
6229
  }
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
- }
6230
+ async callBeforeMutationHooks(queryNode, mutationInfo, loadBeforeMutationEntities, client, queryId) {
6194
6231
  if (this.options.plugins) {
6195
- const mutationModel = this.getMutationModel(queryNode);
6196
6232
  for (const plugin of this.options.plugins) {
6197
6233
  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
- });
6234
+ if (!onEntityMutation?.beforeEntityMutation) {
6235
+ continue;
6205
6236
  }
6237
+ await onEntityMutation.beforeEntityMutation({
6238
+ model: mutationInfo.model,
6239
+ action: mutationInfo.action,
6240
+ queryNode,
6241
+ loadBeforeMutationEntities,
6242
+ client,
6243
+ queryId
6244
+ });
6206
6245
  }
6207
6246
  }
6208
6247
  }
6209
- async callAfterMutationHooks(queryResult, queryNode, mutationInterceptionInfo, connection) {
6210
- if (!mutationInterceptionInfo?.intercept) {
6211
- return;
6212
- }
6248
+ async callAfterMutationHooks(queryResult, queryNode, mutationInfo, client, filterFor, queryId) {
6213
6249
  const hooks = [];
6214
6250
  for (const plugin of this.options.plugins ?? []) {
6215
6251
  const onEntityMutation = plugin.onEntityMutation;
6216
- if (onEntityMutation?.afterEntityMutation) {
6217
- hooks.push(onEntityMutation.afterEntityMutation.bind(plugin));
6252
+ if (!onEntityMutation?.afterEntityMutation) {
6253
+ continue;
6254
+ }
6255
+ if (filterFor === "inTx" && !onEntityMutation.runAfterMutationWithinTransaction) {
6256
+ continue;
6218
6257
  }
6258
+ if (filterFor === "outTx" && onEntityMutation.runAfterMutationWithinTransaction) {
6259
+ continue;
6260
+ }
6261
+ hooks.push(onEntityMutation.afterEntityMutation.bind(plugin));
6219
6262
  }
6220
6263
  if (hooks.length === 0) {
6221
6264
  return;
6222
6265
  }
6223
6266
  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);
6267
+ const loadAfterMutationEntities = /* @__PURE__ */ __name(async () => {
6268
+ if (mutationInfo.action === "delete") {
6269
+ return void 0;
6247
6270
  } else {
6248
- await action();
6271
+ return queryResult.rows;
6249
6272
  }
6273
+ }, "loadAfterMutationEntities");
6274
+ for (const hook of hooks) {
6275
+ await hook({
6276
+ model: mutationModel,
6277
+ action: mutationInfo.action,
6278
+ queryNode,
6279
+ loadAfterMutationEntities,
6280
+ client,
6281
+ queryId
6282
+ });
6250
6283
  }
6251
6284
  }
6252
- async loadEntities(model, where) {
6285
+ async loadEntities(model, where, connection) {
6253
6286
  const selectQuery = this.kysely.selectFrom(model).selectAll();
6254
6287
  let selectQueryNode = selectQuery.toOperationNode();
6255
6288
  selectQueryNode = {
@@ -6257,9 +6290,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
6257
6290
  where: this.andNodes(selectQueryNode.where, where)
6258
6291
  };
6259
6292
  const compiled = this.compileQuery(selectQueryNode);
6260
- const result = await this.executeQuery(compiled, {
6261
- queryId: `zenstack-${nanoid2()}`
6262
- });
6293
+ const result = await connection.executeQuery(compiled);
6263
6294
  return result.rows;
6264
6295
  }
6265
6296
  andNodes(condition1, condition2) {
@@ -6288,7 +6319,7 @@ __export(functions_exports, {
6288
6319
  search: () => search,
6289
6320
  startsWith: () => startsWith
6290
6321
  });
6291
- import { invariant as invariant10, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
6322
+ import { invariant as invariant12, lowerCaseFirst, upperCaseFirst } from "@zenstackhq/common-helpers";
6292
6323
  import { sql as sql7, ValueNode as ValueNode4 } from "kysely";
6293
6324
  import { match as match17 } from "ts-pattern";
6294
6325
  var contains = /* @__PURE__ */ __name((eb, args) => {
@@ -6395,7 +6426,7 @@ var currentOperation = /* @__PURE__ */ __name((_eb, args, { operation }) => {
6395
6426
  }, "currentOperation");
6396
6427
  function processCasing(casing, result, model) {
6397
6428
  const opNode = casing.toOperationNode();
6398
- invariant10(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
6429
+ invariant12(ValueNode4.is(opNode) && typeof opNode.value === "string", '"casting" parameter must be a string value');
6399
6430
  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
6431
  throw new Error(`Invalid casing value: ${opNode.value}. Must be "original", "upper", "lower", "capitalize", or "uncapitalize".`);
6401
6432
  });
@@ -6404,7 +6435,7 @@ function processCasing(casing, result, model) {
6404
6435
  __name(processCasing, "processCasing");
6405
6436
 
6406
6437
  // src/client/helpers/schema-db-pusher.ts
6407
- import { invariant as invariant11 } from "@zenstackhq/common-helpers";
6438
+ import { invariant as invariant13 } from "@zenstackhq/common-helpers";
6408
6439
  import { sql as sql8 } from "kysely";
6409
6440
  import toposort from "toposort";
6410
6441
  import { match as match18 } from "ts-pattern";
@@ -6500,7 +6531,7 @@ var SchemaDbPusher = class {
6500
6531
  }
6501
6532
  addUniqueConstraint(table, modelDef) {
6502
6533
  for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
6503
- invariant11(typeof value === "object", "expecting an object");
6534
+ invariant13(typeof value === "object", "expecting an object");
6504
6535
  if ("type" in value) {
6505
6536
  const fieldDef = modelDef.fields[key];
6506
6537
  if (fieldDef.unique) {
@@ -6568,7 +6599,7 @@ var SchemaDbPusher = class {
6568
6599
  return fieldDef.default && ExpressionUtils.isCall(fieldDef.default) && fieldDef.default.function === "autoincrement";
6569
6600
  }
6570
6601
  addForeignKeyConstraint(table, model, fieldName, fieldDef) {
6571
- invariant11(fieldDef.relation, "field must be a relation");
6602
+ invariant13(fieldDef.relation, "field must be a relation");
6572
6603
  if (!fieldDef.relation.fields || !fieldDef.relation.references) {
6573
6604
  return table;
6574
6605
  }
@@ -6623,7 +6654,7 @@ function valueToPromise(thing) {
6623
6654
  __name(valueToPromise, "valueToPromise");
6624
6655
 
6625
6656
  // src/client/result-processor.ts
6626
- import { invariant as invariant12 } from "@zenstackhq/common-helpers";
6657
+ import { invariant as invariant14 } from "@zenstackhq/common-helpers";
6627
6658
  import Decimal2 from "decimal.js";
6628
6659
  import { match as match19 } from "ts-pattern";
6629
6660
  var ResultProcessor = class {
@@ -6723,14 +6754,14 @@ var ResultProcessor = class {
6723
6754
  if (value instanceof Decimal2) {
6724
6755
  return value;
6725
6756
  }
6726
- invariant12(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
6757
+ invariant14(typeof value === "string" || typeof value === "number" || value instanceof Decimal2, `Expected string, number or Decimal, got ${typeof value}`);
6727
6758
  return new Decimal2(value);
6728
6759
  }
6729
6760
  transformBigInt(value) {
6730
6761
  if (typeof value === "bigint") {
6731
6762
  return value;
6732
6763
  }
6733
- invariant12(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
6764
+ invariant14(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
6734
6765
  return BigInt(value);
6735
6766
  }
6736
6767
  transformBoolean(value) {
@@ -6774,7 +6805,7 @@ var ResultProcessor = class {
6774
6805
  }
6775
6806
  transformJson(value) {
6776
6807
  return match19(this.schema.provider.type).with("sqlite", () => {
6777
- invariant12(typeof value === "string", "Expected string, got " + typeof value);
6808
+ invariant14(typeof value === "string", "Expected string, got " + typeof value);
6778
6809
  return JSON.parse(value);
6779
6810
  }).otherwise(() => value);
6780
6811
  }
@@ -6851,13 +6882,18 @@ var ClientImpl = class _ClientImpl {
6851
6882
  }
6852
6883
  // implementation
6853
6884
  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");
6885
+ 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
6886
  if (typeof input === "function") {
6856
6887
  return this.interactiveTransaction(input, options);
6857
6888
  } else {
6858
6889
  return this.sequentialTransaction(input, options);
6859
6890
  }
6860
6891
  }
6892
+ forceTransaction() {
6893
+ if (!this.kysely.isTransaction) {
6894
+ this.kysely = new Transaction(this.kyselyProps);
6895
+ }
6896
+ }
6861
6897
  async interactiveTransaction(callback, options) {
6862
6898
  if (this.kysely.isTransaction) {
6863
6899
  return callback(this);