@mikro-orm/sql 7.0.2-dev.9 → 7.0.2

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 (87) hide show
  1. package/AbstractSqlConnection.d.ts +95 -47
  2. package/AbstractSqlConnection.js +240 -232
  3. package/AbstractSqlDriver.d.ts +412 -155
  4. package/AbstractSqlDriver.js +2062 -1937
  5. package/AbstractSqlPlatform.d.ts +84 -73
  6. package/AbstractSqlPlatform.js +163 -158
  7. package/PivotCollectionPersister.d.ts +33 -15
  8. package/PivotCollectionPersister.js +158 -160
  9. package/README.md +128 -294
  10. package/SqlEntityManager.d.ts +68 -20
  11. package/SqlEntityManager.js +54 -37
  12. package/SqlEntityRepository.d.ts +15 -14
  13. package/SqlEntityRepository.js +24 -23
  14. package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +12 -12
  15. package/dialects/mssql/MsSqlNativeQueryBuilder.js +192 -194
  16. package/dialects/mysql/BaseMySqlPlatform.d.ts +64 -45
  17. package/dialects/mysql/BaseMySqlPlatform.js +134 -131
  18. package/dialects/mysql/MySqlExceptionConverter.d.ts +6 -6
  19. package/dialects/mysql/MySqlExceptionConverter.js +91 -77
  20. package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +3 -3
  21. package/dialects/mysql/MySqlNativeQueryBuilder.js +66 -69
  22. package/dialects/mysql/MySqlSchemaHelper.d.ts +39 -39
  23. package/dialects/mysql/MySqlSchemaHelper.js +327 -319
  24. package/dialects/oracledb/OracleDialect.d.ts +81 -52
  25. package/dialects/oracledb/OracleDialect.js +155 -149
  26. package/dialects/oracledb/OracleNativeQueryBuilder.d.ts +12 -12
  27. package/dialects/oracledb/OracleNativeQueryBuilder.js +232 -236
  28. package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +108 -105
  29. package/dialects/postgresql/BasePostgreSqlPlatform.js +351 -350
  30. package/dialects/postgresql/FullTextType.d.ts +10 -6
  31. package/dialects/postgresql/FullTextType.js +51 -51
  32. package/dialects/postgresql/PostgreSqlExceptionConverter.d.ts +5 -5
  33. package/dialects/postgresql/PostgreSqlExceptionConverter.js +55 -43
  34. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +1 -1
  35. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +4 -4
  36. package/dialects/postgresql/PostgreSqlSchemaHelper.d.ts +102 -82
  37. package/dialects/postgresql/PostgreSqlSchemaHelper.js +711 -683
  38. package/dialects/sqlite/BaseSqliteConnection.d.ts +3 -5
  39. package/dialects/sqlite/BaseSqliteConnection.js +21 -19
  40. package/dialects/sqlite/NodeSqliteDialect.d.ts +1 -1
  41. package/dialects/sqlite/NodeSqliteDialect.js +23 -23
  42. package/dialects/sqlite/SqliteDriver.d.ts +1 -1
  43. package/dialects/sqlite/SqliteDriver.js +3 -3
  44. package/dialects/sqlite/SqliteExceptionConverter.d.ts +6 -6
  45. package/dialects/sqlite/SqliteExceptionConverter.js +67 -51
  46. package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +2 -2
  47. package/dialects/sqlite/SqliteNativeQueryBuilder.js +7 -7
  48. package/dialects/sqlite/SqlitePlatform.d.ts +63 -72
  49. package/dialects/sqlite/SqlitePlatform.js +139 -139
  50. package/dialects/sqlite/SqliteSchemaHelper.d.ts +70 -60
  51. package/dialects/sqlite/SqliteSchemaHelper.js +533 -520
  52. package/package.json +4 -4
  53. package/plugin/index.d.ts +44 -35
  54. package/plugin/index.js +44 -36
  55. package/plugin/transformer.d.ts +117 -94
  56. package/plugin/transformer.js +890 -881
  57. package/query/ArrayCriteriaNode.d.ts +4 -4
  58. package/query/ArrayCriteriaNode.js +18 -18
  59. package/query/CriteriaNode.d.ts +35 -25
  60. package/query/CriteriaNode.js +133 -123
  61. package/query/CriteriaNodeFactory.d.ts +49 -6
  62. package/query/CriteriaNodeFactory.js +97 -94
  63. package/query/NativeQueryBuilder.d.ts +120 -117
  64. package/query/NativeQueryBuilder.js +484 -480
  65. package/query/ObjectCriteriaNode.d.ts +12 -12
  66. package/query/ObjectCriteriaNode.js +298 -282
  67. package/query/QueryBuilder.d.ts +1546 -904
  68. package/query/QueryBuilder.js +2270 -2145
  69. package/query/QueryBuilderHelper.d.ts +153 -72
  70. package/query/QueryBuilderHelper.js +1079 -1028
  71. package/query/ScalarCriteriaNode.d.ts +3 -3
  72. package/query/ScalarCriteriaNode.js +53 -46
  73. package/query/enums.d.ts +16 -14
  74. package/query/enums.js +16 -14
  75. package/query/raw.d.ts +16 -6
  76. package/query/raw.js +10 -10
  77. package/schema/DatabaseSchema.d.ts +73 -50
  78. package/schema/DatabaseSchema.js +331 -307
  79. package/schema/DatabaseTable.d.ts +96 -73
  80. package/schema/DatabaseTable.js +1012 -927
  81. package/schema/SchemaComparator.d.ts +58 -54
  82. package/schema/SchemaComparator.js +745 -719
  83. package/schema/SchemaHelper.d.ts +110 -80
  84. package/schema/SchemaHelper.js +676 -645
  85. package/schema/SqlSchemaGenerator.d.ts +79 -58
  86. package/schema/SqlSchemaGenerator.js +536 -501
  87. package/typings.d.ts +380 -266
