drixio 1.1.6 → 1.1.8

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/cli.js CHANGED
@@ -47,7 +47,7 @@ function printCustomDashboard(title, rows) {
47
47
  );
48
48
  }
49
49
  function printDashboard(dbConfig) {
50
- const headerTitle = ` Lightweight Interactive TUI Database Client \u2022 v${"1.1.6"} `;
50
+ const headerTitle = ` Lightweight Interactive TUI Database Client \u2022 v${process.env.npm_package_version} `;
51
51
  let dbTypeVal = "None";
52
52
  let targetVal = "-";
53
53
  let sourceVal = "None";
@@ -156,14 +156,49 @@ var init_sqlite = __esm({
156
156
  const info = pragmaQuery.all();
157
157
  const fkQuery = db.prepare(`PRAGMA foreign_key_list(${quoted})`);
158
158
  const fks = fkQuery.all();
159
+ const indexListQuery = db.prepare(`PRAGMA index_list(${quoted})`);
160
+ const indexList = indexListQuery.all();
161
+ const uniqueCols = /* @__PURE__ */ new Set();
162
+ for (const idx of indexList) {
163
+ if (idx.unique === 1) {
164
+ const infoQuery = db.prepare(
165
+ `PRAGMA index_info(${this.quoteIdentifier(idx.name)})`
166
+ );
167
+ const cols = infoQuery.all();
168
+ if (cols.length === 1 && cols[0].name) {
169
+ uniqueCols.add(cols[0].name);
170
+ }
171
+ }
172
+ }
173
+ const enumMap = /* @__PURE__ */ new Map();
174
+ try {
175
+ const createSql = db.prepare(
176
+ `SELECT sql FROM sqlite_master WHERE type='table' AND name=${quoted}`
177
+ ).get();
178
+ if (createSql?.sql) {
179
+ const checkRegex = /CHECK\s*\(\s*["']?(\w+)["']?\s+IN\s*\(([^)]+)\)\s*\)/gi;
180
+ let match;
181
+ while ((match = checkRegex.exec(createSql.sql)) !== null) {
182
+ const colName = match[1];
183
+ const valuesStr = match[2];
184
+ const values = valuesStr.split(",").map((s) => s.trim().replace(/^'|'$/g, "")).filter((s) => s.length > 0);
185
+ if (values.length > 0) {
186
+ enumMap.set(colName, values);
187
+ }
188
+ }
189
+ }
190
+ } catch {
191
+ }
159
192
  return info.map((col) => {
160
193
  const fk = fks.find((f) => f.from === col.name);
161
194
  return {
162
195
  name: col.name,
163
196
  type: col.type,
164
197
  isPk: col.pk > 0,
165
- nullable: col.notnull === 0,
198
+ nullable: col.pk > 0 ? false : col.notnull === 0,
199
+ isUnique: col.pk > 0 || uniqueCols.has(col.name),
166
200
  defaultValue: col.dflt_value != null ? String(col.dflt_value) : void 0,
201
+ enumValues: enumMap.get(col.name),
167
202
  fkTarget: fk ? { table: fk.table, column: fk.to } : void 0
168
203
  };
169
204
  });
@@ -176,7 +211,9 @@ var init_sqlite = __esm({
176
211
  const indexes = [];
177
212
  for (const idx of indexList) {
178
213
  if (idx.origin === "pk") continue;
179
- const indexInfoQuery = db.prepare(`PRAGMA index_info(${this.quoteIdentifier(idx.name)})`);
214
+ const indexInfoQuery = db.prepare(
215
+ `PRAGMA index_info(${this.quoteIdentifier(idx.name)})`
216
+ );
180
217
  const columns = indexInfoQuery.all();
181
218
  indexes.push({
182
219
  name: idx.name,
@@ -204,20 +241,38 @@ var init_sqlite = __esm({
204
241
  }
205
242
  async query(sql) {
206
243
  const db = await this.getDb();
207
- const trimmed = sql.trim().toUpperCase();
208
- const isRead = trimmed.startsWith("SELECT") || trimmed.startsWith("PRAGMA") || trimmed.startsWith("EXPLAIN") || trimmed.startsWith("WITH");
209
- if (isRead) {
210
- const query = db.prepare(sql);
211
- const rows = query.all();
244
+ const stripped = sql.replace(
245
+ /^(\s*--[^\n]*\n|\s*\/\*[\s\S]*?\*\/\s*|\s+)*/g,
246
+ ""
247
+ );
248
+ const upper = stripped.toUpperCase();
249
+ const isRead = upper.startsWith("SELECT") || upper.startsWith("PRAGMA") || upper.startsWith("EXPLAIN") || upper.startsWith("WITH") || upper.startsWith("(");
250
+ const hasReturning = /\bRETURNING\b/i.test(sql);
251
+ if (isRead || hasReturning) {
252
+ const stmt = db.prepare(sql);
253
+ const rows = stmt.all();
212
254
  let columns = [];
213
255
  if (rows.length > 0) {
214
256
  columns = Object.keys(rows[0]);
257
+ } else {
258
+ try {
259
+ const colMeta = stmt.columns();
260
+ if (Array.isArray(colMeta)) {
261
+ columns = colMeta.map((c) => c.name || c.column);
262
+ }
263
+ } catch {
264
+ }
215
265
  }
216
266
  return { columns, rows };
217
267
  } else {
218
- const query = db.prepare(sql);
219
- query.run();
220
- return { columns: ["Result"], rows: [{ Result: "Success" }] };
268
+ const stmt = db.prepare(sql);
269
+ const result = stmt.run();
270
+ const changes = result.changes ?? 0;
271
+ return {
272
+ columns: ["Result", "AffectedRows"],
273
+ rows: [{ Result: "Success", AffectedRows: changes }],
274
+ affectedRows: changes
275
+ };
221
276
  }
222
277
  }
223
278
  async executeSql(sql) {
@@ -238,9 +293,108 @@ var init_sqlite = __esm({
238
293
  const placeholders = cols.map(() => "?").join(", ");
239
294
  const sql = `INSERT INTO ${this.quoteIdentifier(tableName)} (${colsQuoted}) VALUES (${placeholders})`;
240
295
  const stmt = db.prepare(sql);
241
- for (const row of rows) {
242
- const values = cols.map((c) => row[c]);
243
- stmt.run(...values);
296
+ db.exec("BEGIN");
297
+ try {
298
+ for (const row of rows) {
299
+ const values = cols.map((c) => row[c]);
300
+ stmt.run(...values);
301
+ }
302
+ db.exec("COMMIT");
303
+ } catch (e) {
304
+ db.exec("ROLLBACK");
305
+ throw e;
306
+ }
307
+ }
308
+ async recreateTable(tableName, newColumns, renames = {}) {
309
+ const db = await this.getDb();
310
+ const quotedOldTable = this.quoteIdentifier(tableName);
311
+ const tableCheck = db.prepare(
312
+ `SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?`
313
+ ).get(tableName);
314
+ if (!tableCheck) {
315
+ throw new Error(`Table "${tableName}" does not exist.`);
316
+ }
317
+ const indexRows = db.prepare(
318
+ `SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ? AND sql IS NOT NULL`
319
+ ).all(tableName);
320
+ const tempTableName = `_drixio_recreate_${Date.now()}`;
321
+ const quotedTempTable = this.quoteIdentifier(tempTableName);
322
+ const pkColumns = newColumns.filter((c) => c.isPk);
323
+ const isCompositePk = pkColumns.length > 1;
324
+ const colDefs = [];
325
+ for (const col of newColumns) {
326
+ let def = `${this.quoteIdentifier(col.name)} ${col.type || "TEXT"}`;
327
+ if (col.isPk && !isCompositePk) {
328
+ def += " PRIMARY KEY";
329
+ }
330
+ if (!col.nullable && (!col.isPk || isCompositePk)) {
331
+ def += " NOT NULL";
332
+ }
333
+ if (col.defaultValue !== void 0 && col.defaultValue !== null && col.defaultValue !== "") {
334
+ def += ` DEFAULT '${String(col.defaultValue).replace(/'/g, "''")}'`;
335
+ }
336
+ if (col.fkTarget && col.fkTarget.table && col.fkTarget.column) {
337
+ def += ` REFERENCES ${this.quoteIdentifier(col.fkTarget.table)}(${this.quoteIdentifier(col.fkTarget.column)})`;
338
+ }
339
+ if (col.isUnique && (!col.isPk || isCompositePk)) {
340
+ def += " UNIQUE";
341
+ }
342
+ colDefs.push(def);
343
+ }
344
+ if (isCompositePk) {
345
+ const pkColsQuoted = pkColumns.map((c) => this.quoteIdentifier(c.name)).join(", ");
346
+ colDefs.push(`PRIMARY KEY (${pkColsQuoted})`);
347
+ }
348
+ const createSql = `CREATE TABLE ${quotedTempTable} (
349
+ ${colDefs.join(",\n ")}
350
+ );`;
351
+ const newToOldMap = {};
352
+ for (const [oldName, newName] of Object.entries(renames)) {
353
+ newToOldMap[newName] = oldName;
354
+ }
355
+ const oldTableCols = db.prepare(`PRAGMA table_info(${quotedOldTable})`).all().map((r) => r.name);
356
+ const copyNewCols = [];
357
+ const copyOldCols = [];
358
+ for (const col of newColumns) {
359
+ const sourceOldName = newToOldMap[col.name] || col.name;
360
+ if (oldTableCols.includes(sourceOldName)) {
361
+ copyNewCols.push(this.quoteIdentifier(col.name));
362
+ copyOldCols.push(this.quoteIdentifier(sourceOldName));
363
+ }
364
+ }
365
+ let copySql = "";
366
+ if (copyNewCols.length > 0) {
367
+ copySql = `INSERT INTO ${quotedTempTable} (${copyNewCols.join(", ")}) SELECT ${copyOldCols.join(", ")} FROM ${quotedOldTable};`;
368
+ }
369
+ db.exec("PRAGMA foreign_keys = OFF;");
370
+ db.exec("BEGIN TRANSACTION;");
371
+ try {
372
+ db.exec(createSql);
373
+ if (copySql) {
374
+ db.exec(copySql);
375
+ }
376
+ db.exec(`DROP TABLE ${quotedOldTable};`);
377
+ db.exec(`ALTER TABLE ${quotedTempTable} RENAME TO ${quotedOldTable};`);
378
+ for (const idx of indexRows) {
379
+ if (!idx.sql) continue;
380
+ let idxSql = idx.sql;
381
+ for (const [oldName, newName] of Object.entries(renames)) {
382
+ idxSql = idxSql.replace(
383
+ new RegExp(`\\b${oldName}\\b`, "g"),
384
+ newName
385
+ );
386
+ }
387
+ try {
388
+ db.exec(idxSql);
389
+ } catch {
390
+ }
391
+ }
392
+ db.exec("COMMIT;");
393
+ } catch (err) {
394
+ db.exec("ROLLBACK;");
395
+ throw err;
396
+ } finally {
397
+ db.exec("PRAGMA foreign_keys = ON;");
244
398
  }
245
399
  }
246
400
  };
@@ -254,45 +408,54 @@ var init_postgres = __esm({
254
408
  "src/adapters/postgres.ts"() {
255
409
  "use strict";
256
410
  PostgresAdapter = class {
257
- client;
258
- connected = false;
411
+ connectionString;
412
+ pool = null;
259
413
  constructor(connection) {
260
- this.client = new pg.Client({
261
- connectionString: connection
262
- });
414
+ this.connectionString = connection;
263
415
  }
264
- async connectIfNecessary() {
265
- if (!this.connected) {
266
- await this.client.connect();
267
- this.connected = true;
416
+ getPool() {
417
+ if (!this.pool) {
418
+ this.pool = new pg.Pool({
419
+ connectionString: this.connectionString
420
+ });
421
+ this.pool.on("error", () => {
422
+ });
268
423
  }
424
+ return this.pool;
269
425
  }
270
426
  quoteIdentifier(name) {
271
427
  return `"${name.replace(/"/g, '""')}"`;
272
428
  }
273
429
  async getStatus() {
274
430
  try {
275
- await this.connectIfNecessary();
276
- const dbRes = await this.client.query("SELECT current_database() as db, version() as version");
431
+ const dbRes = await this.getPool().query(
432
+ "SELECT current_database() as db, version() as version"
433
+ );
277
434
  const dbName = dbRes.rows[0]?.db;
278
435
  const version = dbRes.rows[0]?.version?.split(" ")[1] || dbRes.rows[0]?.version;
279
436
  let activeConnections = 0;
280
437
  let transactions = 0;
281
438
  let uptime = 0;
282
439
  try {
283
- const uptimeRes = await this.client.query("SELECT EXTRACT(EPOCH FROM (now() - pg_postmaster_start_time())) as uptime");
440
+ const uptimeRes = await this.getPool().query(
441
+ "SELECT EXTRACT(EPOCH FROM (now() - pg_postmaster_start_time())) as uptime"
442
+ );
284
443
  uptime = parseInt(uptimeRes.rows[0]?.uptime || "0", 10);
285
444
  } catch (e) {
286
445
  }
287
446
  try {
288
- const statRes = await this.client.query("SELECT sum(numbackends) as conns, sum(xact_commit + xact_rollback) as txs FROM pg_stat_database");
447
+ const statRes = await this.getPool().query(
448
+ "SELECT sum(numbackends) as conns, sum(xact_commit + xact_rollback) as txs FROM pg_stat_database"
449
+ );
289
450
  activeConnections = parseInt(statRes.rows[0]?.conns || "0", 10);
290
451
  transactions = parseInt(statRes.rows[0]?.txs || "0", 10);
291
452
  } catch (e) {
292
453
  }
293
454
  let sizeBytes = 0;
294
455
  try {
295
- const sizeRes = await this.client.query("SELECT pg_database_size(current_database()) as size");
456
+ const sizeRes = await this.getPool().query(
457
+ "SELECT pg_database_size(current_database()) as size"
458
+ );
296
459
  sizeBytes = parseInt(sizeRes.rows[0]?.size || "0", 10);
297
460
  } catch (e) {
298
461
  }
@@ -314,18 +477,16 @@ var init_postgres = __esm({
314
477
  }
315
478
  }
316
479
  async getTables() {
317
- await this.connectIfNecessary();
318
480
  const query = `
319
481
  SELECT tablename
320
482
  FROM pg_catalog.pg_tables
321
- WHERE schemaname != 'pg_catalog' AND schemaname != 'information_schema'
483
+ WHERE schemaname = 'public'
322
484
  ORDER BY tablename;
323
485
  `;
324
- const res = await this.client.query(query);
486
+ const res = await this.getPool().query(query);
325
487
  return res.rows.map((row) => row.tablename);
326
488
  }
327
489
  async getSchema(tableName) {
328
- await this.connectIfNecessary();
329
490
  const query = `
330
491
  SELECT c.column_name, c.data_type, c.is_nullable, c.column_default,
331
492
  (SELECT count(*)
@@ -336,6 +497,15 @@ var init_postgres = __esm({
336
497
  AND kcu.table_name = c.table_name
337
498
  AND kcu.column_name = c.column_name
338
499
  AND kcu.table_schema = c.table_schema) as is_pk,
500
+ (SELECT count(*)
501
+ FROM information_schema.table_constraints tc2
502
+ JOIN information_schema.constraint_column_usage ccu2
503
+ ON tc2.constraint_name = ccu2.constraint_name
504
+ AND tc2.table_schema = ccu2.table_schema
505
+ WHERE tc2.constraint_type = 'UNIQUE'
506
+ AND tc2.table_name = c.table_name
507
+ AND tc2.table_schema = c.table_schema
508
+ AND ccu2.column_name = c.column_name) as is_unique,
339
509
  (SELECT ccu.table_name || '.' || ccu.column_name
340
510
  FROM information_schema.table_constraints tc
341
511
  JOIN information_schema.key_column_usage kcu
@@ -351,7 +521,7 @@ var init_postgres = __esm({
351
521
  WHERE c.table_name = $1 AND c.table_schema = 'public'
352
522
  ORDER BY c.ordinal_position;
353
523
  `;
354
- const res = await this.client.query(query, [tableName]);
524
+ const res = await this.getPool().query(query, [tableName]);
355
525
  return res.rows.map((col) => {
356
526
  let fkTarget;
357
527
  if (col.fk_target) {
@@ -362,14 +532,14 @@ var init_postgres = __esm({
362
532
  name: col.column_name,
363
533
  type: col.data_type,
364
534
  isPk: parseInt(col.is_pk) > 0,
365
- nullable: col.is_nullable === "YES",
535
+ nullable: parseInt(col.is_pk) > 0 ? false : col.is_nullable === "YES",
536
+ isUnique: parseInt(col.is_pk) > 0 || parseInt(col.is_unique) > 0,
366
537
  defaultValue: col.column_default != null ? String(col.column_default) : void 0,
367
538
  fkTarget
368
539
  };
369
540
  });
370
541
  }
371
542
  async getIndexes(tableName) {
372
- await this.connectIfNecessary();
373
543
  const query = `
374
544
  SELECT
375
545
  i.relname as index_name,
@@ -388,10 +558,11 @@ var init_postgres = __esm({
388
558
  AND a.attnum = ANY(ix.indkey)
389
559
  AND t.relkind = 'r'
390
560
  AND t.relname = $1
561
+ AND t.relnamespace = 'public'::regnamespace
391
562
  ORDER BY
392
- i.relname, a.attnum;
563
+ i.relname, array_position(ix.indkey, a.attnum);
393
564
  `;
394
- const res = await this.client.query(query, [tableName]);
565
+ const res = await this.getPool().query(query, [tableName]);
395
566
  const rows = res.rows;
396
567
  const indexMap = /* @__PURE__ */ new Map();
397
568
  for (const row of rows) {
@@ -409,7 +580,6 @@ var init_postgres = __esm({
409
580
  return Array.from(indexMap.values());
410
581
  }
411
582
  async getData(tableName, limit = 50, offset = 0, whereClause, orderBy) {
412
- await this.connectIfNecessary();
413
583
  const schema = await this.getSchema(tableName);
414
584
  const columns = schema.map((col) => col.name);
415
585
  let sql = `SELECT * FROM ${this.quoteIdentifier(tableName)}`;
@@ -420,38 +590,50 @@ var init_postgres = __esm({
420
590
  sql += ` ORDER BY ${this.quoteIdentifier(orderBy.col)} ${orderBy.asc ? "ASC" : "DESC"}`;
421
591
  }
422
592
  sql += ` LIMIT $1 OFFSET $2`;
423
- const res = await this.client.query(sql, [limit, offset]);
593
+ const res = await this.getPool().query(sql, [limit, offset]);
424
594
  return { columns, rows: res.rows };
425
595
  }
426
596
  async query(sql) {
427
- await this.connectIfNecessary();
428
- const res = await this.client.query(sql);
597
+ const res = await this.getPool().query(sql);
429
598
  let columns = [];
430
599
  if (res.fields) {
431
600
  columns = res.fields.map((f) => f.name);
432
601
  }
433
- return { columns, rows: res.rows || [] };
602
+ return {
603
+ columns,
604
+ rows: res.rows || [],
605
+ affectedRows: typeof res.rowCount === "number" ? res.rowCount : void 0
606
+ };
434
607
  }
435
608
  async executeSql(sql) {
436
- await this.connectIfNecessary();
437
- await this.client.query(sql);
609
+ await this.getPool().query(sql);
438
610
  }
439
611
  async close() {
440
- if (this.connected) {
441
- await this.client.end();
442
- this.connected = false;
612
+ if (this.pool) {
613
+ await this.pool.end();
614
+ this.pool = null;
443
615
  }
444
616
  }
445
617
  async insert(tableName, rows) {
446
618
  if (rows.length === 0) return;
447
- await this.connectIfNecessary();
448
- const cols = Object.keys(rows[0]);
449
- const colsQuoted = cols.map((c) => this.quoteIdentifier(c)).join(", ");
450
- for (const row of rows) {
451
- const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
452
- const sql = `INSERT INTO ${this.quoteIdentifier(tableName)} (${colsQuoted}) VALUES (${placeholders})`;
453
- const values = cols.map((c) => row[c]);
454
- await this.client.query(sql, values);
619
+ const pool = this.getPool();
620
+ const client = await pool.connect();
621
+ try {
622
+ const cols = Object.keys(rows[0]);
623
+ const colsQuoted = cols.map((c) => this.quoteIdentifier(c)).join(", ");
624
+ await client.query("BEGIN");
625
+ for (const row of rows) {
626
+ const placeholders = cols.map((_, i) => `$${i + 1}`).join(", ");
627
+ const sql = `INSERT INTO ${this.quoteIdentifier(tableName)} (${colsQuoted}) VALUES (${placeholders})`;
628
+ const values = cols.map((c) => row[c]);
629
+ await client.query(sql, values);
630
+ }
631
+ await client.query("COMMIT");
632
+ } catch (e) {
633
+ await client.query("ROLLBACK");
634
+ throw e;
635
+ } finally {
636
+ client.release();
455
637
  }
456
638
  }
457
639
  };
@@ -472,9 +654,13 @@ var init_mysql = __esm({
472
654
  }
473
655
  async getPool() {
474
656
  if (!this.pool) {
475
- this.pool = mysql.createPool(this.connection);
657
+ this.pool = mysql.createPool({
658
+ uri: this.connection,
659
+ multipleStatements: true
660
+ });
476
661
  this.pool.on("connection", (connection) => {
477
- connection.query("SET SESSION sql_mode = 'ANSI_QUOTES'");
662
+ connection.query("SET SESSION sql_mode = 'ANSI_QUOTES'").catch(() => {
663
+ });
478
664
  });
479
665
  }
480
666
  return this.pool;
@@ -485,21 +671,31 @@ var init_mysql = __esm({
485
671
  async getStatus() {
486
672
  try {
487
673
  const pool = await this.getPool();
488
- const [dbRow] = await pool.query("SELECT DATABASE() as db, VERSION() as version");
674
+ const [dbRow] = await pool.query(
675
+ "SELECT DATABASE() as db, VERSION() as version"
676
+ );
489
677
  const dbName = dbRow[0]?.db;
490
678
  const version = dbRow[0]?.version;
491
- const [statusRows] = await pool.query("SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_connected', 'Queries', 'Uptime')");
679
+ const [statusRows] = await pool.query(
680
+ "SHOW GLOBAL STATUS WHERE Variable_name IN ('Threads_connected', 'Queries', 'Uptime')"
681
+ );
492
682
  let activeConnections = 0;
493
683
  let queries = 0;
494
684
  let uptime = 0;
495
685
  for (const row of statusRows) {
496
- if (row.Variable_name === "Threads_connected") activeConnections = parseInt(row.Value, 10);
497
- if (row.Variable_name === "Queries") queries = parseInt(row.Value, 10);
498
- if (row.Variable_name === "Uptime") uptime = parseInt(row.Value, 10);
686
+ if (row.Variable_name === "Threads_connected")
687
+ activeConnections = parseInt(row.Value, 10);
688
+ if (row.Variable_name === "Queries")
689
+ queries = parseInt(row.Value, 10);
690
+ if (row.Variable_name === "Uptime")
691
+ uptime = parseInt(row.Value, 10);
499
692
  }
500
693
  let sizeBytes = 0;
501
694
  if (dbName) {
502
- const [sizeRow] = await pool.query("SELECT SUM(data_length + index_length) as size FROM information_schema.TABLES WHERE table_schema = ?", [dbName]);
695
+ const [sizeRow] = await pool.query(
696
+ "SELECT SUM(data_length + index_length) as size FROM information_schema.TABLES WHERE table_schema = ?",
697
+ [dbName]
698
+ );
503
699
  sizeBytes = parseInt(sizeRow[0]?.size || "0", 10);
504
700
  }
505
701
  return {
@@ -521,7 +717,9 @@ var init_mysql = __esm({
521
717
  }
522
718
  async getTables() {
523
719
  const pool = await this.getPool();
524
- const [rows] = await pool.query("SHOW TABLES;");
720
+ const [rows] = await pool.query(
721
+ "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
722
+ );
525
723
  return rows.map((row) => Object.values(row)[0]);
526
724
  }
527
725
  async getSchema(tableName) {
@@ -555,7 +753,8 @@ var init_mysql = __esm({
555
753
  name: col.Field,
556
754
  type: col.Type,
557
755
  isPk: col.Key === "PRI",
558
- nullable: col.Null === "YES",
756
+ nullable: col.Key === "PRI" ? false : col.Null === "YES",
757
+ isUnique: col.Key === "PRI" || col.Key === "UNI",
559
758
  defaultValue: col.Default != null ? String(col.Default) : void 0,
560
759
  enumValues,
561
760
  fkTarget: fk ? {
@@ -567,7 +766,9 @@ var init_mysql = __esm({
567
766
  }
568
767
  async getIndexes(tableName) {
569
768
  const pool = await this.getPool();
570
- const [rows] = await pool.query(`SHOW INDEX FROM ${this.quoteIdentifier(tableName)}`);
769
+ const [rows] = await pool.query(
770
+ `SHOW INDEX FROM ${this.quoteIdentifier(tableName)}`
771
+ );
571
772
  const indexMap = /* @__PURE__ */ new Map();
572
773
  for (const row of rows) {
573
774
  if (row.Key_name === "PRIMARY") continue;
@@ -594,7 +795,10 @@ var init_mysql = __esm({
594
795
  if (orderBy) {
595
796
  sql += ` ORDER BY ${this.quoteIdentifier(orderBy.col)} ${orderBy.asc ? "ASC" : "DESC"}`;
596
797
  }
597
- const [rows] = await pool.query(sql + " LIMIT ? OFFSET ?", [limit, offset]);
798
+ const [rows] = await pool.query(sql + " LIMIT ? OFFSET ?", [
799
+ limit,
800
+ offset
801
+ ]);
598
802
  return { columns, rows };
599
803
  }
600
804
  async query(sql) {
@@ -602,16 +806,17 @@ var init_mysql = __esm({
602
806
  const [rows, fields] = await pool.query(sql);
603
807
  let columns = [];
604
808
  let data = [];
809
+ let affectedRows = void 0;
605
810
  if (fields && Array.isArray(fields)) {
606
811
  columns = fields.map((f) => f.name);
607
812
  data = rows;
608
813
  } else {
609
814
  columns = ["Result"];
610
- data = [
611
- { Result: "Success", AffectedRows: rows.affectedRows }
612
- ];
815
+ const count = rows.affectedRows ?? 0;
816
+ affectedRows = count;
817
+ data = [{ Result: "Success", AffectedRows: count }];
613
818
  }
614
- return { columns, rows: data };
819
+ return { columns, rows: data, affectedRows };
615
820
  }
616
821
  async executeSql(sql) {
617
822
  const pool = await this.getPool();
@@ -626,13 +831,23 @@ var init_mysql = __esm({
626
831
  async insert(tableName, rows) {
627
832
  if (rows.length === 0) return;
628
833
  const pool = await this.getPool();
629
- const cols = Object.keys(rows[0]);
630
- const colsQuoted = cols.map((c) => this.quoteIdentifier(c)).join(", ");
631
- const placeholders = cols.map(() => "?").join(", ");
632
- const sql = `INSERT INTO ${this.quoteIdentifier(tableName)} (${colsQuoted}) VALUES (${placeholders})`;
633
- for (const row of rows) {
634
- const values = cols.map((c) => row[c]);
635
- await pool.query(sql, values);
834
+ const connection = await pool.getConnection();
835
+ try {
836
+ const cols = Object.keys(rows[0]);
837
+ const colsQuoted = cols.map((c) => this.quoteIdentifier(c)).join(", ");
838
+ const placeholders = cols.map(() => "?").join(", ");
839
+ const sql = `INSERT INTO ${this.quoteIdentifier(tableName)} (${colsQuoted}) VALUES (${placeholders})`;
840
+ await connection.beginTransaction();
841
+ for (const row of rows) {
842
+ const values = cols.map((c) => row[c]);
843
+ await connection.query(sql, values);
844
+ }
845
+ await connection.commit();
846
+ } catch (e) {
847
+ await connection.rollback();
848
+ throw e;
849
+ } finally {
850
+ connection.release();
636
851
  }
637
852
  }
638
853
  };
@@ -1034,6 +1249,335 @@ var init_export = __esm({
1034
1249
  }
1035
1250
  });
1036
1251
 
1252
+ // src/core/seeder.ts
1253
+ function getRandomItem(arr) {
1254
+ return arr[Math.floor(Math.random() * arr.length)];
1255
+ }
1256
+ function getRandomInt(min, max) {
1257
+ return Math.floor(Math.random() * (max - min + 1)) + min;
1258
+ }
1259
+ function getRandomFloat(min, max, decimals = 2) {
1260
+ const str = (Math.random() * (max - min) + min).toFixed(decimals);
1261
+ return parseFloat(str);
1262
+ }
1263
+ function getRandomDate(pastDays = 30) {
1264
+ const d = /* @__PURE__ */ new Date();
1265
+ d.setDate(d.getDate() - getRandomInt(0, pastDays));
1266
+ d.setHours(getRandomInt(0, 23), getRandomInt(0, 59), getRandomInt(0, 59));
1267
+ return d.toISOString().replace("T", " ").substring(0, 19);
1268
+ }
1269
+ function inferColumnStrategy(col) {
1270
+ const name = col.name.toLowerCase();
1271
+ const type = (col.type || "").toUpperCase();
1272
+ if (col.fkTarget) {
1273
+ return {
1274
+ type: "fk",
1275
+ label: `FK \u2192 ${col.fkTarget.table}.${col.fkTarget.column}`,
1276
+ target: col.fkTarget
1277
+ };
1278
+ }
1279
+ if (col.isPk && (type.includes("INT") || type === "SERIAL")) {
1280
+ return {
1281
+ type: "pk_auto",
1282
+ label: "Auto-increment (Skip / Handled by DB)"
1283
+ };
1284
+ }
1285
+ if (col.enumValues && col.enumValues.length > 0) {
1286
+ return {
1287
+ type: "enum",
1288
+ label: `Enum (${col.enumValues.slice(0, 3).join(", ")})`,
1289
+ values: col.enumValues
1290
+ };
1291
+ }
1292
+ if (type.includes("BOOL") || type === "TINYINT(1)" || name.startsWith("is_") || name.startsWith("has_")) {
1293
+ return { type: "boolean", label: "Boolean (true / false)" };
1294
+ }
1295
+ if (name.includes("email")) {
1296
+ return { type: "email", label: "Email Address" };
1297
+ }
1298
+ if (name.includes("phone") || name.includes("tel") || name.includes("mobile")) {
1299
+ return { type: "phone", label: "Phone Number" };
1300
+ }
1301
+ if (name.includes("first_name")) {
1302
+ return { type: "first_name", label: "First Name" };
1303
+ }
1304
+ if (name.includes("last_name")) {
1305
+ return { type: "last_name", label: "Last Name" };
1306
+ }
1307
+ if (name.includes("name") || name.includes("author") || name.includes("user")) {
1308
+ return { type: "full_name", label: "Full Name" };
1309
+ }
1310
+ if (name.includes("avatar") || name.includes("image") || name.includes("photo") || name.includes("thumbnail")) {
1311
+ return { type: "avatar", label: "Avatar / Image URL" };
1312
+ }
1313
+ if (name.includes("city")) {
1314
+ return { type: "city", label: "City Name" };
1315
+ }
1316
+ if (name.includes("country")) {
1317
+ return { type: "country", label: "Country Name" };
1318
+ }
1319
+ if (name.includes("address")) {
1320
+ return { type: "address", label: "Street Address" };
1321
+ }
1322
+ if (name.includes("title") || name.includes("subject") || name.includes("headline")) {
1323
+ return { type: "title", label: "Title / Headline" };
1324
+ }
1325
+ if (name.includes("desc") || name.includes("content") || name.includes("body") || name.includes("bio") || name.includes("comment") || type.includes("TEXT")) {
1326
+ return { type: "paragraph", label: "Text / Paragraph" };
1327
+ }
1328
+ if (name.includes("status")) {
1329
+ return { type: "status", label: "Status (active/pending...)" };
1330
+ }
1331
+ if (name.includes("role")) {
1332
+ return { type: "role", label: "Role (admin/member...)" };
1333
+ }
1334
+ if (name.includes("price") || name.includes("amount") || name.includes("cost") || name.includes("salary") || type.includes("DECIMAL") || type.includes("FLOAT") || type.includes("REAL") || type.includes("NUMERIC")) {
1335
+ return { type: "price", label: "Price / Currency" };
1336
+ }
1337
+ if (type.includes("DATE") || type.includes("TIME")) {
1338
+ return { type: "date", label: "Date / Timestamp" };
1339
+ }
1340
+ if (type.includes("INT") || name.includes("age") || name.includes("count") || name.includes("qty") || name.includes("quantity")) {
1341
+ return { type: "integer", label: "Integer (1 - 500)" };
1342
+ }
1343
+ if (type.includes("UUID")) {
1344
+ return { type: "uuid", label: "UUID v4" };
1345
+ }
1346
+ return { type: "string", label: "Random Word / Code" };
1347
+ }
1348
+ function generateFieldValue(strategy, fkCache = {}) {
1349
+ switch (strategy.type) {
1350
+ case "pk_auto":
1351
+ return void 0;
1352
+ // Don't include in insert
1353
+ case "fk": {
1354
+ if (!strategy.target) return 1;
1355
+ const { table, column } = strategy.target;
1356
+ const ids = fkCache[`${table}.${column}`] || [];
1357
+ if (ids.length > 0) {
1358
+ return getRandomItem(ids);
1359
+ }
1360
+ return 1;
1361
+ }
1362
+ case "enum":
1363
+ return strategy.values && strategy.values.length > 0 ? getRandomItem(strategy.values) : "Default";
1364
+ case "boolean":
1365
+ return Math.random() > 0.5 ? 1 : 0;
1366
+ case "email": {
1367
+ const f = getRandomItem(FIRST_NAMES).toLowerCase();
1368
+ const l = getRandomItem(LAST_NAMES).toLowerCase();
1369
+ return `${f}.${l}${getRandomInt(1, 99)}@${getRandomItem(DOMAINS)}`;
1370
+ }
1371
+ case "phone":
1372
+ return `+1 (${getRandomInt(200, 999)}) ${getRandomInt(200, 999)}-${getRandomInt(1e3, 9999)}`;
1373
+ case "first_name":
1374
+ return getRandomItem(FIRST_NAMES);
1375
+ case "last_name":
1376
+ return getRandomItem(LAST_NAMES);
1377
+ case "full_name":
1378
+ return `${getRandomItem(FIRST_NAMES)} ${getRandomItem(LAST_NAMES)}`;
1379
+ case "avatar":
1380
+ return `https://picsum.photos/seed/${getRandomInt(100, 9999)}/200`;
1381
+ case "city":
1382
+ return getRandomItem(CITIES);
1383
+ case "country":
1384
+ return getRandomItem([
1385
+ "United States",
1386
+ "United Kingdom",
1387
+ "Germany",
1388
+ "Japan",
1389
+ "Canada",
1390
+ "Singapore"
1391
+ ]);
1392
+ case "address":
1393
+ return `${getRandomInt(10, 999)} ${getRandomItem(["Market St", "Broadway", "Highland Ave", "Pine Rd", "Maple St"])}`;
1394
+ case "title":
1395
+ return getRandomItem(TITLES);
1396
+ case "paragraph":
1397
+ return getRandomItem(PARAGRAPHS);
1398
+ case "status":
1399
+ return getRandomItem(STATUSES);
1400
+ case "role":
1401
+ return getRandomItem(ROLES);
1402
+ case "price":
1403
+ return getRandomFloat(9.99, 499.99);
1404
+ case "date":
1405
+ return getRandomDate(30);
1406
+ case "integer":
1407
+ return getRandomInt(1, 500);
1408
+ case "uuid":
1409
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
1410
+ const r = Math.random() * 16 | 0;
1411
+ const v = c === "x" ? r : r & 3 | 8;
1412
+ return v.toString(16);
1413
+ });
1414
+ default:
1415
+ return `Item_${getRandomInt(100, 9999)}`;
1416
+ }
1417
+ }
1418
+ async function getFkCandidates(adapter, schema) {
1419
+ const fkCache = {};
1420
+ for (const col of schema) {
1421
+ if (col.fkTarget) {
1422
+ const key = `${col.fkTarget.table}.${col.fkTarget.column}`;
1423
+ if (!fkCache[key]) {
1424
+ try {
1425
+ const data = await adapter.getData(col.fkTarget.table, 50);
1426
+ if (data && data.rows && data.rows.length > 0) {
1427
+ fkCache[key] = data.rows.map((r) => r[col.fkTarget.column]).filter((v) => v !== null && v !== void 0);
1428
+ }
1429
+ } catch {
1430
+ fkCache[key] = [];
1431
+ }
1432
+ }
1433
+ }
1434
+ }
1435
+ return fkCache;
1436
+ }
1437
+ async function previewMockData(adapter, tableName, previewCount = 3) {
1438
+ const schema = await adapter.getSchema(tableName);
1439
+ const fkCache = await getFkCandidates(adapter, schema);
1440
+ const rules = schema.map((col) => ({
1441
+ column: col,
1442
+ strategy: inferColumnStrategy(col)
1443
+ }));
1444
+ const previewRows = [];
1445
+ for (let i = 0; i < previewCount; i++) {
1446
+ const row = {};
1447
+ for (const { column, strategy } of rules) {
1448
+ const val = generateFieldValue(strategy, fkCache);
1449
+ row[column.name] = val !== void 0 ? val : "(auto)";
1450
+ }
1451
+ previewRows.push(row);
1452
+ }
1453
+ return {
1454
+ tableName,
1455
+ rules,
1456
+ previewRows
1457
+ };
1458
+ }
1459
+ async function generateAndInsertMockData(adapter, tableName, count, onProgress) {
1460
+ const schema = await adapter.getSchema(tableName);
1461
+ const fkCache = await getFkCandidates(adapter, schema);
1462
+ const rules = schema.map((col) => ({
1463
+ column: col,
1464
+ strategy: inferColumnStrategy(col)
1465
+ }));
1466
+ const activeRules = rules.filter((r) => r.strategy.type !== "pk_auto");
1467
+ if (activeRules.length === 0) {
1468
+ return 0;
1469
+ }
1470
+ const rowsToInsert = [];
1471
+ for (let i = 0; i < count; i++) {
1472
+ const row = {};
1473
+ for (const { column, strategy } of activeRules) {
1474
+ const val = generateFieldValue(strategy, fkCache);
1475
+ if (val !== void 0) {
1476
+ row[column.name] = val;
1477
+ }
1478
+ }
1479
+ rowsToInsert.push(row);
1480
+ }
1481
+ const CHUNK_SIZE = 250;
1482
+ let inserted = 0;
1483
+ for (let i = 0; i < rowsToInsert.length; i += CHUNK_SIZE) {
1484
+ const chunk = rowsToInsert.slice(i, i + CHUNK_SIZE);
1485
+ await adapter.insert(tableName, chunk);
1486
+ inserted += chunk.length;
1487
+ if (onProgress) {
1488
+ onProgress(inserted, count);
1489
+ }
1490
+ }
1491
+ return inserted;
1492
+ }
1493
+ var FIRST_NAMES, LAST_NAMES, DOMAINS, CITIES, TITLES, PARAGRAPHS, STATUSES, ROLES;
1494
+ var init_seeder = __esm({
1495
+ "src/core/seeder.ts"() {
1496
+ "use strict";
1497
+ FIRST_NAMES = [
1498
+ "James",
1499
+ "Mary",
1500
+ "John",
1501
+ "Patricia",
1502
+ "Robert",
1503
+ "Jennifer",
1504
+ "Michael",
1505
+ "Linda",
1506
+ "William",
1507
+ "Elizabeth",
1508
+ "David",
1509
+ "Barbara",
1510
+ "Richard",
1511
+ "Susan",
1512
+ "Joseph",
1513
+ "Jessica",
1514
+ "Thomas",
1515
+ "Sarah",
1516
+ "Charles",
1517
+ "Karen",
1518
+ "Lucas",
1519
+ "Emma",
1520
+ "Alex",
1521
+ "Olivia"
1522
+ ];
1523
+ LAST_NAMES = [
1524
+ "Smith",
1525
+ "Johnson",
1526
+ "Williams",
1527
+ "Brown",
1528
+ "Jones",
1529
+ "Garcia",
1530
+ "Miller",
1531
+ "Davis",
1532
+ "Rodriguez",
1533
+ "Martinez",
1534
+ "Hernandez",
1535
+ "Lopez",
1536
+ "Gonzalez",
1537
+ "Wilson",
1538
+ "Anderson",
1539
+ "Taylor"
1540
+ ];
1541
+ DOMAINS = [
1542
+ "gmail.com",
1543
+ "outlook.com",
1544
+ "yahoo.com",
1545
+ "example.com",
1546
+ "company.io"
1547
+ ];
1548
+ CITIES = [
1549
+ "New York",
1550
+ "San Francisco",
1551
+ "London",
1552
+ "Tokyo",
1553
+ "Berlin",
1554
+ "Paris",
1555
+ "Sydney",
1556
+ "Toronto",
1557
+ "Singapore",
1558
+ "Amsterdam"
1559
+ ];
1560
+ TITLES = [
1561
+ "Getting started with database design",
1562
+ "10 tips for clean and maintainable code",
1563
+ "Understanding indexing and performance",
1564
+ "How to optimize complex SQL queries",
1565
+ "Modern web application architecture",
1566
+ "Best practices for database migrations",
1567
+ "A deep dive into relational models",
1568
+ "Improving frontend latency and responsiveness"
1569
+ ];
1570
+ PARAGRAPHS = [
1571
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
1572
+ "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
1573
+ "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
1574
+ "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
1575
+ ];
1576
+ STATUSES = ["active", "pending", "completed", "inactive", "archived"];
1577
+ ROLES = ["admin", "editor", "member", "viewer", "moderator"];
1578
+ }
1579
+ });
1580
+
1037
1581
  // src/server/api.ts
1038
1582
  import { Hono } from "hono";
1039
1583
  import { spawn } from "child_process";
@@ -1111,7 +1655,9 @@ function registerApiRoutes(app, dbConfig) {
1111
1655
  const stats = {};
1112
1656
  for (const t of tables) {
1113
1657
  try {
1114
- const res = await adapter.query(`SELECT COUNT(*) as c FROM ${adapter.quoteIdentifier(t)}`);
1658
+ const res = await adapter.query(
1659
+ `SELECT COUNT(*) as c FROM ${adapter.quoteIdentifier(t)}`
1660
+ );
1115
1661
  if (res && res.rows && res.rows.length > 0) {
1116
1662
  const row = res.rows[0];
1117
1663
  const countVal = Object.values(row)[0];
@@ -1137,6 +1683,33 @@ function registerApiRoutes(app, dbConfig) {
1137
1683
  return c.json({ success: false, error: e.message }, 500);
1138
1684
  }
1139
1685
  });
1686
+ api.post("/tables/:name/schema", async (c) => {
1687
+ const tableName = c.req.param("name");
1688
+ try {
1689
+ const body = await c.req.json().catch(() => ({}));
1690
+ const { columns, renames } = body;
1691
+ if (!columns || !Array.isArray(columns)) {
1692
+ return c.json(
1693
+ { success: false, error: "Invalid columns parameter" },
1694
+ 400
1695
+ );
1696
+ }
1697
+ if (adapter.recreateTable) {
1698
+ await adapter.recreateTable(tableName, columns, renames || {});
1699
+ return c.json({ success: true });
1700
+ } else {
1701
+ return c.json(
1702
+ {
1703
+ success: false,
1704
+ error: "Table recreation is currently supported for SQLite"
1705
+ },
1706
+ 400
1707
+ );
1708
+ }
1709
+ } catch (e) {
1710
+ return c.json({ success: false, error: e.message }, 500);
1711
+ }
1712
+ });
1140
1713
  api.get("/tables/:name/indexes", async (c) => {
1141
1714
  const tableName = c.req.param("name");
1142
1715
  try {
@@ -1158,12 +1731,42 @@ function registerApiRoutes(app, dbConfig) {
1158
1731
  orderBy = { col: orderCol, asc: orderAscStr !== "false" };
1159
1732
  }
1160
1733
  try {
1161
- const data = await adapter.getData(tableName, limit, offset, whereClause, orderBy);
1734
+ const data = await adapter.getData(
1735
+ tableName,
1736
+ limit,
1737
+ offset,
1738
+ whereClause,
1739
+ orderBy
1740
+ );
1162
1741
  return c.json({ success: true, data });
1163
1742
  } catch (e) {
1164
1743
  return c.json({ success: false, error: e.message }, 500);
1165
1744
  }
1166
1745
  });
1746
+ api.get("/tables/:name/mock/preview", async (c) => {
1747
+ try {
1748
+ const tableName = c.req.param("name");
1749
+ const data = await previewMockData(adapter, tableName, 3);
1750
+ return c.json({ success: true, data });
1751
+ } catch (e) {
1752
+ return c.json({ success: false, error: e.message }, 500);
1753
+ }
1754
+ });
1755
+ api.post("/tables/:name/mock", async (c) => {
1756
+ try {
1757
+ const tableName = c.req.param("name");
1758
+ const body = await c.req.json().catch(() => ({}));
1759
+ const count = Math.min(Math.max(Number(body.count) || 10, 1), 1e3);
1760
+ const inserted = await generateAndInsertMockData(
1761
+ adapter,
1762
+ tableName,
1763
+ count
1764
+ );
1765
+ return c.json({ success: true, count: inserted });
1766
+ } catch (e) {
1767
+ return c.json({ success: false, error: e.message }, 500);
1768
+ }
1769
+ });
1167
1770
  api.post("/query", async (c) => {
1168
1771
  try {
1169
1772
  const { sql } = await c.req.json();
@@ -1173,34 +1776,26 @@ function registerApiRoutes(app, dbConfig) {
1173
1776
  return c.json({ success: false, error: e.message }, 500);
1174
1777
  }
1175
1778
  });
1176
- api.get("/tables/:name/export", async (c) => {
1177
- const tableName = c.req.param("name");
1178
- const format = c.req.query("format") || "csv";
1179
- const whereClause = c.req.query("where") || "";
1180
- const orderCol = c.req.query("orderCol");
1181
- const orderAscStr = c.req.query("orderAsc");
1182
- let orderBy = void 0;
1183
- if (orderCol) {
1184
- orderBy = { col: orderCol, asc: orderAscStr !== "false" };
1185
- }
1779
+ api.post("/query/export", async (c) => {
1186
1780
  try {
1187
- const batchSize = 1e3;
1188
- let batchOffset = 0;
1189
- const allRows = [];
1190
- let exportColumns = [];
1191
- let lastBatch;
1192
- do {
1193
- lastBatch = await adapter.getData(tableName, batchSize, batchOffset, whereClause, orderBy);
1194
- if (exportColumns.length === 0) exportColumns = lastBatch.columns;
1195
- allRows.push(...lastBatch.rows);
1196
- batchOffset += batchSize;
1197
- } while (lastBatch.rows.length === batchSize);
1198
- const rows = allRows;
1781
+ const { sql } = await c.req.json();
1782
+ if (!sql) {
1783
+ return c.json(
1784
+ { success: false, error: "No SQL query provided" },
1785
+ 400
1786
+ );
1787
+ }
1788
+ const result = await adapter.query(sql);
1789
+ const rows = result.rows;
1199
1790
  const timestamp = getDatetimeStr();
1200
- const exportFilename = `${tableName}_export_${timestamp}`;
1791
+ const format = c.req.query("format") || "csv";
1792
+ const exportFilename = `query_result_${timestamp}`;
1201
1793
  if (format === "json") {
1202
1794
  const jsonStr = JSON.stringify(rows, null, 2);
1203
- c.header("Content-Disposition", `attachment; filename="${exportFilename}.json"`);
1795
+ c.header(
1796
+ "Content-Disposition",
1797
+ `attachment; filename="${exportFilename}.json"`
1798
+ );
1204
1799
  c.header("Content-Type", "application/json");
1205
1800
  return c.body(jsonStr);
1206
1801
  } else {
@@ -1221,10 +1816,106 @@ function registerApiRoutes(app, dbConfig) {
1221
1816
  });
1222
1817
  csvStr = [headerStr, ...rowStrs].join("\n");
1223
1818
  }
1224
- c.header("Content-Disposition", `attachment; filename="${exportFilename}.csv"`);
1819
+ c.header(
1820
+ "Content-Disposition",
1821
+ `attachment; filename="${exportFilename}.csv"`
1822
+ );
1225
1823
  c.header("Content-Type", "text/csv");
1226
1824
  return c.body(csvStr);
1227
1825
  }
1826
+ } catch (e) {
1827
+ return c.json({ success: false, error: e.message }, 500);
1828
+ }
1829
+ });
1830
+ api.get("/tables/:name/export", async (c) => {
1831
+ const tableName = c.req.param("name");
1832
+ const format = c.req.query("format") || "csv";
1833
+ const whereClause = c.req.query("where") || "";
1834
+ const orderCol = c.req.query("orderCol");
1835
+ const orderAscStr = c.req.query("orderAsc");
1836
+ let orderBy = void 0;
1837
+ if (orderCol) {
1838
+ orderBy = { col: orderCol, asc: orderAscStr !== "false" };
1839
+ }
1840
+ try {
1841
+ const timestamp = getDatetimeStr();
1842
+ const exportFilename = `${tableName}_export_${timestamp}`;
1843
+ const stream = new ReadableStream({
1844
+ async start(controller) {
1845
+ const encoder = new TextEncoder();
1846
+ try {
1847
+ const batchSize = 1e3;
1848
+ let batchOffset = 0;
1849
+ let hasMore = true;
1850
+ let isFirstChunk = true;
1851
+ if (format === "json") {
1852
+ controller.enqueue(encoder.encode("[\n"));
1853
+ }
1854
+ while (hasMore) {
1855
+ const batch = await adapter.getData(
1856
+ tableName,
1857
+ batchSize,
1858
+ batchOffset,
1859
+ whereClause,
1860
+ orderBy
1861
+ );
1862
+ if (batch.rows.length === 0) {
1863
+ break;
1864
+ }
1865
+ if (format === "json") {
1866
+ let jsonStr = "";
1867
+ for (let i = 0; i < batch.rows.length; i++) {
1868
+ if (!isFirstChunk || i > 0) {
1869
+ jsonStr += ",\n";
1870
+ }
1871
+ jsonStr += JSON.stringify(batch.rows[i], null, 2);
1872
+ }
1873
+ controller.enqueue(encoder.encode(jsonStr));
1874
+ } else {
1875
+ let csvStr = "";
1876
+ const headers = batch.columns || Object.keys(batch.rows[0] || {});
1877
+ if (isFirstChunk && headers.length > 0) {
1878
+ csvStr += headers.join(",") + "\n";
1879
+ }
1880
+ for (const r of batch.rows) {
1881
+ const rowStr = headers.map((h) => {
1882
+ let val = r[h];
1883
+ if (val === null || val === void 0)
1884
+ val = "";
1885
+ val = String(val);
1886
+ if (val.includes(",") || val.includes('"') || val.includes("\n")) {
1887
+ val = `"${val.replace(/"/g, '""')}"`;
1888
+ }
1889
+ return val;
1890
+ }).join(",");
1891
+ csvStr += rowStr + "\n";
1892
+ }
1893
+ controller.enqueue(encoder.encode(csvStr));
1894
+ }
1895
+ isFirstChunk = false;
1896
+ batchOffset += batchSize;
1897
+ if (batch.rows.length < batchSize) {
1898
+ hasMore = false;
1899
+ }
1900
+ }
1901
+ if (format === "json") {
1902
+ controller.enqueue(encoder.encode("\n]"));
1903
+ }
1904
+ controller.close();
1905
+ } catch (e) {
1906
+ controller.error(e);
1907
+ }
1908
+ }
1909
+ });
1910
+ c.header(
1911
+ "Content-Disposition",
1912
+ `attachment; filename="${exportFilename}.${format}"`
1913
+ );
1914
+ c.header(
1915
+ "Content-Type",
1916
+ format === "json" ? "application/json" : "text/csv"
1917
+ );
1918
+ return c.body(stream);
1228
1919
  } catch (e) {
1229
1920
  return c.text(`Export Failed: ${e.message}`, 500);
1230
1921
  }
@@ -1239,13 +1930,19 @@ function registerApiRoutes(app, dbConfig) {
1239
1930
  return new Promise((resolve, reject) => {
1240
1931
  const cp = spawn(cmd, args);
1241
1932
  let started = false;
1933
+ const stream = nodeToWebStream(cp.stdout);
1242
1934
  cp.on("error", (err) => {
1243
- if (!started) reject(new Error(`Native tool '${cmd}' not found. Please install ${envName}.`));
1935
+ if (!started)
1936
+ reject(
1937
+ new Error(
1938
+ `Native tool '${cmd}' not found. Please install ${envName}.`
1939
+ )
1940
+ );
1244
1941
  });
1245
1942
  setTimeout(() => {
1246
1943
  if (!cp.killed) {
1247
1944
  started = true;
1248
- resolve(nodeToWebStream(cp.stdout));
1945
+ resolve(stream);
1249
1946
  }
1250
1947
  }, 100);
1251
1948
  });
@@ -1257,7 +1954,11 @@ function registerApiRoutes(app, dbConfig) {
1257
1954
  filename = `${baseName}_backup_${timeStr}.sql`;
1258
1955
  if (type === "sqlite") {
1259
1956
  const dbPath = url.replace("file:", "");
1260
- stream = await executeNativeDump("sqlite3", [dbPath, ".dump"], "SQLite CLI");
1957
+ stream = await executeNativeDump(
1958
+ "sqlite3",
1959
+ [dbPath, ".dump"],
1960
+ "SQLite CLI"
1961
+ );
1261
1962
  } else if (type === "mysql") {
1262
1963
  const parsed = new URL(url);
1263
1964
  const user = parsed.username;
@@ -1265,23 +1966,44 @@ function registerApiRoutes(app, dbConfig) {
1265
1966
  const host = parsed.hostname;
1266
1967
  const port = parsed.port || "3306";
1267
1968
  const dbname = parsed.pathname.substring(1);
1268
- stream = await executeNativeDump("mysqldump", ["-u", user, `-p${pass}`, "-h", host, "-P", port, dbname], "MySQL Client");
1969
+ stream = await executeNativeDump(
1970
+ "mysqldump",
1971
+ ["-u", user, `-p${pass}`, "-h", host, "-P", port, dbname],
1972
+ "MySQL Client"
1973
+ );
1269
1974
  } else if (type === "postgres") {
1270
- stream = await executeNativeDump("pg_dump", [url], "PostgreSQL CLI");
1975
+ stream = await executeNativeDump(
1976
+ "pg_dump",
1977
+ [url],
1978
+ "PostgreSQL CLI"
1979
+ );
1271
1980
  } else {
1272
1981
  throw new Error("Unsupported database type for native export");
1273
1982
  }
1274
- c.header("Content-Disposition", `attachment; filename="${filename}"`);
1983
+ c.header(
1984
+ "Content-Disposition",
1985
+ `attachment; filename="${filename}"`
1986
+ );
1275
1987
  c.header("Content-Type", "application/sql");
1276
1988
  return c.body(stream);
1277
1989
  } catch (err) {
1278
- if (type === "sqlite" && err.message.includes("Native tool")) {
1279
- const sql = await generateSqliteDump(adapter);
1990
+ if (err.message.includes("Native tool")) {
1991
+ let fallbackStream;
1280
1992
  const baseName = getDbName();
1281
1993
  const timeStr = getDatetimeStr();
1282
- c.header("Content-Disposition", `attachment; filename="${baseName}_backup_${timeStr}.sql"`);
1994
+ if (type === "sqlite") {
1995
+ fallbackStream = generateSqliteDumpStream(adapter);
1996
+ } else if (type === "mysql") {
1997
+ fallbackStream = generateMysqlDumpStream(adapter);
1998
+ } else {
1999
+ throw err;
2000
+ }
2001
+ c.header(
2002
+ "Content-Disposition",
2003
+ `attachment; filename="${baseName}_backup_${timeStr}.sql"`
2004
+ );
1283
2005
  c.header("Content-Type", "application/sql");
1284
- return c.body(sql);
2006
+ return c.body(fallbackStream);
1285
2007
  }
1286
2008
  throw err;
1287
2009
  }
@@ -1291,6 +2013,89 @@ function registerApiRoutes(app, dbConfig) {
1291
2013
  return c.body(errorHtml);
1292
2014
  }
1293
2015
  });
2016
+ api.post("/database/import", async (c) => {
2017
+ try {
2018
+ const body = await c.req.parseBody();
2019
+ const file = body["file"];
2020
+ if (!(file instanceof File)) {
2021
+ return c.json({ success: false, error: "No file uploaded" }, 400);
2022
+ }
2023
+ const sqlContent = await file.text();
2024
+ const type = dbConfig.type;
2025
+ const url = dbConfig.targetUrl;
2026
+ const executeNativeImport = (cmd, args, fileContent, envName) => {
2027
+ return new Promise((resolve, reject) => {
2028
+ const cp = spawn(cmd, args);
2029
+ let started = false;
2030
+ let errStr = "";
2031
+ cp.on("error", (err) => {
2032
+ if (!started)
2033
+ reject(
2034
+ new Error(
2035
+ `Native tool '${cmd}' not found. Please install ${envName}.`
2036
+ )
2037
+ );
2038
+ });
2039
+ cp.stderr.on("data", (d) => errStr += d.toString());
2040
+ cp.on("close", (code) => {
2041
+ if (code === 0) resolve();
2042
+ else reject(new Error(`Native import failed: ${errStr}`));
2043
+ });
2044
+ cp.stdin.write(fileContent);
2045
+ cp.stdin.end();
2046
+ started = true;
2047
+ });
2048
+ };
2049
+ try {
2050
+ if (type === "sqlite") {
2051
+ const dbPath = url.replace("file:", "");
2052
+ await executeNativeImport(
2053
+ "sqlite3",
2054
+ [dbPath],
2055
+ sqlContent,
2056
+ "SQLite CLI"
2057
+ );
2058
+ } else if (type === "mysql") {
2059
+ const parsed = new URL(url);
2060
+ const user = parsed.username;
2061
+ const pass = parsed.password;
2062
+ const host = parsed.hostname;
2063
+ const port = parsed.port || "3306";
2064
+ const dbname = parsed.pathname.substring(1);
2065
+ await executeNativeImport(
2066
+ "mysql",
2067
+ ["-u", user, `-p${pass}`, "-h", host, "-P", port, dbname],
2068
+ sqlContent,
2069
+ "MySQL Client"
2070
+ );
2071
+ } else if (type === "postgres") {
2072
+ await executeNativeImport(
2073
+ "psql",
2074
+ [url],
2075
+ sqlContent,
2076
+ "PostgreSQL CLI"
2077
+ );
2078
+ } else {
2079
+ throw new Error("Unsupported database type for native import");
2080
+ }
2081
+ } catch (err) {
2082
+ if (err.message.includes("Native tool")) {
2083
+ await adapter.executeSql(sqlContent);
2084
+ } else {
2085
+ throw err;
2086
+ }
2087
+ }
2088
+ return c.json({
2089
+ success: true,
2090
+ message: "Import completed successfully"
2091
+ });
2092
+ } catch (e) {
2093
+ return c.json(
2094
+ { success: false, error: `Import Failed: ${e.message}` },
2095
+ 500
2096
+ );
2097
+ }
2098
+ });
1294
2099
  api.get("/database/dictionary", async (c) => {
1295
2100
  try {
1296
2101
  const dbName = getDbName();
@@ -1313,7 +2118,10 @@ function registerApiRoutes(app, dbConfig) {
1313
2118
  md += `
1314
2119
  `;
1315
2120
  }
1316
- c.header("Content-Disposition", `attachment; filename="${dbName}_dictionary_${getDatetimeStr()}.md"`);
2121
+ c.header(
2122
+ "Content-Disposition",
2123
+ `attachment; filename="${dbName}_dictionary_${getDatetimeStr()}.md"`
2124
+ );
1317
2125
  c.header("Content-Type", "text/markdown");
1318
2126
  return c.body(md);
1319
2127
  } catch (e) {
@@ -1327,17 +2135,25 @@ function registerApiRoutes(app, dbConfig) {
1327
2135
  const filename = `${getDbName()}_schema_${getDatetimeStr()}.sql`;
1328
2136
  if (type === "sqlite") {
1329
2137
  let sqlDump = "-- Drixio SQLite Schema Dump\n\n";
1330
- const tablesResult = await adapter.query("SELECT sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';");
2138
+ const tablesResult = await adapter.query(
2139
+ "SELECT sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';"
2140
+ );
1331
2141
  for (const row of tablesResult.rows) {
1332
2142
  if (row.sql) sqlDump += `${row.sql};
1333
2143
 
1334
2144
  `;
1335
2145
  }
1336
- c.header("Content-Disposition", `attachment; filename="${filename}"`);
2146
+ c.header(
2147
+ "Content-Disposition",
2148
+ `attachment; filename="${filename}"`
2149
+ );
1337
2150
  c.header("Content-Type", "application/sql");
1338
2151
  return c.body(sqlDump);
1339
2152
  } else {
1340
- return c.text("Schema-only export for this DB type currently requires manual DDL extraction. Coming soon!", 501);
2153
+ return c.text(
2154
+ "Schema-only export for this DB type currently requires manual DDL extraction. Coming soon!",
2155
+ 501
2156
+ );
1341
2157
  }
1342
2158
  } catch (e) {
1343
2159
  return c.text(`Schema Export Failed: ${e.message}`, 500);
@@ -1345,38 +2161,150 @@ function registerApiRoutes(app, dbConfig) {
1345
2161
  });
1346
2162
  app.route("/api", api);
1347
2163
  }
1348
- async function generateSqliteDump(adapter) {
1349
- let sqlDump = "-- Drixio SQLite Fallback Backup\n\n";
1350
- try {
1351
- const tablesResult = await adapter.query("SELECT name, sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';");
1352
- for (const row of tablesResult.rows) {
1353
- if (!row.sql) continue;
1354
- sqlDump += `${row.sql};
2164
+ function generateSqliteDumpStream(adapter) {
2165
+ return new ReadableStream({
2166
+ async start(controller) {
2167
+ const encoder = new TextEncoder();
2168
+ try {
2169
+ controller.enqueue(
2170
+ encoder.encode("-- Drixio SQLite Fallback Backup\n\n")
2171
+ );
2172
+ const tablesResult = await adapter.query(
2173
+ "SELECT name, sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';"
2174
+ );
2175
+ for (const row of tablesResult.rows) {
2176
+ if (!row.sql) continue;
2177
+ controller.enqueue(encoder.encode(`${row.sql};
1355
2178
 
2179
+ `));
2180
+ const tableName = row.name;
2181
+ const batchSize = 1e3;
2182
+ let offset = 0;
2183
+ let hasMore = true;
2184
+ while (hasMore) {
2185
+ const batch = await adapter.getData(
2186
+ tableName,
2187
+ batchSize,
2188
+ offset
2189
+ );
2190
+ if (batch.rows.length === 0) {
2191
+ break;
2192
+ }
2193
+ let insertStrs = "";
2194
+ for (const d of batch.rows) {
2195
+ const keys = Object.keys(d).map((k) => adapter.quoteIdentifier(k)).join(", ");
2196
+ const vals = Object.values(d).map((v) => {
2197
+ if (v === null) return "NULL";
2198
+ if (typeof v === "number") return v;
2199
+ return `'${String(v).replace(/'/g, "''")}'`;
2200
+ }).join(", ");
2201
+ insertStrs += `INSERT INTO ${adapter.quoteIdentifier(tableName)} (${keys}) VALUES (${vals});
1356
2202
  `;
1357
- const data = await adapter.query(`SELECT * FROM ${adapter.quoteIdentifier(row.name)}`);
1358
- for (const d of data.rows) {
1359
- const keys = Object.keys(d).map((k) => adapter.quoteIdentifier(k)).join(", ");
1360
- const vals = Object.values(d).map((v) => {
1361
- if (v === null) return "NULL";
1362
- if (typeof v === "number") return v;
1363
- return `'${String(v).replace(/'/g, "''")}'`;
1364
- }).join(", ");
1365
- sqlDump += `INSERT INTO ${adapter.quoteIdentifier(row.name)} (${keys}) VALUES (${vals});
1366
- `;
2203
+ }
2204
+ controller.enqueue(encoder.encode(insertStrs));
2205
+ offset += batchSize;
2206
+ if (batch.rows.length < batchSize) {
2207
+ hasMore = false;
2208
+ }
2209
+ }
2210
+ controller.enqueue(encoder.encode("\n"));
2211
+ }
2212
+ controller.close();
2213
+ } catch (e) {
2214
+ controller.enqueue(
2215
+ encoder.encode(`-- Error generating backup: ${e}
2216
+ `)
2217
+ );
2218
+ controller.close();
1367
2219
  }
1368
- sqlDump += "\n";
1369
2220
  }
1370
- } catch (e) {
1371
- sqlDump += `-- Error generating backup: ${e}
2221
+ });
2222
+ }
2223
+ function generateMysqlDumpStream(adapter) {
2224
+ return new ReadableStream({
2225
+ async start(controller) {
2226
+ const encoder = new TextEncoder();
2227
+ try {
2228
+ controller.enqueue(
2229
+ encoder.encode("-- Drixio MySQL Fallback Backup\n\n")
2230
+ );
2231
+ const tables = await adapter.getTables();
2232
+ for (const table of tables) {
2233
+ try {
2234
+ const createTableResult = await adapter.query(
2235
+ `SHOW CREATE TABLE ${adapter.quoteIdentifier(table)}`
2236
+ );
2237
+ if (createTableResult.rows && createTableResult.rows.length > 0) {
2238
+ const row = createTableResult.rows[0];
2239
+ const vals = Object.values(row);
2240
+ const createSql = row["Create Table"] || row["Create View"] || (vals.length > 1 ? vals[1] : null);
2241
+ if (createSql) {
2242
+ controller.enqueue(encoder.encode(`${createSql};
2243
+
2244
+ `));
2245
+ }
2246
+ }
2247
+ const batchSize = 1e3;
2248
+ let offset = 0;
2249
+ let hasMore = true;
2250
+ while (hasMore) {
2251
+ const batch = await adapter.getData(
2252
+ table,
2253
+ batchSize,
2254
+ offset
2255
+ );
2256
+ if (batch.rows.length === 0) {
2257
+ break;
2258
+ }
2259
+ let insertStrs = "";
2260
+ for (const d of batch.rows) {
2261
+ const keys = Object.keys(d).map((k) => adapter.quoteIdentifier(k)).join(", ");
2262
+ const vals = Object.values(d).map((v) => {
2263
+ if (v === null) return "NULL";
2264
+ if (typeof v === "number") return v;
2265
+ let str = String(v);
2266
+ str = str.replace(/\\/g, "\\\\");
2267
+ str = str.replace(/'/g, "''");
2268
+ str = str.replace(/\n/g, "\\n");
2269
+ str = str.replace(/\r/g, "\\r");
2270
+ return `'${str}'`;
2271
+ }).join(", ");
2272
+ insertStrs += `INSERT INTO ${adapter.quoteIdentifier(table)} (${keys}) VALUES (${vals});
1372
2273
  `;
1373
- }
1374
- return sqlDump;
2274
+ }
2275
+ controller.enqueue(encoder.encode(insertStrs));
2276
+ offset += batchSize;
2277
+ if (batch.rows.length < batchSize) {
2278
+ hasMore = false;
2279
+ }
2280
+ }
2281
+ controller.enqueue(encoder.encode("\n"));
2282
+ } catch (tableErr) {
2283
+ controller.enqueue(
2284
+ encoder.encode(
2285
+ `-- Error backing up table ${table}: ${tableErr}
2286
+
2287
+ `
2288
+ )
2289
+ );
2290
+ }
2291
+ }
2292
+ controller.close();
2293
+ } catch (e) {
2294
+ controller.enqueue(
2295
+ encoder.encode(`-- Error generating backup: ${e}
2296
+ `)
2297
+ );
2298
+ controller.close();
2299
+ }
2300
+ }
2301
+ });
1375
2302
  }
1376
2303
  var init_api = __esm({
1377
2304
  "src/server/api.ts"() {
1378
2305
  "use strict";
1379
2306
  init_factory();
2307
+ init_seeder();
1380
2308
  }
1381
2309
  });
1382
2310
 
@@ -1658,40 +2586,6 @@ __export(seed_exports, {
1658
2586
  runSeedCommand: () => runSeedCommand
1659
2587
  });
1660
2588
  import pc14 from "picocolors";
1661
- function generateRandomString(length) {
1662
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
1663
- let result = "";
1664
- for (let i = 0; i < length; i++) result += chars.charAt(Math.floor(Math.random() * chars.length));
1665
- return result;
1666
- }
1667
- function generateRandomEmail() {
1668
- const domains = ["gmail.com", "yahoo.com", "outlook.com", "example.com"];
1669
- const name = generateRandomString(8).toLowerCase();
1670
- const domain = domains[Math.floor(Math.random() * domains.length)];
1671
- return `${name}@${domain}`;
1672
- }
1673
- function generateFakeData(col) {
1674
- const name = col.name.toLowerCase();
1675
- if (name.includes("email")) return generateRandomEmail();
1676
- if (name.includes("phone")) return `+1${Math.floor(Math.random() * 9e9 + 1e9)}`;
1677
- if (name.includes("name")) return `User_${generateRandomString(5)}`;
1678
- if (name.includes("url") || name.includes("link")) return `https://example.com/${generateRandomString(6)}`;
1679
- if (name.includes("date") || name.includes("time") || name.includes("created") || name.includes("updated")) {
1680
- const d = new Date(Date.now() - Math.floor(Math.random() * 1e10));
1681
- return d.toISOString().replace("T", " ").slice(0, 19);
1682
- }
1683
- const type = col.type.toLowerCase();
1684
- if (type.includes("int") || type.includes("num") || type.includes("float") || type.includes("double")) {
1685
- return Math.floor(Math.random() * 1e3);
1686
- }
1687
- if (type.includes("bool") || type === "tinyint(1)") {
1688
- return Math.random() > 0.5;
1689
- }
1690
- if (type.includes("char") || type.includes("text") || type.includes("string")) {
1691
- return generateRandomString(10);
1692
- }
1693
- return generateRandomString(5);
1694
- }
1695
2589
  async function runSeedCommand(dbConfig, args) {
1696
2590
  if (dbConfig.type === "unknown") {
1697
2591
  console.log(pc14.red("Error: No database connection found. Cannot run seed."));
@@ -1708,7 +2602,7 @@ async function runSeedCommand(dbConfig, args) {
1708
2602
  process.exit(1);
1709
2603
  }
1710
2604
  tableName = await select11({
1711
- message: "Which table do you want to seed with fake data?",
2605
+ message: "Which table do you want to seed with realistic fake data?",
1712
2606
  choices: allTables.map((t) => ({ name: t, value: t }))
1713
2607
  });
1714
2608
  }
@@ -1722,52 +2616,23 @@ async function runSeedCommand(dbConfig, args) {
1722
2616
  }
1723
2617
  }
1724
2618
  console.log(pc14.cyan(`
1725
- Analyzing schema for table '${tableName}'...`));
1726
- let schema;
2619
+ Analyzing schema & foreign keys for table '${tableName}'...`));
1727
2620
  try {
1728
- schema = await adapter.getSchema(tableName);
1729
- } catch (e) {
1730
- console.log(pc14.red(`Error: ${e.message}`));
1731
- process.exit(1);
1732
- }
1733
- const targetCols = schema.filter((c) => !c.isPk);
1734
- if (targetCols.length === 0) {
1735
- console.log(pc14.yellow("Table only has Primary Key columns. Seeding might fail if they don't auto-increment."));
1736
- }
1737
- console.log(pc14.cyan(`Generating ${count} records...`));
1738
- const rowsToInsert = [];
1739
- for (let i = 0; i < count; i++) {
1740
- const row = {};
1741
- for (const col of targetCols.length > 0 ? targetCols : schema) {
1742
- row[col.name] = generateFakeData(col);
1743
- }
1744
- rowsToInsert.push(row);
1745
- }
1746
- const CHUNK_SIZE = 500;
1747
- let inserted = 0;
1748
- try {
1749
- if (dbConfig.type === "sqlite") await adapter.executeSql("PRAGMA foreign_keys = OFF;");
1750
- else if (dbConfig.type === "mysql") await adapter.executeSql("SET FOREIGN_KEY_CHECKS = 0;");
1751
- else if (dbConfig.type === "postgres") await adapter.executeSql("SET session_replication_role = replica;");
1752
- for (let i = 0; i < rowsToInsert.length; i += CHUNK_SIZE) {
1753
- const chunk = rowsToInsert.slice(i, i + CHUNK_SIZE);
1754
- await adapter.insert(tableName, chunk);
1755
- inserted += chunk.length;
1756
- process.stdout.write(`\r${pc14.dim(`Progress: ${inserted} / ${count}`)}`);
1757
- }
2621
+ const inserted = await generateAndInsertMockData(
2622
+ adapter,
2623
+ tableName,
2624
+ count,
2625
+ (current, total) => {
2626
+ process.stdout.write(`\r${pc14.dim(`Progress: ${current} / ${total}`)}`);
2627
+ }
2628
+ );
1758
2629
  console.log(pc14.green(`
1759
2630
 
1760
- \u2714 Successfully seeded ${inserted} fake records into ${tableName}!`));
2631
+ \u2714 Successfully generated and seeded ${inserted} realistic records into ${tableName}!`));
1761
2632
  } catch (e) {
1762
2633
  console.log(pc14.red(`
1763
2634
  \u2718 Seed failed: ${e.message}`));
1764
2635
  } finally {
1765
- try {
1766
- if (dbConfig.type === "sqlite") await adapter.executeSql("PRAGMA foreign_keys = ON;");
1767
- else if (dbConfig.type === "mysql") await adapter.executeSql("SET FOREIGN_KEY_CHECKS = 1;");
1768
- else if (dbConfig.type === "postgres") await adapter.executeSql("SET session_replication_role = DEFAULT;");
1769
- } catch (e) {
1770
- }
1771
2636
  await adapter.close();
1772
2637
  }
1773
2638
  process.exit(0);
@@ -1776,6 +2641,7 @@ var init_seed = __esm({
1776
2641
  "subcommands/seed.ts"() {
1777
2642
  "use strict";
1778
2643
  init_factory();
2644
+ init_seeder();
1779
2645
  }
1780
2646
  });
1781
2647