@holo-js/db-mysql 0.3.15 → 0.3.17

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.d.ts CHANGED
@@ -27,9 +27,7 @@ declare class MySQLAdapter<TConfig extends PoolOptions = PoolOptions> implements
27
27
  private readonly createPoolInstance?;
28
28
  private readonly config;
29
29
  private connected;
30
- private transactionClient?;
31
- private leasedTransactionClient;
32
- private readonly transactionScope;
30
+ private readonly transactionClients;
33
31
  constructor(options?: MySQLAdapterOptions<TConfig>);
34
32
  initialize(): Promise<void>;
35
33
  isDatabaseMissingError(error: unknown): boolean;
@@ -47,10 +45,6 @@ declare class MySQLAdapter<TConfig extends PoolOptions = PoolOptions> implements
47
45
  releaseSavepoint(name: string): Promise<void>;
48
46
  private getQueryable;
49
47
  ensureDatabaseExists(): Promise<void>;
50
- private leaseTransactionClient;
51
- private requireTransactionClient;
52
- private releaseTransactionClient;
53
- private releaseScopedTransaction;
54
48
  private normalizeSavepointName;
55
49
  }
56
50
  declare function createMySQLAdapter<TConfig extends PoolOptions = PoolOptions>(options?: MySQLAdapterOptions<TConfig>): MySQLAdapter<TConfig>;
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { AsyncLocalStorage } from "async_hooks";
2
+ import { holoRuntimeInternals } from "@holo-js/db";
3
3
  import mysql from "mysql2/promise";
4
4
  var TransactionError = class extends Error {
5
5
  };
@@ -63,6 +63,15 @@ function wrapMySQLPool(pool) {
63
63
  end: rawPool.end.bind(rawPool)
64
64
  };
65
65
  }
66
+ function createNativeMySQLPool(config) {
67
+ const pool = mysql.createPool({ ...config, timezone: config.timezone ?? "Z" });
68
+ if (!config.timezone || config.timezone === "Z") {
69
+ pool.pool.on("connection", (connection) => {
70
+ connection.query("SET time_zone = '+00:00'");
71
+ });
72
+ }
73
+ return wrapMySQLPool(pool);
74
+ }
66
75
  function isMySQLDatabaseMissing(error) {
67
76
  return typeof error === "object" && error !== null && ("code" in error && error.code === "ER_BAD_DB_ERROR" || "errno" in error && error.errno === 1049);
68
77
  }
