@atscript/db-mysql 0.1.38 → 0.1.40

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.cjs CHANGED
@@ -1,38 +1,20 @@
1
- "use strict";
2
- //#region rolldown:runtime
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
- key = keys[i];
12
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
- get: ((k) => from[k]).bind(null, key),
14
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
- });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
- value: mod,
21
- enumerable: true
22
- }) : target, mod));
23
-
24
- //#endregion
25
- const __atscript_db = __toESM(require("@atscript/db"));
26
- const __atscript_db_sql_tools = __toESM(require("@atscript/db-sql-tools"));
27
- const __atscript_core = __toESM(require("@atscript/core"));
28
-
29
- //#region packages/db-mysql/src/sql-builder.ts
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_plugin = require("./plugin-C53PKZHf.cjs");
3
+ let _atscript_db = require("@atscript/db");
4
+ let _atscript_db_sql_tools = require("@atscript/db-sql-tools");
5
+ //#region src/sql-builder.ts
6
+ /** Escapes a MySQL identifier by doubling backticks. */
30
7
  function esc(name) {
31
8
  return name.replace(/`/g, "``");
32
9
  }
10
+ /** Backtick-quotes a single identifier. */
33
11
  function qi(name) {
34
12
  return `\`${esc(name)}\``;
35
13
  }
14
+ /**
15
+ * Backtick-quotes a table name, handling `schema.table` format.
16
+ * Input is a raw name like `mydb.users` or just `users`.
17
+ */
36
18
  function quoteTableName(name) {
37
19
  const dot = name.indexOf(".");
38
20
  if (dot >= 0) return `${qi(name.slice(0, dot))}.${qi(name.slice(dot + 1))}`;
@@ -46,9 +28,9 @@ const mysqlDialect = {
46
28
  return quoteTableName(name);
47
29
  },
48
30
  unlimitedLimit: "18446744073709551615",
49
- toValue: __atscript_db_sql_tools.toSqlValue,
31
+ toValue: _atscript_db_sql_tools.toSqlValue,
50
32
  toParam(value) {
51
- if (value === undefined) return null;
33
+ if (value === void 0) return null;
52
34
  return typeof value === "boolean" ? value ? 1 : 0 : value;
53
35
  },
54
36
  regex(quotedCol, value) {
@@ -60,27 +42,51 @@ const mysqlDialect = {
60
42
  },
61
43
  createViewPrefix: "CREATE OR REPLACE VIEW"
62
44
  };
45
+ /**
46
+ * Builds an INSERT statement.
47
+ */
63
48
  function buildInsert(table, data) {
64
- return (0, __atscript_db_sql_tools.buildInsert)(mysqlDialect, table, data);
49
+ return (0, _atscript_db_sql_tools.buildInsert)(mysqlDialect, table, data);
65
50
  }
51
+ /**
52
+ * Builds a SELECT statement with optional sort, limit, offset, projection.
53
+ */
66
54
  function buildSelect(table, where, controls) {
67
- return (0, __atscript_db_sql_tools.buildSelect)(mysqlDialect, table, where, controls);
55
+ return (0, _atscript_db_sql_tools.buildSelect)(mysqlDialect, table, where, controls);
68
56
  }
69
- function buildUpdate(table, data, where, limit) {
70
- return (0, __atscript_db_sql_tools.buildUpdate)(mysqlDialect, table, data, where, limit);
57
+ /**
58
+ * Builds an UPDATE ... SET ... WHERE statement with optional LIMIT.
59
+ */
60
+ function buildUpdate(table, data, where, limit, ops) {
61
+ return (0, _atscript_db_sql_tools.buildUpdate)(mysqlDialect, table, data, where, limit, ops);
71
62
  }
63
+ /**
64
+ * Builds a DELETE ... WHERE statement with optional LIMIT.
65
+ */
72
66
  function buildDelete(table, where, limit) {
73
- return (0, __atscript_db_sql_tools.buildDelete)(mysqlDialect, table, where, limit);
67
+ return (0, _atscript_db_sql_tools.buildDelete)(mysqlDialect, table, where, limit);
74
68
  }
69
+ /**
70
+ * Builds a CREATE OR REPLACE VIEW statement from a view plan and column mappings.
71
+ */
75
72
  function buildCreateView(viewName, plan, columns, resolveFieldRef) {
76
- return (0, __atscript_db_sql_tools.buildCreateView)(mysqlDialect, viewName, plan, columns, resolveFieldRef);
73
+ return (0, _atscript_db_sql_tools.buildCreateView)(mysqlDialect, viewName, plan, columns, resolveFieldRef);
77
74
  }
75
+ /**
76
+ * Builds a SELECT ... GROUP BY statement with aggregate functions.
77
+ */
78
78
  function buildAggregateSelect(table, where, controls) {
79
- return (0, __atscript_db_sql_tools.buildAggregateSelect)(mysqlDialect, table, where, controls);
79
+ return (0, _atscript_db_sql_tools.buildAggregateSelect)(mysqlDialect, table, where, controls);
80
80
  }
81
+ /**
82
+ * Builds a COUNT query for the number of distinct groups.
83
+ */
81
84
  function buildAggregateCount(table, where, controls) {
82
- return (0, __atscript_db_sql_tools.buildAggregateCount)(mysqlDialect, table, where, controls);
85
+ return (0, _atscript_db_sql_tools.buildAggregateCount)(mysqlDialect, table, where, controls);
83
86
  }
87
+ /**
88
+ * Maps portable collation values to MySQL collation names.
89
+ */
84
90
  function collationToMysql(collation) {
85
91
  switch (collation) {
86
92
  case "binary": return "utf8mb4_bin";
@@ -98,7 +104,8 @@ function collationToMysql(collation) {
98
104
  * For FK fields, delegates to the target PK's type via `field.fkTargetField`
99
105
  * so the FK column type always matches the referenced column.
100
106
  */
101
- /** Maps integer primitive tags to MySQL integer types. */ function intTypeFromTags(tags, unsigned) {
107
+ /** Maps integer primitive tags to MySQL integer types. */
108
+ function intTypeFromTags(tags, unsigned) {
102
109
  if (tags?.has("int8")) return unsigned ? "TINYINT UNSIGNED" : "TINYINT";
103
110
  if (tags?.has("uint8") || tags?.has("byte")) return "TINYINT UNSIGNED";
104
111
  if (tags?.has("int16")) return unsigned ? "SMALLINT UNSIGNED" : "SMALLINT";
@@ -118,36 +125,36 @@ function mysqlTypeFromField(field) {
118
125
  const unsigned = metadata?.has("db.mysql.unsigned") ?? false;
119
126
  const precision = metadata?.get("db.column.precision");
120
127
  switch (field.designType) {
121
- case "number": {
128
+ case "number":
122
129
  if (precision) return `DECIMAL(${precision.precision},${precision.scale})`;
123
130
  if (field.defaultValue?.kind === "fn" && field.defaultValue.fn === "increment") return unsigned ? "BIGINT UNSIGNED" : "BIGINT";
124
131
  if (field.defaultValue?.kind === "fn" && field.defaultValue.fn === "now") return "TIMESTAMP";
125
132
  if (tags?.has("int")) return intTypeFromTags(tags, unsigned);
126
133
  return "DOUBLE";
127
- }
128
134
  case "integer": return intTypeFromTags(tags, unsigned);
129
- case "decimal": {
135
+ case "decimal":
130
136
  if (precision) return `DECIMAL(${precision.precision},${precision.scale})`;
131
137
  return "DECIMAL(10,2)";
132
- }
133
138
  case "boolean": return "TINYINT(1)";
134
139
  case "string": {
135
140
  if (tags?.has("char")) return "CHAR(1)";
136
- const maxLen = metadata?.get("expect.maxLength")?.length;
137
- if (maxLen !== undefined && maxLen <= 65535) return `VARCHAR(${maxLen})`;
138
- if (maxLen !== undefined && maxLen > 65535) return "LONGTEXT";
141
+ const maxLen = (metadata?.get("expect.maxLength"))?.length;
142
+ if (maxLen !== void 0 && maxLen <= 65535) return `VARCHAR(${maxLen})`;
143
+ if (maxLen !== void 0 && maxLen > 65535) return "LONGTEXT";
139
144
  if (field.isPrimaryKey || field.defaultValue) return "VARCHAR(255)";
140
145
  return "TEXT";
141
146
  }
142
147
  case "json":
143
148
  case "object":
144
149
  case "array": return "JSON";
145
- default: {
150
+ default:
146
151
  if (field.isPrimaryKey || field.defaultValue) return "VARCHAR(255)";
147
152
  return "TEXT";
148
- }
149
153
  }
150
154
  }
155
+ /**
156
+ * Builds a CREATE TABLE IF NOT EXISTS statement with MySQL options.
157
+ */
151
158
  function buildCreateTable(table, fields, foreignKeys, options) {
152
159
  const colDefs = [];
153
160
  const primaryKeys = fields.filter((f) => f.isPrimaryKey);
@@ -157,14 +164,14 @@ function buildCreateTable(table, fields, foreignKeys, options) {
157
164
  let def = `${qi(field.physicalName)} ${sqlType}`;
158
165
  if (options?.incrementFields?.has(field.physicalName)) def += " AUTO_INCREMENT";
159
166
  if (!field.optional && !field.isPrimaryKey && !options?.incrementFields?.has(field.physicalName)) def += " NOT NULL";
160
- if (field.defaultValue?.kind === "value") def += ` DEFAULT ${(0, __atscript_db_sql_tools.defaultValueToSqlLiteral)(field.designType, field.defaultValue.value)}`;
161
- else if (field.defaultValue?.kind === "fn") {
167
+ if (field.defaultValue?.kind === "value") def += ` DEFAULT ${(0, _atscript_db_sql_tools.defaultValueToSqlLiteral)(field.designType, field.defaultValue.value)}`;
168
+ else if (field.defaultValue?.kind === "fn") {
162
169
  if (field.defaultValue.fn === "uuid") def += " DEFAULT (UUID())";
163
- else if (field.defaultValue.fn === "now") def += " DEFAULT CURRENT_TIMESTAMP";
170
+ else if (field.defaultValue.fn === "now") def += " DEFAULT CURRENT_TIMESTAMP";
164
171
  }
165
172
  const nativeCollate = field.type?.metadata?.get("db.mysql.collate");
166
173
  if (nativeCollate) def += ` COLLATE ${nativeCollate}`;
167
- else if (field.collate) def += ` COLLATE ${collationToMysql(field.collate)}`;
174
+ else if (field.collate) def += ` COLLATE ${collationToMysql(field.collate)}`;
168
175
  const onUpdate = options?.onUpdateFields?.get(field.physicalName);
169
176
  if (onUpdate) def += ` ON UPDATE ${onUpdate}`;
170
177
  colDefs.push(def);
@@ -183,8 +190,8 @@ else if (field.collate) def += ` COLLATE ${collationToMysql(field.collate)}`;
183
190
  const localCols = fk.fields.map((f) => qi(f)).join(", ");
184
191
  const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
185
192
  let constraint = `FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
186
- if (fk.onDelete) constraint += ` ON DELETE ${(0, __atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
187
- if (fk.onUpdate) constraint += ` ON UPDATE ${(0, __atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
193
+ if (fk.onDelete) constraint += ` ON DELETE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
194
+ if (fk.onUpdate) constraint += ` ON UPDATE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
188
195
  colDefs.push(constraint);
189
196
  }
190
197
  let sql = `CREATE TABLE IF NOT EXISTS ${quoteTableName(table)} (${colDefs.join(", ")})`;
@@ -192,28 +199,23 @@ else if (field.collate) def += ` COLLATE ${collationToMysql(field.collate)}`;
192
199
  const charset = options?.charset ?? "utf8mb4";
193
200
  const collation = options?.collation ?? "utf8mb4_unicode_ci";
194
201
  sql += ` ENGINE=${engine} DEFAULT CHARSET=${charset} COLLATE=${collation}`;
195
- if (options?.autoIncrementStart !== undefined) sql += ` AUTO_INCREMENT=${options.autoIncrementStart}`;
202
+ if (options?.autoIncrementStart !== void 0) sql += ` AUTO_INCREMENT=${options.autoIncrementStart}`;
196
203
  return sql;
197
204
  }
198
-
199
205
  //#endregion
200
- //#region packages/db-mysql/src/filter-builder.ts
206
+ //#region src/filter-builder.ts
207
+ /**
208
+ * Translates a uniqu filter expression into a parameterized MySQL WHERE clause.
209
+ *
210
+ * @returns `{ sql, params }` — the WHERE clause (without "WHERE") and bound params.
211
+ * Returns `{ sql: '1=1', params: [] }` for empty/null filters.
212
+ */
201
213
  function buildWhere(filter) {
202
- return (0, __atscript_db_sql_tools.buildWhere)(mysqlDialect, filter);
214
+ return (0, _atscript_db_sql_tools.buildWhere)(mysqlDialect, filter);
203
215
  }
204
-
205
216
  //#endregion
206
- //#region packages/db-mysql/src/mysql-adapter.ts
207
- function _define_property$1(obj, key, value) {
208
- if (key in obj) Object.defineProperty(obj, key, {
209
- value,
210
- enumerable: true,
211
- configurable: true,
212
- writable: true
213
- });
214
- else obj[key] = value;
215
- return obj;
216
- }
217
+ //#region src/mysql-adapter.ts
218
+ /** Parses a MySQL UTC datetime string ('YYYY-MM-DD HH:MM:SS') to epoch ms. Returns the original value if parsing fails. */
217
219
  function utcDatetimeToEpochMs(value) {
218
220
  if (typeof value === "number") return value;
219
221
  if (value instanceof Date) return value.getTime();
@@ -223,14 +225,50 @@ function utcDatetimeToEpochMs(value) {
223
225
  }
224
226
  return value;
225
227
  }
226
- /** Formats epoch ms as 'YYYY-MM-DD HH:MM:SS' in UTC for MySQL TIMESTAMP columns. */ function epochMsToUtcDatetime(ms) {
228
+ /** Formats epoch ms as 'YYYY-MM-DD HH:MM:SS' in UTC for MySQL TIMESTAMP columns. */
229
+ function epochMsToUtcDatetime(ms) {
227
230
  const d = new Date(ms);
228
231
  return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")} ${String(d.getUTCHours()).padStart(2, "0")}:${String(d.getUTCMinutes()).padStart(2, "0")}:${String(d.getUTCSeconds()).padStart(2, "0")}`;
229
232
  }
230
- var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
231
- /** Schema name for INFORMATION_SCHEMA queries (null falls through to DATABASE()). */ get _schema() {
233
+ /**
234
+ * MySQL adapter for {@link AtscriptDbTable}.
235
+ *
236
+ * Accepts any {@link TMysqlDriver} implementation — the actual MySQL driver
237
+ * is fully swappable (mysql2/promise pool, custom implementations, etc.).
238
+ *
239
+ * Usage:
240
+ * ```typescript
241
+ * import { Mysql2Driver, MysqlAdapter } from '@atscript/db-mysql'
242
+ * import { DbSpace } from '@atscript/db'
243
+ *
244
+ * const driver = new Mysql2Driver('mysql://root@localhost:3306/mydb')
245
+ * const space = new DbSpace(() => new MysqlAdapter(driver))
246
+ * const users = space.getTable(UsersType)
247
+ * ```
248
+ */
249
+ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
250
+ supportsColumnModify = true;
251
+ static NATIVE_DEFAULT_FNS = new Set(["now", "increment"]);
252
+ _engine = "InnoDB";
253
+ _charset = "utf8mb4";
254
+ _collation = "utf8mb4_unicode_ci";
255
+ _autoIncrementStart;
256
+ _incrementFields = /* @__PURE__ */ new Set();
257
+ _onUpdateFields = /* @__PURE__ */ new Map();
258
+ /** Whether the connected MySQL instance supports native VECTOR type (MySQL 9.0+). */
259
+ _supportsVector;
260
+ /** Vector fields: physical field name → { dimensions, similarity, indexName }. */
261
+ _vectorFields = /* @__PURE__ */ new Map();
262
+ /** Default similarity thresholds per vector field (from @db.search.vector.threshold). */
263
+ _vectorThresholds = /* @__PURE__ */ new Map();
264
+ /** Schema name for INFORMATION_SCHEMA queries (null falls through to DATABASE()). */
265
+ get _schema() {
232
266
  return this._table.schema ?? null;
233
267
  }
268
+ constructor(driver) {
269
+ super();
270
+ this.driver = driver;
271
+ }
234
272
  async _beginTransaction() {
235
273
  const conn = await this.driver.getConnection();
236
274
  await conn.exec("START TRANSACTION");
@@ -258,11 +296,12 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
258
296
  /**
259
297
  * Returns the active executor: dedicated connection if inside a transaction,
260
298
  * otherwise the pool-based driver.
261
- */ _exec() {
262
- const txState = this._getTransactionState();
263
- return txState ?? this.driver;
299
+ */
300
+ _exec() {
301
+ return this._getTransactionState() ?? this.driver;
264
302
  }
265
- /** MySQL InnoDB enforces FK constraints natively. */ supportsNativeForeignKeys() {
303
+ /** MySQL InnoDB enforces FK constraints natively. */
304
+ supportsNativeForeignKeys() {
266
305
  return true;
267
306
  }
268
307
  prepareId(id, _fieldType) {
@@ -274,8 +313,8 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
274
313
  nativeDefaultFns() {
275
314
  return MysqlAdapter.NATIVE_DEFAULT_FNS;
276
315
  }
277
- onBeforeFlatten(type) {
278
- const meta = type.metadata;
316
+ onBeforeFlatten(_type) {
317
+ const meta = _type.metadata;
279
318
  const engine = meta.get("db.mysql.engine");
280
319
  if (engine) this._engine = engine;
281
320
  const charset = meta.get("db.mysql.charset");
@@ -300,7 +339,7 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
300
339
  indexName
301
340
  });
302
341
  const threshold = metadata.get("db.search.vector.threshold");
303
- if (threshold !== undefined) this._vectorThresholds.set(indexName, threshold);
342
+ if (threshold !== void 0) this._vectorThresholds.set(indexName, threshold);
304
343
  }
305
344
  }
306
345
  getDesiredTableOptions() {
@@ -344,18 +383,15 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
344
383
  const tableName = this.resolveTableName();
345
384
  const clauses = [];
346
385
  for (const change of changes) switch (change.key) {
347
- case "engine": {
386
+ case "engine":
348
387
  clauses.push(`ENGINE = ${change.newValue}`);
349
388
  break;
350
- }
351
- case "charset": {
389
+ case "charset":
352
390
  clauses.push(`CHARACTER SET = ${change.newValue}`);
353
391
  break;
354
- }
355
- case "collation": {
392
+ case "collation":
356
393
  clauses.push(`COLLATE = ${change.newValue}`);
357
394
  break;
358
- }
359
395
  }
360
396
  if (clauses.length > 0) {
361
397
  const ddl = `ALTER TABLE ${quoteTableName(tableName)} ${clauses.join(", ")}`;
@@ -367,12 +403,12 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
367
403
  * Returns a value formatter for TIMESTAMP-mapped fields.
368
404
  * Number fields with @db.default.now map to MySQL TIMESTAMP — the formatter
369
405
  * converts epoch ms to a UTC datetime string for the wire protocol.
370
- */ formatValue(field) {
406
+ */
407
+ formatValue(field) {
371
408
  if (field.designType === "number" && field.defaultValue?.kind === "fn" && field.defaultValue.fn === "now") return {
372
409
  toStorage: (value) => typeof value === "number" ? epochMsToUtcDatetime(value) : value,
373
410
  fromStorage: utcDatetimeToEpochMs
374
411
  };
375
- return undefined;
376
412
  }
377
413
  /**
378
414
  * Wraps an async write operation to catch MySQL constraint errors
@@ -382,24 +418,18 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
382
418
  * - 1062 = ER_DUP_ENTRY (unique constraint violation)
383
419
  * - 1451 = ER_ROW_IS_REFERENCED_2 (FK violation on delete)
384
420
  * - 1452 = ER_NO_REFERENCED_ROW_2 (FK violation on insert/update)
385
- */ async _wrapConstraintError(fn) {
421
+ */
422
+ async _wrapConstraintError(fn) {
386
423
  try {
387
424
  return await fn();
388
425
  } catch (error) {
389
426
  if (error && typeof error === "object" && "errno" in error) {
390
427
  const err = error;
391
- if (err.errno === 1062) {
392
- const match = err.message?.match(/for key '(?:\w+\.)?(\w+)'/);
393
- const field = match?.[1] ?? "";
394
- throw new __atscript_db.DbError("CONFLICT", [{
395
- path: field,
396
- message: err.sqlMessage ?? err.message
397
- }]);
398
- }
399
- if (err.errno === 1451 || err.errno === 1452) {
400
- const errors = this._mapFkError(err.message);
401
- throw new __atscript_db.DbError("FK_VIOLATION", errors);
402
- }
428
+ if (err.errno === 1062) throw new _atscript_db.DbError("CONFLICT", [{
429
+ path: (err.message?.match(/for key '(?:\w+\.)?(\w+)'/))?.[1] ?? "",
430
+ message: err.sqlMessage ?? err.message
431
+ }]);
432
+ if (err.errno === 1451 || err.errno === 1452) throw new _atscript_db.DbError("FK_VIOLATION", this._mapFkError(err.message));
403
433
  }
404
434
  throw error;
405
435
  }
@@ -408,9 +438,8 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
408
438
  const fkMatch = message.match(/FOREIGN KEY \(`(\w+)`\)/);
409
439
  if (fkMatch) {
410
440
  const physicalCol = fkMatch[1];
411
- const field = this._table.fieldDescriptors.find((f) => f.physicalName === physicalCol);
412
441
  return [{
413
- path: field?.path ?? physicalCol,
442
+ path: this._table.fieldDescriptors.find((f) => f.physicalName === physicalCol)?.path ?? physicalCol,
414
443
  message
415
444
  }];
416
445
  }
@@ -477,28 +506,25 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
477
506
  }
478
507
  async count(query) {
479
508
  const where = buildWhere(query.filter);
480
- const tableName = this.resolveTableName();
481
- const sql = `SELECT COUNT(*) as cnt FROM ${quoteTableName(tableName)} WHERE ${where.sql}`;
509
+ const sql = `SELECT COUNT(*) as cnt FROM ${quoteTableName(this.resolveTableName())} WHERE ${where.sql}`;
482
510
  this._log(sql, where.params);
483
- const row = await this._exec().get(sql, where.params);
484
- return row?.cnt ?? 0;
511
+ return (await this._exec().get(sql, where.params))?.cnt ?? 0;
485
512
  }
486
513
  async aggregate(query) {
487
514
  const where = buildWhere(query.filter);
488
515
  const tableName = this.resolveTableName();
489
516
  if (query.controls.$count) {
490
- const { sql: sql$1, params: params$1 } = buildAggregateCount(tableName, where, query.controls);
491
- this._log(sql$1, params$1);
492
- const row = await this._exec().get(sql$1, params$1);
493
- return [{ count: row?.count ?? 0 }];
517
+ const { sql, params } = buildAggregateCount(tableName, where, query.controls);
518
+ this._log(sql, params);
519
+ return [{ count: (await this._exec().get(sql, params))?.count ?? 0 }];
494
520
  }
495
521
  const { sql, params } = buildAggregateSelect(tableName, where, query.controls);
496
522
  this._log(sql, params);
497
523
  return this._exec().all(sql, params);
498
524
  }
499
- async updateOne(filter, data) {
525
+ async updateOne(filter, data, ops) {
500
526
  const where = buildWhere(filter);
501
- const { sql, params } = buildUpdate(this.resolveTableName(), data, where, 1);
527
+ const { sql, params } = buildUpdate(this.resolveTableName(), data, where, 1, ops);
502
528
  this._log(sql, params);
503
529
  const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
504
530
  return {
@@ -506,9 +532,9 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
506
532
  modifiedCount: result.changedRows
507
533
  };
508
534
  }
509
- async updateMany(filter, data) {
535
+ async updateMany(filter, data, ops) {
510
536
  const where = buildWhere(filter);
511
- const { sql, params } = buildUpdate(this.resolveTableName(), data, where);
537
+ const { sql, params } = buildUpdate(this.resolveTableName(), data, where, void 0, ops);
512
538
  this._log(sql, params);
513
539
  const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
514
540
  return {
@@ -540,19 +566,17 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
540
566
  const where = buildWhere(filter);
541
567
  const { sql, params } = buildDelete(this.resolveTableName(), where, 1);
542
568
  this._log(sql, params);
543
- const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
544
- return { deletedCount: result.affectedRows };
569
+ return { deletedCount: (await this._wrapConstraintError(() => this._exec().run(sql, params))).affectedRows };
545
570
  }
546
571
  async deleteMany(filter) {
547
572
  const where = buildWhere(filter);
548
573
  const { sql, params } = buildDelete(this.resolveTableName(), where);
549
574
  this._log(sql, params);
550
- const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
551
- return { deletedCount: result.affectedRows };
575
+ return { deletedCount: (await this._wrapConstraintError(() => this._exec().run(sql, params))).affectedRows };
552
576
  }
553
577
  async ensureTable() {
554
- if (this._supportsVector === undefined && this._vectorFields.size > 0) await this._detectVectorSupport();
555
- if (this._table instanceof __atscript_db.AtscriptDbView) return this._ensureView();
578
+ if (this._supportsVector === void 0 && this._vectorFields.size > 0) await this._detectVectorSupport();
579
+ if (this._table instanceof _atscript_db.AtscriptDbView) return this._ensureView();
556
580
  const sql = buildCreateTable(this.resolveTableName(), this._table.fieldDescriptors, this._table.foreignKeys, {
557
581
  engine: this._engine,
558
582
  charset: this._charset,
@@ -575,11 +599,10 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
575
599
  }
576
600
  async getExistingColumnsForTable(tableName) {
577
601
  const schema = this._schema;
578
- const rows = await this._exec().all(`SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT
602
+ return (await this._exec().all(`SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT
579
603
  FROM INFORMATION_SCHEMA.COLUMNS
580
604
  WHERE TABLE_NAME = ? AND TABLE_SCHEMA = COALESCE(?, DATABASE())
581
- ORDER BY ORDINAL_POSITION`, [tableName, schema]);
582
- return rows.map((r) => ({
605
+ ORDER BY ORDINAL_POSITION`, [tableName, schema])).map((r) => ({
583
606
  name: r.COLUMN_NAME,
584
607
  type: r.COLUMN_TYPE.toUpperCase(),
585
608
  notnull: r.IS_NULLABLE === "NO",
@@ -601,8 +624,8 @@ var MysqlAdapter = class MysqlAdapter extends __atscript_db.BaseDbAdapter {
601
624
  const sqlType = this.typeMapper(field);
602
625
  let ddl = `ALTER TABLE ${quoteTableName(tableName)} ADD COLUMN ${qi(field.physicalName)} ${sqlType}`;
603
626
  if (!field.optional && !field.isPrimaryKey) ddl += " NOT NULL";
604
- if (field.defaultValue?.kind === "value") ddl += ` DEFAULT ${(0, __atscript_db_sql_tools.defaultValueToSqlLiteral)(field.designType, field.defaultValue.value)}`;
605
- else if (!field.optional && !field.isPrimaryKey) ddl += ` DEFAULT ${(0, __atscript_db_sql_tools.defaultValueForType)(field.designType)}`;
627
+ if (field.defaultValue?.kind === "value") ddl += ` DEFAULT ${(0, _atscript_db_sql_tools.defaultValueToSqlLiteral)(field.designType, field.defaultValue.value)}`;
628
+ else if (!field.optional && !field.isPrimaryKey) ddl += ` DEFAULT ${(0, _atscript_db_sql_tools.defaultValueForType)(field.designType)}`;
606
629
  if (field.collate) {
607
630
  const nativeCollate = field.type?.metadata?.get("db.mysql.collate");
608
631
  ddl += ` COLLATE ${nativeCollate ?? collationToMysql(field.collate)}`;
@@ -629,9 +652,9 @@ else if (!field.optional && !field.isPrimaryKey) ddl += ` DEFAULT ${(0, __atscri
629
652
  const sqlType = this.typeMapper(field);
630
653
  let ddl = `ALTER TABLE ${quoteTableName(tableName)} MODIFY COLUMN ${qi(field.physicalName)} ${sqlType}`;
631
654
  if (!field.optional && !field.isPrimaryKey) ddl += " NOT NULL";
632
- if (field.defaultValue?.kind === "value") ddl += ` DEFAULT ${(0, __atscript_db_sql_tools.defaultValueToSqlLiteral)(field.designType, field.defaultValue.value)}`;
633
- else if (field.defaultValue?.kind === "fn") ddl += ` DEFAULT ${field.defaultValue.fn === "now" ? "CURRENT_TIMESTAMP" : field.defaultValue.fn === "uuid" ? "(UUID())" : `(${field.defaultValue.fn}())`}`;
634
- else ddl += " DEFAULT NULL";
655
+ if (field.defaultValue?.kind === "value") ddl += ` DEFAULT ${(0, _atscript_db_sql_tools.defaultValueToSqlLiteral)(field.designType, field.defaultValue.value)}`;
656
+ else if (field.defaultValue?.kind === "fn") ddl += ` DEFAULT ${field.defaultValue.fn === "now" ? "CURRENT_TIMESTAMP" : field.defaultValue.fn === "uuid" ? "(UUID())" : `(${field.defaultValue.fn}())`}`;
657
+ else ddl += " DEFAULT NULL";
635
658
  this._log(ddl);
636
659
  await this._exec().exec(ddl);
637
660
  }
@@ -665,7 +688,7 @@ else ddl += " DEFAULT NULL";
665
688
  const selectExprs = commonCols.map((c) => {
666
689
  const field = fieldsByName.get(c);
667
690
  if (field && !field.optional && !field.isPrimaryKey) {
668
- const fallback = field.defaultValue?.kind === "value" ? (0, __atscript_db_sql_tools.defaultValueToSqlLiteral)(field.designType, field.defaultValue.value) : (0, __atscript_db_sql_tools.defaultValueForType)(field.designType);
691
+ const fallback = field.defaultValue?.kind === "value" ? (0, _atscript_db_sql_tools.defaultValueToSqlLiteral)(field.designType, field.defaultValue.value) : (0, _atscript_db_sql_tools.defaultValueForType)(field.designType);
669
692
  return `COALESCE(${qi(c)}, ${fallback}) AS ${qi(c)}`;
670
693
  }
671
694
  return qi(c);
@@ -741,10 +764,7 @@ else ddl += " DEFAULT NULL";
741
764
  const fulltext = index.type === "fulltext" ? "FULLTEXT " : "";
742
765
  const isFulltext = index.type === "fulltext";
743
766
  const cols = index.fields.map((f) => {
744
- const col = qi(f.name);
745
- const prefix = !isFulltext && stringFields.has(f.name) ? "(255)" : "";
746
- const order = isFulltext ? "" : ` ${f.sort === "desc" ? "DESC" : "ASC"}`;
747
- return `${col}${prefix}${order}`;
767
+ return `${qi(f.name)}${!isFulltext && stringFields.has(f.name) ? "(255)" : ""}${isFulltext ? "" : ` ${f.sort === "desc" ? "DESC" : "ASC"}`}`;
748
768
  }).join(", ");
749
769
  const sql = `CREATE ${fulltext}${unique}INDEX ${qi(index.key)} ON ${quoteTableName(this.resolveTableName())} (${cols})`;
750
770
  this._log(sql);
@@ -759,25 +779,25 @@ else ddl += " DEFAULT NULL";
759
779
  }
760
780
  async syncForeignKeys() {
761
781
  const existingByName = await this._getExistingFkConstraints();
762
- const desiredFkKeys = new Set();
763
- for (const fk of this._table.foreignKeys.values()) desiredFkKeys.add([...fk.fields].sort().join(","));
782
+ const desiredFkKeys = /* @__PURE__ */ new Set();
783
+ for (const fk of this._table.foreignKeys.values()) desiredFkKeys.add([...fk.fields].toSorted().join(","));
764
784
  for (const [constraintName, columns] of existingByName) {
765
- const key = columns.sort().join(",");
785
+ const key = columns.toSorted().join(",");
766
786
  if (!desiredFkKeys.has(key)) {
767
787
  const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} DROP FOREIGN KEY ${qi(constraintName)}`;
768
788
  this._log(ddl);
769
789
  await this._exec().exec(ddl);
770
790
  }
771
791
  }
772
- const existingKeys = new Set([...existingByName.values()].map((cols) => cols.sort().join(",")));
792
+ const existingKeys = new Set([...existingByName.values()].map((cols) => cols.toSorted().join(",")));
773
793
  for (const fk of this._table.foreignKeys.values()) {
774
- const key = [...fk.fields].sort().join(",");
794
+ const key = [...fk.fields].toSorted().join(",");
775
795
  if (!existingKeys.has(key)) {
776
796
  const localCols = fk.fields.map((f) => qi(f)).join(", ");
777
797
  const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
778
798
  let ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} ADD FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
779
- if (fk.onDelete) ddl += ` ON DELETE ${(0, __atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
780
- if (fk.onUpdate) ddl += ` ON UPDATE ${(0, __atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
799
+ if (fk.onDelete) ddl += ` ON DELETE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
800
+ if (fk.onUpdate) ddl += ` ON UPDATE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
781
801
  this._log(ddl);
782
802
  await this._exec().exec(ddl);
783
803
  }
@@ -788,7 +808,7 @@ else ddl += " DEFAULT NULL";
788
808
  const keySet = new Set(fkFieldKeys);
789
809
  const existingByName = await this._getExistingFkConstraints();
790
810
  for (const [constraintName, cols] of existingByName) {
791
- const key = cols.sort().join(",");
811
+ const key = cols.toSorted().join(",");
792
812
  if (keySet.has(key)) {
793
813
  const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} DROP FOREIGN KEY ${qi(constraintName)}`;
794
814
  this._log(ddl);
@@ -796,12 +816,13 @@ else ddl += " DEFAULT NULL";
796
816
  }
797
817
  }
798
818
  }
799
- /** Queries INFORMATION_SCHEMA for existing FK constraints, grouped by constraint name → column names. */ async _getExistingFkConstraints() {
819
+ /** Queries INFORMATION_SCHEMA for existing FK constraints, grouped by constraint name → column names. */
820
+ async _getExistingFkConstraints() {
800
821
  const rows = await this._exec().all(`SELECT kcu.CONSTRAINT_NAME, kcu.COLUMN_NAME
801
822
  FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
802
823
  WHERE kcu.TABLE_NAME = ? AND kcu.TABLE_SCHEMA = COALESCE(?, DATABASE())
803
824
  AND kcu.REFERENCED_TABLE_NAME IS NOT NULL`, [this._table.tableName, this._schema]);
804
- const byName = new Map();
825
+ const byName = /* @__PURE__ */ new Map();
805
826
  for (const row of rows) {
806
827
  let cols = byName.get(row.CONSTRAINT_NAME);
807
828
  if (!cols) {
@@ -843,8 +864,7 @@ else ddl += " DEFAULT NULL";
843
864
  const countPromise = (async () => {
844
865
  const sql = `SELECT COUNT(*) as cnt FROM ${quoteTableName(tableName)} WHERE ${combinedWhere.sql}`;
845
866
  this._log(sql, combinedWhere.params);
846
- const row = await this._exec().get(sql, combinedWhere.params);
847
- return row?.cnt ?? 0;
867
+ return (await this._exec().get(sql, combinedWhere.params))?.cnt ?? 0;
848
868
  })();
849
869
  const [data, count] = await Promise.all([selectPromise, countPromise]);
850
870
  return {
@@ -867,14 +887,14 @@ else ddl += " DEFAULT NULL";
867
887
  for (const index of this._table.indexes.values()) if (index.type === "fulltext") {
868
888
  if (!indexName || index.key === indexName) return index;
869
889
  }
870
- return undefined;
871
890
  }
872
891
  /**
873
892
  * Detects native VECTOR type support by inspecting the server version.
874
893
  * MySQL 9.0+ supports the VECTOR column type natively.
875
894
  * Caches the result for the lifetime of this adapter instance.
876
- */ async _detectVectorSupport() {
877
- if (this._supportsVector !== undefined) return this._supportsVector;
895
+ */
896
+ async _detectVectorSupport() {
897
+ if (this._supportsVector !== void 0) return this._supportsVector;
878
898
  try {
879
899
  const row = await this.driver.get("SELECT VERSION() as v", []);
880
900
  if (row?.v) {
@@ -909,7 +929,8 @@ else ddl += " DEFAULT NULL";
909
929
  count: countRow?.cnt ?? 0
910
930
  };
911
931
  }
912
- /** Resolves vector field and computes shared context for vector search SQL builders. */ _prepareVectorSearch(vector, query, indexName) {
932
+ /** Resolves vector field and computes shared context for vector search SQL builders. */
933
+ _prepareVectorSearch(vector, query, indexName) {
913
934
  let field;
914
935
  let vec;
915
936
  if (indexName) {
@@ -947,13 +968,13 @@ else ddl += " DEFAULT NULL";
947
968
  const inner = `SELECT *, ${ctx.distanceFn}(${qi(ctx.field)}, STRING_TO_VECTOR(?)) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${ctx.where.sql}`;
948
969
  const params = [ctx.vectorStr, ...ctx.where.params];
949
970
  let sql = `SELECT * FROM (${inner}) _v`;
950
- if (ctx.threshold !== undefined) {
971
+ if (ctx.threshold !== void 0) {
951
972
  sql += ` WHERE _distance <= ?`;
952
973
  params.push(2 * (1 - ctx.threshold));
953
974
  }
954
975
  sql += ` ORDER BY _distance ASC`;
955
- if (ctx.controls.$skip) sql += ` LIMIT ${ctx.controls.$limit || 1e3} OFFSET ${ctx.controls.$skip}`;
956
- else sql += ` LIMIT ${ctx.controls.$limit || 20}`;
976
+ if (ctx.controls.$skip) sql += ` LIMIT ${Number(ctx.controls.$limit) || 1e3} OFFSET ${Number(ctx.controls.$skip)}`;
977
+ else sql += ` LIMIT ${Number(ctx.controls.$limit) || 20}`;
957
978
  return {
958
979
  sql,
959
980
  params
@@ -964,7 +985,7 @@ else sql += ` LIMIT ${ctx.controls.$limit || 20}`;
964
985
  const inner = `SELECT ${ctx.distanceFn}(${qi(ctx.field)}, STRING_TO_VECTOR(?)) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${ctx.where.sql}`;
965
986
  const params = [ctx.vectorStr, ...ctx.where.params];
966
987
  let sql = `SELECT COUNT(*) AS cnt FROM (${inner}) _v`;
967
- if (ctx.threshold !== undefined) {
988
+ if (ctx.threshold !== void 0) {
968
989
  sql += ` WHERE _distance <= ?`;
969
990
  params.push(2 * (1 - ctx.threshold));
970
991
  }
@@ -973,16 +994,13 @@ else sql += ` LIMIT ${ctx.controls.$limit || 20}`;
973
994
  params
974
995
  };
975
996
  }
976
- /** Resolves threshold: query-time $threshold > schema-level @db.search.vector.threshold. */ _resolveVectorThreshold(controls, indexName) {
997
+ /** Resolves threshold: query-time $threshold > schema-level @db.search.vector.threshold. */
998
+ _resolveVectorThreshold(controls, indexName) {
977
999
  const queryThreshold = controls.$threshold;
978
- if (queryThreshold !== undefined) return queryThreshold;
1000
+ if (queryThreshold !== void 0) return queryThreshold;
979
1001
  return this._vectorThresholds.get(indexName);
980
1002
  }
981
- constructor(driver) {
982
- super(), _define_property$1(this, "driver", void 0), _define_property$1(this, "supportsColumnModify", void 0), _define_property$1(this, "_engine", void 0), _define_property$1(this, "_charset", void 0), _define_property$1(this, "_collation", void 0), _define_property$1(this, "_autoIncrementStart", void 0), _define_property$1(this, "_incrementFields", void 0), _define_property$1(this, "_onUpdateFields", void 0), _define_property$1(this, "_supportsVector", void 0), _define_property$1(this, "_vectorFields", void 0), _define_property$1(this, "_vectorThresholds", void 0), this.driver = driver, this.supportsColumnModify = true, this._engine = "InnoDB", this._charset = "utf8mb4", this._collation = "utf8mb4_unicode_ci", this._incrementFields = new Set(), this._onUpdateFields = new Map(), this._vectorFields = new Map(), this._vectorThresholds = new Map();
983
- }
984
1003
  };
985
- _define_property$1(MysqlAdapter, "NATIVE_DEFAULT_FNS", new Set(["now", "increment"]));
986
1004
  /**
987
1005
  * Normalizes MySQL INFORMATION_SCHEMA.COLUMNS.COLUMN_DEFAULT values
988
1006
  * to match the format produced by `serializeDefaultValue()`.
@@ -991,47 +1009,41 @@ _define_property$1(MysqlAdapter, "NATIVE_DEFAULT_FNS", new Set(["now", "incremen
991
1009
  * `uuid()`), but the diff engine compares against serialized form (`fn:now`,
992
1010
  * `fn:uuid`). Without normalization, every table with function defaults
993
1011
  * produces phantom ALTER diffs on re-plan.
994
- */ function normalizeMysqlDefault(value) {
995
- if (value === null) return undefined;
1012
+ */
1013
+ function normalizeMysqlDefault(value) {
1014
+ if (value === null) return;
996
1015
  const lower = value.toLowerCase();
997
1016
  if (lower === "current_timestamp" || lower === "current_timestamp()") return "fn:now";
998
1017
  if (lower === "uuid()") return "fn:uuid";
999
1018
  if (value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1).replace(/''/g, "'");
1000
1019
  return value;
1001
1020
  }
1002
- /** Maps generic similarity metric to MySQL 9+ distance function name. */ function similarityToMysqlFn(similarity) {
1021
+ /** Maps generic similarity metric to MySQL 9+ distance function name. */
1022
+ function similarityToMysqlFn(similarity) {
1003
1023
  switch (similarity) {
1004
1024
  case "euclidean": return "VEC_DISTANCE_EUCLIDEAN";
1005
1025
  case "dotProduct": return "VEC_DISTANCE_DOT";
1006
1026
  default: return "VEC_DISTANCE_COSINE";
1007
1027
  }
1008
1028
  }
1009
- /** Formats a number[] vector as MySQL's STRING_TO_VECTOR input: '[1.0, 2.0, ...]'. */ function vectorToString(vector) {
1029
+ /** Formats a number[] vector as MySQL's STRING_TO_VECTOR input: '[1.0, 2.0, ...]'. */
1030
+ function vectorToString(vector) {
1010
1031
  return `[${vector.join(",")}]`;
1011
1032
  }
1012
-
1013
1033
  //#endregion
1014
- //#region packages/db-mysql/src/mysql2-driver.ts
1015
- function _define_property(obj, key, value) {
1016
- if (key in obj) Object.defineProperty(obj, key, {
1017
- value,
1018
- enumerable: true,
1019
- configurable: true,
1020
- writable: true
1021
- });
1022
- else obj[key] = value;
1023
- return obj;
1024
- }
1025
- /** mysql2 rejects `undefined` in bind arrays — coerce to `null`. */ function sanitizeParams(params) {
1034
+ //#region src/mysql2-driver.ts
1035
+ /** mysql2 rejects `undefined` in bind arrays — coerce to `null`. */
1036
+ function sanitizeParams(params) {
1026
1037
  if (!params) return [];
1027
- return params.map((v) => v === undefined ? null : v);
1038
+ return params.map((v) => v === void 0 ? null : v);
1028
1039
  }
1029
1040
  /**
1030
1041
  * Custom type-casting for mysql2 result columns to maintain cross-adapter consistency.
1031
1042
  *
1032
1043
  * - TIMESTAMP/DATETIME → epoch milliseconds (number) instead of Date objects
1033
1044
  * - DECIMAL/NEWDECIMAL → number instead of string
1034
- */ function atscriptTypeCast(field, next) {
1045
+ */
1046
+ function atscriptTypeCast(field, next) {
1035
1047
  if (field.type === "TIMESTAMP" || field.type === "DATETIME") {
1036
1048
  const str = field.string();
1037
1049
  if (str === null) return null;
@@ -1043,13 +1055,66 @@ else obj[key] = value;
1043
1055
  }
1044
1056
  return next();
1045
1057
  }
1058
+ /**
1059
+ * {@link TMysqlDriver} implementation backed by `mysql2/promise`.
1060
+ *
1061
+ * Accepts a connection URI string, a `PoolOptions` object, or a pre-created
1062
+ * `Pool` instance from `mysql2/promise`.
1063
+ *
1064
+ * ```typescript
1065
+ * import { Mysql2Driver } from '@atscript/db-mysql'
1066
+ *
1067
+ * // Connection URI
1068
+ * const driver = new Mysql2Driver('mysql://root:pass@localhost:3306/mydb')
1069
+ *
1070
+ * // Pool options
1071
+ * const driver = new Mysql2Driver({
1072
+ * host: 'localhost',
1073
+ * user: 'root',
1074
+ * database: 'mydb',
1075
+ * waitForConnections: true,
1076
+ * connectionLimit: 10,
1077
+ * })
1078
+ *
1079
+ * // Pre-created pool
1080
+ * import mysql from 'mysql2/promise'
1081
+ * const pool = mysql.createPool({ host: 'localhost', database: 'mydb' })
1082
+ * const driver = new Mysql2Driver(pool)
1083
+ * ```
1084
+ *
1085
+ * Requires `mysql2` to be installed:
1086
+ * ```bash
1087
+ * pnpm add mysql2
1088
+ * ```
1089
+ */
1046
1090
  var Mysql2Driver = class {
1091
+ pool;
1092
+ poolInit;
1093
+ constructor(poolOrConfig) {
1094
+ if (typeof poolOrConfig === "object" && "execute" in poolOrConfig) this.pool = poolOrConfig;
1095
+ else this.poolInit = import("mysql2/promise").then((mysql) => {
1096
+ if (typeof poolOrConfig === "string") this.pool = mysql.createPool({
1097
+ uri: poolOrConfig,
1098
+ timezone: "+00:00",
1099
+ supportBigNumbers: true,
1100
+ bigNumberStrings: false,
1101
+ typeCast: atscriptTypeCast
1102
+ });
1103
+ else this.pool = mysql.createPool({
1104
+ ...poolOrConfig,
1105
+ timezone: "+00:00",
1106
+ supportBigNumbers: true,
1107
+ bigNumberStrings: false,
1108
+ typeCast: atscriptTypeCast
1109
+ });
1110
+ return this.pool;
1111
+ });
1112
+ }
1047
1113
  getPool() {
1048
1114
  return this.pool || this.poolInit;
1049
1115
  }
1050
1116
  async run(sql, params) {
1051
- const pool = await this.getPool();
1052
- const [result] = await pool.query(sql, sanitizeParams(params));
1117
+ const [result] = await (await this.getPool()).query(sql, sanitizeParams(params));
1053
1118
  const header = result;
1054
1119
  return {
1055
1120
  affectedRows: header.affectedRows ?? 0,
@@ -1058,22 +1123,18 @@ var Mysql2Driver = class {
1058
1123
  };
1059
1124
  }
1060
1125
  async all(sql, params) {
1061
- const pool = await this.getPool();
1062
- const [rows] = await pool.query(sql, sanitizeParams(params));
1126
+ const [rows] = await (await this.getPool()).query(sql, sanitizeParams(params));
1063
1127
  return rows;
1064
1128
  }
1065
1129
  async get(sql, params) {
1066
- const pool = await this.getPool();
1067
- const [rows] = await pool.query(sql, sanitizeParams(params));
1130
+ const [rows] = await (await this.getPool()).query(sql, sanitizeParams(params));
1068
1131
  return rows[0] ?? null;
1069
1132
  }
1070
1133
  async exec(sql) {
1071
- const pool = await this.getPool();
1072
- await pool.query(sql);
1134
+ await (await this.getPool()).query(sql);
1073
1135
  }
1074
1136
  async getConnection() {
1075
- const pool = await this.getPool();
1076
- const conn = await pool.getConnection();
1137
+ const conn = await (await this.getPool()).getConnection();
1077
1138
  return {
1078
1139
  async run(sql, params) {
1079
1140
  const [result] = await conn.query(sql, sanitizeParams(params));
@@ -1101,130 +1162,28 @@ var Mysql2Driver = class {
1101
1162
  };
1102
1163
  }
1103
1164
  async close() {
1104
- const pool = await this.getPool();
1105
- await pool.end();
1106
- }
1107
- constructor(poolOrConfig) {
1108
- _define_property(this, "pool", void 0);
1109
- _define_property(this, "poolInit", void 0);
1110
- if (typeof poolOrConfig === "object" && "execute" in poolOrConfig) this.pool = poolOrConfig;
1111
- else this.poolInit = import("mysql2/promise").then((mysql) => {
1112
- if (typeof poolOrConfig === "string") this.pool = mysql.createPool({
1113
- uri: poolOrConfig,
1114
- timezone: "+00:00",
1115
- supportBigNumbers: true,
1116
- bigNumberStrings: false,
1117
- typeCast: atscriptTypeCast
1118
- });
1119
- else this.pool = mysql.createPool({
1120
- ...poolOrConfig,
1121
- timezone: "+00:00",
1122
- supportBigNumbers: true,
1123
- bigNumberStrings: false,
1124
- typeCast: atscriptTypeCast
1125
- });
1126
- return this.pool;
1127
- });
1165
+ await (await this.getPool()).end();
1128
1166
  }
1129
1167
  };
1130
-
1131
1168
  //#endregion
1132
- //#region packages/db-mysql/src/plugin/annotations.ts
1133
- const annotations = {
1134
- engine: new __atscript_core.AnnotationSpec({
1135
- description: "Specifies the MySQL storage engine.\n\n**Default:** `\"InnoDB\"`\n\n```atscript\n@db.mysql.engine \"MyISAM\"\nexport interface Logs { ... }\n```",
1136
- nodeType: ["interface"],
1137
- multiple: false,
1138
- argument: {
1139
- name: "engine",
1140
- type: "string",
1141
- values: [
1142
- "InnoDB",
1143
- "MyISAM",
1144
- "MEMORY",
1145
- "CSV",
1146
- "ARCHIVE"
1147
- ],
1148
- description: "MySQL storage engine name."
1149
- }
1150
- }),
1151
- charset: new __atscript_core.AnnotationSpec({
1152
- description: "Specifies the character set for the table or column.\n\n**Default:** `\"utf8mb4\"`\n\n```atscript\n@db.mysql.charset \"latin1\"\nexport interface Legacy { ... }\n```",
1153
- nodeType: ["interface", "prop"],
1154
- multiple: false,
1155
- argument: {
1156
- name: "charset",
1157
- type: "string",
1158
- values: [
1159
- "utf8mb4",
1160
- "utf8",
1161
- "latin1",
1162
- "ascii",
1163
- "binary"
1164
- ],
1165
- description: "MySQL character set name."
1166
- }
1167
- }),
1168
- collate: new __atscript_core.AnnotationSpec({
1169
- description: "Specifies a native MySQL collation (overrides portable `@db.column.collate`).\n\n```atscript\n@db.mysql.collate \"utf8mb4_turkish_ci\"\nname: string\n```",
1170
- nodeType: ["interface", "prop"],
1171
- multiple: false,
1172
- argument: {
1173
- name: "collation",
1174
- type: "string",
1175
- description: "Native MySQL collation name (e.g., \"utf8mb4_turkish_ci\")."
1176
- }
1177
- }),
1178
- unsigned: new __atscript_core.AnnotationSpec({
1179
- description: "Adds the UNSIGNED modifier to an integer column.\n\n```atscript\n@db.mysql.unsigned\nage: number.int\n```",
1180
- nodeType: ["prop"],
1181
- multiple: false
1182
- }),
1183
- type: new __atscript_core.AnnotationSpec({
1184
- description: "Overrides the native MySQL column type.\n\n```atscript\n@db.mysql.type \"MEDIUMTEXT\"\nbio: string\n```",
1185
- nodeType: ["prop"],
1186
- multiple: false,
1187
- argument: {
1188
- name: "type",
1189
- type: "string",
1190
- description: "Native MySQL column type (e.g., \"MEDIUMTEXT\", \"TINYTEXT\")."
1191
- }
1192
- }),
1193
- onUpdate: new __atscript_core.AnnotationSpec({
1194
- description: "Sets the MySQL ON UPDATE clause for a column.\n\n```atscript\n@db.mysql.onUpdate \"CURRENT_TIMESTAMP\"\nupdatedAt: number.timestamp\n```",
1195
- nodeType: ["prop"],
1196
- multiple: false,
1197
- argument: {
1198
- name: "expression",
1199
- type: "string",
1200
- values: ["CURRENT_TIMESTAMP"],
1201
- description: "Expression to evaluate on row update."
1202
- }
1203
- })
1204
- };
1205
-
1206
- //#endregion
1207
- //#region packages/db-mysql/src/plugin/index.ts
1208
- const MysqlPlugin = () => ({
1209
- name: "mysql",
1210
- config() {
1211
- return { annotations: { db: { mysql: annotations } } };
1212
- }
1213
- });
1214
-
1215
- //#endregion
1216
- //#region packages/db-mysql/src/index.ts
1169
+ //#region src/index.ts
1170
+ /**
1171
+ * Creates a {@link DbSpace} backed by a MySQL connection pool.
1172
+ *
1173
+ * @param uri - MySQL connection URI (e.g., `mysql://root@localhost:3306/mydb`)
1174
+ * @param options - Additional pool options passed to mysql2.
1175
+ * @returns A `DbSpace` that creates `MysqlAdapter` instances per table.
1176
+ */
1217
1177
  function createAdapter(uri, options) {
1218
1178
  const driver = new Mysql2Driver({
1219
1179
  uri,
1220
1180
  ...options
1221
1181
  });
1222
- return new __atscript_db.DbSpace(() => new MysqlAdapter(driver));
1182
+ return new _atscript_db.DbSpace(() => new MysqlAdapter(driver));
1223
1183
  }
1224
-
1225
1184
  //#endregion
1226
- exports.Mysql2Driver = Mysql2Driver
1227
- exports.MysqlAdapter = MysqlAdapter
1228
- exports.MysqlPlugin = MysqlPlugin
1229
- exports.buildWhere = buildWhere
1230
- exports.createAdapter = createAdapter
1185
+ exports.Mysql2Driver = Mysql2Driver;
1186
+ exports.MysqlAdapter = MysqlAdapter;
1187
+ exports.MysqlPlugin = require_plugin.MysqlPlugin;
1188
+ exports.buildWhere = buildWhere;
1189
+ exports.createAdapter = createAdapter;