@db-bridge/core 1.1.7 → 1.2.0

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Berke Erdoğan
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Berke Erdoğan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  SOFTWARE.
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { parseArgs } from 'util';
3
- import { resolve, basename, extname, join } from 'path';
3
+ import { resolve, dirname, basename, extname, join } from 'path';
4
4
  import { existsSync } from 'fs';
5
5
  import { pathToFileURL } from 'url';
6
6
  import { createHash } from 'crypto';
@@ -81,6 +81,11 @@ function applyDefaults(config) {
81
81
  seeds: {
82
82
  directory: "./src/seeds",
83
83
  ...config.seeds
84
+ },
85
+ types: {
86
+ output: "./src/types/database.ts",
87
+ camelCase: false,
88
+ ...config.types
84
89
  }
85
90
  };
86
91
  }
@@ -1076,7 +1081,7 @@ var MigrationLock = class {
1076
1081
  }
1077
1082
  }
1078
1083
  sleep(ms) {
1079
- return new Promise((resolve7) => setTimeout(resolve7, ms));
1084
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
1080
1085
  }
1081
1086
  };
1082
1087
 
@@ -1689,8 +1694,11 @@ var ForeignKeyChain = class {
1689
1694
  var SchemaBuilder = class {
1690
1695
  dialectInstance;
1691
1696
  adapter;
1697
+ collectMode;
1698
+ collectedStatements = [];
1692
1699
  constructor(options) {
1693
1700
  this.adapter = options.adapter;
1701
+ this.collectMode = options.collectMode ?? false;
1694
1702
  switch (options.dialect) {
1695
1703
  case "mysql": {
1696
1704
  this.dialectInstance = new MySQLDialect();
@@ -1796,6 +1804,14 @@ var SchemaBuilder = class {
1796
1804
  * Execute SQL statement
1797
1805
  */
1798
1806
  async execute(sql, params) {
1807
+ if (this.collectMode) {
1808
+ let statement = sql;
1809
+ if (params && params.length > 0) {
1810
+ statement += ` -- params: ${JSON.stringify(params)}`;
1811
+ }
1812
+ this.collectedStatements.push(statement);
1813
+ return;
1814
+ }
1799
1815
  if (this.adapter) {
1800
1816
  await this.adapter.execute(sql, params);
1801
1817
  } else {
@@ -1805,6 +1821,18 @@ var SchemaBuilder = class {
1805
1821
  }
1806
1822
  }
1807
1823
  }
1824
+ /**
1825
+ * Get collected SQL statements (only in collectMode)
1826
+ */
1827
+ getCollectedStatements() {
1828
+ return [...this.collectedStatements];
1829
+ }
1830
+ /**
1831
+ * Clear collected SQL statements
1832
+ */
1833
+ clearCollectedStatements() {
1834
+ this.collectedStatements = [];
1835
+ }
1808
1836
  /**
1809
1837
  * Execute SQL query
1810
1838
  */
@@ -2260,7 +2288,23 @@ var FileMigrationRunner = class {
2260
2288
  const action = direction === "up" ? "Running" : "Rolling back";
2261
2289
  this.options.logger.info(`${action}: ${migration.name}`);
2262
2290
  if (this.options.dryRun) {
2263
- this.options.logger.info(`DRY RUN: Would ${direction} ${migration.name}`);
2291
+ const schema = new SchemaBuilder({
2292
+ dialect: this.options.dialect,
2293
+ collectMode: true
2294
+ });
2295
+ await migration[direction](schema);
2296
+ const statements = schema.getCollectedStatements();
2297
+ if (statements.length > 0) {
2298
+ this.options.logger.info(`DRY RUN: ${direction.toUpperCase()} ${migration.name}`);
2299
+ this.options.logger.info("SQL statements that would be executed:");
2300
+ for (const sql of statements) {
2301
+ this.options.logger.info(` ${sql}`);
2302
+ }
2303
+ } else {
2304
+ this.options.logger.info(
2305
+ `DRY RUN: ${direction.toUpperCase()} ${migration.name} (no SQL statements)`
2306
+ );
2307
+ }
2264
2308
  return;
2265
2309
  }
2266
2310
  const transaction = migration.transactional ? await this.adapter.beginTransaction() : null;
@@ -2428,6 +2472,263 @@ async function freshCommand(options = {}) {
2428
2472
  }
2429
2473
  }
2430
2474
 
2475
+ // src/types/TypeGenerator.ts
2476
+ var SQL_TYPE_MAP = {
2477
+ // Integers
2478
+ tinyint: "number",
2479
+ smallint: "number",
2480
+ mediumint: "number",
2481
+ int: "number",
2482
+ integer: "number",
2483
+ bigint: "number",
2484
+ // Floats
2485
+ float: "number",
2486
+ double: "number",
2487
+ decimal: "number",
2488
+ numeric: "number",
2489
+ real: "number",
2490
+ // Strings
2491
+ char: "string",
2492
+ varchar: "string",
2493
+ tinytext: "string",
2494
+ text: "string",
2495
+ mediumtext: "string",
2496
+ longtext: "string",
2497
+ enum: "string",
2498
+ set: "string",
2499
+ // Binary
2500
+ binary: "Buffer",
2501
+ varbinary: "Buffer",
2502
+ tinyblob: "Buffer",
2503
+ blob: "Buffer",
2504
+ mediumblob: "Buffer",
2505
+ longblob: "Buffer",
2506
+ // Date/Time
2507
+ date: "Date",
2508
+ datetime: "Date",
2509
+ timestamp: "Date",
2510
+ time: "string",
2511
+ year: "number",
2512
+ // Boolean
2513
+ boolean: "boolean",
2514
+ bool: "boolean",
2515
+ // JSON
2516
+ json: "Record<string, unknown>",
2517
+ jsonb: "Record<string, unknown>",
2518
+ // UUID (PostgreSQL)
2519
+ uuid: "string",
2520
+ // Arrays (PostgreSQL)
2521
+ array: "unknown[]"
2522
+ };
2523
+ var TypeGenerator = class {
2524
+ constructor(adapter, dialect) {
2525
+ this.adapter = adapter;
2526
+ this.dialect = dialect;
2527
+ }
2528
+ /**
2529
+ * Generate TypeScript interfaces from database schema
2530
+ */
2531
+ async generate(options = {}) {
2532
+ const tables = await this.getTables(options);
2533
+ const output = [];
2534
+ if (options.header) {
2535
+ output.push(options.header);
2536
+ output.push("");
2537
+ } else {
2538
+ output.push("/**");
2539
+ output.push(" * Auto-generated TypeScript types from database schema");
2540
+ output.push(` * Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`);
2541
+ output.push(" * DO NOT EDIT - This file is auto-generated");
2542
+ output.push(" */");
2543
+ output.push("");
2544
+ }
2545
+ for (const table of tables) {
2546
+ const tableInfo = await this.getTableInfo(table);
2547
+ const interfaceCode = this.generateInterface(tableInfo, options);
2548
+ output.push(interfaceCode);
2549
+ output.push("");
2550
+ }
2551
+ return output.join("\n");
2552
+ }
2553
+ /**
2554
+ * Get list of tables from database
2555
+ */
2556
+ async getTables(options) {
2557
+ let tables;
2558
+ if (this.dialect === "mysql") {
2559
+ const result = await this.adapter.query(
2560
+ `SELECT table_name FROM information_schema.tables
2561
+ WHERE table_schema = DATABASE() AND table_type = 'BASE TABLE'`
2562
+ );
2563
+ tables = result.rows.map((r) => r["table_name"] || r["TABLE_NAME"]).filter((t) => t !== null && t !== void 0);
2564
+ } else {
2565
+ const result = await this.adapter.query(
2566
+ `SELECT table_name FROM information_schema.tables
2567
+ WHERE table_schema = 'public' AND table_type = 'BASE TABLE'`
2568
+ );
2569
+ tables = result.rows.map((r) => r["table_name"] || r["TABLE_NAME"]).filter((t) => t !== null && t !== void 0);
2570
+ }
2571
+ if (options.tables && options.tables.length > 0) {
2572
+ tables = tables.filter((t) => options.tables.includes(t));
2573
+ }
2574
+ if (options.exclude && options.exclude.length > 0) {
2575
+ tables = tables.filter((t) => !options.exclude.includes(t));
2576
+ }
2577
+ tables = tables.filter((t) => !t.startsWith("db_migrations") && !t.startsWith("db_bridge"));
2578
+ return tables.sort();
2579
+ }
2580
+ /**
2581
+ * Get column information for a table
2582
+ */
2583
+ async getTableInfo(tableName) {
2584
+ let columns;
2585
+ if (this.dialect === "mysql") {
2586
+ columns = await this.getMySQLColumns(tableName);
2587
+ } else {
2588
+ columns = await this.getPostgreSQLColumns(tableName);
2589
+ }
2590
+ return { name: tableName, columns };
2591
+ }
2592
+ /**
2593
+ * Get MySQL column information
2594
+ */
2595
+ async getMySQLColumns(tableName) {
2596
+ const result = await this.adapter.query(`SHOW FULL COLUMNS FROM \`${tableName}\``);
2597
+ return result.rows.map((row) => ({
2598
+ name: row.Field,
2599
+ type: this.parseColumnType(row.Type),
2600
+ nullable: row.Null === "YES",
2601
+ defaultValue: row.Default,
2602
+ isPrimary: row.Key === "PRI",
2603
+ isAutoIncrement: row.Extra.includes("auto_increment"),
2604
+ comment: row.Comment || void 0
2605
+ }));
2606
+ }
2607
+ /**
2608
+ * Get PostgreSQL column information
2609
+ */
2610
+ async getPostgreSQLColumns(tableName) {
2611
+ const result = await this.adapter.query(
2612
+ `
2613
+ SELECT
2614
+ c.column_name,
2615
+ c.data_type,
2616
+ c.is_nullable,
2617
+ c.column_default,
2618
+ c.is_identity,
2619
+ pgd.description
2620
+ FROM information_schema.columns c
2621
+ LEFT JOIN pg_catalog.pg_statio_all_tables st ON c.table_name = st.relname
2622
+ LEFT JOIN pg_catalog.pg_description pgd ON pgd.objoid = st.relid
2623
+ AND pgd.objsubid = c.ordinal_position
2624
+ WHERE c.table_name = $1
2625
+ ORDER BY c.ordinal_position
2626
+ `,
2627
+ [tableName]
2628
+ );
2629
+ return result.rows.map((row) => ({
2630
+ name: row.column_name,
2631
+ type: row.data_type,
2632
+ nullable: row.is_nullable === "YES",
2633
+ defaultValue: row.column_default,
2634
+ isPrimary: false,
2635
+ // Would need additional query
2636
+ isAutoIncrement: row.is_identity === "YES" || (row.column_default?.includes("nextval") ?? false),
2637
+ comment: row.description
2638
+ }));
2639
+ }
2640
+ /**
2641
+ * Parse column type (extract base type from full type string)
2642
+ */
2643
+ parseColumnType(fullType) {
2644
+ const baseType = fullType.toLowerCase().replace(/\(.*\)/, "").trim();
2645
+ return baseType.replace(" unsigned", "");
2646
+ }
2647
+ /**
2648
+ * Map SQL type to TypeScript type
2649
+ */
2650
+ mapType(sqlType, nullable) {
2651
+ const baseType = this.parseColumnType(sqlType);
2652
+ if (sqlType.toLowerCase().includes("tinyint(1)")) {
2653
+ return nullable ? "boolean | null" : "boolean";
2654
+ }
2655
+ const tsType = SQL_TYPE_MAP[baseType] || "unknown";
2656
+ return nullable ? `${tsType} | null` : tsType;
2657
+ }
2658
+ /**
2659
+ * Generate TypeScript interface for a table
2660
+ */
2661
+ generateInterface(table, options) {
2662
+ const lines = [];
2663
+ const interfaceName = this.toInterfaceName(table.name);
2664
+ if (options.includeComments) {
2665
+ lines.push("/**");
2666
+ lines.push(` * ${interfaceName} - ${table.name} table`);
2667
+ lines.push(" */");
2668
+ }
2669
+ lines.push(`export interface ${interfaceName} {`);
2670
+ for (const column of table.columns) {
2671
+ const propertyName = options.camelCase ? this.toCamelCase(column.name) : column.name;
2672
+ const tsType = this.mapType(column.type, column.nullable);
2673
+ const optional = options.optionalNullable && column.nullable ? "?" : "";
2674
+ if (options.includeComments && column.comment) {
2675
+ lines.push(` /** ${column.comment} */`);
2676
+ }
2677
+ lines.push(` ${propertyName}${optional}: ${tsType};`);
2678
+ }
2679
+ lines.push("}");
2680
+ return lines.join("\n");
2681
+ }
2682
+ /**
2683
+ * Convert table name to PascalCase interface name
2684
+ */
2685
+ toInterfaceName(tableName) {
2686
+ return tableName.split("_").map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
2687
+ }
2688
+ /**
2689
+ * Convert snake_case to camelCase
2690
+ */
2691
+ toCamelCase(name) {
2692
+ return name.replaceAll(/_([a-z])/g, (_, letter) => letter.toUpperCase());
2693
+ }
2694
+ };
2695
+
2696
+ // src/cli/commands/generate-types.ts
2697
+ async function generateTypesCommand(options = {}) {
2698
+ let adapter;
2699
+ try {
2700
+ const config = await loadConfig();
2701
+ adapter = await createAdapterFromConfig(config);
2702
+ info("Generating TypeScript types from database schema...");
2703
+ console.log("");
2704
+ const generator = new TypeGenerator(adapter, config.connection.dialect);
2705
+ const types = await generator.generate({
2706
+ tables: options.tables ? options.tables.split(",").map((t) => t.trim()) : void 0,
2707
+ exclude: options.exclude ? options.exclude.split(",").map((t) => t.trim()) : void 0,
2708
+ camelCase: options.camelCase ?? false,
2709
+ includeComments: options.comments ?? true,
2710
+ optionalNullable: true
2711
+ });
2712
+ const outputPath = resolve(
2713
+ process.cwd(),
2714
+ options.output || config.types?.output || "./src/types/database.ts"
2715
+ );
2716
+ await mkdir(dirname(outputPath), { recursive: true });
2717
+ await writeFile(outputPath, types, "utf8");
2718
+ console.log("");
2719
+ success(`Types generated: ${outputPath}`);
2720
+ const interfaceCount = (types.match(/export interface/g) || []).length;
2721
+ info(`Generated ${interfaceCount} interface(s)`);
2722
+ } catch (error_) {
2723
+ error(error_.message);
2724
+ process.exit(1);
2725
+ } finally {
2726
+ if (adapter) {
2727
+ await adapter.disconnect();
2728
+ }
2729
+ }
2730
+ }
2731
+
2431
2732
  // src/cli/commands/latest.ts
2432
2733
  async function latestCommand(options = {}) {
2433
2734
  let adapter;
@@ -2481,20 +2782,61 @@ async function makeCommand(name) {
2481
2782
  process.exit(1);
2482
2783
  }
2483
2784
  }
2785
+ var DEFAULT_PRIORITY = 100;
2484
2786
  var SeederLoader = class {
2485
2787
  constructor(directory) {
2486
2788
  this.directory = directory;
2487
2789
  }
2488
2790
  /**
2489
- * Load all seeder files from directory
2791
+ * Load all seeder files from directory (sorted by priority/dependencies)
2490
2792
  */
2491
2793
  async loadAll() {
2492
2794
  const files = await readdir(this.directory);
2493
- const seederFiles = files.filter((f) => /\.(ts|js|mjs)$/.test(f) && !f.endsWith(".d.ts")).sort().map((f) => ({
2795
+ const seederPaths = files.filter((f) => /\.(ts|js|mjs)$/.test(f) && !f.endsWith(".d.ts")).map((f) => ({
2494
2796
  name: this.getSeederName(f),
2495
2797
  path: resolve(this.directory, f)
2496
2798
  }));
2497
- return seederFiles;
2799
+ const seederFiles = [];
2800
+ for (const file of seederPaths) {
2801
+ const seeder = await this.load(file.path);
2802
+ seederFiles.push({
2803
+ name: file.name,
2804
+ path: file.path,
2805
+ priority: seeder.priority ?? DEFAULT_PRIORITY,
2806
+ depends: seeder.depends
2807
+ });
2808
+ }
2809
+ return this.sortByDependencies(seederFiles);
2810
+ }
2811
+ /**
2812
+ * Sort seeders by dependencies (topological sort) then by priority
2813
+ */
2814
+ sortByDependencies(files) {
2815
+ const fileMap = new Map(files.map((f) => [f.name, f]));
2816
+ const visited = /* @__PURE__ */ new Set();
2817
+ const result = [];
2818
+ const visit = (file) => {
2819
+ if (visited.has(file.name)) {
2820
+ return;
2821
+ }
2822
+ visited.add(file.name);
2823
+ if (file.depends) {
2824
+ for (const dep of file.depends) {
2825
+ const depFile = fileMap.get(dep) || fileMap.get(`${dep}_seeder`);
2826
+ if (depFile) {
2827
+ visit(depFile);
2828
+ }
2829
+ }
2830
+ }
2831
+ result.push(file);
2832
+ };
2833
+ const sortedByPriority = [...files].sort(
2834
+ (a, b) => (a.priority ?? DEFAULT_PRIORITY) - (b.priority ?? DEFAULT_PRIORITY)
2835
+ );
2836
+ for (const file of sortedByPriority) {
2837
+ visit(file);
2838
+ }
2839
+ return result;
2498
2840
  }
2499
2841
  /**
2500
2842
  * Load a specific seeder by path
@@ -2536,10 +2878,16 @@ var SeederLoader = class {
2536
2878
  import type { Seeder, DatabaseAdapter } from '@db-bridge/core';
2537
2879
 
2538
2880
  export default {
2881
+ // Priority: lower runs first (default: 100)
2882
+ // priority: 10,
2883
+
2884
+ // Dependencies: seeders that must run before this one
2885
+ // depends: ['users'],
2886
+
2539
2887
  async run(adapter: DatabaseAdapter): Promise<void> {
2540
2888
  // Insert seed data
2541
2889
  // await adapter.execute(\`
2542
- // INSERT INTO users (name, email) VALUES
2890
+ // INSERT INTO ${name} (name, email) VALUES
2543
2891
  // ('John Doe', 'john@example.com'),
2544
2892
  // ('Jane Doe', 'jane@example.com')
2545
2893
  // \`);
@@ -2874,12 +3222,20 @@ Seed Commands:
2874
3222
  db:seed Run database seeders
2875
3223
  db:seed --class=<name> Run a specific seeder
2876
3224
 
3225
+ Type Generation:
3226
+ generate:types Generate TypeScript interfaces from schema
3227
+
2877
3228
  Options:
2878
3229
  --help, -h Show this help message
2879
3230
  --version, -v Show version number
2880
3231
  --dry-run Show what would be done without executing
2881
3232
  --step=<n> Number of batches to rollback (for rollback command)
2882
3233
  --class=<name> Specific seeder class to run (for db:seed)
3234
+ --output=<path> Output file path (for generate:types)
3235
+ --tables=<list> Comma-separated list of tables to include
3236
+ --exclude=<list> Comma-separated list of tables to exclude
3237
+ --camel-case Use camelCase for property names
3238
+ --comments Include JSDoc comments (default: true)
2883
3239
 
2884
3240
  Examples:
2885
3241
  db-bridge migrate:make create_users_table
@@ -2888,6 +3244,8 @@ Examples:
2888
3244
  db-bridge make:seeder users
2889
3245
  db-bridge db:seed
2890
3246
  db-bridge db:seed --class=users
3247
+ db-bridge generate:types
3248
+ db-bridge generate:types --output=./src/types/db.ts --camel-case
2891
3249
  `;
2892
3250
  async function main() {
2893
3251
  const args = process.argv.slice(2);
@@ -2902,7 +3260,12 @@ async function main() {
2902
3260
  version: { type: "boolean", short: "v" },
2903
3261
  "dry-run": { type: "boolean" },
2904
3262
  step: { type: "string" },
2905
- class: { type: "string" }
3263
+ class: { type: "string" },
3264
+ output: { type: "string" },
3265
+ tables: { type: "string" },
3266
+ exclude: { type: "string" },
3267
+ "camel-case": { type: "boolean" },
3268
+ comments: { type: "boolean" }
2906
3269
  },
2907
3270
  allowPositionals: true
2908
3271
  });
@@ -2911,7 +3274,12 @@ async function main() {
2911
3274
  version: values.version,
2912
3275
  dryRun: values["dry-run"],
2913
3276
  step: values.step ? parseInt(values.step, 10) : void 0,
2914
- class: values.class
3277
+ class: values.class,
3278
+ output: values.output,
3279
+ tables: values.tables,
3280
+ exclude: values.exclude,
3281
+ camelCase: values["camel-case"],
3282
+ comments: values.comments
2915
3283
  };
2916
3284
  command = positionals[0] || "";
2917
3285
  commandArgs = positionals.slice(1);
@@ -2921,6 +3289,8 @@ async function main() {
2921
3289
  options.help = args.includes("--help") || args.includes("-h");
2922
3290
  options.version = args.includes("--version") || args.includes("-v");
2923
3291
  options.dryRun = args.includes("--dry-run");
3292
+ options.camelCase = args.includes("--camel-case");
3293
+ options.comments = args.includes("--comments");
2924
3294
  const stepArg = args.find((a) => a.startsWith("--step="));
2925
3295
  if (stepArg) {
2926
3296
  options.step = parseInt(stepArg.split("=")[1] || "1", 10);
@@ -2929,6 +3299,18 @@ async function main() {
2929
3299
  if (classArg) {
2930
3300
  options.class = classArg.split("=")[1];
2931
3301
  }
3302
+ const outputArg = args.find((a) => a.startsWith("--output="));
3303
+ if (outputArg) {
3304
+ options.output = outputArg.split("=")[1];
3305
+ }
3306
+ const tablesArg = args.find((a) => a.startsWith("--tables="));
3307
+ if (tablesArg) {
3308
+ options.tables = tablesArg.split("=")[1];
3309
+ }
3310
+ const excludeArg = args.find((a) => a.startsWith("--exclude="));
3311
+ if (excludeArg) {
3312
+ options.exclude = excludeArg.split("=")[1];
3313
+ }
2932
3314
  }
2933
3315
  if (options.help || command === "help") {
2934
3316
  console.log(HELP);
@@ -2990,6 +3372,16 @@ async function main() {
2990
3372
  await seedCommand({ class: options.class });
2991
3373
  break;
2992
3374
  }
3375
+ case "generate:types": {
3376
+ await generateTypesCommand({
3377
+ output: options.output,
3378
+ tables: options.tables,
3379
+ exclude: options.exclude,
3380
+ camelCase: options.camelCase,
3381
+ comments: options.comments
3382
+ });
3383
+ break;
3384
+ }
2993
3385
  default: {
2994
3386
  console.error(`Unknown command: ${command}`);
2995
3387
  console.log('Run "db-bridge --help" for usage information.');