@@ -73,15 +82,27 @@ var MySQLAdapter = class {
73
82
  createPoolInstance;
74
83
  config;
75
84
  connected;
76
- transactionClient;
77
- leasedTransactionClient = false;
78
- transactionScope = new AsyncLocalStorage();
85
+ transactionClients;
79
86
  constructor(options = {}) {
80
87
  this.directClient = options.client;
81
88
  this.pool = options.pool;
82
- this.createPoolInstance = options.createPool ?? (options.client || options.pool ? void 0 : (config) => wrapMySQLPool(mysql.createPool(config)));
89
+ this.createPoolInstance = options.createPool ?? (options.client || options.pool ? void 0 : createNativeMySQLPool);
83
90
  this.config = options.config ?? (options.uri ? { uri: options.uri } : {});
84
91
  this.connected = !!(options.client || options.pool);
92
+ this.transactionClients = new holoRuntimeInternals.PooledTransactionClients(
93
+ "MySQL",
94
+ this.directClient,
95
+ async () => {
96
+ await this.initialize();
97
+ if (this.directClient) {
98
+ return this.directClient;
99
+ }
100
+ if (!this.pool) {
101
+ throw new TransactionError("MySQL adapter is not initialized with a pool or client.");
102
+ }
103
+ return this.pool.getConnection();
104
+ }
105
+ );
85
106
  }
86
107
  async initialize() {
87
108
  if (this.connected) {
@@ -99,11 +120,7 @@ var MySQLAdapter = class {
99
120
  if (!this.connected) {
100
121
  return;
101
122
  }
102
- if (this.transactionClient && this.leasedTransactionClient) {
103
- this.transactionClient.release?.();
104
- this.transactionClient = void 0;
105
- this.leasedTransactionClient = false;
106
- }
123
+ this.transactionClients.disconnect();
107
124
  if (this.pool) {
108
125
  await this.pool.end();
109
126
  this.pool = void 0;
@@ -115,30 +132,8 @@ var MySQLAdapter = class {
115
132
  isConnected() {
116
133
  return this.connected;
117
134
  }
118
- async runWithTransactionScope(callback) {
119
- const active = this.transactionScope.getStore();
120
- if (active) {
121
- return callback();
122
- }
123
- await this.initialize();
124
- if (this.directClient) {
125
- return this.transactionScope.run({
126
- client: this.directClient
127
- }, callback);
128
- }
129
- if (!this.pool) {
130
- throw new TransactionError("MySQL adapter is not initialized with a pool or client.");
131
- }
132
- const state = {
133
- client: await this.pool.getConnection()
134
- };
135
- return this.transactionScope.run(state, async () => {
136
- try {
137
- return await callback();
138
- } finally {
139
- this.releaseScopedTransaction(state);
140
- }
141
- });
135
+ runWithTransactionScope(callback) {
136
+ return this.transactionClients.run(callback);
142
137
  }
143
138
  async query(sql, bindings = []) {
144
139
  const queryable = await this.getQueryable();
@@ -162,35 +157,32 @@ var MySQLAdapter = class {
162
157
  };
163
158
  }
164
159
  async beginTransaction() {
165
- const client = await this.leaseTransactionClient();
160
+ const client = await this.transactionClients.lease();
166
161
  await client.query("START TRANSACTION", []);
167
162
  }
168
163
  async commit() {
169
- const client = this.requireTransactionClient();
164
+ const client = this.transactionClients.require();
170
165
  await client.query("COMMIT", []);
171
- this.releaseTransactionClient();
166
+ this.transactionClients.release();
172
167
  }
173
168
  async rollback() {
174
- const client = this.requireTransactionClient();
169
+ const client = this.transactionClients.require();
175
170
  await client.query("ROLLBACK", []);
176
- this.releaseTransactionClient();
171
+ this.transactionClients.release();
177
172
  }
178
173
  async createSavepoint(name) {
179
- await this.requireTransactionClient().query(`SAVEPOINT ${this.normalizeSavepointName(name)}`, []);
174
+ await this.transactionClients.require().query(`SAVEPOINT ${this.normalizeSavepointName(name)}`, []);
180
175
  }
181
176
  async rollbackToSavepoint(name) {
182
- await this.requireTransactionClient().query(`ROLLBACK TO SAVEPOINT ${this.normalizeSavepointName(name)}`, []);
177
+ await this.transactionClients.require().query(`ROLLBACK TO SAVEPOINT ${this.normalizeSavepointName(name)}`, []);
183
178
  }
184
179
  async releaseSavepoint(name) {
185
- await this.requireTransactionClient().query(`RELEASE SAVEPOINT ${this.normalizeSavepointName(name)}`, []);
180
+ await this.transactionClients.require().query(`RELEASE SAVEPOINT ${this.normalizeSavepointName(name)}`, []);
186
181
  }
187
182
  async getQueryable() {
188
- const scoped = this.transactionScope.getStore();
189
- if (scoped) {
190
- return scoped.client;
191
- }
192
- if (this.transactionClient) {
193
- return this.transactionClient;
183
+ const active = this.transactionClients.current;
184
+ if (active) {
185
+ return active;
194
186
  }
195
187
  await this.initialize();
196
188
  if (this.directClient) {
@@ -228,47 +220,6 @@ var MySQLAdapter = class {
228
220
  await bootstrapPool.end();
229
221
  }
230
222
  }
231
- async leaseTransactionClient() {
232
- const scoped = this.transactionScope.getStore();
233
- if (scoped) {
234
- return scoped.client;
235
- }
236
- if (this.transactionClient) {
237
- return this.transactionClient;
238
- }
239
- await this.initialize();
240
- if (this.directClient) {
241
- this.transactionClient = this.directClient;
242
- this.leasedTransactionClient = false;
243
- return this.transactionClient;
244
- }
245
- if (!this.pool) {
246
- throw new TransactionError("MySQL adapter is not initialized with a pool or client.");
247
- }
248
- this.transactionClient = await this.pool.getConnection();
249
- this.leasedTransactionClient = true;
250
- return this.transactionClient;
251
- }
252
- requireTransactionClient() {
253
- const scoped = this.transactionScope.getStore();
254
- if (scoped) {
255
- return scoped.client;
256
- }
257
- if (!this.transactionClient) {
258
- throw new TransactionError("No active MySQL transaction client is available.");
259
- }
260
- return this.transactionClient;
261
- }
262
- releaseTransactionClient() {
263
- if (this.transactionClient && this.leasedTransactionClient) {
264
- this.transactionClient.release?.();
265
- }
266
- this.transactionClient = void 0;
267
- this.leasedTransactionClient = false;
268
- }
269
- releaseScopedTransaction(state) {
270
- state.client.release?.();
271
- }
272
223
  normalizeSavepointName(name) {
273
224
  if (!/^[A-Z_]\w*$/i.test(name)) {
274
225
  throw new TransactionError(`Invalid savepoint name "${name}".`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holo-js/db-mysql",
3
- "version": "0.3.15",
3
+ "version": "0.3.17",
4
4
  "description": "Holo-JS Framework - MySQL database adapter",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,18 +24,18 @@
24
24
  "test:integration": "HOLO_MYSQL_INTEGRATION=1 vitest --run tests/mysql.test.ts"
25
25
  },
26
26
  "peerDependencies": {
27
- "@holo-js/db": "^0.3.15"
27
+ "@holo-js/db": "^0.3.17"
28
28
  },
29
29
  "dependencies": {
30
30
  "mysql2": "^3.17.1"
31
31
  },
32
32
  "devDependencies": {
33
- "@holo-js/db": "^0.3.15",
33
+ "@holo-js/db": "^0.3.17",
34
34
  "tsup": "^8.3.5",
35
35
  "typescript": "^5.7.2",
36
36
  "vitest": "^4.1.5"
37
37
  },
38
38
  "engines": {
39
- "node": ">=22.12.0"
39
+ "node": "^22.12.0 || ^24.0.0 || ^26.0.0"
40
40
  }
41
41
  }