@db-bridge/core 1.0.0 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  import { createHash, pbkdf2Sync, randomBytes, createCipheriv, createDecipheriv } from 'crypto';
2
2
  import { constants, gzipSync, gunzipSync } from 'zlib';
3
3
  import { EventEmitter } from 'eventemitter3';
4
+ import { readdir, readFile } from 'fs/promises';
5
+ import { extname, join, basename, resolve } from 'path';
6
+ import { pathToFileURL } from 'url';
7
+ import { hostname } from 'os';
4
8
 
5
9
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
10
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -351,7 +355,7 @@ async function withTimeout(promise, timeoutMs, message) {
351
355
  }
352
356
  }
353
357
  function sleep(ms) {
354
- return new Promise((resolve) => setTimeout(resolve, ms));
358
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
355
359
  }
356
360
 
357
361
  // src/utils/validation.ts
@@ -1657,7 +1661,7 @@ var HealthChecker = class {
1657
1661
  if (result.status === "healthy") {
1658
1662
  return;
1659
1663
  }
1660
- await new Promise((resolve) => setTimeout(resolve, 1e3));
1664
+ await new Promise((resolve2) => setTimeout(resolve2, 1e3));
1661
1665
  }
1662
1666
  throw new Error(`Health check did not become healthy within ${maxWaitTime}ms`);
1663
1667
  }
@@ -2105,6 +2109,2533 @@ var MigrationRunner = class {
2105
2109
  };
2106
2110
  }
2107
2111
  };