@@ -1,56 +1,104 @@
1
1
  import { type ControlledTransaction, type Dialect, Kysely } from 'kysely';
2
- import { type AnyEntity, Connection, type Dictionary, type EntityData, type IsolationLevel, type LogContext, type LoggingOptions, type MaybePromise, type QueryResult, RawQueryFragment, type Transaction, type TransactionEventBroadcaster } from '@mikro-orm/core';
2
+ import {
3
+ type AnyEntity,
4
+ Connection,
5
+ type Dictionary,
6
+ type EntityData,
7
+ type IsolationLevel,
8
+ type LogContext,
9
+ type LoggingOptions,
10
+ type MaybePromise,
11
+ type QueryResult,
12
+ RawQueryFragment,
13
+ type Transaction,
14
+ type TransactionEventBroadcaster,
15
+ } from '@mikro-orm/core';
3
16
  import type { AbstractSqlPlatform } from './AbstractSqlPlatform.js';
4
17
  import { NativeQueryBuilder } from './query/NativeQueryBuilder.js';
18
+ /** Base class for SQL database connections, built on top of Kysely. */
5
19
  export declare abstract class AbstractSqlConnection extends Connection {
6
- #private;
7
- protected platform: AbstractSqlPlatform;
8
- abstract createKyselyDialect(overrides: Dictionary): MaybePromise<Dialect>;
9
- connect(options?: {
10
- skipOnConnect?: boolean;
11
- }): Promise<void>;
12
- createKysely(): MaybePromise<void>;
13
- /**
14
- * @inheritDoc
15
- */
16
- close(force?: boolean): Promise<void>;
17
- /**
18
- * @inheritDoc
19
- */
20
- isConnected(): Promise<boolean>;
21
- /**
22
- * @inheritDoc
23
- */
24
- checkConnection(): Promise<{
20
+ #private;
21
+ protected platform: AbstractSqlPlatform;
22
+ /** Creates a Kysely dialect instance with driver-specific configuration. */
23
+ abstract createKyselyDialect(overrides: Dictionary): MaybePromise<Dialect>;
24
+ /** Establishes the database connection and runs the onConnect hook. */
25
+ connect(options?: { skipOnConnect?: boolean }): Promise<void>;
26
+ /** Initializes the Kysely client from driver options or a user-provided Kysely instance. */
27
+ createKysely(): MaybePromise<void>;
28
+ /**
29
+ * @inheritDoc
30
+ */
31
+ close(force?: boolean): Promise<void>;
32
+ /**
33
+ * @inheritDoc
34
+ */
35
+ isConnected(): Promise<boolean>;
36
+ /**
37
+ * @inheritDoc
38
+ */
39
+ checkConnection(): Promise<
40
+ | {
25
41
  ok: true;
26
- } | {
42
+ }
43
+ | {
27
44
  ok: false;
28
45
  reason: string;
29
46
  error?: Error;
30
- }>;
31
- getClient<T = any>(): Kysely<T>;
32
- initClient(): Promise<void>;
33
- transactional<T>(cb: (trx: Transaction<ControlledTransaction<any, any>>) => Promise<T>, options?: {
34
- isolationLevel?: IsolationLevel;
35
- readOnly?: boolean;
36
- ctx?: ControlledTransaction<any>;
37
- eventBroadcaster?: TransactionEventBroadcaster;
38
- loggerContext?: LogContext;
39
- }): Promise<T>;
40
- begin(options?: {
41
- isolationLevel?: IsolationLevel;
42
- readOnly?: boolean;
43
- ctx?: ControlledTransaction<any, any>;
44
- eventBroadcaster?: TransactionEventBroadcaster;
45
- loggerContext?: LogContext;
46
- }): Promise<ControlledTransaction<any, any>>;
47
- commit(ctx: ControlledTransaction<any, any>, eventBroadcaster?: TransactionEventBroadcaster, loggerContext?: LogContext): Promise<void>;
48
- rollback(ctx: ControlledTransaction<any, any>, eventBroadcaster?: TransactionEventBroadcaster, loggerContext?: LogContext): Promise<void>;
49
- private prepareQuery;
50
- execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(query: string | NativeQueryBuilder | RawQueryFragment, params?: readonly unknown[], method?: 'all' | 'get' | 'run', ctx?: Transaction, loggerContext?: LoggingOptions): Promise<T>;
51
- stream<T extends EntityData<AnyEntity>>(query: string | NativeQueryBuilder | RawQueryFragment, params?: readonly unknown[], ctx?: Transaction<Kysely<any>>, loggerContext?: LoggingOptions): AsyncIterableIterator<T>;
52
- /** @inheritDoc */
53
- executeDump(dump: string): Promise<void>;
54
- protected getSql(query: string, formatted: string, context?: LogContext): string;
55
- protected transformRawResult<T>(res: any, method?: 'all' | 'get' | 'run'): T;
47
+ }
48
+ >;
49
+ /** Returns the underlying Kysely client, creating it synchronously if needed. */
50
+ getClient<T = any>(): Kysely<T>;
51
+ /** Ensures the Kysely client is initialized, creating it asynchronously if needed. */
52
+ initClient(): Promise<void>;
53
+ /** Executes a callback within a transaction, committing on success and rolling back on error. */
54
+ transactional<T>(
55
+ cb: (trx: Transaction<ControlledTransaction<any, any>>) => Promise<T>,
56
+ options?: {
57
+ isolationLevel?: IsolationLevel;
58
+ readOnly?: boolean;
59
+ ctx?: ControlledTransaction<any>;
60
+ eventBroadcaster?: TransactionEventBroadcaster;
61
+ loggerContext?: LogContext;
62
+ },
63
+ ): Promise<T>;
64
+ /** Begins a new transaction or creates a savepoint if a transaction context already exists. */
65
+ begin(options?: {
66
+ isolationLevel?: IsolationLevel;
67
+ readOnly?: boolean;
68
+ ctx?: ControlledTransaction<any, any>;
69
+ eventBroadcaster?: TransactionEventBroadcaster;
70
+ loggerContext?: LogContext;
71
+ }): Promise<ControlledTransaction<any, any>>;
72
+ /** Commits the transaction or releases the savepoint. */
73
+ commit(
74
+ ctx: ControlledTransaction<any, any>,
75
+ eventBroadcaster?: TransactionEventBroadcaster,
76
+ loggerContext?: LogContext,
77
+ ): Promise<void>;
78
+ /** Rolls back the transaction or rolls back to the savepoint. */
79
+ rollback(
80
+ ctx: ControlledTransaction<any, any>,
81
+ eventBroadcaster?: TransactionEventBroadcaster,
82
+ loggerContext?: LogContext,
83
+ ): Promise<void>;
84
+ private prepareQuery;
85
+ /** Executes a SQL query and returns the result based on the method: `'all'` for rows, `'get'` for single row, `'run'` for affected count. */
86
+ execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(
87
+ query: string | NativeQueryBuilder | RawQueryFragment,
88
+ params?: readonly unknown[],
89
+ method?: 'all' | 'get' | 'run',
90
+ ctx?: Transaction,
91
+ loggerContext?: LoggingOptions,
92
+ ): Promise<T>;
93
+ /** Executes a SQL query and returns an async iterable that yields results row by row. */
94
+ stream<T extends EntityData<AnyEntity>>(
95
+ query: string | NativeQueryBuilder | RawQueryFragment,
96
+ params?: readonly unknown[],
97
+ ctx?: Transaction<Kysely<any>>,
98
+ loggerContext?: LoggingOptions,
99
+ ): AsyncIterableIterator<T>;
100
+ /** @inheritDoc */
101
+ executeDump(dump: string): Promise<void>;
102
+ protected getSql(query: string, formatted: string, context?: LogContext): string;
103
+ protected transformRawResult<T>(res: any, method?: 'all' | 'get' | 'run'): T;
56
104
  }
