kysely 0.28.18 → 0.28.19

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.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/dialect/mssql/mssql-driver.d.ts +3 -0
  3. package/dist/cjs/dialect/mysql/mysql-driver.d.ts +3 -0
  4. package/dist/cjs/dialect/postgres/postgres-dialect-config.d.ts +2 -2
  5. package/dist/cjs/dialect/postgres/postgres-driver.d.ts +6 -1
  6. package/dist/cjs/dialect/postgres/postgres-driver.js +30 -3
  7. package/dist/cjs/dialect/sqlite/sqlite-driver.d.ts +3 -0
  8. package/dist/cjs/driver/aborted-transaction-error.d.ts +11 -0
  9. package/dist/cjs/driver/aborted-transaction-error.js +20 -0
  10. package/dist/cjs/driver/driver.d.ts +3 -0
  11. package/dist/cjs/driver/dummy-driver.d.ts +3 -0
  12. package/dist/cjs/driver/runtime-driver.d.ts +3 -0
  13. package/dist/cjs/index.d.ts +1 -0
  14. package/dist/cjs/index.js +1 -0
  15. package/dist/cjs/kysely.d.ts +9 -4
  16. package/dist/cjs/kysely.js +60 -38
  17. package/dist/esm/dialect/mssql/mssql-driver.d.ts +3 -0
  18. package/dist/esm/dialect/mysql/mysql-driver.d.ts +3 -0
  19. package/dist/esm/dialect/postgres/postgres-dialect-config.d.ts +2 -2
  20. package/dist/esm/dialect/postgres/postgres-driver.d.ts +6 -1
  21. package/dist/esm/dialect/postgres/postgres-driver.js +30 -3
  22. package/dist/esm/dialect/sqlite/sqlite-driver.d.ts +3 -0
  23. package/dist/esm/driver/aborted-transaction-error.d.ts +11 -0
  24. package/dist/esm/driver/aborted-transaction-error.js +16 -0
  25. package/dist/esm/driver/driver.d.ts +3 -0
  26. package/dist/esm/driver/dummy-driver.d.ts +3 -0
  27. package/dist/esm/driver/runtime-driver.d.ts +3 -0
  28. package/dist/esm/index.d.ts +1 -0
  29. package/dist/esm/index.js +1 -0
  30. package/dist/esm/kysely.d.ts +9 -4
  31. package/dist/esm/kysely.js +60 -38
  32. package/package.json +1 -1
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://stand-with-ukraine.pp.ua)
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/kysely?style=flat&label=latest)](https://github.com/kysely-org/kysely/releases/latest)
4
- [![Socket Badge](https://badge.socket.dev/npm/package/kysely/0.28.18)](https://socket.dev/npm/package/kysely/overview/0.28.18)
4
+ [![Socket Badge](https://badge.socket.dev/npm/package/kysely/0.28.19)](https://socket.dev/npm/package/kysely/overview/0.28.19)
5
5
  [![Tests](https://github.com/kysely-org/kysely/actions/workflows/test.yml/badge.svg)](https://github.com/kysely-org/kysely)
6
6
  [![License](https://img.shields.io/github/license/kysely-org/kysely?style=flat)](https://github.com/kysely-org/kysely/blob/master/LICENSE)
7
7
  [![Issues](https://img.shields.io/github/issues-closed/kysely-org/kysely?logo=github)](https://github.com/kysely-org/kysely/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc)
@@ -25,6 +25,9 @@ export declare class MssqlDriver implements Driver {
25
25
  beginTransaction(connection: MssqlConnection, settings: TransactionSettings): Promise<void>;
26
26
  /**
27
27
  * Commits a transaction.
28
+ *
29
+ * Throws {@link AbortedTransactionError} if the database confirms that
30
+ * the transaction was rolled back instead of committed.
28
31
  */
29
32
  commitTransaction(connection: MssqlConnection): Promise<void>;
30
33
  /**
@@ -24,6 +24,9 @@ export declare class MysqlDriver implements Driver {
24
24
  beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void>;
25
25
  /**
26
26
  * Commits a transaction.
27
+ *
28
+ * Throws {@link AbortedTransactionError} if the database confirms that
29
+ * the transaction was rolled back instead of committed.
27
30
  */
28
31
  commitTransaction(connection: DatabaseConnection): Promise<void>;
29
32
  /**
@@ -61,7 +61,7 @@ export interface PostgresPool {
61
61
  export interface PostgresPoolClient {
62
62
  query<R>(sql: string, parameters: ReadonlyArray<unknown>): Promise<PostgresQueryResult<R>>;
63
63
  query<R>(cursor: PostgresCursor<R>): PostgresCursor<R>;
64
- release(): void;
64
+ release(destroy?: boolean): void;
65
65
  }
66
66
  export interface PostgresCursor<T> {
67
67
  read(rowsCount: number): Promise<T[]>;
@@ -69,7 +69,7 @@ export interface PostgresCursor<T> {
69
69
  }
70
70
  export type PostgresCursorConstructor = new <T>(sql: string, parameters: unknown[]) => PostgresCursor<T>;
71
71
  export interface PostgresQueryResult<R> {
72
- command: 'UPDATE' | 'DELETE' | 'INSERT' | 'SELECT' | 'MERGE';
72
+ command: 'UPDATE' | 'DELETE' | 'INSERT' | 'SELECT' | 'MERGE' | 'COMMIT' | 'ROLLBACK';
73
73
  rowCount: number;
74
74
  rows: R[];
75
75
  }
@@ -4,6 +4,7 @@ import { CompiledQuery } from '../../query-compiler/compiled-query.js';
4
4
  import type { QueryCompiler } from '../../query-compiler/query-compiler.js';
5
5
  import type { PostgresCursorConstructor, PostgresDialectConfig, PostgresPoolClient } from './postgres-dialect-config.js';
6
6
  declare const PRIVATE_RELEASE_METHOD: unique symbol;
7
+ declare const PRIVATE_MARK_FOR_DISCARD_METHOD: unique symbol;
7
8
  export declare class PostgresDriver implements Driver {
8
9
  #private;
9
10
  constructor(config: PostgresDialectConfig);
@@ -24,12 +25,15 @@ export declare class PostgresDriver implements Driver {
24
25
  beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void>;
25
26
  /**
26
27
  * Commits a transaction.
28
+ *
29
+ * Throws {@link AbortedTransactionError} if the database confirms that
30
+ * the transaction was rolled back instead of committed.
27
31
  */
28
32
  commitTransaction(connection: DatabaseConnection): Promise<void>;
29
33
  /**
30
34
  * Rolls back a transaction.
31
35
  */
32
- rollbackTransaction(connection: DatabaseConnection): Promise<void>;
36
+ rollbackTransaction(connection: PostgresConnection): Promise<void>;
33
37
  savepoint(connection: DatabaseConnection, savepointName: string, compileQuery: QueryCompiler['compileQuery']): Promise<void>;
34
38
  rollbackToSavepoint(connection: DatabaseConnection, savepointName: string, compileQuery: QueryCompiler['compileQuery']): Promise<void>;
35
39
  releaseSavepoint(connection: DatabaseConnection, savepointName: string, compileQuery: QueryCompiler['compileQuery']): Promise<void>;
@@ -51,5 +55,6 @@ declare class PostgresConnection implements DatabaseConnection {
51
55
  executeQuery<O>(compiledQuery: CompiledQuery): Promise<QueryResult<O>>;
52
56
  streamQuery<O>(compiledQuery: CompiledQuery, chunkSize: number): AsyncIterableIterator<QueryResult<O>>;
53
57
  [PRIVATE_RELEASE_METHOD](): void;
58
+ [PRIVATE_MARK_FOR_DISCARD_METHOD](): void;
54
59
  }
55
60
  export {};
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PostgresDriver = void 0;
4
+ const aborted_transaction_error_js_1 = require("../../driver/aborted-transaction-error.js");
4
5
  const savepoint_parser_js_1 = require("../../parser/savepoint-parser.js");
5
6
  const compiled_query_js_1 = require("../../query-compiler/compiled-query.js");
6
7
  const object_utils_js_1 = require("../../util/object-utils.js");
7
8
  const query_id_js_1 = require("../../util/query-id.js");
8
9
  const stack_trace_utils_js_1 = require("../../util/stack-trace-utils.js");
9
10
  const PRIVATE_RELEASE_METHOD = Symbol();
11
+ const PRIVATE_MARK_FOR_DISCARD_METHOD = Symbol();
10
12
  class PostgresDriver {
11
13
  #config;
12
14
  #connections = new WeakMap();
@@ -60,10 +62,21 @@ class PostgresDriver {
60
62
  }
61
63
  }
62
64
  async commitTransaction(connection) {
63
- await connection.executeQuery(compiled_query_js_1.CompiledQuery.raw('commit'));
65
+ const { rows } = await connection.executeQuery(compiled_query_js_1.CompiledQuery.raw('commit'));
66
+ // PostgreSQL completes COMMIT with a ROLLBACK tag if an earlier
67
+ // statement error left the transaction aborted.
68
+ if (rows[0]?.command === 'ROLLBACK') {
69
+ throw new aborted_transaction_error_js_1.AbortedTransactionError();
70
+ }
64
71
  }
65
72
  async rollbackTransaction(connection) {
66
- await connection.executeQuery(compiled_query_js_1.CompiledQuery.raw('rollback'));
73
+ try {
74
+ await connection.executeQuery(compiled_query_js_1.CompiledQuery.raw('rollback'));
75
+ }
76
+ catch (err) {
77
+ connection[PRIVATE_MARK_FOR_DISCARD_METHOD]();
78
+ throw err;
79
+ }
67
80
  }
68
81
  async savepoint(connection, savepointName, compileQuery) {
69
82
  await connection.executeQuery(compileQuery((0, savepoint_parser_js_1.parseSavepointCommand)('savepoint', savepointName), (0, query_id_js_1.createQueryId)()));
@@ -89,13 +102,18 @@ exports.PostgresDriver = PostgresDriver;
89
102
  class PostgresConnection {
90
103
  #client;
91
104
  #options;
105
+ #discarded;
92
106
  constructor(client, options) {
93
107
  this.#client = client;
94
108
  this.#options = options;
95
109
  }
96
110
  async executeQuery(compiledQuery) {
111
+ this.#assertNotDiscarded();
97
112
  try {
98
113
  const { command, rowCount, rows } = await this.#client.query(compiledQuery.sql, [...compiledQuery.parameters]);
114
+ if (command === 'ROLLBACK' || command === 'COMMIT') {
115
+ return { rows: [{ command }] };
116
+ }
99
117
  return {
100
118
  numAffectedRows: command === 'INSERT' ||
101
119
  command === 'UPDATE' ||
@@ -117,6 +135,7 @@ class PostgresConnection {
117
135
  if (!Number.isInteger(chunkSize) || chunkSize <= 0) {
118
136
  throw new Error('chunkSize must be a positive integer');
119
137
  }
138
+ this.#assertNotDiscarded();
120
139
  const cursor = this.#client.query(new this.#options.cursor(compiledQuery.sql, compiledQuery.parameters.slice()));
121
140
  try {
122
141
  while (true) {
@@ -134,6 +153,14 @@ class PostgresConnection {
134
153
  }
135
154
  }
136
155
  [PRIVATE_RELEASE_METHOD]() {
137
- this.#client.release();
156
+ this.#client.release(Boolean(this.#discarded));
157
+ }
158
+ [PRIVATE_MARK_FOR_DISCARD_METHOD]() {
159
+ this.#discarded = true;
160
+ }
161
+ #assertNotDiscarded() {
162
+ if (this.#discarded) {
163
+ throw new Error('Postgres connection has been discarded');
164
+ }
138
165
  }
139
166
  }
@@ -22,6 +22,9 @@ export declare class SqliteDriver implements Driver {
22
22
  beginTransaction(connection: DatabaseConnection): Promise<void>;
23
23
  /**
24
24
  * Commits a transaction.
25
+ *
26
+ * Throws {@link AbortedTransactionError} if the database confirms that
27
+ * the transaction was rolled back instead of committed.
25
28
  */
26
29
  commitTransaction(connection: DatabaseConnection): Promise<void>;
27
30
  /**
@@ -0,0 +1,11 @@
1
+ declare const ABORTED_TRANSACTION_ERROR: unique symbol;
2
+ /**
3
+ * Thrown when the database rolls back a transaction instead of committing it.
4
+ */
5
+ export declare class AbortedTransactionError extends Error {
6
+ name: string;
7
+ readonly [ABORTED_TRANSACTION_ERROR] = true;
8
+ constructor();
9
+ }
10
+ export declare function isAbortedTransactionError(error: unknown): error is AbortedTransactionError;
11
+ export {};
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AbortedTransactionError = void 0;
4
+ exports.isAbortedTransactionError = isAbortedTransactionError;
5
+ const object_utils_js_1 = require("../util/object-utils.js");
6
+ const ABORTED_TRANSACTION_ERROR = Symbol.for('kysely.AbortedTransactionError');
7
+ /**
8
+ * Thrown when the database rolls back a transaction instead of committing it.
9
+ */
10
+ class AbortedTransactionError extends Error {
11
+ name = 'AbortedTransactionError';
12
+ [ABORTED_TRANSACTION_ERROR] = true;
13
+ constructor() {
14
+ super('Transaction was rolled back instead of committed');
15
+ }
16
+ }
17
+ exports.AbortedTransactionError = AbortedTransactionError;
18
+ function isAbortedTransactionError(error) {
19
+ return (0, object_utils_js_1.isObject)(error) && ABORTED_TRANSACTION_ERROR in error;
20
+ }
@@ -23,6 +23,9 @@ export interface Driver {
23
23
  beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void>;
24
24
  /**
25
25
  * Commits a transaction.
26
+ *
27
+ * Throws {@link AbortedTransactionError} if the database confirms that
28
+ * the transaction was rolled back instead of committed.
26
29
  */
27
30
  commitTransaction(connection: DatabaseConnection): Promise<void>;
28
31
  /**
@@ -55,6 +55,9 @@ export declare class DummyDriver implements Driver {
55
55
  beginTransaction(): Promise<void>;
56
56
  /**
57
57
  * Commits a transaction.
58
+ *
59
+ * Throws {@link AbortedTransactionError} if the database confirms that
60
+ * the transaction was rolled back instead of committed.
58
61
  */
59
62
  commitTransaction(): Promise<void>;
60
63
  /**
@@ -31,6 +31,9 @@ export declare class RuntimeDriver implements Driver {
31
31
  beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void>;
32
32
  /**
33
33
  * Commits a transaction.
34
+ *
35
+ * Throws {@link AbortedTransactionError} if the database confirms that
36
+ * the transaction was rolled back instead of committed.
34
37
  */
35
38
  commitTransaction(connection: DatabaseConnection): Promise<void>;
36
39
  /**
@@ -57,6 +57,7 @@ export * from './dynamic/dynamic.js';
57
57
  export * from './dynamic/dynamic-reference-builder.js';
58
58
  export * from './dynamic/dynamic-table-builder.js';
59
59
  export * from './driver/driver.js';
60
+ export * from './driver/aborted-transaction-error.js';
60
61
  export * from './driver/database-connection.js';
61
62
  export * from './driver/connection-provider.js';
62
63
  export * from './driver/default-connection-provider.js';
package/dist/cjs/index.js CHANGED
@@ -75,6 +75,7 @@ __exportStar(require("./dynamic/dynamic.js"), exports);
75
75
  __exportStar(require("./dynamic/dynamic-reference-builder.js"), exports);
76
76
  __exportStar(require("./dynamic/dynamic-table-builder.js"), exports);
77
77
  __exportStar(require("./driver/driver.js"), exports);
78
+ __exportStar(require("./driver/aborted-transaction-error.js"), exports);
78
79
  __exportStar(require("./driver/database-connection.js"), exports);
79
80
  __exportStar(require("./driver/connection-provider.js"), exports);
80
81
  __exportStar(require("./driver/default-connection-provider.js"), exports);
@@ -665,6 +665,9 @@ export declare class ControlledTransaction<DB, S extends string[] = []> extends
665
665
  /**
666
666
  * Commits the transaction.
667
667
  *
668
+ * If the database rolls back instead of committing, marks the transaction
669
+ * as rolled back, releases the connection and throws {@link AbortedTransactionError}.
670
+ *
668
671
  * Waits for ongoing queries to finish. Streams must be exhausted or closed
669
672
  * before awaiting this command. When consuming a stream with `for await`,
670
673
  * exit the loop before committing.
@@ -694,6 +697,9 @@ export declare class ControlledTransaction<DB, S extends string[] = []> extends
694
697
  /**
695
698
  * Rolls back the transaction.
696
699
  *
700
+ * If a commit already reported that the database rolled back the transaction,
701
+ * succeeds without sending another rollback command.
702
+ *
697
703
  * The connection is released even if the rollback fails, so the transaction
698
704
  * cannot be used afterwards in either case.
699
705
  *
@@ -876,13 +882,12 @@ export declare class ControlledTransaction<DB, S extends string[] = []> extends
876
882
  */
877
883
  withTables<T extends Record<string, Record<string, any>>>(): ControlledTransaction<DrainOuterGeneric<DB & T>, S>;
878
884
  }
879
- interface ControlledTransctionState {
880
- isCommitted: boolean;
881
- isRolledBack: boolean;
885
+ interface ControlledTransactionState {
886
+ status: 'active' | 'committed' | 'rolled back' | 'aborted';
882
887
  }
883
888
  interface ControlledTransactionProps extends KyselyProps {
884
889
  readonly connection: ControlledConnection;
885
- readonly state?: ControlledTransctionState;
890
+ readonly transactionState?: ControlledTransactionState;
886
891
  }
887
892
  export declare class Command<T> {
888
893
  #private;
@@ -9,6 +9,7 @@ const query_creator_js_1 = require("./query-creator.js");
9
9
  const default_query_executor_js_1 = require("./query-executor/default-query-executor.js");
10
10
  const object_utils_js_1 = require("./util/object-utils.js");
11
11
  const runtime_driver_js_1 = require("./driver/runtime-driver.js");
12
+ const aborted_transaction_error_js_1 = require("./driver/aborted-transaction-error.js");
12
13
  const single_connection_provider_js_1 = require("./driver/single-connection-provider.js");
13
14
  const driver_js_1 = require("./driver/driver.js");
14
15
  const function_module_js_1 = require("./query-builder/function-module.js");
@@ -575,8 +576,10 @@ class TransactionBuilder {
575
576
  const settings = { isolationLevel, accessMode };
576
577
  (0, driver_js_1.validateTransactionSettings)(settings);
577
578
  return this.#props.executor.provideConnection(async (connection) => {
578
- const state = { isCommitted: false, isRolledBack: false };
579
- const executor = new NotCommittedOrRolledBackAssertingExecutor(this.#props.executor.withConnectionProvider(new single_connection_provider_js_1.SingleConnectionProvider(connection)), state);
579
+ const transactionState = {
580
+ status: 'active',
581
+ };
582
+ const executor = new NotCommittedOrRolledBackAssertingExecutor(this.#props.executor.withConnectionProvider(new single_connection_provider_js_1.SingleConnectionProvider(connection)), transactionState);
580
583
  const transaction = new Transaction({
581
584
  ...kyselyProps,
582
585
  executor,
@@ -587,13 +590,16 @@ class TransactionBuilder {
587
590
  transactionBegun = true;
588
591
  const result = await callback(transaction);
589
592
  await this.#props.driver.commitTransaction(connection);
590
- state.isCommitted = true;
593
+ transactionState.status = 'committed';
591
594
  return result;
592
595
  }
593
596
  catch (error) {
594
- if (transactionBegun) {
597
+ if ((0, aborted_transaction_error_js_1.isAbortedTransactionError)(error)) {
598
+ transactionState.status = 'aborted';
599
+ }
600
+ else if (transactionBegun) {
595
601
  await this.#props.driver.rollbackTransaction(connection);
596
- state.isRolledBack = true;
602
+ transactionState.status = 'rolled back';
597
603
  }
598
604
  throw error;
599
605
  }
@@ -633,7 +639,7 @@ class ControlledTransactionBuilder {
633
639
  return new ControlledTransaction({
634
640
  ...props,
635
641
  connection,
636
- state: { isCommitted: false, isRolledBack: false },
642
+ transactionState: { status: 'active' },
637
643
  executor: this.#props.executor.withConnectionProvider(new single_connection_provider_js_1.SingleConnectionProvider(connection.connection)),
638
644
  });
639
645
  }
@@ -643,30 +649,33 @@ class ControlledTransaction extends Transaction {
643
649
  #props;
644
650
  #compileQuery;
645
651
  constructor(props) {
646
- const transactionState = props.state ?? {
647
- isCommitted: false,
648
- isRolledBack: false,
652
+ const controlledState = props.transactionState ?? {
653
+ status: 'active',
649
654
  };
650
655
  const controlledProps = {
651
656
  ...props,
652
- state: transactionState,
653
- executor: new NotCommittedOrRolledBackAssertingExecutor(props.executor, transactionState),
657
+ transactionState: controlledState,
658
+ executor: new NotCommittedOrRolledBackAssertingExecutor(props.executor, controlledState),
654
659
  };
655
- const { connection, state, ...transactionProps } = controlledProps;
660
+ const { connection, transactionState, ...transactionProps } = controlledProps;
656
661
  super(transactionProps);
657
662
  this.#props = (0, object_utils_js_1.freeze)(controlledProps);
658
663
  const queryId = (0, query_id_js_1.createQueryId)();
659
664
  this.#compileQuery = (node) => controlledProps.executor.compileQuery(node, queryId);
660
665
  }
661
666
  get isCommitted() {
662
- return this.#props.state.isCommitted;
667
+ return this.#props.transactionState.status === 'committed';
663
668
  }
664
669
  get isRolledBack() {
665
- return this.#props.state.isRolledBack;
670
+ return (this.#props.transactionState.status === 'rolled back' ||
671
+ this.#props.transactionState.status === 'aborted');
666
672
  }
667
673
  /**
668
674
  * Commits the transaction.
669
675
  *
676
+ * If the database rolls back instead of committing, marks the transaction
677
+ * as rolled back, releases the connection and throws {@link AbortedTransactionError}.
678
+ *
670
679
  * Waits for ongoing queries to finish. Streams must be exhausted or closed
671
680
  * before awaiting this command. When consuming a stream with `for await`,
672
681
  * exit the loop before committing.
@@ -695,8 +704,17 @@ class ControlledTransaction extends Transaction {
695
704
  commit() {
696
705
  return new Command(async () => {
697
706
  await this.#props.executor.provideConnection(async (connection) => {
698
- await this.#props.driver.commitTransaction(connection);
699
- this.#props.state.isCommitted = true;
707
+ try {
708
+ await this.#props.driver.commitTransaction(connection);
709
+ }
710
+ catch (error) {
711
+ if ((0, aborted_transaction_error_js_1.isAbortedTransactionError)(error)) {
712
+ this.#props.transactionState.status = 'aborted';
713
+ this.#props.connection.release();
714
+ }
715
+ throw error;
716
+ }
717
+ this.#props.transactionState.status = 'committed';
700
718
  this.#props.connection.release();
701
719
  });
702
720
  });
@@ -704,6 +722,9 @@ class ControlledTransaction extends Transaction {
704
722
  /**
705
723
  * Rolls back the transaction.
706
724
  *
725
+ * If a commit already reported that the database rolled back the transaction,
726
+ * succeeds without sending another rollback command.
727
+ *
707
728
  * The connection is released even if the rollback fails, so the transaction
708
729
  * cannot be used afterwards in either case.
709
730
  *
@@ -734,13 +755,16 @@ class ControlledTransaction extends Transaction {
734
755
  */
735
756
  rollback() {
736
757
  return new Command(async () => {
758
+ if (this.#props.transactionState.status === 'aborted') {
759
+ return;
760
+ }
737
761
  await this.#props.executor.provideConnection(async (connection) => {
738
762
  // A failed rollback can't be meaningfully retried (e.g. dead connection).
739
763
  try {
740
764
  await this.#props.driver.rollbackTransaction(connection);
741
765
  }
742
766
  finally {
743
- this.#props.state.isRolledBack = true;
767
+ this.#props.transactionState.status = 'rolled back';
744
768
  this.#props.connection.release();
745
769
  }
746
770
  });
@@ -912,11 +936,11 @@ class Command {
912
936
  }
913
937
  }
914
938
  exports.Command = Command;
915
- function assertNotCommittedOrRolledBack(state) {
916
- if (state.isCommitted) {
939
+ function assertNotCommittedOrRolledBack(transactionState) {
940
+ if (transactionState.status === 'committed') {
917
941
  throw new Error('Transaction is already committed');
918
942
  }
919
- if (state.isRolledBack) {
943
+ if (transactionState.status !== 'active') {
920
944
  throw new Error('Transaction is already rolled back');
921
945
  }
922
946
  }
@@ -928,15 +952,13 @@ function assertNotCommittedOrRolledBack(state) {
928
952
  */
929
953
  class NotCommittedOrRolledBackAssertingExecutor {
930
954
  #executor;
931
- #state;
932
- constructor(executor, state) {
933
- if (executor instanceof NotCommittedOrRolledBackAssertingExecutor) {
934
- this.#executor = executor.#executor;
935
- }
936
- else {
937
- this.#executor = executor;
938
- }
939
- this.#state = state;
955
+ #transactionState;
956
+ constructor(executor, transactionState) {
957
+ this.#executor =
958
+ executor instanceof NotCommittedOrRolledBackAssertingExecutor
959
+ ? executor.#executor
960
+ : executor;
961
+ this.#transactionState = transactionState;
940
962
  }
941
963
  get adapter() {
942
964
  return this.#executor.adapter;
@@ -951,37 +973,37 @@ class NotCommittedOrRolledBackAssertingExecutor {
951
973
  return this.#executor.compileQuery(node, queryId);
952
974
  }
953
975
  provideConnection(consumer) {
954
- assertNotCommittedOrRolledBack(this.#state);
976
+ assertNotCommittedOrRolledBack(this.#transactionState);
955
977
  return this.#executor.provideConnection(async (connection) => {
956
- assertNotCommittedOrRolledBack(this.#state);
978
+ assertNotCommittedOrRolledBack(this.#transactionState);
957
979
  return await consumer(connection);
958
980
  });
959
981
  }
960
982
  executeQuery(compiledQuery) {
961
- assertNotCommittedOrRolledBack(this.#state);
983
+ assertNotCommittedOrRolledBack(this.#transactionState);
962
984
  return this.#executor
963
985
  .withConnectionProvider(this)
964
986
  .executeQuery(compiledQuery);
965
987
  }
966
988
  stream(compiledQuery, chunkSize) {
967
- assertNotCommittedOrRolledBack(this.#state);
989
+ assertNotCommittedOrRolledBack(this.#transactionState);
968
990
  return this.#executor
969
991
  .withConnectionProvider(this)
970
992
  .stream(compiledQuery, chunkSize);
971
993
  }
972
994
  withConnectionProvider(connectionProvider) {
973
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withConnectionProvider(connectionProvider), this.#state);
995
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withConnectionProvider(connectionProvider), this.#transactionState);
974
996
  }
975
997
  withPlugin(plugin) {
976
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPlugin(plugin), this.#state);
998
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPlugin(plugin), this.#transactionState);
977
999
  }
978
1000
  withPlugins(plugins) {
979
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPlugins(plugins), this.#state);
1001
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPlugins(plugins), this.#transactionState);
980
1002
  }
981
1003
  withPluginAtFront(plugin) {
982
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPluginAtFront(plugin), this.#state);
1004
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPluginAtFront(plugin), this.#transactionState);
983
1005
  }
984
1006
  withoutPlugins() {
985
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withoutPlugins(), this.#state);
1007
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withoutPlugins(), this.#transactionState);
986
1008
  }
987
1009
  }
@@ -25,6 +25,9 @@ export declare class MssqlDriver implements Driver {
25
25
  beginTransaction(connection: MssqlConnection, settings: TransactionSettings): Promise<void>;
26
26
  /**
27
27
  * Commits a transaction.
28
+ *
29
+ * Throws {@link AbortedTransactionError} if the database confirms that
30
+ * the transaction was rolled back instead of committed.
28
31
  */
29
32
  commitTransaction(connection: MssqlConnection): Promise<void>;
30
33
  /**
@@ -24,6 +24,9 @@ export declare class MysqlDriver implements Driver {
24
24
  beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void>;
25
25
  /**
26
26
  * Commits a transaction.
27
+ *
28
+ * Throws {@link AbortedTransactionError} if the database confirms that
29
+ * the transaction was rolled back instead of committed.
27
30
  */
28
31
  commitTransaction(connection: DatabaseConnection): Promise<void>;
29
32
  /**
@@ -61,7 +61,7 @@ export interface PostgresPool {
61
61
  export interface PostgresPoolClient {
62
62
  query<R>(sql: string, parameters: ReadonlyArray<unknown>): Promise<PostgresQueryResult<R>>;
63
63
  query<R>(cursor: PostgresCursor<R>): PostgresCursor<R>;
64
- release(): void;
64
+ release(destroy?: boolean): void;
65
65
  }
66
66
  export interface PostgresCursor<T> {
67
67
  read(rowsCount: number): Promise<T[]>;
@@ -69,7 +69,7 @@ export interface PostgresCursor<T> {
69
69
  }
70
70
  export type PostgresCursorConstructor = new <T>(sql: string, parameters: unknown[]) => PostgresCursor<T>;
71
71
  export interface PostgresQueryResult<R> {
72
- command: 'UPDATE' | 'DELETE' | 'INSERT' | 'SELECT' | 'MERGE';
72
+ command: 'UPDATE' | 'DELETE' | 'INSERT' | 'SELECT' | 'MERGE' | 'COMMIT' | 'ROLLBACK';
73
73
  rowCount: number;
74
74
  rows: R[];
75
75
  }
@@ -4,6 +4,7 @@ import { CompiledQuery } from '../../query-compiler/compiled-query.js';
4
4
  import type { QueryCompiler } from '../../query-compiler/query-compiler.js';
5
5
  import type { PostgresCursorConstructor, PostgresDialectConfig, PostgresPoolClient } from './postgres-dialect-config.js';
6
6
  declare const PRIVATE_RELEASE_METHOD: unique symbol;
7
+ declare const PRIVATE_MARK_FOR_DISCARD_METHOD: unique symbol;
7
8
  export declare class PostgresDriver implements Driver {
8
9
  #private;
9
10
  constructor(config: PostgresDialectConfig);
@@ -24,12 +25,15 @@ export declare class PostgresDriver implements Driver {
24
25
  beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void>;
25
26
  /**
26
27
  * Commits a transaction.
28
+ *
29
+ * Throws {@link AbortedTransactionError} if the database confirms that
30
+ * the transaction was rolled back instead of committed.
27
31
  */
28
32
  commitTransaction(connection: DatabaseConnection): Promise<void>;
29
33
  /**
30
34
  * Rolls back a transaction.
31
35
  */
32
- rollbackTransaction(connection: DatabaseConnection): Promise<void>;
36
+ rollbackTransaction(connection: PostgresConnection): Promise<void>;
33
37
  savepoint(connection: DatabaseConnection, savepointName: string, compileQuery: QueryCompiler['compileQuery']): Promise<void>;
34
38
  rollbackToSavepoint(connection: DatabaseConnection, savepointName: string, compileQuery: QueryCompiler['compileQuery']): Promise<void>;
35
39
  releaseSavepoint(connection: DatabaseConnection, savepointName: string, compileQuery: QueryCompiler['compileQuery']): Promise<void>;
@@ -51,5 +55,6 @@ declare class PostgresConnection implements DatabaseConnection {
51
55
  executeQuery<O>(compiledQuery: CompiledQuery): Promise<QueryResult<O>>;
52
56
  streamQuery<O>(compiledQuery: CompiledQuery, chunkSize: number): AsyncIterableIterator<QueryResult<O>>;
53
57
  [PRIVATE_RELEASE_METHOD](): void;
58
+ [PRIVATE_MARK_FOR_DISCARD_METHOD](): void;
54
59
  }
55
60
  export {};
@@ -1,10 +1,12 @@
1
1
  /// <reference types="./postgres-driver.d.ts" />
2
+ import { AbortedTransactionError } from '../../driver/aborted-transaction-error.js';
2
3
  import { parseSavepointCommand } from '../../parser/savepoint-parser.js';
3
4
  import { CompiledQuery } from '../../query-compiler/compiled-query.js';
4
5
  import { isFunction, freeze } from '../../util/object-utils.js';
5
6
  import { createQueryId } from '../../util/query-id.js';
6
7
  import { extendStackTrace } from '../../util/stack-trace-utils.js';
7
8
  const PRIVATE_RELEASE_METHOD = Symbol();
9
+ const PRIVATE_MARK_FOR_DISCARD_METHOD = Symbol();
8
10
  export class PostgresDriver {
9
11
  #config;
10
12
  #connections = new WeakMap();
@@ -58,10 +60,21 @@ export class PostgresDriver {
58
60
  }
59
61
  }
60
62
  async commitTransaction(connection) {
61
- await connection.executeQuery(CompiledQuery.raw('commit'));
63
+ const { rows } = await connection.executeQuery(CompiledQuery.raw('commit'));
64
+ // PostgreSQL completes COMMIT with a ROLLBACK tag if an earlier
65
+ // statement error left the transaction aborted.
66
+ if (rows[0]?.command === 'ROLLBACK') {
67
+ throw new AbortedTransactionError();
68
+ }
62
69
  }
63
70
  async rollbackTransaction(connection) {
64
- await connection.executeQuery(CompiledQuery.raw('rollback'));
71
+ try {
72
+ await connection.executeQuery(CompiledQuery.raw('rollback'));
73
+ }
74
+ catch (err) {
75
+ connection[PRIVATE_MARK_FOR_DISCARD_METHOD]();
76
+ throw err;
77
+ }
65
78
  }
66
79
  async savepoint(connection, savepointName, compileQuery) {
67
80
  await connection.executeQuery(compileQuery(parseSavepointCommand('savepoint', savepointName), createQueryId()));
@@ -86,13 +99,18 @@ export class PostgresDriver {
86
99
  class PostgresConnection {
87
100
  #client;
88
101
  #options;
102
+ #discarded;
89
103
  constructor(client, options) {
90
104
  this.#client = client;
91
105
  this.#options = options;
92
106
  }
93
107
  async executeQuery(compiledQuery) {
108
+ this.#assertNotDiscarded();
94
109
  try {
95
110
  const { command, rowCount, rows } = await this.#client.query(compiledQuery.sql, [...compiledQuery.parameters]);
111
+ if (command === 'ROLLBACK' || command === 'COMMIT') {
112
+ return { rows: [{ command }] };
113
+ }
96
114
  return {
97
115
  numAffectedRows: command === 'INSERT' ||
98
116
  command === 'UPDATE' ||
@@ -114,6 +132,7 @@ class PostgresConnection {
114
132
  if (!Number.isInteger(chunkSize) || chunkSize <= 0) {
115
133
  throw new Error('chunkSize must be a positive integer');
116
134
  }
135
+ this.#assertNotDiscarded();
117
136
  const cursor = this.#client.query(new this.#options.cursor(compiledQuery.sql, compiledQuery.parameters.slice()));
118
137
  try {
119
138
  while (true) {
@@ -131,6 +150,14 @@ class PostgresConnection {
131
150
  }
132
151
  }
133
152
  [PRIVATE_RELEASE_METHOD]() {
134
- this.#client.release();
153
+ this.#client.release(Boolean(this.#discarded));
154
+ }
155
+ [PRIVATE_MARK_FOR_DISCARD_METHOD]() {
156
+ this.#discarded = true;
157
+ }
158
+ #assertNotDiscarded() {
159
+ if (this.#discarded) {
160
+ throw new Error('Postgres connection has been discarded');
161
+ }
135
162
  }
136
163
  }
@@ -22,6 +22,9 @@ export declare class SqliteDriver implements Driver {
22
22
  beginTransaction(connection: DatabaseConnection): Promise<void>;
23
23
  /**
24
24
  * Commits a transaction.
25
+ *
26
+ * Throws {@link AbortedTransactionError} if the database confirms that
27
+ * the transaction was rolled back instead of committed.
25
28
  */
26
29
  commitTransaction(connection: DatabaseConnection): Promise<void>;
27
30
  /**
@@ -0,0 +1,11 @@
1
+ declare const ABORTED_TRANSACTION_ERROR: unique symbol;
2
+ /**
3
+ * Thrown when the database rolls back a transaction instead of committing it.
4
+ */
5
+ export declare class AbortedTransactionError extends Error {
6
+ name: string;
7
+ readonly [ABORTED_TRANSACTION_ERROR] = true;
8
+ constructor();
9
+ }
10
+ export declare function isAbortedTransactionError(error: unknown): error is AbortedTransactionError;
11
+ export {};
@@ -0,0 +1,16 @@
1
+ /// <reference types="./aborted-transaction-error.d.ts" />
2
+ import { isObject } from '../util/object-utils.js';
3
+ const ABORTED_TRANSACTION_ERROR = Symbol.for('kysely.AbortedTransactionError');
4
+ /**
5
+ * Thrown when the database rolls back a transaction instead of committing it.
6
+ */
7
+ export class AbortedTransactionError extends Error {
8
+ name = 'AbortedTransactionError';
9
+ [ABORTED_TRANSACTION_ERROR] = true;
10
+ constructor() {
11
+ super('Transaction was rolled back instead of committed');
12
+ }
13
+ }
14
+ export function isAbortedTransactionError(error) {
15
+ return isObject(error) && ABORTED_TRANSACTION_ERROR in error;
16
+ }
@@ -23,6 +23,9 @@ export interface Driver {
23
23
  beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void>;
24
24
  /**
25
25
  * Commits a transaction.
26
+ *
27
+ * Throws {@link AbortedTransactionError} if the database confirms that
28
+ * the transaction was rolled back instead of committed.
26
29
  */
27
30
  commitTransaction(connection: DatabaseConnection): Promise<void>;
28
31
  /**
@@ -55,6 +55,9 @@ export declare class DummyDriver implements Driver {
55
55
  beginTransaction(): Promise<void>;
56
56
  /**
57
57
  * Commits a transaction.
58
+ *
59
+ * Throws {@link AbortedTransactionError} if the database confirms that
60
+ * the transaction was rolled back instead of committed.
58
61
  */
59
62
  commitTransaction(): Promise<void>;
60
63
  /**
@@ -31,6 +31,9 @@ export declare class RuntimeDriver implements Driver {
31
31
  beginTransaction(connection: DatabaseConnection, settings: TransactionSettings): Promise<void>;
32
32
  /**
33
33
  * Commits a transaction.
34
+ *
35
+ * Throws {@link AbortedTransactionError} if the database confirms that
36
+ * the transaction was rolled back instead of committed.
34
37
  */
35
38
  commitTransaction(connection: DatabaseConnection): Promise<void>;
36
39
  /**
@@ -57,6 +57,7 @@ export * from './dynamic/dynamic.js';
57
57
  export * from './dynamic/dynamic-reference-builder.js';
58
58
  export * from './dynamic/dynamic-table-builder.js';
59
59
  export * from './driver/driver.js';
60
+ export * from './driver/aborted-transaction-error.js';
60
61
  export * from './driver/database-connection.js';
61
62
  export * from './driver/connection-provider.js';
62
63
  export * from './driver/default-connection-provider.js';
package/dist/esm/index.js CHANGED
@@ -58,6 +58,7 @@ export * from './dynamic/dynamic.js';
58
58
  export * from './dynamic/dynamic-reference-builder.js';
59
59
  export * from './dynamic/dynamic-table-builder.js';
60
60
  export * from './driver/driver.js';
61
+ export * from './driver/aborted-transaction-error.js';
61
62
  export * from './driver/database-connection.js';
62
63
  export * from './driver/connection-provider.js';
63
64
  export * from './driver/default-connection-provider.js';
@@ -665,6 +665,9 @@ export declare class ControlledTransaction<DB, S extends string[] = []> extends
665
665
  /**
666
666
  * Commits the transaction.
667
667
  *
668
+ * If the database rolls back instead of committing, marks the transaction
669
+ * as rolled back, releases the connection and throws {@link AbortedTransactionError}.
670
+ *
668
671
  * Waits for ongoing queries to finish. Streams must be exhausted or closed
669
672
  * before awaiting this command. When consuming a stream with `for await`,
670
673
  * exit the loop before committing.
@@ -694,6 +697,9 @@ export declare class ControlledTransaction<DB, S extends string[] = []> extends
694
697
  /**
695
698
  * Rolls back the transaction.
696
699
  *
700
+ * If a commit already reported that the database rolled back the transaction,
701
+ * succeeds without sending another rollback command.
702
+ *
697
703
  * The connection is released even if the rollback fails, so the transaction
698
704
  * cannot be used afterwards in either case.
699
705
  *
@@ -876,13 +882,12 @@ export declare class ControlledTransaction<DB, S extends string[] = []> extends
876
882
  */
877
883
  withTables<T extends Record<string, Record<string, any>>>(): ControlledTransaction<DrainOuterGeneric<DB & T>, S>;
878
884
  }
879
- interface ControlledTransctionState {
880
- isCommitted: boolean;
881
- isRolledBack: boolean;
885
+ interface ControlledTransactionState {
886
+ status: 'active' | 'committed' | 'rolled back' | 'aborted';
882
887
  }
883
888
  interface ControlledTransactionProps extends KyselyProps {
884
889
  readonly connection: ControlledConnection;
885
- readonly state?: ControlledTransctionState;
890
+ readonly transactionState?: ControlledTransactionState;
886
891
  }
887
892
  export declare class Command<T> {
888
893
  #private;
@@ -6,6 +6,7 @@ import { QueryCreator } from './query-creator.js';
6
6
  import { DefaultQueryExecutor } from './query-executor/default-query-executor.js';
7
7
  import { freeze, isObject, isUndefined } from './util/object-utils.js';
8
8
  import { RuntimeDriver } from './driver/runtime-driver.js';
9
+ import { isAbortedTransactionError, } from './driver/aborted-transaction-error.js';
9
10
  import { SingleConnectionProvider } from './driver/single-connection-provider.js';
10
11
  import { validateTransactionSettings, } from './driver/driver.js';
11
12
  import { createFunctionModule, } from './query-builder/function-module.js';
@@ -569,8 +570,10 @@ export class TransactionBuilder {
569
570
  const settings = { isolationLevel, accessMode };
570
571
  validateTransactionSettings(settings);
571
572
  return this.#props.executor.provideConnection(async (connection) => {
572
- const state = { isCommitted: false, isRolledBack: false };
573
- const executor = new NotCommittedOrRolledBackAssertingExecutor(this.#props.executor.withConnectionProvider(new SingleConnectionProvider(connection)), state);
573
+ const transactionState = {
574
+ status: 'active',
575
+ };
576
+ const executor = new NotCommittedOrRolledBackAssertingExecutor(this.#props.executor.withConnectionProvider(new SingleConnectionProvider(connection)), transactionState);
574
577
  const transaction = new Transaction({
575
578
  ...kyselyProps,
576
579
  executor,
@@ -581,13 +584,16 @@ export class TransactionBuilder {
581
584
  transactionBegun = true;
582
585
  const result = await callback(transaction);
583
586
  await this.#props.driver.commitTransaction(connection);
584
- state.isCommitted = true;
587
+ transactionState.status = 'committed';
585
588
  return result;
586
589
  }
587
590
  catch (error) {
588
- if (transactionBegun) {
591
+ if (isAbortedTransactionError(error)) {
592
+ transactionState.status = 'aborted';
593
+ }
594
+ else if (transactionBegun) {
589
595
  await this.#props.driver.rollbackTransaction(connection);
590
- state.isRolledBack = true;
596
+ transactionState.status = 'rolled back';
591
597
  }
592
598
  throw error;
593
599
  }
@@ -626,7 +632,7 @@ export class ControlledTransactionBuilder {
626
632
  return new ControlledTransaction({
627
633
  ...props,
628
634
  connection,
629
- state: { isCommitted: false, isRolledBack: false },
635
+ transactionState: { status: 'active' },
630
636
  executor: this.#props.executor.withConnectionProvider(new SingleConnectionProvider(connection.connection)),
631
637
  });
632
638
  }
@@ -635,30 +641,33 @@ export class ControlledTransaction extends Transaction {
635
641
  #props;
636
642
  #compileQuery;
637
643
  constructor(props) {
638
- const transactionState = props.state ?? {
639
- isCommitted: false,
640
- isRolledBack: false,
644
+ const controlledState = props.transactionState ?? {
645
+ status: 'active',
641
646
  };
642
647
  const controlledProps = {
643
648
  ...props,
644
- state: transactionState,
645
- executor: new NotCommittedOrRolledBackAssertingExecutor(props.executor, transactionState),
649
+ transactionState: controlledState,
650
+ executor: new NotCommittedOrRolledBackAssertingExecutor(props.executor, controlledState),
646
651
  };
647
- const { connection, state, ...transactionProps } = controlledProps;
652
+ const { connection, transactionState, ...transactionProps } = controlledProps;
648
653
  super(transactionProps);
649
654
  this.#props = freeze(controlledProps);
650
655
  const queryId = createQueryId();
651
656
  this.#compileQuery = (node) => controlledProps.executor.compileQuery(node, queryId);
652
657
  }
653
658
  get isCommitted() {
654
- return this.#props.state.isCommitted;
659
+ return this.#props.transactionState.status === 'committed';
655
660
  }
656
661
  get isRolledBack() {
657
- return this.#props.state.isRolledBack;
662
+ return (this.#props.transactionState.status === 'rolled back' ||
663
+ this.#props.transactionState.status === 'aborted');
658
664
  }
659
665
  /**
660
666
  * Commits the transaction.
661
667
  *
668
+ * If the database rolls back instead of committing, marks the transaction
669
+ * as rolled back, releases the connection and throws {@link AbortedTransactionError}.
670
+ *
662
671
  * Waits for ongoing queries to finish. Streams must be exhausted or closed
663
672
  * before awaiting this command. When consuming a stream with `for await`,
664
673
  * exit the loop before committing.
@@ -687,8 +696,17 @@ export class ControlledTransaction extends Transaction {
687
696
  commit() {
688
697
  return new Command(async () => {
689
698
  await this.#props.executor.provideConnection(async (connection) => {
690
- await this.#props.driver.commitTransaction(connection);
691
- this.#props.state.isCommitted = true;
699
+ try {
700
+ await this.#props.driver.commitTransaction(connection);
701
+ }
702
+ catch (error) {
703
+ if (isAbortedTransactionError(error)) {
704
+ this.#props.transactionState.status = 'aborted';
705
+ this.#props.connection.release();
706
+ }
707
+ throw error;
708
+ }
709
+ this.#props.transactionState.status = 'committed';
692
710
  this.#props.connection.release();
693
711
  });
694
712
  });
@@ -696,6 +714,9 @@ export class ControlledTransaction extends Transaction {
696
714
  /**
697
715
  * Rolls back the transaction.
698
716
  *
717
+ * If a commit already reported that the database rolled back the transaction,
718
+ * succeeds without sending another rollback command.
719
+ *
699
720
  * The connection is released even if the rollback fails, so the transaction
700
721
  * cannot be used afterwards in either case.
701
722
  *
@@ -726,13 +747,16 @@ export class ControlledTransaction extends Transaction {
726
747
  */
727
748
  rollback() {
728
749
  return new Command(async () => {
750
+ if (this.#props.transactionState.status === 'aborted') {
751
+ return;
752
+ }
729
753
  await this.#props.executor.provideConnection(async (connection) => {
730
754
  // A failed rollback can't be meaningfully retried (e.g. dead connection).
731
755
  try {
732
756
  await this.#props.driver.rollbackTransaction(connection);
733
757
  }
734
758
  finally {
735
- this.#props.state.isRolledBack = true;
759
+ this.#props.transactionState.status = 'rolled back';
736
760
  this.#props.connection.release();
737
761
  }
738
762
  });
@@ -902,11 +926,11 @@ export class Command {
902
926
  return await this.#cb();
903
927
  }
904
928
  }
905
- function assertNotCommittedOrRolledBack(state) {
906
- if (state.isCommitted) {
929
+ function assertNotCommittedOrRolledBack(transactionState) {
930
+ if (transactionState.status === 'committed') {
907
931
  throw new Error('Transaction is already committed');
908
932
  }
909
- if (state.isRolledBack) {
933
+ if (transactionState.status !== 'active') {
910
934
  throw new Error('Transaction is already rolled back');
911
935
  }
912
936
  }
@@ -918,15 +942,13 @@ function assertNotCommittedOrRolledBack(state) {
918
942
  */
919
943
  class NotCommittedOrRolledBackAssertingExecutor {
920
944
  #executor;
921
- #state;
922
- constructor(executor, state) {
923
- if (executor instanceof NotCommittedOrRolledBackAssertingExecutor) {
924
- this.#executor = executor.#executor;
925
- }
926
- else {
927
- this.#executor = executor;
928
- }
929
- this.#state = state;
945
+ #transactionState;
946
+ constructor(executor, transactionState) {
947
+ this.#executor =
948
+ executor instanceof NotCommittedOrRolledBackAssertingExecutor
949
+ ? executor.#executor
950
+ : executor;
951
+ this.#transactionState = transactionState;
930
952
  }
931
953
  get adapter() {
932
954
  return this.#executor.adapter;
@@ -941,37 +963,37 @@ class NotCommittedOrRolledBackAssertingExecutor {
941
963
  return this.#executor.compileQuery(node, queryId);
942
964
  }
943
965
  provideConnection(consumer) {
944
- assertNotCommittedOrRolledBack(this.#state);
966
+ assertNotCommittedOrRolledBack(this.#transactionState);
945
967
  return this.#executor.provideConnection(async (connection) => {
946
- assertNotCommittedOrRolledBack(this.#state);
968
+ assertNotCommittedOrRolledBack(this.#transactionState);
947
969
  return await consumer(connection);
948
970
  });
949
971
  }
950
972
  executeQuery(compiledQuery) {
951
- assertNotCommittedOrRolledBack(this.#state);
973
+ assertNotCommittedOrRolledBack(this.#transactionState);
952
974
  return this.#executor
953
975
  .withConnectionProvider(this)
954
976
  .executeQuery(compiledQuery);
955
977
  }
956
978
  stream(compiledQuery, chunkSize) {
957
- assertNotCommittedOrRolledBack(this.#state);
979
+ assertNotCommittedOrRolledBack(this.#transactionState);
958
980
  return this.#executor
959
981
  .withConnectionProvider(this)
960
982
  .stream(compiledQuery, chunkSize);
961
983
  }
962
984
  withConnectionProvider(connectionProvider) {
963
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withConnectionProvider(connectionProvider), this.#state);
985
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withConnectionProvider(connectionProvider), this.#transactionState);
964
986
  }
965
987
  withPlugin(plugin) {
966
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPlugin(plugin), this.#state);
988
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPlugin(plugin), this.#transactionState);
967
989
  }
968
990
  withPlugins(plugins) {
969
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPlugins(plugins), this.#state);
991
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPlugins(plugins), this.#transactionState);
970
992
  }
971
993
  withPluginAtFront(plugin) {
972
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPluginAtFront(plugin), this.#state);
994
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withPluginAtFront(plugin), this.#transactionState);
973
995
  }
974
996
  withoutPlugins() {
975
- return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withoutPlugins(), this.#state);
997
+ return new NotCommittedOrRolledBackAssertingExecutor(this.#executor.withoutPlugins(), this.#transactionState);
976
998
  }
977
999
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kysely",
3
- "version": "0.28.18",
3
+ "version": "0.28.19",
4
4
  "description": "Type safe SQL query builder",
5
5
  "repository": {
6
6
  "type": "git",