2112
+ var MIGRATION_PATTERN = /^(\d{14})_(.+)\.(ts|js|mjs)$/;
2113
+ var MigrationLoader = class {
2114
+ directory;
2115
+ extensions;
2116
+ constructor(directory, extensions = [".ts", ".js", ".mjs"]) {
2117
+ this.directory = directory;
2118
+ this.extensions = extensions;
2119
+ }
2120
+ /**
2121
+ * Scan directory for migration files
2122
+ */
2123
+ async scanDirectory() {
2124
+ const files = [];
2125
+ try {
2126
+ const entries = await readdir(this.directory, { withFileTypes: true });
2127
+ for (const entry of entries) {
2128
+ if (!entry.isFile()) {
2129
+ continue;
2130
+ }
2131
+ const ext = extname(entry.name);
2132
+ if (!this.extensions.includes(ext)) {
2133
+ continue;
2134
+ }
2135
+ const match = entry.name.match(MIGRATION_PATTERN);
2136
+ if (!match) {
2137
+ continue;
2138
+ }
2139
+ const [, timestamp, description] = match;
2140
+ files.push({
2141
+ name: basename(entry.name, ext),
2142
+ path: join(this.directory, entry.name),
2143
+ timestamp,
2144
+ description: description.replaceAll("_", " ")
2145
+ });
2146
+ }
2147
+ files.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
2148
+ return files;
2149
+ } catch (error) {
2150
+ if (error.code === "ENOENT") {
2151
+ throw new Error(`Migration directory not found: ${this.directory}`);
2152
+ }
2153
+ throw error;
2154
+ }
2155
+ }
2156
+ /**
2157
+ * Load a single migration file
2158
+ */
2159
+ async loadMigration(file) {
2160
+ try {
2161
+ const fileUrl = pathToFileURL(file.path).href;
2162
+ const module = await import(fileUrl);
2163
+ const migration = module.default || module;
2164
+ if (typeof migration.up !== "function") {
2165
+ throw new TypeError(`Migration ${file.name} is missing 'up' function`);
2166
+ }
2167
+ if (typeof migration.down !== "function") {
2168
+ throw new TypeError(`Migration ${file.name} is missing 'down' function`);
2169
+ }
2170
+ return {
2171
+ name: file.name,
2172
+ up: migration.up,
2173
+ down: migration.down,
2174
+ transactional: migration.transactional ?? true,
2175
+ phase: migration.phase
2176
+ };
2177
+ } catch (error) {
2178
+ throw new Error(`Failed to load migration ${file.name}: ${error.message}`);
2179
+ }
2180
+ }
2181
+ /**
2182
+ * Load all migrations from directory
2183
+ */
2184
+ async loadAll() {
2185
+ const files = await this.scanDirectory();
2186
+ const migrations = [];
2187
+ for (const file of files) {
2188
+ const migration = await this.loadMigration(file);
2189
+ migrations.push(migration);
2190
+ }
2191
+ return migrations;
2192
+ }
2193
+ /**
2194
+ * Get migration files (metadata only, without loading)
2195
+ */
2196
+ async getMigrationFiles() {
2197
+ return this.scanDirectory();
2198
+ }
2199
+ /**
2200
+ * Calculate checksum for a migration file
2201
+ */
2202
+ async calculateChecksum(file) {
2203
+ const content = await readFile(file.path, "utf8");
2204
+ const normalized = content.replaceAll("\r\n", "\n").trim();
2205
+ return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
2206
+ }
2207
+ /**
2208
+ * Calculate checksums for all migration files
2209
+ */
2210
+ async calculateAllChecksums() {
2211
+ const files = await this.scanDirectory();
2212
+ const checksums = /* @__PURE__ */ new Map();
2213
+ for (const file of files) {
2214
+ const checksum = await this.calculateChecksum(file);
2215
+ checksums.set(file.name, checksum);
2216
+ }
2217
+ return checksums;
2218
+ }
2219
+ /**
2220
+ * Generate a new migration filename
2221
+ */
2222
+ static generateFilename(description) {
2223
+ const now = /* @__PURE__ */ new Date();
2224
+ const timestamp = [
2225
+ now.getFullYear(),
2226
+ String(now.getMonth() + 1).padStart(2, "0"),
2227
+ String(now.getDate()).padStart(2, "0"),
2228
+ String(now.getHours()).padStart(2, "0"),
2229
+ String(now.getMinutes()).padStart(2, "0"),
2230
+ String(now.getSeconds()).padStart(2, "0")
2231
+ ].join("");
2232
+ const sanitizedDescription = description.toLowerCase().replaceAll(/[^\da-z]+/g, "_").replaceAll(/^_+|_+$/g, "");
2233
+ return `${timestamp}_${sanitizedDescription}.ts`;
2234
+ }
2235
+ /**
2236
+ * Get migration template content
2237
+ */
2238
+ static getMigrationTemplate(name) {
2239
+ return `/**
2240
+ * Migration: ${name}
2241
+ * Created at: ${(/* @__PURE__ */ new Date()).toISOString()}
2242
+ */
2243
+
2244
+ import type { SchemaBuilder } from '@db-bridge/core';
2245
+
2246
+ export default {
2247
+ name: '${name}',
2248
+
2249
+ async up(schema: SchemaBuilder): Promise<void> {
2250
+ // Write your migration here
2251
+ // Example:
2252
+ // await schema.createTable('users', (table) => {
2253
+ // table.increments('id');
2254
+ // table.string('email', 255).unique().notNull();
2255
+ // table.timestamps();
2256
+ // });
2257
+ },
2258
+
2259
+ async down(schema: SchemaBuilder): Promise<void> {
2260
+ // Reverse the migration
2261
+ // Example:
2262
+ // await schema.dropTableIfExists('users');
2263
+ },
2264
+ };
2265
+ `;
2266
+ }
2267
+ };
2268
+
2269
+ // src/schema/dialects/MySQLDialect.ts
2270
+ var MySQLDialect = class {
2271
+ dialect = "mysql";
2272
+ /**
2273
+ * Quote an identifier (table/column name)
2274
+ */
2275
+ quoteIdentifier(name) {
2276
+ return `\`${name.replaceAll("`", "``")}\``;
2277
+ }
2278
+ /**
2279
+ * Quote a value for SQL
2280
+ */
2281
+ quoteValue(value) {
2282
+ if (value === null || value === void 0) {
2283
+ return "NULL";
2284
+ }
2285
+ if (typeof value === "boolean") {
2286
+ return value ? "1" : "0";
2287
+ }
2288
+ if (typeof value === "number") {
2289
+ return String(value);
2290
+ }
2291
+ if (typeof value === "string") {
2292
+ return `'${value.replaceAll("'", "''")}'`;
2293
+ }
2294
+ return `'${String(value).replaceAll("'", "''")}'`;
2295
+ }
2296
+ /**
2297
+ * Generate CREATE TABLE statement
2298
+ */
2299
+ createTable(definition) {
2300
+ const parts = [];
2301
+ for (const column of definition.columns) {
2302
+ parts.push(this.columnToSQL(column));
2303
+ }
2304
+ if (definition.primaryKey && definition.primaryKey.length > 0) {
2305
+ const pkColumns = definition.primaryKey.map((c) => this.quoteIdentifier(c)).join(", ");
2306
+ parts.push(`PRIMARY KEY (${pkColumns})`);
2307
+ }
2308
+ for (const index of definition.indexes) {
2309
+ parts.push(this.indexToSQL(index));
2310
+ }
2311
+ for (const fk of definition.foreignKeys) {
2312
+ parts.push(this.foreignKeyToSQL(fk));
2313
+ }
2314
+ let sql2 = `CREATE TABLE ${this.quoteIdentifier(definition.name)} (
2315
+ ${parts.join(",\n ")}
2316
+ )`;
2317
+ const options = [];
2318
+ if (definition.engine) {
2319
+ options.push(`ENGINE=${definition.engine}`);
2320
+ } else {
2321
+ options.push("ENGINE=InnoDB");
2322
+ }
2323
+ if (definition.charset) {
2324
+ options.push(`DEFAULT CHARSET=${definition.charset}`);
2325
+ } else {
2326
+ options.push("DEFAULT CHARSET=utf8mb4");
2327
+ }
2328
+ if (definition.collation) {
2329
+ options.push(`COLLATE=${definition.collation}`);
2330
+ }
2331
+ if (definition.comment) {
2332
+ options.push(`COMMENT=${this.quoteValue(definition.comment)}`);
2333
+ }
2334
+ if (options.length > 0) {
2335
+ sql2 += ` ${options.join(" ")}`;
2336
+ }
2337
+ return sql2;
2338
+ }
2339
+ /**
2340
+ * Generate DROP TABLE statement
2341
+ */
2342
+ dropTable(tableName) {
2343
+ return `DROP TABLE ${this.quoteIdentifier(tableName)}`;
2344
+ }
2345
+ /**
2346
+ * Generate DROP TABLE IF EXISTS statement
2347
+ */
2348
+ dropTableIfExists(tableName) {
2349
+ return `DROP TABLE IF EXISTS ${this.quoteIdentifier(tableName)}`;
2350
+ }
2351
+ /**
2352
+ * Generate RENAME TABLE statement
2353
+ */
2354
+ renameTable(from, to) {
2355
+ return `RENAME TABLE ${this.quoteIdentifier(from)} TO ${this.quoteIdentifier(to)}`;
2356
+ }
2357
+ /**
2358
+ * Generate ALTER TABLE statements
2359
+ */
2360
+ alterTable(definition) {
2361
+ const statements = [];
2362
+ const tableName = this.quoteIdentifier(definition.tableName);
2363
+ for (const op of definition.operations) {
2364
+ switch (op.type) {
2365
+ case "addColumn": {
2366
+ statements.push(`ALTER TABLE ${tableName} ADD COLUMN ${this.columnToSQL(op.column)}`);
2367
+ break;
2368
+ }
2369
+ case "dropColumn": {
2370
+ statements.push(`ALTER TABLE ${tableName} DROP COLUMN ${this.quoteIdentifier(op.name)}`);
2371
+ break;
2372
+ }
2373
+ case "renameColumn": {
2374
+ statements.push(
2375
+ `ALTER TABLE ${tableName} RENAME COLUMN ${this.quoteIdentifier(op.from)} TO ${this.quoteIdentifier(op.to)}`
2376
+ );
2377
+ break;
2378
+ }
2379
+ case "modifyColumn": {
2380
+ statements.push(`ALTER TABLE ${tableName} MODIFY COLUMN ${this.columnToSQL(op.column)}`);
2381
+ break;
2382
+ }
2383
+ case "addIndex": {
2384
+ statements.push(`ALTER TABLE ${tableName} ADD ${this.indexToSQL(op.index)}`);
2385
+ break;
2386
+ }
2387
+ case "dropIndex": {
2388
+ statements.push(`ALTER TABLE ${tableName} DROP INDEX ${this.quoteIdentifier(op.name)}`);
2389
+ break;
2390
+ }
2391
+ case "addForeignKey": {
2392
+ statements.push(`ALTER TABLE ${tableName} ADD ${this.foreignKeyToSQL(op.foreignKey)}`);
2393
+ break;
2394
+ }
2395
+ case "dropForeignKey": {
2396
+ statements.push(
2397
+ `ALTER TABLE ${tableName} DROP FOREIGN KEY ${this.quoteIdentifier(op.name)}`
2398
+ );
2399
+ break;
2400
+ }
2401
+ case "addPrimary": {
2402
+ const pkCols = op.columns.map((c) => this.quoteIdentifier(c)).join(", ");
2403
+ statements.push(`ALTER TABLE ${tableName} ADD PRIMARY KEY (${pkCols})`);
2404
+ break;
2405
+ }
2406
+ case "dropPrimary": {
2407
+ statements.push(`ALTER TABLE ${tableName} DROP PRIMARY KEY`);
2408
+ break;
2409
+ }
2410
+ }
2411
+ }
2412
+ return statements;
2413
+ }
2414
+ /**
2415
+ * Generate query to check if table exists
2416
+ */
2417
+ hasTable(tableName) {
2418
+ return `SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ${this.quoteValue(tableName)} LIMIT 1`;
2419
+ }
2420
+ /**
2421
+ * Generate query to check if column exists
2422
+ */
2423
+ hasColumn(tableName, columnName) {
2424
+ return `SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = ${this.quoteValue(tableName)} AND column_name = ${this.quoteValue(columnName)} LIMIT 1`;
2425
+ }
2426
+ /**
2427
+ * Convert column definition to SQL
2428
+ */
2429
+ columnToSQL(column) {
2430
+ const parts = [this.quoteIdentifier(column.name)];
2431
+ parts.push(this.columnTypeToSQL(column));
2432
+ if (column.unsigned) {
2433
+ parts.push("UNSIGNED");
2434
+ }
2435
+ if (column.nullable) {
2436
+ parts.push("NULL");
2437
+ } else {
2438
+ parts.push("NOT NULL");
2439
+ }
2440
+ if (column.defaultRaw) {
2441
+ parts.push(`DEFAULT ${column.defaultRaw}`);
2442
+ } else if (column.defaultValue !== void 0) {
2443
+ parts.push(`DEFAULT ${this.quoteValue(column.defaultValue)}`);
2444
+ }
2445
+ if (column.autoIncrement) {
2446
+ parts.push("AUTO_INCREMENT");
2447
+ }
2448
+ if (column.primary && !column.autoIncrement) {
2449
+ parts.push("PRIMARY KEY");
2450
+ } else if (column.primary && column.autoIncrement) {
2451
+ parts.push("PRIMARY KEY");
2452
+ }
2453
+ if (column.unique && !column.primary) {
2454
+ parts.push("UNIQUE");
2455
+ }
2456
+ if (column.comment) {
2457
+ parts.push(`COMMENT ${this.quoteValue(column.comment)}`);
2458
+ }
2459
+ if (column.first) {
2460
+ parts.push("FIRST");
2461
+ } else if (column.after) {
2462
+ parts.push(`AFTER ${this.quoteIdentifier(column.after)}`);
2463
+ }
2464
+ return parts.join(" ");
2465
+ }
2466
+ /**
2467
+ * Convert column type to MySQL type
2468
+ */
2469
+ columnTypeToSQL(column) {
2470
+ switch (column.type) {
2471
+ case "increments": {
2472
+ return "INT UNSIGNED AUTO_INCREMENT";
2473
+ }
2474
+ case "bigIncrements": {
2475
+ return "BIGINT UNSIGNED AUTO_INCREMENT";
2476
+ }
2477
+ case "integer": {
2478
+ return "INT";
2479
+ }
2480
+ case "bigInteger": {
2481
+ return "BIGINT";
2482
+ }
2483
+ case "smallInteger": {
2484
+ return "SMALLINT";
2485
+ }
2486
+ case "tinyInteger": {
2487
+ return "TINYINT";
2488
+ }
2489
+ case "float": {
2490
+ return "FLOAT";
2491
+ }
2492
+ case "double": {
2493
+ return "DOUBLE";
2494
+ }
2495
+ case "decimal": {
2496
+ const precision = column.precision ?? 10;
2497
+ const scale = column.scale ?? 2;
2498
+ return `DECIMAL(${precision},${scale})`;
2499
+ }
2500
+ case "string": {
2501
+ return `VARCHAR(${column.length ?? 255})`;
2502
+ }
2503
+ case "text": {
2504
+ return "TEXT";
2505
+ }
2506
+ case "mediumText": {
2507
+ return "MEDIUMTEXT";
2508
+ }
2509
+ case "longText": {
2510
+ return "LONGTEXT";
2511
+ }
2512
+ case "boolean": {
2513
+ return "TINYINT(1)";
2514
+ }
2515
+ case "date": {
2516
+ return "DATE";
2517
+ }
2518
+ case "datetime": {
2519
+ return "DATETIME";
2520
+ }
2521
+ case "timestamp": {
2522
+ return "TIMESTAMP";
2523
+ }
2524
+ case "time": {
2525
+ return "TIME";
2526
+ }
2527
+ case "json":
2528
+ case "jsonb": {
2529
+ return "JSON";
2530
+ }
2531
+ case "uuid": {
2532
+ return "CHAR(36)";
2533
+ }
2534
+ case "binary": {
2535
+ return "BLOB";
2536
+ }
2537
+ case "enum": {
2538
+ if (column.enumValues && column.enumValues.length > 0) {
2539
+ const values = column.enumValues.map((v) => this.quoteValue(v)).join(", ");
2540
+ return `ENUM(${values})`;
2541
+ }
2542
+ return "VARCHAR(255)";
2543
+ }
2544
+ default: {
2545
+ return "VARCHAR(255)";
2546
+ }
2547
+ }
2548
+ }
2549
+ /**
2550
+ * Convert index definition to SQL
2551
+ */
2552
+ indexToSQL(index) {
2553
+ const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
2554
+ const name = index.name ? this.quoteIdentifier(index.name) : "";
2555
+ if (index.type === "fulltext") {
2556
+ return `FULLTEXT INDEX ${name} (${columns})`;
2557
+ }
2558
+ if (index.unique) {
2559
+ return `UNIQUE INDEX ${name} (${columns})`;
2560
+ }
2561
+ return `INDEX ${name} (${columns})`;
2562
+ }
2563
+ /**
2564
+ * Convert foreign key definition to SQL
2565
+ */
2566
+ foreignKeyToSQL(fk) {
2567
+ const parts = ["CONSTRAINT"];
2568
+ if (fk.name) {
2569
+ parts.push(this.quoteIdentifier(fk.name));
2570
+ }
2571
+ parts.push(`FOREIGN KEY (${this.quoteIdentifier(fk.column)})`);
2572
+ parts.push(
2573
+ `REFERENCES ${this.quoteIdentifier(fk.table)} (${this.quoteIdentifier(fk.referenceColumn)})`
2574
+ );
2575
+ if (fk.onDelete) {
2576
+ parts.push(`ON DELETE ${fk.onDelete}`);
2577
+ }
2578
+ if (fk.onUpdate) {
2579
+ parts.push(`ON UPDATE ${fk.onUpdate}`);
2580
+ }
2581
+ return parts.join(" ");
2582
+ }
2583
+ };
2584
+
2585
+ // src/schema/dialects/PostgreSQLDialect.ts
2586
+ var PostgreSQLDialect = class {
2587
+ dialect = "postgresql";
2588
+ /**
2589
+ * Quote an identifier (table/column name)
2590
+ */
2591
+ quoteIdentifier(name) {
2592
+ return `"${name.replaceAll('"', '""')}"`;
2593
+ }
2594
+ /**
2595
+ * Quote a value for SQL
2596
+ */
2597
+ quoteValue(value) {
2598
+ if (value === null || value === void 0) {
2599
+ return "NULL";
2600
+ }
2601
+ if (typeof value === "boolean") {
2602
+ return value ? "TRUE" : "FALSE";
2603
+ }
2604
+ if (typeof value === "number") {
2605
+ return String(value);
2606
+ }
2607
+ if (typeof value === "string") {
2608
+ return `'${value.replaceAll("'", "''")}'`;
2609
+ }
2610
+ return `'${String(value).replaceAll("'", "''")}'`;
2611
+ }
2612
+ /**
2613
+ * Generate CREATE TABLE statement
2614
+ */
2615
+ createTable(definition) {
2616
+ const parts = [];
2617
+ for (const column of definition.columns) {
2618
+ parts.push(this.columnToSQL(column));
2619
+ }
2620
+ if (definition.primaryKey && definition.primaryKey.length > 0) {
2621
+ const pkColumns = definition.primaryKey.map((c) => this.quoteIdentifier(c)).join(", ");
2622
+ parts.push(`PRIMARY KEY (${pkColumns})`);
2623
+ }
2624
+ for (const fk of definition.foreignKeys) {
2625
+ parts.push(this.foreignKeyToSQL(fk));
2626
+ }
2627
+ const sql2 = `CREATE TABLE ${this.quoteIdentifier(definition.name)} (
2628
+ ${parts.join(",\n ")}
2629
+ )`;
2630
+ const statements = [sql2];
2631
+ if (definition.comment) {
2632
+ statements.push(
2633
+ `COMMENT ON TABLE ${this.quoteIdentifier(definition.name)} IS ${this.quoteValue(definition.comment)}`
2634
+ );
2635
+ }
2636
+ return statements.join(";\n");
2637
+ }
2638
+ /**
2639
+ * Generate DROP TABLE statement
2640
+ */
2641
+ dropTable(tableName) {
2642
+ return `DROP TABLE ${this.quoteIdentifier(tableName)}`;
2643
+ }
2644
+ /**
2645
+ * Generate DROP TABLE IF EXISTS statement
2646
+ */
2647
+ dropTableIfExists(tableName) {
2648
+ return `DROP TABLE IF EXISTS ${this.quoteIdentifier(tableName)}`;
2649
+ }
2650
+ /**
2651
+ * Generate ALTER TABLE ... RENAME statement
2652
+ */
2653
+ renameTable(from, to) {
2654
+ return `ALTER TABLE ${this.quoteIdentifier(from)} RENAME TO ${this.quoteIdentifier(to)}`;
2655
+ }
2656
+ /**
2657
+ * Generate ALTER TABLE statements
2658
+ */
2659
+ alterTable(definition) {
2660
+ const statements = [];
2661
+ const tableName = this.quoteIdentifier(definition.tableName);
2662
+ for (const op of definition.operations) {
2663
+ switch (op.type) {
2664
+ case "addColumn": {
2665
+ statements.push(`ALTER TABLE ${tableName} ADD COLUMN ${this.columnToSQL(op.column)}`);
2666
+ break;
2667
+ }
2668
+ case "dropColumn": {
2669
+ statements.push(`ALTER TABLE ${tableName} DROP COLUMN ${this.quoteIdentifier(op.name)}`);
2670
+ break;
2671
+ }
2672
+ case "renameColumn": {
2673
+ statements.push(
2674
+ `ALTER TABLE ${tableName} RENAME COLUMN ${this.quoteIdentifier(op.from)} TO ${this.quoteIdentifier(op.to)}`
2675
+ );
2676
+ break;
2677
+ }
2678
+ case "modifyColumn": {
2679
+ const col = op.column;
2680
+ statements.push(
2681
+ `ALTER TABLE ${tableName} ALTER COLUMN ${this.quoteIdentifier(col.name)} TYPE ${this.columnTypeToSQL(col)}`
2682
+ );
2683
+ if (col.nullable) {
2684
+ statements.push(
2685
+ `ALTER TABLE ${tableName} ALTER COLUMN ${this.quoteIdentifier(col.name)} DROP NOT NULL`
2686
+ );
2687
+ } else {
2688
+ statements.push(
2689
+ `ALTER TABLE ${tableName} ALTER COLUMN ${this.quoteIdentifier(col.name)} SET NOT NULL`
2690
+ );
2691
+ }
2692
+ if (col.defaultRaw) {
2693
+ statements.push(
2694
+ `ALTER TABLE ${tableName} ALTER COLUMN ${this.quoteIdentifier(col.name)} SET DEFAULT ${col.defaultRaw}`
2695
+ );
2696
+ } else if (col.defaultValue !== void 0) {
2697
+ statements.push(
2698
+ `ALTER TABLE ${tableName} ALTER COLUMN ${this.quoteIdentifier(col.name)} SET DEFAULT ${this.quoteValue(col.defaultValue)}`
2699
+ );
2700
+ }
2701
+ break;
2702
+ }
2703
+ case "addIndex": {
2704
+ statements.push(this.createIndex(definition.tableName, op.index));
2705
+ break;
2706
+ }
2707
+ case "dropIndex": {
2708
+ statements.push(`DROP INDEX ${this.quoteIdentifier(op.name)}`);
2709
+ break;
2710
+ }
2711
+ case "addForeignKey": {
2712
+ statements.push(`ALTER TABLE ${tableName} ADD ${this.foreignKeyToSQL(op.foreignKey)}`);
2713
+ break;
2714
+ }
2715
+ case "dropForeignKey": {
2716
+ statements.push(
2717
+ `ALTER TABLE ${tableName} DROP CONSTRAINT ${this.quoteIdentifier(op.name)}`
2718
+ );
2719
+ break;
2720
+ }
2721
+ case "addPrimary": {
2722
+ const pkCols = op.columns.map((c) => this.quoteIdentifier(c)).join(", ");
2723
+ statements.push(`ALTER TABLE ${tableName} ADD PRIMARY KEY (${pkCols})`);
2724
+ break;
2725
+ }
2726
+ case "dropPrimary": {
2727
+ statements.push(
2728
+ `ALTER TABLE ${tableName} DROP CONSTRAINT ${this.quoteIdentifier(`${definition.tableName}_pkey`)}`
2729
+ );
2730
+ break;
2731
+ }
2732
+ }
2733
+ }
2734
+ return statements;
2735
+ }
2736
+ /**
2737
+ * Generate query to check if table exists
2738
+ */
2739
+ hasTable(tableName) {
2740
+ return `SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = ${this.quoteValue(tableName)} LIMIT 1`;
2741
+ }
2742
+ /**
2743
+ * Generate query to check if column exists
2744
+ */
2745
+ hasColumn(tableName, columnName) {
2746
+ return `SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = ${this.quoteValue(tableName)} AND column_name = ${this.quoteValue(columnName)} LIMIT 1`;
2747
+ }
2748
+ /**
2749
+ * Create index statement
2750
+ */
2751
+ createIndex(tableName, index) {
2752
+ const columns = index.columns.map((c) => this.quoteIdentifier(c)).join(", ");
2753
+ const indexName = index.name || `idx_${tableName}_${index.columns.join("_")}`;
2754
+ const unique = index.unique ? "UNIQUE " : "";
2755
+ return `CREATE ${unique}INDEX ${this.quoteIdentifier(indexName)} ON ${this.quoteIdentifier(tableName)} (${columns})`;
2756
+ }
2757
+ /**
2758
+ * Convert column definition to SQL
2759
+ */
2760
+ columnToSQL(column) {
2761
+ const parts = [this.quoteIdentifier(column.name)];
2762
+ parts.push(this.columnTypeToSQL(column));
2763
+ if (!column.nullable) {
2764
+ parts.push("NOT NULL");
2765
+ }
2766
+ if (column.defaultRaw) {
2767
+ parts.push(`DEFAULT ${column.defaultRaw}`);
2768
+ } else if (column.defaultValue !== void 0) {
2769
+ parts.push(`DEFAULT ${this.quoteValue(column.defaultValue)}`);
2770
+ }
2771
+ if (column.primary && column.type !== "increments" && column.type !== "bigIncrements") {
2772
+ parts.push("PRIMARY KEY");
2773
+ }
2774
+ if (column.unique && !column.primary) {
2775
+ parts.push("UNIQUE");
2776
+ }
2777
+ return parts.join(" ");
2778
+ }
2779
+ /**
2780
+ * Convert column type to PostgreSQL type
2781
+ */
2782
+ columnTypeToSQL(column) {
2783
+ switch (column.type) {
2784
+ case "increments": {
2785
+ return "SERIAL PRIMARY KEY";
2786
+ }
2787
+ case "bigIncrements": {
2788
+ return "BIGSERIAL PRIMARY KEY";
2789
+ }
2790
+ case "integer": {
2791
+ return "INTEGER";
2792
+ }
2793
+ case "bigInteger": {
2794
+ return "BIGINT";
2795
+ }
2796
+ case "smallInteger": {
2797
+ return "SMALLINT";
2798
+ }
2799
+ case "tinyInteger": {
2800
+ return "SMALLINT";
2801
+ }
2802
+ // PostgreSQL doesn't have TINYINT
2803
+ case "float": {
2804
+ return "REAL";
2805
+ }
2806
+ case "double": {
2807
+ return "DOUBLE PRECISION";
2808
+ }
2809
+ case "decimal": {
2810
+ const precision = column.precision ?? 10;
2811
+ const scale = column.scale ?? 2;
2812
+ return `NUMERIC(${precision},${scale})`;
2813
+ }
2814
+ case "string": {
2815
+ return `VARCHAR(${column.length ?? 255})`;
2816
+ }
2817
+ case "text":
2818
+ case "mediumText":
2819
+ case "longText": {
2820
+ return "TEXT";
2821
+ }
2822
+ case "boolean": {
2823
+ return "BOOLEAN";
2824
+ }
2825
+ case "date": {
2826
+ return "DATE";
2827
+ }
2828
+ case "datetime":
2829
+ case "timestamp": {
2830
+ return "TIMESTAMP";
2831
+ }
2832
+ case "time": {
2833
+ return "TIME";
2834
+ }
2835
+ case "json": {
2836
+ return "JSON";
2837
+ }
2838
+ case "jsonb": {
2839
+ return "JSONB";
2840
+ }
2841
+ case "uuid": {
2842
+ return "UUID";
2843
+ }
2844
+ case "binary": {
2845
+ return "BYTEA";
2846
+ }
2847
+ case "enum": {
2848
+ if (column.enumValues && column.enumValues.length > 0) {
2849
+ const values = column.enumValues.map((v) => this.quoteValue(v)).join(", ");
2850
+ return `VARCHAR(255) CHECK (${this.quoteIdentifier(column.name)} IN (${values}))`;
2851
+ }
2852
+ return "VARCHAR(255)";
2853
+ }
2854
+ default: {
2855
+ return "VARCHAR(255)";
2856
+ }
2857
+ }
2858
+ }
2859
+ /**
2860
+ * Convert foreign key definition to SQL
2861
+ */
2862
+ foreignKeyToSQL(fk) {
2863
+ const parts = ["CONSTRAINT"];
2864
+ if (fk.name) {
2865
+ parts.push(this.quoteIdentifier(fk.name));
2866
+ } else {
2867
+ parts.push(this.quoteIdentifier(`fk_${fk.column}_${fk.table}`));
2868
+ }
2869
+ parts.push(`FOREIGN KEY (${this.quoteIdentifier(fk.column)})`);
2870
+ parts.push(
2871
+ `REFERENCES ${this.quoteIdentifier(fk.table)} (${this.quoteIdentifier(fk.referenceColumn)})`
2872
+ );
2873
+ if (fk.onDelete) {
2874
+ parts.push(`ON DELETE ${fk.onDelete}`);
2875
+ }
2876
+ if (fk.onUpdate) {
2877
+ parts.push(`ON UPDATE ${fk.onUpdate}`);
2878
+ }
2879
+ return parts.join(" ");
2880
+ }
2881
+ };
2882
+
2883
+ // src/migrations/MigrationLock.ts
2884
+ var MigrationLock = class {
2885
+ adapter;
2886
+ tableName;
2887
+ timeout;
2888
+ dialect;
2889
+ lockId;
2890
+ isLocked = false;
2891
+ constructor(adapter, options) {
2892
+ this.adapter = adapter;
2893
+ this.tableName = options.tableName ?? "db_migrations_lock";
2894
+ this.timeout = options.timeout ?? 6e4;
2895
+ this.lockId = `${hostname()}_${process.pid}_${Date.now()}`;
2896
+ this.dialect = options.dialect === "mysql" ? new MySQLDialect() : new PostgreSQLDialect();
2897
+ }
2898
+ /**
2899
+ * Initialize the lock table
2900
+ */
2901
+ async initialize() {
2902
+ const tableName = this.dialect.quoteIdentifier(this.tableName);
2903
+ if (this.dialect.dialect === "mysql") {
2904
+ await this.adapter.execute(`
2905
+ CREATE TABLE IF NOT EXISTS ${tableName} (
2906
+ id INT PRIMARY KEY,
2907
+ is_locked TINYINT NOT NULL DEFAULT 0,
2908
+ locked_at TIMESTAMP NULL,
2909
+ locked_by VARCHAR(255) NULL
2910
+ ) ENGINE=InnoDB
2911
+ `);
2912
+ } else {
2913
+ await this.adapter.execute(`
2914
+ CREATE TABLE IF NOT EXISTS ${tableName} (
2915
+ id INT PRIMARY KEY,
2916
+ is_locked BOOLEAN NOT NULL DEFAULT FALSE,
2917
+ locked_at TIMESTAMP NULL,
2918
+ locked_by VARCHAR(255) NULL
2919
+ )
2920
+ `);
2921
+ }
2922
+ const checkSql = this.dialect.dialect === "mysql" ? `SELECT 1 FROM ${tableName} WHERE id = 1` : `SELECT 1 FROM ${tableName} WHERE id = 1`;
2923
+ const result = await this.adapter.query(checkSql);
2924
+ if (result.rows.length === 0) {
2925
+ if (this.dialect.dialect === "mysql") {
2926
+ await this.adapter.execute(`INSERT INTO ${tableName} (id, is_locked) VALUES (1, 0)`);
2927
+ } else {
2928
+ await this.adapter.execute(`INSERT INTO ${tableName} (id, is_locked) VALUES (1, FALSE)`);
2929
+ }
2930
+ }
2931
+ }
2932
+ /**
2933
+ * Acquire the migration lock
2934
+ */
2935
+ async acquire() {
2936
+ const tableName = this.dialect.quoteIdentifier(this.tableName);
2937
+ const startTime = Date.now();
2938
+ while (Date.now() - startTime < this.timeout) {
2939
+ try {
2940
+ if (this.dialect.dialect === "mysql") {
2941
+ const result = await this.adapter.execute(
2942
+ `
2943
+ UPDATE ${tableName}
2944
+ SET is_locked = 1,
2945
+ locked_at = NOW(),
2946
+ locked_by = ?
2947
+ WHERE id = 1 AND is_locked = 0
2948
+ `,
2949
+ [this.lockId]
2950
+ );
2951
+ if ((result.affectedRows ?? 0) > 0) {
2952
+ this.isLocked = true;
2953
+ return true;
2954
+ }
2955
+ } else {
2956
+ const result = await this.adapter.execute(
2957
+ `
2958
+ UPDATE ${tableName}
2959
+ SET is_locked = TRUE,
2960
+ locked_at = NOW(),
2961
+ locked_by = $1
2962
+ WHERE id = 1 AND is_locked = FALSE
2963
+ RETURNING id
2964
+ `,
2965
+ [this.lockId]
2966
+ );
2967
+ if (result.rows.length > 0) {
2968
+ this.isLocked = true;
2969
+ return true;
2970
+ }
2971
+ }
2972
+ const staleResult = await this.adapter.query(`SELECT locked_at, locked_by FROM ${tableName} WHERE id = 1`);
2973
+ if (staleResult.rows.length > 0) {
2974
+ const lockedAt = staleResult.rows[0].locked_at;
2975
+ if (lockedAt && Date.now() - new Date(lockedAt).getTime() > this.timeout) {
2976
+ console.warn(
2977
+ `Releasing stale migration lock held by ${staleResult.rows[0].locked_by}`
2978
+ );
2979
+ await this.forceRelease();
2980
+ continue;
2981
+ }
2982
+ }
2983
+ await this.sleep(1e3);
2984
+ } catch (error) {
2985
+ console.error("Error acquiring migration lock:", error);
2986
+ throw error;
2987
+ }
2988
+ }
2989
+ return false;
2990
+ }
2991
+ /**
2992
+ * Release the migration lock
2993
+ */
2994
+ async release() {
2995
+ if (!this.isLocked) {
2996
+ return;
2997
+ }
2998
+ const tableName = this.dialect.quoteIdentifier(this.tableName);
2999
+ try {
3000
+ if (this.dialect.dialect === "mysql") {
3001
+ await this.adapter.execute(
3002
+ `
3003
+ UPDATE ${tableName}
3004
+ SET is_locked = 0,
3005
+ locked_at = NULL,
3006
+ locked_by = NULL
3007
+ WHERE id = 1 AND locked_by = ?
3008
+ `,
3009
+ [this.lockId]
3010
+ );
3011
+ } else {
3012
+ await this.adapter.execute(
3013
+ `
3014
+ UPDATE ${tableName}
3015
+ SET is_locked = FALSE,
3016
+ locked_at = NULL,
3017
+ locked_by = NULL
3018
+ WHERE id = 1 AND locked_by = $1
3019
+ `,
3020
+ [this.lockId]
3021
+ );
3022
+ }
3023
+ this.isLocked = false;
3024
+ } catch (error) {
3025
+ console.error("Error releasing migration lock:", error);
3026
+ throw error;
3027
+ }
3028
+ }
3029
+ /**
3030
+ * Force release the lock (for stale locks)
3031
+ */
3032
+ async forceRelease() {
3033
+ const tableName = this.dialect.quoteIdentifier(this.tableName);
3034
+ if (this.dialect.dialect === "mysql") {
3035
+ await this.adapter.execute(`
3036
+ UPDATE ${tableName}
3037
+ SET is_locked = 0,
3038
+ locked_at = NULL,
3039
+ locked_by = NULL
3040
+ WHERE id = 1
3041
+ `);
3042
+ } else {
3043
+ await this.adapter.execute(`
3044
+ UPDATE ${tableName}
3045
+ SET is_locked = FALSE,
3046
+ locked_at = NULL,
3047
+ locked_by = NULL
3048
+ WHERE id = 1
3049
+ `);
3050
+ }
3051
+ this.isLocked = false;
3052
+ }
3053
+ /**
3054
+ * Check if lock is currently held
3055
+ */
3056
+ async isHeld() {
3057
+ const tableName = this.dialect.quoteIdentifier(this.tableName);
3058
+ const result = await this.adapter.query(
3059
+ `SELECT is_locked FROM ${tableName} WHERE id = 1`
3060
+ );
3061
+ if (result.rows.length === 0) {
3062
+ return false;
3063
+ }
3064
+ const isLocked = result.rows[0].is_locked;
3065
+ return isLocked === 1 || isLocked === true;
3066
+ }
3067
+ /**
3068
+ * Get lock info
3069
+ */
3070
+ async getLockInfo() {
3071
+ const tableName = this.dialect.quoteIdentifier(this.tableName);
3072
+ const result = await this.adapter.query(`SELECT is_locked, locked_at, locked_by FROM ${tableName} WHERE id = 1`);
3073
+ if (result.rows.length === 0) {
3074
+ return { isLocked: false, lockedAt: null, lockedBy: null };
3075
+ }
3076
+ const row = result.rows[0];
3077
+ return {
3078
+ isLocked: row.is_locked === 1 || row.is_locked === true,
3079
+ lockedAt: row.locked_at,
3080
+ lockedBy: row.locked_by
3081
+ };
3082
+ }
3083
+ /**
3084
+ * Execute a function with lock
3085
+ */
3086
+ async withLock(fn) {
3087
+ const acquired = await this.acquire();
3088
+ if (!acquired) {
3089
+ throw new Error(
3090
+ `Could not acquire migration lock within ${this.timeout}ms. Another migration may be running.`
3091
+ );
3092
+ }
3093
+ try {
3094
+ return await fn();
3095
+ } finally {
3096
+ await this.release();
3097
+ }
3098
+ }
3099
+ sleep(ms) {
3100
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
3101
+ }
3102
+ };
3103
+
3104
+ // src/schema/ColumnBuilder.ts
3105
+ var ColumnBuilder = class {
3106
+ definition;
3107
+ constructor(name, type) {
3108
+ this.definition = {
3109
+ name,
3110
+ type,
3111
+ nullable: type !== "increments" && type !== "bigIncrements",
3112
+ unsigned: false,
3113
+ autoIncrement: type === "increments" || type === "bigIncrements",
3114
+ primary: type === "increments" || type === "bigIncrements",
3115
+ unique: false,
3116
+ index: false,
3117
+ first: false
3118
+ };
3119
+ }
3120
+ /**
3121
+ * Set column length (for string types)
3122
+ */
3123
+ length(length) {
3124
+ this.definition.length = length;
3125
+ return this;
3126
+ }
3127
+ /**
3128
+ * Set precision and scale (for decimal types)
3129
+ */
3130
+ precision(precision, scale) {
3131
+ this.definition.precision = precision;
3132
+ this.definition.scale = scale;
3133
+ return this;
3134
+ }
3135
+ /**
3136
+ * Mark column as nullable
3137
+ */
3138
+ nullable() {
3139
+ this.definition.nullable = true;
3140
+ return this;
3141
+ }
3142
+ /**
3143
+ * Mark column as not nullable
3144
+ */
3145
+ notNull() {
3146
+ this.definition.nullable = false;
3147
+ return this;
3148
+ }
3149
+ /**
3150
+ * Alias for notNull()
3151
+ */
3152
+ notNullable() {
3153
+ return this.notNull();
3154
+ }
3155
+ /**
3156
+ * Set default value
3157
+ */
3158
+ default(value) {
3159
+ this.definition.defaultValue = value;
3160
+ return this;
3161
+ }
3162
+ /**
3163
+ * Set default value as raw SQL
3164
+ */
3165
+ defaultRaw(sql2) {
3166
+ this.definition.defaultRaw = sql2;
3167
+ return this;
3168
+ }
3169
+ /**
3170
+ * Set default to current timestamp
3171
+ */
3172
+ defaultNow() {
3173
+ this.definition.defaultRaw = "CURRENT_TIMESTAMP";
3174
+ return this;
3175
+ }
3176
+ /**
3177
+ * Mark column as unsigned (MySQL)
3178
+ */
3179
+ unsigned() {
3180
+ this.definition.unsigned = true;
3181
+ return this;
3182
+ }
3183
+ /**
3184
+ * Mark column as auto increment
3185
+ */
3186
+ autoIncrement() {
3187
+ this.definition.autoIncrement = true;
3188
+ return this;
3189
+ }
3190
+ /**
3191
+ * Mark column as primary key
3192
+ */
3193
+ primary() {
3194
+ this.definition.primary = true;
3195
+ return this;
3196
+ }
3197
+ /**
3198
+ * Mark column as unique
3199
+ */
3200
+ unique() {
3201
+ this.definition.unique = true;
3202
+ return this;
3203
+ }
3204
+ /**
3205
+ * Add index to column
3206
+ */
3207
+ index() {
3208
+ this.definition.index = true;
3209
+ return this;
3210
+ }
3211
+ /**
3212
+ * Add comment to column
3213
+ */
3214
+ comment(comment) {
3215
+ this.definition.comment = comment;
3216
+ return this;
3217
+ }
3218
+ /**
3219
+ * Position column after another column (MySQL)
3220
+ */
3221
+ after(columnName) {
3222
+ this.definition.after = columnName;
3223
+ return this;
3224
+ }
3225
+ /**
3226
+ * Position column first (MySQL)
3227
+ */
3228
+ first() {
3229
+ this.definition.first = true;
3230
+ return this;
3231
+ }
3232
+ /**
3233
+ * Set enum values
3234
+ */
3235
+ values(values) {
3236
+ this.definition.enumValues = values;
3237
+ return this;
3238
+ }
3239
+ /**
3240
+ * Add foreign key reference
3241
+ */
3242
+ references(column) {
3243
+ const fkBuilder = new ForeignKeyBuilder(this, column);
3244
+ return fkBuilder;
3245
+ }
3246
+ /**
3247
+ * Set foreign key definition (internal)
3248
+ */
3249
+ setForeignKey(fk) {
3250
+ this.definition.references = fk;
3251
+ }
3252
+ /**
3253
+ * Get the column definition
3254
+ */
3255
+ getDefinition() {
3256
+ return { ...this.definition };
3257
+ }
3258
+ };
3259
+ var ForeignKeyBuilder = class {
3260
+ columnBuilder;
3261
+ fkDefinition;
3262
+ constructor(columnBuilder, referenceColumn) {
3263
+ this.columnBuilder = columnBuilder;
3264
+ this.fkDefinition = {
3265
+ column: columnBuilder.getDefinition().name,
3266
+ referenceColumn
3267
+ };
3268
+ }
3269
+ /**
3270
+ * Set the referenced table
3271
+ */
3272
+ on(tableName) {
3273
+ this.fkDefinition.table = tableName;
3274
+ this.applyToColumn();
3275
+ return this;
3276
+ }
3277
+ /**
3278
+ * Alias for on()
3279
+ */
3280
+ inTable(tableName) {
3281
+ return this.on(tableName);
3282
+ }
3283
+ /**
3284
+ * Set ON DELETE action
3285
+ */
3286
+ onDelete(action) {
3287
+ this.fkDefinition.onDelete = action;
3288
+ this.applyToColumn();
3289
+ return this;
3290
+ }
3291
+ /**
3292
+ * Set ON UPDATE action
3293
+ */
3294
+ onUpdate(action) {
3295
+ this.fkDefinition.onUpdate = action;
3296
+ this.applyToColumn();
3297
+ return this;
3298
+ }
3299
+ /**
3300
+ * Set constraint name
3301
+ */
3302
+ name(name) {
3303
+ this.fkDefinition.name = name;
3304
+ this.applyToColumn();
3305
+ return this;
3306
+ }
3307
+ /**
3308
+ * Apply the foreign key definition to the column
3309
+ */
3310
+ applyToColumn() {
3311
+ if (this.fkDefinition.table && this.fkDefinition.referenceColumn) {
3312
+ this.columnBuilder.setForeignKey(this.fkDefinition);
3313
+ }
3314
+ }
3315
+ /**
3316
+ * Get the column builder for chaining
3317
+ */
3318
+ getColumnBuilder() {
3319
+ return this.columnBuilder;
3320
+ }
3321
+ };
3322
+
3323
+ // src/schema/TableBuilder.ts
3324
+ var TableBuilder = class {
3325
+ tableName;
3326
+ columns = [];
3327
+ indexes = [];
3328
+ foreignKeys = [];
3329
+ primaryKeyColumns;
3330
+ tableEngine;
3331
+ tableCharset;
3332
+ tableCollation;
3333
+ tableComment;
3334
+ constructor(tableName) {
3335
+ this.tableName = tableName;
3336
+ }
3337
+ // ============================================
3338
+ // Column Types
3339
+ // ============================================
3340
+ /**
3341
+ * Auto-incrementing integer primary key
3342
+ */
3343
+ increments(name = "id") {
3344
+ return this.addColumn(name, "increments");
3345
+ }
3346
+ /**
3347
+ * Auto-incrementing big integer primary key
3348
+ */
3349
+ bigIncrements(name = "id") {
3350
+ return this.addColumn(name, "bigIncrements");
3351
+ }
3352
+ /**
3353
+ * Integer column
3354
+ */
3355
+ integer(name) {
3356
+ return this.addColumn(name, "integer");
3357
+ }
3358
+ /**
3359
+ * Big integer column
3360
+ */
3361
+ bigInteger(name) {
3362
+ return this.addColumn(name, "bigInteger");
3363
+ }
3364
+ /**
3365
+ * Small integer column
3366
+ */
3367
+ smallInteger(name) {
3368
+ return this.addColumn(name, "smallInteger");
3369
+ }
3370
+ /**
3371
+ * Tiny integer column
3372
+ */
3373
+ tinyInteger(name) {
3374
+ return this.addColumn(name, "tinyInteger");
3375
+ }
3376
+ /**
3377
+ * Float column
3378
+ */
3379
+ float(name) {
3380
+ return this.addColumn(name, "float");
3381
+ }
3382
+ /**
3383
+ * Double column
3384
+ */
3385
+ double(name) {
3386
+ return this.addColumn(name, "double");
3387
+ }
3388
+ /**
3389
+ * Decimal column
3390
+ */
3391
+ decimal(name, precision = 10, scale = 2) {
3392
+ return this.addColumn(name, "decimal").precision(precision, scale);
3393
+ }
3394
+ /**
3395
+ * String (VARCHAR) column
3396
+ */
3397
+ string(name, length = 255) {
3398
+ return this.addColumn(name, "string").length(length);
3399
+ }
3400
+ /**
3401
+ * Text column
3402
+ */
3403
+ text(name) {
3404
+ return this.addColumn(name, "text");
3405
+ }
3406
+ /**
3407
+ * Medium text column
3408
+ */
3409
+ mediumText(name) {
3410
+ return this.addColumn(name, "mediumText");
3411
+ }
3412
+ /**
3413
+ * Long text column
3414
+ */
3415
+ longText(name) {
3416
+ return this.addColumn(name, "longText");
3417
+ }
3418
+ /**
3419
+ * Boolean column
3420
+ */
3421
+ boolean(name) {
3422
+ return this.addColumn(name, "boolean");
3423
+ }
3424
+ /**
3425
+ * Date column
3426
+ */
3427
+ date(name) {
3428
+ return this.addColumn(name, "date");
3429
+ }
3430
+ /**
3431
+ * Datetime column
3432
+ */
3433
+ datetime(name) {
3434
+ return this.addColumn(name, "datetime");
3435
+ }
3436
+ /**
3437
+ * Timestamp column
3438
+ */
3439
+ timestamp(name) {
3440
+ return this.addColumn(name, "timestamp");
3441
+ }
3442
+ /**
3443
+ * Time column
3444
+ */
3445
+ time(name) {
3446
+ return this.addColumn(name, "time");
3447
+ }
3448
+ /**
3449
+ * JSON column
3450
+ */
3451
+ json(name) {
3452
+ return this.addColumn(name, "json");
3453
+ }
3454
+ /**
3455
+ * JSONB column (PostgreSQL)
3456
+ */
3457
+ jsonb(name) {
3458
+ return this.addColumn(name, "jsonb");
3459
+ }
3460
+ /**
3461
+ * UUID column
3462
+ */
3463
+ uuid(name) {
3464
+ return this.addColumn(name, "uuid");
3465
+ }
3466
+ /**
3467
+ * Binary column
3468
+ */
3469
+ binary(name) {
3470
+ return this.addColumn(name, "binary");
3471
+ }
3472
+ /**
3473
+ * Enum column
3474
+ */
3475
+ enum(name, values) {
3476
+ return this.addColumn(name, "enum").values(values);
3477
+ }
3478
+ // ============================================
3479
+ // Shortcut Methods
3480
+ // ============================================
3481
+ /**
3482
+ * Add created_at and updated_at timestamp columns
3483
+ */
3484
+ timestamps() {
3485
+ this.timestamp("created_at").notNull().defaultNow();
3486
+ this.timestamp("updated_at").notNull().defaultNow();
3487
+ }
3488
+ /**
3489
+ * Add deleted_at timestamp column for soft deletes
3490
+ */
3491
+ softDeletes() {
3492
+ return this.timestamp("deleted_at").nullable();
3493
+ }
3494
+ /**
3495
+ * Add foreign id column with foreign key
3496
+ */
3497
+ foreignId(name) {
3498
+ const tableName = `${name.replace(/_id$/, "")}s`;
3499
+ const column = this.integer(name).unsigned().notNull();
3500
+ this.foreign(name).references("id").on(tableName);
3501
+ return column;
3502
+ }
3503
+ /**
3504
+ * Add UUID primary key column
3505
+ */
3506
+ uuidPrimary(name = "id") {
3507
+ return this.uuid(name).primary().notNull();
3508
+ }
3509
+ // ============================================
3510
+ // Indexes
3511
+ // ============================================
3512
+ /**
3513
+ * Add an index
3514
+ */
3515
+ index(columns, name) {
3516
+ const columnArray = Array.isArray(columns) ? columns : [columns];
3517
+ this.indexes.push({
3518
+ name: name || `idx_${this.tableName}_${columnArray.join("_")}`,
3519
+ columns: columnArray,
3520
+ unique: false
3521
+ });
3522
+ return this;
3523
+ }
3524
+ /**
3525
+ * Add a unique index
3526
+ */
3527
+ unique(columns, name) {
3528
+ const columnArray = Array.isArray(columns) ? columns : [columns];
3529
+ this.indexes.push({
3530
+ name: name || `uniq_${this.tableName}_${columnArray.join("_")}`,
3531
+ columns: columnArray,
3532
+ unique: true
3533
+ });
3534
+ return this;
3535
+ }
3536
+ /**
3537
+ * Add a fulltext index (MySQL)
3538
+ */
3539
+ fulltext(columns, name) {
3540
+ const columnArray = Array.isArray(columns) ? columns : [columns];
3541
+ this.indexes.push({
3542
+ name: name || `ft_${this.tableName}_${columnArray.join("_")}`,
3543
+ columns: columnArray,
3544
+ unique: false,
3545
+ type: "fulltext"
3546
+ });
3547
+ return this;
3548
+ }
3549
+ /**
3550
+ * Set primary key columns
3551
+ */
3552
+ primary(columns) {
3553
+ this.primaryKeyColumns = Array.isArray(columns) ? columns : [columns];
3554
+ return this;
3555
+ }
3556
+ // ============================================
3557
+ // Foreign Keys
3558
+ // ============================================
3559
+ /**
3560
+ * Add a foreign key constraint
3561
+ */
3562
+ foreign(column) {
3563
+ return new ForeignKeyChain(this, column);
3564
+ }
3565
+ /**
3566
+ * Add foreign key (internal)
3567
+ */
3568
+ addForeignKey(fk) {
3569
+ this.foreignKeys.push(fk);
3570
+ }
3571
+ // ============================================
3572
+ // Table Options
3573
+ // ============================================
3574
+ /**
3575
+ * Set table engine (MySQL)
3576
+ */
3577
+ engine(engine) {
3578
+ this.tableEngine = engine;
3579
+ return this;
3580
+ }
3581
+ /**
3582
+ * Set table charset (MySQL)
3583
+ */
3584
+ charset(charset) {
3585
+ this.tableCharset = charset;
3586
+ return this;
3587
+ }
3588
+ /**
3589
+ * Set table collation (MySQL)
3590
+ */
3591
+ collation(collation) {
3592
+ this.tableCollation = collation;
3593
+ return this;
3594
+ }
3595
+ /**
3596
+ * Set table comment
3597
+ */
3598
+ comment(comment) {
3599
+ this.tableComment = comment;
3600
+ return this;
3601
+ }
3602
+ // ============================================
3603
+ // Internal Methods
3604
+ // ============================================
3605
+ /**
3606
+ * Add a column and return its builder
3607
+ */
3608
+ addColumn(name, type) {
3609
+ const builder = new ColumnBuilder(name, type);
3610
+ this.columns.push(builder.getDefinition());
3611
+ const index = this.columns.length - 1;
3612
+ const proxy = new Proxy(builder, {
3613
+ get: (target, prop, receiver) => {
3614
+ const result = Reflect.get(target, prop, receiver);
3615
+ if (typeof result === "function") {
3616
+ return (...args) => {
3617
+ const returnValue = result.apply(target, args);
3618
+ this.columns[index] = target.getDefinition();
3619
+ return returnValue === target ? proxy : returnValue;
3620
+ };
3621
+ }
3622
+ return result;
3623
+ }
3624
+ });
3625
+ return proxy;
3626
+ }
3627
+ /**
3628
+ * Get the table definition
3629
+ */
3630
+ getDefinition() {
3631
+ return {
3632
+ name: this.tableName,
3633
+ columns: [...this.columns],
3634
+ indexes: [...this.indexes],
3635
+ foreignKeys: [...this.foreignKeys],
3636
+ primaryKey: this.primaryKeyColumns,
3637
+ engine: this.tableEngine,
3638
+ charset: this.tableCharset,
3639
+ collation: this.tableCollation,
3640
+ comment: this.tableComment
3641
+ };
3642
+ }
3643
+ };
3644
+ var ForeignKeyChain = class {
3645
+ tableBuilder;
3646
+ fkDefinition;
3647
+ constructor(tableBuilder, column) {
3648
+ this.tableBuilder = tableBuilder;
3649
+ this.fkDefinition = { column };
3650
+ }
3651
+ /**
3652
+ * Set the referenced column
3653
+ */
3654
+ references(column) {
3655
+ this.fkDefinition.referenceColumn = column;
3656
+ return this;
3657
+ }
3658
+ /**
3659
+ * Set the referenced table
3660
+ */
3661
+ on(tableName) {
3662
+ this.fkDefinition.table = tableName;
3663
+ this.apply();
3664
+ return this;
3665
+ }
3666
+ /**
3667
+ * Alias for on()
3668
+ */
3669
+ inTable(tableName) {
3670
+ return this.on(tableName);
3671
+ }
3672
+ /**
3673
+ * Set ON DELETE action
3674
+ */
3675
+ onDelete(action) {
3676
+ this.fkDefinition.onDelete = action;
3677
+ this.apply();
3678
+ return this;
3679
+ }
3680
+ /**
3681
+ * Set ON UPDATE action
3682
+ */
3683
+ onUpdate(action) {
3684
+ this.fkDefinition.onUpdate = action;
3685
+ this.apply();
3686
+ return this;
3687
+ }
3688
+ /**
3689
+ * Set constraint name
3690
+ */
3691
+ name(name) {
3692
+ this.fkDefinition.name = name;
3693
+ this.apply();
3694
+ return this;
3695
+ }
3696
+ /**
3697
+ * Apply the foreign key to the table
3698
+ */
3699
+ apply() {
3700
+ if (this.fkDefinition.column && this.fkDefinition.table && this.fkDefinition.referenceColumn) {
3701
+ if (!this.fkDefinition.name) {
3702
+ this.fkDefinition.name = `fk_${this.fkDefinition.column}_${this.fkDefinition.table}`;
3703
+ }
3704
+ this.tableBuilder.addForeignKey(this.fkDefinition);
3705
+ }
3706
+ }
3707
+ };
3708
+
3709
+ // src/schema/SchemaBuilder.ts
3710
+ var SchemaBuilder = class {
3711
+ dialectInstance;
3712
+ adapter;
3713
+ constructor(options) {
3714
+ this.adapter = options.adapter;
3715
+ switch (options.dialect) {
3716
+ case "mysql": {
3717
+ this.dialectInstance = new MySQLDialect();
3718
+ break;
3719
+ }
3720
+ case "postgresql": {
3721
+ this.dialectInstance = new PostgreSQLDialect();
3722
+ break;
3723
+ }
3724
+ default: {
3725
+ throw new Error(`Unsupported dialect: ${options.dialect}`);
3726
+ }
3727
+ }
3728
+ }
3729
+ /**
3730
+ * Get the dialect instance
3731
+ */
3732
+ get dialect() {
3733
+ return this.dialectInstance;
3734
+ }
3735
+ /**
3736
+ * Create a new table
3737
+ */
3738
+ async createTable(tableName, callback) {
3739
+ const builder = new TableBuilder(tableName);
3740
+ callback(builder);
3741
+ const definition = builder.getDefinition();
3742
+ const sql2 = this.dialectInstance.createTable(definition);
3743
+ await this.execute(sql2);
3744
+ if (this.dialectInstance.dialect === "postgresql" && definition.indexes.length > 0) {
3745
+ const pgDialect = this.dialectInstance;
3746
+ for (const index of definition.indexes) {
3747
+ const indexSql = pgDialect.createIndex(tableName, index);
3748
+ await this.execute(indexSql);
3749
+ }
3750
+ }
3751
+ }
3752
+ /**
3753
+ * Create a table if it doesn't exist
3754
+ */
3755
+ async createTableIfNotExists(tableName, callback) {
3756
+ const exists2 = await this.hasTable(tableName);
3757
+ if (!exists2) {
3758
+ await this.createTable(tableName, callback);
3759
+ }
3760
+ }
3761
+ /**
3762
+ * Drop a table
3763
+ */
3764
+ async dropTable(tableName) {
3765
+ const sql2 = this.dialectInstance.dropTable(tableName);
3766
+ await this.execute(sql2);
3767
+ }
3768
+ /**
3769
+ * Drop a table if it exists
3770
+ */
3771
+ async dropTableIfExists(tableName) {
3772
+ const sql2 = this.dialectInstance.dropTableIfExists(tableName);
3773
+ await this.execute(sql2);
3774
+ }
3775
+ /**
3776
+ * Rename a table
3777
+ */
3778
+ async renameTable(from, to) {
3779
+ const sql2 = this.dialectInstance.renameTable(from, to);
3780
+ await this.execute(sql2);
3781
+ }
3782
+ /**
3783
+ * Check if a table exists
3784
+ */
3785
+ async hasTable(tableName) {
3786
+ const sql2 = this.dialectInstance.hasTable(tableName);
3787
+ const result = await this.query(sql2);
3788
+ return result.length > 0;
3789
+ }
3790
+ /**
3791
+ * Check if a column exists in a table
3792
+ */
3793
+ async hasColumn(tableName, columnName) {
3794
+ const sql2 = this.dialectInstance.hasColumn(tableName, columnName);
3795
+ const result = await this.query(sql2);
3796
+ return result.length > 0;
3797
+ }
3798
+ /**
3799
+ * Alter a table
3800
+ */
3801
+ async alterTable(tableName, callback) {
3802
+ const builder = new AlterTableBuilder(tableName);
3803
+ callback(builder);
3804
+ const definition = builder.getDefinition();
3805
+ const statements = this.dialectInstance.alterTable(definition);
3806
+ for (const sql2 of statements) {
3807
+ await this.execute(sql2);
3808
+ }
3809
+ }
3810
+ /**
3811
+ * Execute raw SQL
3812
+ */
3813
+ async raw(sql2, params) {
3814
+ await this.execute(sql2, params);
3815
+ }
3816
+ /**
3817
+ * Execute SQL statement
3818
+ */
3819
+ async execute(sql2, params) {
3820
+ if (this.adapter) {
3821
+ await this.adapter.execute(sql2, params);
3822
+ } else {
3823
+ console.log("SQL:", sql2);
3824
+ if (params && params.length > 0) {
3825
+ console.log("Params:", params);
3826
+ }
3827
+ }
3828
+ }
3829
+ /**
3830
+ * Execute SQL query
3831
+ */
3832
+ async query(sql2) {
3833
+ if (this.adapter) {
3834
+ const result = await this.adapter.query(sql2);
3835
+ return result.rows;
3836
+ }
3837
+ return [];
3838
+ }
3839
+ /**
3840
+ * Generate SQL without executing (for preview/dry-run)
3841
+ */
3842
+ generateCreateTableSQL(tableName, callback) {
3843
+ const builder = new TableBuilder(tableName);
3844
+ callback(builder);
3845
+ return this.dialectInstance.createTable(builder.getDefinition());
3846
+ }
3847
+ /**
3848
+ * Generate ALTER TABLE SQL without executing
3849
+ */
3850
+ generateAlterTableSQL(tableName, callback) {
3851
+ const builder = new AlterTableBuilder(tableName);
3852
+ callback(builder);
3853
+ return this.dialectInstance.alterTable(builder.getDefinition());
3854
+ }
3855
+ };
3856
+ var AlterTableBuilder = class {
3857
+ tableName;
3858
+ operations = [];
3859
+ constructor(tableName) {
3860
+ this.tableName = tableName;
3861
+ }
3862
+ /**
3863
+ * Add a new column
3864
+ */
3865
+ addColumn(name, type, options) {
3866
+ this.operations.push({
3867
+ type: "addColumn",
3868
+ column: {
3869
+ name,
3870
+ type,
3871
+ nullable: true,
3872
+ unsigned: false,
3873
+ autoIncrement: false,
3874
+ primary: false,
3875
+ unique: false,
3876
+ index: false,
3877
+ first: false,
3878
+ ...options
3879
+ }
3880
+ });
3881
+ return this;
3882
+ }
3883
+ /**
3884
+ * Drop a column
3885
+ */
3886
+ dropColumn(name) {
3887
+ this.operations.push({ type: "dropColumn", name });
3888
+ return this;
3889
+ }
3890
+ /**
3891
+ * Rename a column
3892
+ */
3893
+ renameColumn(from, to) {
3894
+ this.operations.push({ type: "renameColumn", from, to });
3895
+ return this;
3896
+ }
3897
+ /**
3898
+ * Modify a column
3899
+ */
3900
+ modifyColumn(name, type, options) {
3901
+ this.operations.push({
3902
+ type: "modifyColumn",
3903
+ column: {
3904
+ name,
3905
+ type,
3906
+ nullable: true,
3907
+ unsigned: false,
3908
+ autoIncrement: false,
3909
+ primary: false,
3910
+ unique: false,
3911
+ index: false,
3912
+ first: false,
3913
+ ...options
3914
+ }
3915
+ });
3916
+ return this;
3917
+ }
3918
+ /**
3919
+ * Add an index
3920
+ */
3921
+ addIndex(columns, name) {
3922
+ const columnArray = Array.isArray(columns) ? columns : [columns];
3923
+ this.operations.push({
3924
+ type: "addIndex",
3925
+ index: {
3926
+ name: name || `idx_${this.tableName}_${columnArray.join("_")}`,
3927
+ columns: columnArray,
3928
+ unique: false
3929
+ }
3930
+ });
3931
+ return this;
3932
+ }
3933
+ /**
3934
+ * Add a unique index
3935
+ */
3936
+ addUnique(columns, name) {
3937
+ const columnArray = Array.isArray(columns) ? columns : [columns];
3938
+ this.operations.push({
3939
+ type: "addIndex",
3940
+ index: {
3941
+ name: name || `uniq_${this.tableName}_${columnArray.join("_")}`,
3942
+ columns: columnArray,
3943
+ unique: true
3944
+ }
3945
+ });
3946
+ return this;
3947
+ }
3948
+ /**
3949
+ * Drop an index
3950
+ */
3951
+ dropIndex(name) {
3952
+ this.operations.push({ type: "dropIndex", name });
3953
+ return this;
3954
+ }
3955
+ /**
3956
+ * Add a foreign key
3957
+ */
3958
+ addForeign(column) {
3959
+ return new AlterForeignKeyBuilder(this, column);
3960
+ }
3961
+ /**
3962
+ * Add foreign key (internal)
3963
+ */
3964
+ addForeignKeyOperation(fk) {
3965
+ this.operations.push({ type: "addForeignKey", foreignKey: fk });
3966
+ }
3967
+ /**
3968
+ * Drop a foreign key
3969
+ */
3970
+ dropForeign(name) {
3971
+ this.operations.push({ type: "dropForeignKey", name });
3972
+ return this;
3973
+ }
3974
+ /**
3975
+ * Add primary key
3976
+ */
3977
+ addPrimary(columns) {
3978
+ const columnArray = Array.isArray(columns) ? columns : [columns];
3979
+ this.operations.push({ type: "addPrimary", columns: columnArray });
3980
+ return this;
3981
+ }
3982
+ /**
3983
+ * Drop primary key
3984
+ */
3985
+ dropPrimary() {
3986
+ this.operations.push({ type: "dropPrimary" });
3987
+ return this;
3988
+ }
3989
+ /**
3990
+ * Get the alter table definition
3991
+ */
3992
+ getDefinition() {
3993
+ return {
3994
+ tableName: this.tableName,
3995
+ operations: [...this.operations]
3996
+ };
3997
+ }
3998
+ };
3999
+ var AlterForeignKeyBuilder = class {
4000
+ builder;
4001
+ fkDefinition;
4002
+ constructor(builder, column) {
4003
+ this.builder = builder;
4004
+ this.fkDefinition = { column };
4005
+ }
4006
+ references(column) {
4007
+ this.fkDefinition.referenceColumn = column;
4008
+ return this;
4009
+ }
4010
+ on(tableName) {
4011
+ this.fkDefinition.table = tableName;
4012
+ this.apply();
4013
+ return this;
4014
+ }
4015
+ onDelete(action) {
4016
+ this.fkDefinition.onDelete = action;
4017
+ this.apply();
4018
+ return this;
4019
+ }
4020
+ onUpdate(action) {
4021
+ this.fkDefinition.onUpdate = action;
4022
+ this.apply();
4023
+ return this;
4024
+ }
4025
+ name(name) {
4026
+ this.fkDefinition.name = name;
4027
+ this.apply();
4028
+ return this;
4029
+ }
4030
+ apply() {
4031
+ if (this.fkDefinition.column && this.fkDefinition.table && this.fkDefinition.referenceColumn) {
4032
+ if (!this.fkDefinition.name) {
4033
+ this.fkDefinition.name = `fk_${this.fkDefinition.column}_${this.fkDefinition.table}`;
4034
+ }
4035
+ this.builder.addForeignKeyOperation(this.fkDefinition);
4036
+ }
4037
+ }
4038
+ };
4039
+
4040
+ // src/migrations/FileMigrationRunner.ts
4041
+ var FileMigrationRunner = class {
4042
+ adapter;
4043
+ loader;
4044
+ lock;
4045
+ schema;
4046
+ options;
4047
+ constructor(adapter, options) {
4048
+ this.adapter = adapter;
4049
+ this.options = {
4050
+ directory: options.directory,
4051
+ tableName: options.tableName ?? "db_migrations",
4052
+ lockTableName: options.lockTableName ?? "db_migrations_lock",
4053
+ lockTimeout: options.lockTimeout ?? 6e4,
4054
+ validateChecksums: options.validateChecksums ?? true,
4055
+ dialect: options.dialect,
4056
+ logger: options.logger ?? console,
4057
+ dryRun: options.dryRun ?? false
4058
+ };
4059
+ this.loader = new MigrationLoader(options.directory);
4060
+ this.lock = new MigrationLock(adapter, {
4061
+ tableName: this.options.lockTableName,
4062
+ timeout: this.options.lockTimeout,
4063
+ dialect: options.dialect
4064
+ });
4065
+ this.schema = new SchemaBuilder({
4066
+ dialect: options.dialect,
4067
+ adapter
4068
+ });
4069
+ }
4070
+ /**
4071
+ * Initialize migration tables
4072
+ */
4073
+ async initialize() {
4074
+ if (this.options.dryRun) {
4075
+ this.options.logger.info("DRY RUN: Would create migration tables");
4076
+ return;
4077
+ }
4078
+ const tableName = this.options.tableName;
4079
+ const hasTable = await this.schema.hasTable(tableName);
4080
+ if (!hasTable) {
4081
+ await this.schema.createTable(tableName, (table) => {
4082
+ table.increments("id");
4083
+ table.string("name", 255).notNull().unique();
4084
+ table.integer("batch").notNull();
4085
+ table.timestamp("executed_at").notNull().defaultNow();
4086
+ table.integer("execution_time_ms").notNull();
4087
+ table.string("checksum", 64).notNull();
4088
+ table.index("batch");
4089
+ table.index("executed_at");
4090
+ });
4091
+ this.options.logger.info(`Created migrations table: ${tableName}`);
4092
+ }
4093
+ await this.lock.initialize();
4094
+ }
4095
+ /**
4096
+ * Run all pending migrations
4097
+ */
4098
+ async latest() {
4099
+ await this.lock.initialize();
4100
+ return this.lock.withLock(async () => {
4101
+ await this.initialize();
4102
+ const pending = await this.getPendingMigrations();
4103
+ if (pending.length === 0) {
4104
+ this.options.logger.info("No pending migrations");
4105
+ return [];
4106
+ }
4107
+ const batch = await this.getNextBatch();
4108
+ const executed = [];
4109
+ this.options.logger.info(`Running ${pending.length} migrations (batch ${batch})`);
4110
+ for (const migration of pending) {
4111
+ await this.runMigration(migration, "up", batch);
4112
+ executed.push(migration.name);
4113
+ }
4114
+ return executed;
4115
+ });
4116
+ }
4117
+ /**
4118
+ * Rollback the last batch of migrations
4119
+ */
4120
+ async rollback(steps = 1) {
4121
+ await this.lock.initialize();
4122
+ return this.lock.withLock(async () => {
4123
+ await this.initialize();
4124
+ const batches = await this.getLastBatches(steps);
4125
+ if (batches.length === 0) {
4126
+ this.options.logger.info("No migrations to rollback");
4127
+ return [];
4128
+ }
4129
+ const rolledBack = [];
4130
+ for (const batch of batches) {
4131
+ this.options.logger.info(`Rolling back batch ${batch.batch}`);
4132
+ const migrations = await this.loadMigrationsByName(
4133
+ batch.migrations.map((m) => m.name).reverse()
4134
+ );
4135
+ for (const migration of migrations) {
4136
+ await this.runMigration(migration, "down", batch.batch);
4137
+ rolledBack.push(migration.name);
4138
+ }
4139
+ }
4140
+ return rolledBack;
4141
+ });
4142
+ }
4143
+ /**
4144
+ * Reset all migrations
4145
+ */
4146
+ async reset() {
4147
+ await this.lock.initialize();
4148
+ return this.lock.withLock(async () => {
4149
+ await this.initialize();
4150
+ const executed = await this.getExecutedMigrations();
4151
+ if (executed.length === 0) {
4152
+ this.options.logger.info("No migrations to reset");
4153
+ return [];
4154
+ }
4155
+ const rolledBack = [];
4156
+ const migrations = await this.loadMigrationsByName(executed.map((m) => m.name).reverse());
4157
+ for (const migration of migrations) {
4158
+ const record = executed.find((e) => e.name === migration.name);
4159
+ await this.runMigration(migration, "down", record.batch);
4160
+ rolledBack.push(migration.name);
4161
+ }
4162
+ return rolledBack;
4163
+ });
4164
+ }
4165
+ /**
4166
+ * Reset and re-run all migrations
4167
+ */
4168
+ async fresh() {
4169
+ await this.reset();
4170
+ return this.latest();
4171
+ }
4172
+ /**
4173
+ * Get migration status
4174
+ */
4175
+ async status() {
4176
+ await this.initialize();
4177
+ const allMigrations = await this.loader.getMigrationFiles();
4178
+ const executed = await this.getExecutedMigrations();
4179
+ const executedMap = new Map(executed.map((e) => [e.name, e]));
4180
+ return allMigrations.map((file) => {
4181
+ const record = executedMap.get(file.name);
4182
+ return {
4183
+ name: file.name,
4184
+ batch: record?.batch ?? null,
4185
+ executedAt: record?.executed_at ?? null,
4186
+ pending: !record
4187
+ };
4188
+ });
4189
+ }
4190
+ /**
4191
+ * Validate migrations
4192
+ */
4193
+ async validate() {
4194
+ const errors = [];
4195
+ try {
4196
+ const migrations = await this.loader.loadAll();
4197
+ const executed = await this.getExecutedMigrations();
4198
+ for (const record of executed) {
4199
+ const migration = migrations.find((m) => m.name === record.name);
4200
+ if (!migration) {
4201
+ errors.push(`Migration '${record.name}' exists in database but not in codebase`);
4202
+ continue;
4203
+ }
4204
+ if (this.options.validateChecksums) {
4205
+ const checksum = this.calculateChecksum(migration);
4206
+ if (checksum !== record.checksum) {
4207
+ errors.push(
4208
+ `Checksum mismatch for migration '${record.name}'. The migration may have been modified.`
4209
+ );
4210
+ }
4211
+ }
4212
+ }
4213
+ } catch (error) {
4214
+ errors.push(`Validation error: ${error.message}`);
4215
+ }
4216
+ return {
4217
+ valid: errors.length === 0,
4218
+ errors
4219
+ };
4220
+ }
4221
+ /**
4222
+ * Get pending migrations
4223
+ */
4224
+ async getPendingMigrations() {
4225
+ const allMigrations = await this.loader.loadAll();
4226
+ const executed = await this.getExecutedMigrations();
4227
+ const executedNames = new Set(executed.map((e) => e.name));
4228
+ return allMigrations.filter((m) => !executedNames.has(m.name));
4229
+ }
4230
+ /**
4231
+ * Get executed migrations from database
4232
+ */
4233
+ async getExecutedMigrations() {
4234
+ const result = await this.adapter.query(
4235
+ `SELECT * FROM ${this.options.tableName} ORDER BY id ASC`
4236
+ );
4237
+ return result.rows;
4238
+ }
4239
+ /**
4240
+ * Get the next batch number
4241
+ */
4242
+ async getNextBatch() {
4243
+ const result = await this.adapter.query(
4244
+ `SELECT MAX(batch) as max_batch FROM ${this.options.tableName}`
4245
+ );
4246
+ return (result.rows[0]?.max_batch ?? 0) + 1;
4247
+ }
4248
+ /**
4249
+ * Get the last N batches
4250
+ */
4251
+ async getLastBatches(count2) {
4252
+ const result = await this.adapter.query(
4253
+ `SELECT * FROM ${this.options.tableName} ORDER BY batch DESC, id DESC`
4254
+ );
4255
+ const batches = /* @__PURE__ */ new Map();
4256
+ for (const record of result.rows) {
4257
+ if (!batches.has(record.batch)) {
4258
+ batches.set(record.batch, []);
4259
+ }
4260
+ batches.get(record.batch).push(record);
4261
+ }
4262
+ const batchNumbers = Array.from(batches.keys()).slice(0, count2);
4263
+ return batchNumbers.map((batch) => ({
4264
+ batch,
4265
+ migrations: batches.get(batch)
4266
+ }));
4267
+ }
4268
+ /**
4269
+ * Load migrations by name
4270
+ */
4271
+ async loadMigrationsByName(names) {
4272
+ const allMigrations = await this.loader.loadAll();
4273
+ const migrationMap = new Map(allMigrations.map((m) => [m.name, m]));
4274
+ return names.map((name) => migrationMap.get(name)).filter((m) => m !== void 0);
4275
+ }
4276
+ /**
4277
+ * Run a single migration
4278
+ */
4279
+ async runMigration(migration, direction, batch) {
4280
+ const startTime = Date.now();
4281
+ const action = direction === "up" ? "Running" : "Rolling back";
4282
+ this.options.logger.info(`${action}: ${migration.name}`);
4283
+ if (this.options.dryRun) {
4284
+ this.options.logger.info(`DRY RUN: Would ${direction} ${migration.name}`);
4285
+ return;
4286
+ }
4287
+ const transaction = migration.transactional ? await this.adapter.beginTransaction() : null;
4288
+ try {
4289
+ const schema = new SchemaBuilder({
4290
+ dialect: this.options.dialect,
4291
+ adapter: this.adapter
4292
+ });
4293
+ await migration[direction](schema);
4294
+ const executionTime = Date.now() - startTime;
4295
+ if (direction === "up") {
4296
+ const checksum = this.calculateChecksum(migration);
4297
+ await this.adapter.execute(
4298
+ `INSERT INTO ${this.options.tableName}
4299
+ (name, batch, executed_at, execution_time_ms, checksum)
4300
+ VALUES (?, ?, NOW(), ?, ?)`,
4301
+ [migration.name, batch, executionTime, checksum]
4302
+ );
4303
+ } else {
4304
+ await this.adapter.execute(`DELETE FROM ${this.options.tableName} WHERE name = ?`, [
4305
+ migration.name
4306
+ ]);
4307
+ }
4308
+ if (transaction) {
4309
+ await transaction.commit();
4310
+ }
4311
+ this.options.logger.info(
4312
+ `${direction === "up" ? "Completed" : "Rolled back"}: ${migration.name} (${executionTime}ms)`
4313
+ );
4314
+ } catch (error) {
4315
+ if (transaction) {
4316
+ await transaction.rollback();
4317
+ }
4318
+ throw new Error(
4319
+ `Failed to ${direction} migration '${migration.name}': ${error.message}`
4320
+ );
4321
+ }
4322
+ }
4323
+ /**
4324
+ * Calculate migration checksum
4325
+ */
4326
+ calculateChecksum(migration) {
4327
+ const content = `${migration.name}:${migration.up.toString()}:${migration.down.toString()}`;
4328
+ return createHash("sha256").update(content).digest("hex");
4329
+ }
4330
+ };
4331
+
4332
+ // src/migrations/ExpandContract.ts
4333
+ var ExpandContractHelper = class {
4334
+ constructor(adapter, schema) {
4335
+ this.adapter = adapter;
4336
+ this.schema = schema;
4337
+ }
4338
+ /**
4339
+ * Rename a column using expand/contract pattern
4340
+ * Expand: Add new column
4341
+ * Migrate: Copy data from old to new
4342
+ * Contract: Drop old column
4343
+ */
4344
+ async renameColumn(table, oldColumn, newColumn, phase) {
4345
+ switch (phase) {
4346
+ case "expand": {
4347
+ await this.schema.alterTable(table, (t) => {
4348
+ t.addColumn(newColumn, "text");
4349
+ });
4350
+ break;
4351
+ }
4352
+ case "migrate": {
4353
+ await this.adapter.execute(
4354
+ `UPDATE ${table} SET ${newColumn} = ${oldColumn} WHERE ${newColumn} IS NULL`
4355
+ );
4356
+ break;
4357
+ }
4358
+ case "contract": {
4359
+ await this.schema.alterTable(table, (t) => {
4360
+ t.dropColumn(oldColumn);
4361
+ });
4362
+ break;
4363
+ }
4364
+ }
4365
+ }
4366
+ /**
4367
+ * Change column type using expand/contract pattern
4368
+ */
4369
+ async changeColumnType(table, column, newType, transform, phase) {
4370
+ const tempColumn = `${column}_new`;
4371
+ switch (phase) {
4372
+ case "expand": {
4373
+ await this.adapter.execute(`ALTER TABLE ${table} ADD COLUMN ${tempColumn} ${newType}`);
4374
+ break;
4375
+ }
4376
+ case "migrate": {
4377
+ await this.adapter.execute(`UPDATE ${table} SET ${tempColumn} = ${transform}`);
4378
+ break;
4379
+ }
4380
+ case "contract": {
4381
+ await this.adapter.execute(`ALTER TABLE ${table} DROP COLUMN ${column}`);
4382
+ await this.adapter.execute(`ALTER TABLE ${table} RENAME COLUMN ${tempColumn} TO ${column}`);
4383
+ break;
4384
+ }
4385
+ }
4386
+ }
4387
+ /**
4388
+ * Split a table into two tables using expand/contract
4389
+ */
4390
+ async splitTable(sourceTable, newTable, columnsToMove, foreignKeyColumn, phase) {
4391
+ switch (phase) {
4392
+ case "expand": {
4393
+ await this.schema.createTable(newTable, (t) => {
4394
+ t.increments("id");
4395
+ t.integer(foreignKeyColumn).notNull();
4396
+ });
4397
+ break;
4398
+ }
4399
+ case "migrate": {
4400
+ const cols = columnsToMove.join(", ");
4401
+ await this.adapter.execute(
4402
+ `INSERT INTO ${newTable} (${foreignKeyColumn}, ${cols})
4403
+ SELECT id, ${cols} FROM ${sourceTable}`
4404
+ );
4405
+ break;
4406
+ }
4407
+ case "contract": {
4408
+ for (const col of columnsToMove) {
4409
+ await this.schema.alterTable(sourceTable, (t) => {
4410
+ t.dropColumn(col);
4411
+ });
4412
+ }
4413
+ break;
4414
+ }
4415
+ }
4416
+ }
4417
+ /**
4418
+ * Merge two tables into one using expand/contract
4419
+ */
4420
+ async mergeTables(targetTable, sourceTable, columnsToMerge, joinColumn, phase) {
4421
+ switch (phase) {
4422
+ case "expand": {
4423
+ for (const col of columnsToMerge) {
4424
+ await this.schema.alterTable(targetTable, (t) => {
4425
+ t.addColumn(col, "text");
4426
+ });
4427
+ }
4428
+ break;
4429
+ }
4430
+ case "migrate": {
4431
+ const setClauses = columnsToMerge.map((col) => `${targetTable}.${col} = ${sourceTable}.${col}`).join(", ");
4432
+ await this.adapter.execute(
4433
+ `UPDATE ${targetTable}
4434
+ SET ${setClauses}
4435
+ FROM ${sourceTable}
4436
+ WHERE ${targetTable}.id = ${sourceTable}.${joinColumn}`
4437
+ );
4438
+ break;
4439
+ }
4440
+ case "contract": {
4441
+ await this.schema.dropTable(sourceTable);
4442
+ break;
4443
+ }
4444
+ }
4445
+ }
4446
+ /**
4447
+ * Add NOT NULL constraint safely
4448
+ */
4449
+ async addNotNullConstraint(table, column, defaultValue, phase) {
4450
+ switch (phase) {
4451
+ case "expand": {
4452
+ await this.adapter.execute(
4453
+ `UPDATE ${table} SET ${column} = ${defaultValue} WHERE ${column} IS NULL`
4454
+ );
4455
+ break;
4456
+ }
4457
+ case "migrate": {
4458
+ const result = await this.adapter.query(
4459
+ `SELECT COUNT(*) as count FROM ${table} WHERE ${column} IS NULL`
4460
+ );
4461
+ if (result.rows[0]?.count && result.rows[0].count > 0) {
4462
+ throw new Error(
4463
+ `Cannot add NOT NULL: ${result.rows[0].count} rows still have NULL values`
4464
+ );
4465
+ }
4466
+ break;
4467
+ }
4468
+ case "contract": {
4469
+ await this.schema.alterTable(table, (t) => {
4470
+ t.modifyColumn(column, "text", { nullable: false });
4471
+ });
4472
+ break;
4473
+ }
4474
+ }
4475
+ }
4476
+ };
4477
+ function createExpandContractHelper(adapter, schema) {
4478
+ return new ExpandContractHelper(adapter, schema);
4479
+ }
4480
+ var SeederLoader = class {
4481
+ constructor(directory) {
4482
+ this.directory = directory;
4483
+ }
4484
+ /**
4485
+ * Load all seeder files from directory
4486
+ */
4487
+ async loadAll() {
4488
+ const files = await readdir(this.directory);
4489
+ const seederFiles = files.filter((f) => /\.(ts|js|mjs)$/.test(f) && !f.endsWith(".d.ts")).sort().map((f) => ({
4490
+ name: this.getSeederName(f),
4491
+ path: resolve(this.directory, f)
4492
+ }));
4493
+ return seederFiles;
4494
+ }
4495
+ /**
4496
+ * Load a specific seeder by path
4497
+ */
4498
+ async load(seederPath) {
4499
+ const fileUrl = pathToFileURL(seederPath).href;
4500
+ const module = await import(fileUrl);
4501
+ const seeder = module.default || module;
4502
+ if (!seeder || typeof seeder.run !== "function") {
4503
+ throw new Error(`Invalid seeder: ${seederPath} - must export a run() function`);
4504
+ }
4505
+ return seeder;
4506
+ }
4507
+ /**
4508
+ * Get seeder name from filename
4509
+ */
4510
+ getSeederName(filename) {
4511
+ return basename(filename).replace(/\.(ts|js|mjs)$/, "");
4512
+ }
4513
+ /**
4514
+ * Generate a new seeder filename
4515
+ */
4516
+ static generateFilename(name) {
4517
+ const snakeName = name.replaceAll(/([a-z])([A-Z])/g, "$1_$2").replaceAll(/[\s-]+/g, "_").toLowerCase();
4518
+ return `${snakeName}_seeder.ts`;
4519
+ }
4520
+ /**
4521
+ * Get seeder template
4522
+ */
4523
+ static getSeederTemplate(name) {
4524
+ const className = name.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
4525
+ return `/**
4526
+ * ${className} Seeder
4527
+ */
4528
+
4529
+ import type { Seeder, DatabaseAdapter } from '@db-bridge/core';
4530
+
4531
+ export default {
4532
+ async run(adapter: DatabaseAdapter): Promise<void> {
4533
+ // Insert seed data
4534
+ // await adapter.execute(\`
4535
+ // INSERT INTO users (name, email) VALUES
4536
+ // ('John Doe', 'john@example.com'),
4537
+ // ('Jane Doe', 'jane@example.com')
4538
+ // \`);
4539
+ },
4540
+ } satisfies Seeder;
4541
+ `;
4542
+ }
4543
+ };
4544
+
4545
+ // src/seeds/SeederRunner.ts
4546
+ var SeederRunner = class {
4547
+ constructor(adapter, options) {
4548
+ this.adapter = adapter;
4549
+ this.options = options;
4550
+ this.loader = new SeederLoader(options.directory);
4551
+ }
4552
+ loader;
4553
+ options;
4554
+ /**
4555
+ * Run all seeders (or filtered by options)
4556
+ */
4557
+ async run() {
4558
+ const files = await this.loader.loadAll();
4559
+ const filteredFiles = this.filterSeeders(files);
4560
+ const results = [];
4561
+ for (const file of filteredFiles) {
4562
+ const startTime = Date.now();
4563
+ try {
4564
+ const seeder = await this.loader.load(file.path);
4565
+ await seeder.run(this.adapter);
4566
+ results.push({
4567
+ name: file.name,
4568
+ success: true,
4569
+ duration: Date.now() - startTime
4570
+ });
4571
+ } catch (error) {
4572
+ results.push({
4573
+ name: file.name,
4574
+ success: false,
4575
+ error: error.message,
4576
+ duration: Date.now() - startTime
4577
+ });
4578
+ break;
4579
+ }
4580
+ }
4581
+ return results;
4582
+ }
4583
+ /**
4584
+ * Run a specific seeder by name
4585
+ */
4586
+ async runSeeder(name) {
4587
+ const files = await this.loader.loadAll();
4588
+ const file = files.find((f) => f.name === name || f.name === `${name}_seeder`);
4589
+ if (!file) {
4590
+ return {
4591
+ name,
4592
+ success: false,
4593
+ error: `Seeder not found: ${name}`,
4594
+ duration: 0
4595
+ };
4596
+ }
4597
+ const startTime = Date.now();
4598
+ try {
4599
+ const seeder = await this.loader.load(file.path);
4600
+ await seeder.run(this.adapter);
4601
+ return {
4602
+ name: file.name,
4603
+ success: true,
4604
+ duration: Date.now() - startTime
4605
+ };
4606
+ } catch (error) {
4607
+ return {
4608
+ name: file.name,
4609
+ success: false,
4610
+ error: error.message,
4611
+ duration: Date.now() - startTime
4612
+ };
4613
+ }
4614
+ }
4615
+ /**
4616
+ * Filter seeders based on options
4617
+ */
4618
+ filterSeeders(files) {
4619
+ let filtered = files;
4620
+ if (this.options.only && this.options.only.length > 0) {
4621
+ filtered = filtered.filter(
4622
+ (f) => this.options.only.some((name) => f.name === name || f.name === `${name}_seeder`)
4623
+ );
4624
+ }
4625
+ if (this.options.except && this.options.except.length > 0) {
4626
+ filtered = filtered.filter(
4627
+ (f) => !this.options.except.some((name) => f.name === name || f.name === `${name}_seeder`)
4628
+ );
4629
+ }
4630
+ return filtered;
4631
+ }
4632
+ /**
4633
+ * List all available seeders
4634
+ */
4635
+ async list() {
4636
+ return this.loader.loadAll();
4637
+ }
4638
+ };
2108
4639
  var PerformanceMonitor = class extends EventEmitter {
2109
4640
  traces = /* @__PURE__ */ new Map();
2110
4641
  slowQueries = [];
@@ -4188,13 +6719,13 @@ var SQLDialect = class {
4188
6719
  const fromClause = components.fromAlias ? `${this.escapeIdentifier(components.from)} AS ${this.escapeIdentifier(components.fromAlias)}` : this.escapeIdentifier(components.from);
4189
6720
  parts.push(fromClause);
4190
6721
  }
4191
- for (const join of components.joins) {
4192
- parts.push(`${join.type} JOIN ${this.escapeIdentifier(join.table)}`);
4193
- if (join.alias) {
4194
- parts.push(`AS ${this.escapeIdentifier(join.alias)}`);
6722
+ for (const join2 of components.joins) {
6723
+ parts.push(`${join2.type} JOIN ${this.escapeIdentifier(join2.table)}`);
6724
+ if (join2.alias) {
6725
+ parts.push(`AS ${this.escapeIdentifier(join2.alias)}`);
4195
6726
  }
4196
- parts.push(`ON ${join.condition}`);
4197
- bindings.push(...join.bindings);
6727
+ parts.push(`ON ${join2.condition}`);
6728
+ bindings.push(...join2.bindings);
4198
6729
  }
4199
6730
  if (components.where.length > 0) {
4200
6731
  parts.push("WHERE");
@@ -4341,7 +6872,7 @@ var SQLDialect = class {
4341
6872
  };
4342
6873
 
4343
6874
  // src/dialect/mysql-dialect.ts
4344
- var MySQLDialect = class extends SQLDialect {
6875
+ var MySQLDialect2 = class extends SQLDialect {
4345
6876
  name = "mysql";
4346
6877
  config = {
4347
6878
  identifierQuote: "`",
@@ -4453,7 +6984,7 @@ var MySQLDialect = class extends SQLDialect {
4453
6984
  };
4454
6985
 
4455
6986
  // src/dialect/postgresql-dialect.ts
4456
- var PostgreSQLDialect = class extends SQLDialect {
6987
+ var PostgreSQLDialect2 = class extends SQLDialect {
4457
6988
  name = "postgresql";
4458
6989
  config = {
4459
6990
  identifierQuote: '"',
@@ -4607,10 +7138,10 @@ var DialectFactory = class {
4607
7138
  const normalizedType = this.normalizeType(type);
4608
7139
  switch (normalizedType) {
4609
7140
  case "mysql": {
4610
- return new MySQLDialect();
7141
+ return new MySQLDialect2();
4611
7142
  }
4612
7143
  case "postgresql": {
4613
- return new PostgreSQLDialect();
7144
+ return new PostgreSQLDialect2();
4614
7145
  }
4615
7146
  default: {
4616
7147
  throw new Error(`Unsupported database type: ${type}`);
@@ -6316,7 +8847,7 @@ function calculateDelay(attempt, baseDelay, maxDelay, multiplier) {
6316
8847
  return Math.floor(cappedDelay + jitter);
6317
8848
  }
6318
8849
  function sleep2(ms) {
6319
- return new Promise((resolve) => setTimeout(resolve, ms));
8850
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
6320
8851
  }
6321
8852
  function createRetryMiddleware(options = {}) {
6322
8853
  const {
@@ -7164,12 +9695,12 @@ var DBBridge2 = class _DBBridge {
7164
9695
  const dbType = this.config.type;
7165
9696
  switch (dbType) {
7166
9697
  case "mysql": {
7167
- this._dialect = new MySQLDialect();
9698
+ this._dialect = new MySQLDialect2();
7168
9699
  break;
7169
9700
  }
7170
9701
  case "postgresql":
7171
9702
  case "postgres": {
7172
- this._dialect = new PostgreSQLDialect();
9703
+ this._dialect = new PostgreSQLDialect2();
7173
9704
  break;
7174
9705
  }
7175
9706
  case "redis": {
@@ -7793,6 +10324,6 @@ var DBBridge3 = class _DBBridge {
7793
10324
  }
7794
10325
  };
7795
10326
 
7796
- export { ANALYSIS_DEFAULTS, BaseAdapter, BaseQueryBuilder, BaseTransaction, CACHE_DEFAULTS, CONNECTION_DEFAULTS, CRYPTO_DEFAULTS, CacheAPI, CacheError, CacheKeyGenerator, CacheManager, CacheableQuery, CachedAdapter, CachedDBBridge, DBBridge as Client, ConnectionError, CryptoAlgorithms, CryptoProvider, DBBridge2 as DBBridge, DBBridgeError, DBBridge3 as DBBridgeFactory, DEFAULT_POOL_CONFIG, DEFAULT_TIMEOUTS, DURATION_BUCKETS, DatabaseError, DefaultCacheStrategy, DeleteBuilder, DialectFactory, HEALTH_DEFAULTS, HealthChecker, ISOLATION_LEVELS, InsertBuilder, IsolationLevel, LOGGING_DEFAULTS, MetricsCollector, MiddlewareChain, MigrationRunner, ModularCacheManager, ModularPerformanceMonitor, MySQLDialect, NotImplementedError, POOL_DEFAULTS, POOL_DEFAULTS_LEGACY, PerformanceMonitor, PoolExhaustedError, PostgreSQLDialect, QUERY_DEFAULTS, QueryContext, QueryError, QueryTimeoutError, RETRY_DEFAULTS, SIZE_UNITS, SQLDialect, SelectBuilder, SmartCacheStrategy, TIME_UNITS, TimeoutError, TransactionError, UpdateBuilder, ValidationError, WhereBuilder, avg, cacheKey, chunk, composeMiddleware, compress, count, createAdapter, createCacheInvalidationMiddleware, createCacheKeyPattern, createCacheMiddleware, createCachedAdapter, createCircuitBreakerMiddleware, createDeadlineMiddleware, createLoggingMiddleware, createMetricsMiddleware, createModularQueryBuilder, createQueryState, createRetryMiddleware, createTimeoutMiddleware, crypto, cursorPaginate, decompress, encryptRow, exists, generateCacheKey, generateUUID, getCompressionRatio, isCompressed, isDeleteResult, isInsertResult, isSelectResult, isUpdateResult, max, min, paginate, parseCacheKey, processDataForEncryption, processResultsForDecryption, registerAdapterFactory, retry, sanitizeCacheKey, shouldCompress, sql, sum, validateColumnName, validateConnectionConfig, validateSQL, validateTableName, whereBetweenDates, whereDate, whereDay, whereLastDays, whereMonth, whereToday, whereYear, whereYesterday, withTimeout };
10327
+ export { ANALYSIS_DEFAULTS, AlterTableBuilder, BaseAdapter, BaseQueryBuilder, BaseTransaction, CACHE_DEFAULTS, CONNECTION_DEFAULTS, CRYPTO_DEFAULTS, CacheAPI, CacheError, CacheKeyGenerator, CacheManager, CacheableQuery, CachedAdapter, CachedDBBridge, DBBridge as Client, ColumnBuilder, ConnectionError, CryptoAlgorithms, CryptoProvider, DBBridge2 as DBBridge, DBBridgeError, DBBridge3 as DBBridgeFactory, DEFAULT_POOL_CONFIG, DEFAULT_TIMEOUTS, DURATION_BUCKETS, DatabaseError, DefaultCacheStrategy, DeleteBuilder, DialectFactory, ExpandContractHelper, FileMigrationRunner, ForeignKeyBuilder, ForeignKeyChain, HEALTH_DEFAULTS, HealthChecker, ISOLATION_LEVELS, InsertBuilder, IsolationLevel, LOGGING_DEFAULTS, MetricsCollector, MiddlewareChain, MigrationLoader, MigrationLock, MigrationRunner, ModularCacheManager, ModularPerformanceMonitor, MySQLDialect2 as MySQLDialect, NotImplementedError, POOL_DEFAULTS, POOL_DEFAULTS_LEGACY, PerformanceMonitor, PoolExhaustedError, PostgreSQLDialect2 as PostgreSQLDialect, QUERY_DEFAULTS, QueryContext, QueryError, QueryTimeoutError, RETRY_DEFAULTS, SIZE_UNITS, SQLDialect, SchemaBuilder, MySQLDialect as SchemaMySQLDialect, PostgreSQLDialect as SchemaPostgreSQLDialect, SeederLoader, SeederRunner, SelectBuilder, SmartCacheStrategy, TIME_UNITS, TableBuilder, TimeoutError, TransactionError, UpdateBuilder, ValidationError, WhereBuilder, avg, cacheKey, chunk, composeMiddleware, compress, count, createAdapter, createCacheInvalidationMiddleware, createCacheKeyPattern, createCacheMiddleware, createCachedAdapter, createCircuitBreakerMiddleware, createDeadlineMiddleware, createExpandContractHelper, createLoggingMiddleware, createMetricsMiddleware, createModularQueryBuilder, createQueryState, createRetryMiddleware, createTimeoutMiddleware, crypto, cursorPaginate, decompress, encryptRow, exists, generateCacheKey, generateUUID, getCompressionRatio, isCompressed, isDeleteResult, isInsertResult, isSelectResult, isUpdateResult, max, min, paginate, parseCacheKey, processDataForEncryption, processResultsForDecryption, registerAdapterFactory, retry, sanitizeCacheKey, shouldCompress, sql, sum, validateColumnName, validateConnectionConfig, validateSQL, validateTableName, whereBetweenDates, whereDate, whereDay, whereLastDays, whereMonth, whereToday, whereYear, whereYesterday, withTimeout };
7797
10328
  //# sourceMappingURL=index.js.map
7798
10329
  //# sourceMappingURL=index.js.map