@@ -1,249 +1,257 @@
1
1
  import { CompiledQuery, Kysely } from 'kysely';
2
- import { Connection, EventType, RawQueryFragment, Utils, } from '@mikro-orm/core';
2
+ import { Connection, EventType, RawQueryFragment, Utils } from '@mikro-orm/core';
3
3
  import { NativeQueryBuilder } from './query/NativeQueryBuilder.js';
4
+ /** Base class for SQL database connections, built on top of Kysely. */
4
5
  export class AbstractSqlConnection extends Connection {
5
- #client;
6
- async connect(options) {
7
- await this.initClient();
8
- this.connected = true;
9
- if (options?.skipOnConnect !== true) {
10
- await this.onConnect();
11
- }
6
+ #client;
7
+ /** Establishes the database connection and runs the onConnect hook. */
8
+ async connect(options) {
9
+ await this.initClient();
10
+ this.connected = true;
11
+ if (options?.skipOnConnect !== true) {
12
+ await this.onConnect();
12
13
  }
13
- createKysely() {
14
- let driverOptions = this.options.driverOptions ?? this.config.get('driverOptions');
15
- if (typeof driverOptions === 'function') {
16
- driverOptions = driverOptions();
17
- }
18
- if (driverOptions instanceof Kysely) {
19
- this.logger.log('info', 'Reusing Kysely client provided via `driverOptions`');
20
- this.#client = driverOptions;
21
- }
22
- else if ('createDriver' in driverOptions) {
23
- this.logger.log('info', 'Reusing Kysely dialect provided via `driverOptions`');
24
- this.#client = new Kysely({ dialect: driverOptions });
25
- }
26
- else {
27
- const dialect = this.createKyselyDialect(driverOptions);
28
- if (dialect instanceof Promise) {
29
- return dialect.then(d => {
30
- this.#client = new Kysely({ dialect: d });
31
- });
32
- }
33
- this.#client = new Kysely({ dialect });
34
- }
14
+ }
15
+ /** Initializes the Kysely client from driver options or a user-provided Kysely instance. */
16
+ createKysely() {
17
+ let driverOptions = this.options.driverOptions ?? this.config.get('driverOptions');
18
+ if (typeof driverOptions === 'function') {
19
+ driverOptions = driverOptions();
35
20
  }
36
- /**
37
- * @inheritDoc
38
- */
39
- async close(force) {
40
- await super.close(force);
41
- await this.#client?.destroy();
42
- this.connected = false;
43
- this.#client = undefined;
44
- }
45
- /**
46
- * @inheritDoc
47
- */
48
- async isConnected() {
49
- const check = await this.checkConnection();
50
- return check.ok;
51
- }
52
- /**
53
- * @inheritDoc
54
- */
55
- async checkConnection() {
56
- if (!this.connected) {
57
- return { ok: false, reason: 'Connection not established' };
58
- }
59
- try {
60
- await this.getClient().executeQuery(CompiledQuery.raw('select 1'));
61
- return { ok: true };
62
- }
63
- catch (error) {
64
- return { ok: false, reason: error.message, error };
65
- }
21
+ if (driverOptions instanceof Kysely) {
22
+ this.logger.log('info', 'Reusing Kysely client provided via `driverOptions`');
23
+ this.#client = driverOptions;
24
+ } else if ('createDriver' in driverOptions) {
25
+ this.logger.log('info', 'Reusing Kysely dialect provided via `driverOptions`');
26
+ this.#client = new Kysely({ dialect: driverOptions });
27
+ } else {
28
+ const dialect = this.createKyselyDialect(driverOptions);
29
+ if (dialect instanceof Promise) {
30
+ return dialect.then(d => {
31
+ this.#client = new Kysely({ dialect: d });
32
+ });
33
+ }
34
+ this.#client = new Kysely({ dialect });
66
35
  }
67
- getClient() {
68
- if (!this.#client) {
69
- const maybePromise = this.createKysely();
70
- /* v8 ignore next */
71
- if (maybePromise instanceof Promise) {
72
- throw new Error('Current driver requires async initialization, use `MikroORM.init()` instead of the constructor');
73
- }
74
- }
75
- return this.#client;
36
+ }
37
+ /**
38
+ * @inheritDoc
39
+ */
40
+ async close(force) {
41
+ await super.close(force);
42
+ await this.#client?.destroy();
43
+ this.connected = false;
44
+ this.#client = undefined;
45
+ }
46
+ /**
47
+ * @inheritDoc
48
+ */
49
+ async isConnected() {
50
+ const check = await this.checkConnection();
51
+ return check.ok;
52
+ }
53
+ /**
54
+ * @inheritDoc
55
+ */
56
+ async checkConnection() {
57
+ if (!this.connected) {
58
+ return { ok: false, reason: 'Connection not established' };
76
59
  }
77
- async initClient() {
78
- if (!this.#client) {
79
- await this.createKysely();
80
- }
60
+ try {
61
+ await this.getClient().executeQuery(CompiledQuery.raw('select 1'));
62
+ return { ok: true };
63
+ } catch (error) {
64
+ return { ok: false, reason: error.message, error };
81
65
  }
82
- async transactional(cb, options = {}) {
83
- const trx = await this.begin(options);
84
- try {
85
- const ret = await cb(trx);
86
- await this.commit(trx, options.eventBroadcaster, options.loggerContext);
87
- return ret;
88
- }
89
- catch (error) {
90
- await this.rollback(trx, options.eventBroadcaster, options.loggerContext);
91
- throw error;
92
- }
66
+ }
67
+ /** Returns the underlying Kysely client, creating it synchronously if needed. */
68
+ getClient() {
69
+ if (!this.#client) {
70
+ const maybePromise = this.createKysely();
71
+ /* v8 ignore next */
72
+ if (maybePromise instanceof Promise) {
73
+ throw new Error(
74
+ 'Current driver requires async initialization, use `MikroORM.init()` instead of the constructor',
75
+ );
76
+ }
93
77
  }
94
- async begin(options = {}) {
95
- if (options.ctx) {
96
- const ctx = options.ctx;
97
- await options.eventBroadcaster?.dispatchEvent(EventType.beforeTransactionStart, ctx);
98
- ctx.index ??= 0;
99
- const savepointName = `trx${ctx.index + 1}`;
100
- const trx = await options.ctx.savepoint(savepointName).execute();
101
- Reflect.defineProperty(trx, 'index', { value: ctx.index + 1 });
102
- Reflect.defineProperty(trx, 'savepointName', { value: savepointName });
103
- this.logQuery(this.platform.getSavepointSQL(savepointName), options.loggerContext);
104
- await options.eventBroadcaster?.dispatchEvent(EventType.afterTransactionStart, trx);
105
- return trx;
106
- }
107
- await this.ensureConnection();
108
- await options.eventBroadcaster?.dispatchEvent(EventType.beforeTransactionStart);
109
- let trxBuilder = this.getClient().startTransaction();
110
- if (options.isolationLevel) {
111
- trxBuilder = trxBuilder.setIsolationLevel(options.isolationLevel);
112
- }
113
- if (options.readOnly) {
114
- trxBuilder = trxBuilder.setAccessMode('read only');
115
- }
116
- const trx = await trxBuilder.execute();
117
- if (options.ctx) {
118
- const ctx = options.ctx;
119
- ctx.index ??= 0;
120
- const savepointName = `trx${ctx.index + 1}`;
121
- Reflect.defineProperty(trx, 'index', { value: ctx.index + 1 });
122
- Reflect.defineProperty(trx, 'savepointName', { value: savepointName });
123
- this.logQuery(this.platform.getSavepointSQL(savepointName), options.loggerContext);
124
- }
125
- else {
126
- for (const query of this.platform.getBeginTransactionSQL(options)) {
127
- this.logQuery(query, options.loggerContext);
128
- }
129
- }
130
- await options.eventBroadcaster?.dispatchEvent(EventType.afterTransactionStart, trx);
131
- return trx;
78
+ return this.#client;
79
+ }
80
+ /** Ensures the Kysely client is initialized, creating it asynchronously if needed. */
81
+ async initClient() {
82
+ if (!this.#client) {
83
+ await this.createKysely();
132
84
  }
133
- async commit(ctx, eventBroadcaster, loggerContext) {
134
- if (ctx.isRolledBack) {
135
- return;
136
- }
137
- await eventBroadcaster?.dispatchEvent(EventType.beforeTransactionCommit, ctx);
138
- if ('savepointName' in ctx) {
139
- await ctx.releaseSavepoint(ctx.savepointName).execute();
140
- this.logQuery(this.platform.getReleaseSavepointSQL(ctx.savepointName), loggerContext);
141
- }
142
- else {
143
- await ctx.commit().execute();
144
- this.logQuery(this.platform.getCommitTransactionSQL(), loggerContext);
145
- }
146
- await eventBroadcaster?.dispatchEvent(EventType.afterTransactionCommit, ctx);
85
+ }
86
+ /** Executes a callback within a transaction, committing on success and rolling back on error. */
87
+ async transactional(cb, options = {}) {
88
+ const trx = await this.begin(options);
89
+ try {
90
+ const ret = await cb(trx);
91
+ await this.commit(trx, options.eventBroadcaster, options.loggerContext);
92
+ return ret;
93
+ } catch (error) {
94
+ await this.rollback(trx, options.eventBroadcaster, options.loggerContext);
95
+ throw error;
147
96
  }
148
- async rollback(ctx, eventBroadcaster, loggerContext) {
149
- await eventBroadcaster?.dispatchEvent(EventType.beforeTransactionRollback, ctx);
150
- if ('savepointName' in ctx) {
151
- await ctx.rollbackToSavepoint(ctx.savepointName).execute();
152
- this.logQuery(this.platform.getRollbackToSavepointSQL(ctx.savepointName), loggerContext);
153
- }
154
- else {
155
- await ctx.rollback().execute();
156
- this.logQuery(this.platform.getRollbackTransactionSQL(), loggerContext);
157
- }
158
- await eventBroadcaster?.dispatchEvent(EventType.afterTransactionRollback, ctx);
97
+ }
98
+ /** Begins a new transaction or creates a savepoint if a transaction context already exists. */
99
+ async begin(options = {}) {
100
+ if (options.ctx) {
101
+ const ctx = options.ctx;
102
+ await options.eventBroadcaster?.dispatchEvent(EventType.beforeTransactionStart, ctx);
103
+ ctx.index ??= 0;
104
+ const savepointName = `trx${ctx.index + 1}`;
105
+ const trx = await options.ctx.savepoint(savepointName).execute();
106
+ Reflect.defineProperty(trx, 'index', { value: ctx.index + 1 });
107
+ Reflect.defineProperty(trx, 'savepointName', { value: savepointName });
108
+ this.logQuery(this.platform.getSavepointSQL(savepointName), options.loggerContext);
109
+ await options.eventBroadcaster?.dispatchEvent(EventType.afterTransactionStart, trx);
110
+ return trx;
159
111
  }
160
- prepareQuery(query, params = []) {
161
- if (query instanceof NativeQueryBuilder) {
162
- query = query.toRaw();
163
- }
164
- if (query instanceof RawQueryFragment) {
165
- params = query.params;
166
- query = query.sql;
167
- }
168
- query = this.config.get('onQuery')(query, params);
169
- const formatted = this.platform.formatQuery(query, params);
170
- return { query, params, formatted };
171
- }
172
- async execute(query, params = [], method = 'all', ctx, loggerContext) {
173
- await this.ensureConnection();
174
- const q = this.prepareQuery(query, params);
175
- const sql = this.getSql(q.query, q.formatted, loggerContext);
176
- return this.executeQuery(sql, async () => {
177
- const compiled = CompiledQuery.raw(q.formatted);
178
- const res = await (ctx ?? this.#client).executeQuery(compiled);
179
- return this.transformRawResult(res, method);
180
- }, { ...q, ...loggerContext });
181
- }
182
- async *stream(query, params = [], ctx, loggerContext) {
183
- await this.ensureConnection();
184
- const q = this.prepareQuery(query, params);
185
- const sql = this.getSql(q.query, q.formatted, loggerContext);
186
- // construct the compiled query manually with `kind: 'SelectQueryNode'` to avoid sqlite validation for select queries when streaming
187
- const compiled = {
188
- query: {
189
- kind: 'SelectQueryNode',
190
- },
191
- sql: q.formatted,
192
- parameters: [],
193
- };
194
- try {
195
- const res = (ctx ?? this.getClient()).getExecutor().stream(compiled, 1);
196
- this.logQuery(sql, {
197
- sql,
198
- params,
199
- ...loggerContext,
200
- affected: Utils.isPlainObject(res) ? res.affectedRows : undefined,
201
- });
202
- for await (const items of res) {
203
- for (const row of this.transformRawResult(items, 'all')) {
204
- yield row;
205
- }
206
- }
207
- }
208
- catch (e) {
209
- this.logQuery(sql, { sql, params, ...loggerContext, level: 'error' });
210
- throw e;
211
- }
112
+ await this.ensureConnection();
113
+ await options.eventBroadcaster?.dispatchEvent(EventType.beforeTransactionStart);
114
+ let trxBuilder = this.getClient().startTransaction();
115
+ if (options.isolationLevel) {
116
+ trxBuilder = trxBuilder.setIsolationLevel(options.isolationLevel);
212
117
  }
213
- /** @inheritDoc */
214
- async executeDump(dump) {
215
- await this.ensureConnection();
216
- try {
217
- const raw = CompiledQuery.raw(dump);
218
- await this.getClient().executeQuery(raw);
219
- }
220
- catch (e) {
221
- /* v8 ignore next */
222
- throw this.platform.getExceptionConverter().convertException(e);
223
- }
118
+ if (options.readOnly) {
119
+ trxBuilder = trxBuilder.setAccessMode('read only');
224
120
  }
225
- getSql(query, formatted, context) {
226
- const logger = this.config.getLogger();
227
- if (!logger.isEnabled('query', context)) {
228
- return query;
229
- }
230
- if (logger.isEnabled('query-params', context)) {
231
- return formatted;
232
- }
233
- return query;
121
+ const trx = await trxBuilder.execute();
122
+ if (options.ctx) {
123
+ const ctx = options.ctx;
124
+ ctx.index ??= 0;
125
+ const savepointName = `trx${ctx.index + 1}`;
126
+ Reflect.defineProperty(trx, 'index', { value: ctx.index + 1 });
127
+ Reflect.defineProperty(trx, 'savepointName', { value: savepointName });
128
+ this.logQuery(this.platform.getSavepointSQL(savepointName), options.loggerContext);
129
+ } else {
130
+ for (const query of this.platform.getBeginTransactionSQL(options)) {
131
+ this.logQuery(query, options.loggerContext);
132
+ }
234
133
  }
235
- transformRawResult(res, method) {
236
- if (method === 'get') {
237
- return res.rows[0];
238
- }
239
- if (method === 'all') {
240
- return res.rows;
241
- }
242
- return {
243
- affectedRows: Number(res.numAffectedRows ?? res.rows.length),
244
- insertId: res.insertId != null ? Number(res.insertId) : res.insertId,
245
- row: res.rows[0],
246
- rows: res.rows,
247
- };
134
+ await options.eventBroadcaster?.dispatchEvent(EventType.afterTransactionStart, trx);
135
+ return trx;
136
+ }
137
+ /** Commits the transaction or releases the savepoint. */
138
+ async commit(ctx, eventBroadcaster, loggerContext) {
139
+ if (ctx.isRolledBack) {
140
+ return;
141
+ }
142
+ await eventBroadcaster?.dispatchEvent(EventType.beforeTransactionCommit, ctx);
143
+ if ('savepointName' in ctx) {
144
+ await ctx.releaseSavepoint(ctx.savepointName).execute();
145
+ this.logQuery(this.platform.getReleaseSavepointSQL(ctx.savepointName), loggerContext);
146
+ } else {
147
+ await ctx.commit().execute();
148
+ this.logQuery(this.platform.getCommitTransactionSQL(), loggerContext);
149
+ }
150
+ await eventBroadcaster?.dispatchEvent(EventType.afterTransactionCommit, ctx);
151
+ }
152
+ /** Rolls back the transaction or rolls back to the savepoint. */
153
+ async rollback(ctx, eventBroadcaster, loggerContext) {
154
+ await eventBroadcaster?.dispatchEvent(EventType.beforeTransactionRollback, ctx);
155
+ if ('savepointName' in ctx) {
156
+ await ctx.rollbackToSavepoint(ctx.savepointName).execute();
157
+ this.logQuery(this.platform.getRollbackToSavepointSQL(ctx.savepointName), loggerContext);
158
+ } else {
159
+ await ctx.rollback().execute();
160
+ this.logQuery(this.platform.getRollbackTransactionSQL(), loggerContext);
161
+ }
162
+ await eventBroadcaster?.dispatchEvent(EventType.afterTransactionRollback, ctx);
163
+ }
164
+ prepareQuery(query, params = []) {
165
+ if (query instanceof NativeQueryBuilder) {
166
+ query = query.toRaw();
167
+ }
168
+ if (query instanceof RawQueryFragment) {
169
+ params = query.params;
170
+ query = query.sql;
171
+ }
172
+ query = this.config.get('onQuery')(query, params);
173
+ const formatted = this.platform.formatQuery(query, params);
174
+ return { query, params, formatted };
175
+ }
176
+ /** Executes a SQL query and returns the result based on the method: `'all'` for rows, `'get'` for single row, `'run'` for affected count. */
177
+ async execute(query, params = [], method = 'all', ctx, loggerContext) {
178
+ await this.ensureConnection();
179
+ const q = this.prepareQuery(query, params);
180
+ const sql = this.getSql(q.query, q.formatted, loggerContext);
181
+ return this.executeQuery(
182
+ sql,
183
+ async () => {
184
+ const compiled = CompiledQuery.raw(q.formatted);
185
+ const res = await (ctx ?? this.#client).executeQuery(compiled);
186
+ return this.transformRawResult(res, method);
187
+ },
188
+ { ...q, ...loggerContext },
189
+ );
190
+ }
191
+ /** Executes a SQL query and returns an async iterable that yields results row by row. */
192
+ async *stream(query, params = [], ctx, loggerContext) {
193
+ await this.ensureConnection();
194
+ const q = this.prepareQuery(query, params);
195
+ const sql = this.getSql(q.query, q.formatted, loggerContext);
196
+ // construct the compiled query manually with `kind: 'SelectQueryNode'` to avoid sqlite validation for select queries when streaming
197
+ const compiled = {
198
+ query: {
199
+ kind: 'SelectQueryNode',
200
+ },
201
+ sql: q.formatted,
202
+ parameters: [],
203
+ };
204
+ try {
205
+ const res = (ctx ?? this.getClient()).getExecutor().stream(compiled, 1);
206
+ this.logQuery(sql, {
207
+ sql,
208
+ params,
209
+ ...loggerContext,
210
+ affected: Utils.isPlainObject(res) ? res.affectedRows : undefined,
211
+ });
212
+ for await (const items of res) {
213
+ for (const row of this.transformRawResult(items, 'all')) {
214
+ yield row;
215
+ }
216
+ }
217
+ } catch (e) {
218
+ this.logQuery(sql, { sql, params, ...loggerContext, level: 'error' });
219
+ throw e;
220
+ }
221
+ }
222
+ /** @inheritDoc */
223
+ async executeDump(dump) {
224
+ await this.ensureConnection();
225
+ try {
226
+ const raw = CompiledQuery.raw(dump);
227
+ await this.getClient().executeQuery(raw);
228
+ } catch (e) {
229
+ /* v8 ignore next */
230
+ throw this.platform.getExceptionConverter().convertException(e);
231
+ }
232
+ }
233
+ getSql(query, formatted, context) {
234
+ const logger = this.config.getLogger();
235
+ if (!logger.isEnabled('query', context)) {
236
+ return query;
237
+ }
238
+ if (logger.isEnabled('query-params', context)) {
239
+ return formatted;
240
+ }
241
+ return query;
242
+ }
243
+ transformRawResult(res, method) {
244
+ if (method === 'get') {
245
+ return res.rows[0];
246
+ }
247
+ if (method === 'all') {
248
+ return res.rows;
248
249
  }
250
+ return {
251
+ affectedRows: Number(res.numAffectedRows ?? res.rows.length),
252
+ insertId: res.insertId != null ? Number(res.insertId) : res.insertId,
253
+ row: res.rows[0],
254
+ rows: res.rows,
255
+ };
256
+ }
249
257
  }