@plyaz/db 0.3.0 → 0.3.1

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/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import * as fs3 from 'fs';
2
+ import * as fs4 from 'fs';
3
3
  import * as path4 from 'path';
4
4
  import { Command } from 'commander';
5
5
  import { DatabaseError } from '@plyaz/errors';
@@ -13,8 +13,10 @@ import { Pool } from 'pg';
13
13
  import { eq, sql, isNotNull, isNull, between, like, not, inArray, lte, lt, gte, gt, asc, desc } from 'drizzle-orm';
14
14
  import { PgColumn } from 'drizzle-orm/pg-core';
15
15
  import { createClient } from '@supabase/supabase-js';
16
- import { randomBytes, createCipheriv, createDecipheriv } from 'crypto';
17
- import { pathToFileURL } from 'url';
16
+ import { randomBytes, createCipheriv, createDecipheriv, randomUUID } from 'crypto';
17
+ import * as readline from 'readline';
18
+ import { pathToFileURL, fileURLToPath } from 'url';
19
+ import { execSync } from 'child_process';
18
20
 
19
21
  var __defProp = Object.defineProperty;
20
22
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -59,7 +61,7 @@ function suggestDownMigration(sqlContent, filename) {
59
61
  };
60
62
  }
61
63
  function addDownSection(filePath) {
62
- const content = fs3.readFileSync(filePath, "utf-8");
64
+ const content = fs4.readFileSync(filePath, "utf-8");
63
65
  if (content.includes("-- DOWN")) {
64
66
  return content;
65
67
  }
@@ -68,16 +70,16 @@ function addDownSection(filePath) {
68
70
  return content + downSection;
69
71
  }
70
72
  function processDirectory(migrationsPath, dryRun = true) {
71
- if (!fs3.existsSync(migrationsPath)) {
73
+ if (!fs4.existsSync(migrationsPath)) {
72
74
  console.error(`Migration directory not found: ${migrationsPath}`);
73
75
  return;
74
76
  }
75
- const files = fs3.readdirSync(migrationsPath).filter((f) => f.endsWith(".sql"));
77
+ const files = fs4.readdirSync(migrationsPath).filter((f) => f.endsWith(".sql"));
76
78
  console.log(`Found ${files.length} SQL migration files
77
79
  `);
78
80
  for (const file of files) {
79
81
  const filePath = path4.join(migrationsPath, file);
80
- const content = fs3.readFileSync(filePath, "utf-8");
82
+ const content = fs4.readFileSync(filePath, "utf-8");
81
83
  if (content.includes("-- DOWN")) {
82
84
  console.log(`✓ ${file} - Already has DOWN section`);
83
85
  continue;
@@ -91,7 +93,7 @@ function processDirectory(migrationsPath, dryRun = true) {
91
93
  const downSection = newContent.split("-- DOWN")[1];
92
94
  console.log(downSection);
93
95
  } else {
94
- fs3.writeFileSync(filePath, newContent, "utf-8");
96
+ fs4.writeFileSync(filePath, newContent, "utf-8");
95
97
  console.log(`✓ ${file} - Added DOWN section`);
96
98
  }
97
99
  }
@@ -258,12 +260,12 @@ var MigrationManager = class {
258
260
  * Discover migration files from migrations directory (including subdirectories)
259
261
  */
260
262
  async discoverMigrations() {
261
- if (!fs3.existsSync(this.migrationsPath)) {
263
+ if (!fs4.existsSync(this.migrationsPath)) {
262
264
  return [];
263
265
  }
264
266
  const migrations = [];
265
267
  const scanDirectory = /* @__PURE__ */ __name((dir) => {
266
- const entries = fs3.readdirSync(dir, { withFileTypes: true });
268
+ const entries = fs4.readdirSync(dir, { withFileTypes: true });
267
269
  for (const entry of entries) {
268
270
  const fullPath = path4.join(dir, entry.name);
269
271
  if (entry.isDirectory()) {
@@ -426,7 +428,7 @@ var MigrationManager = class {
426
428
  * Load SQL migration from file
427
429
  */
428
430
  loadSqlMigration(migrationFile) {
429
- const sql2 = fs3.readFileSync(migrationFile.filePath, "utf-8");
431
+ const sql2 = fs4.readFileSync(migrationFile.filePath, "utf-8");
430
432
  const { upSQL, downSQL } = this.parseSqlSections(sql2);
431
433
  return {
432
434
  version: migrationFile.version,
@@ -770,10 +772,10 @@ var SeedManager = class {
770
772
  * Discover seed files from seeds directory
771
773
  */
772
774
  async discoverSeeds() {
773
- if (!fs3.existsSync(this.seedsPath)) {
775
+ if (!fs4.existsSync(this.seedsPath)) {
774
776
  return [];
775
777
  }
776
- const files = fs3.readdirSync(this.seedsPath);
778
+ const files = fs4.readdirSync(this.seedsPath);
777
779
  const seeds = [];
778
780
  for (const file of files) {
779
781
  const match = file.match(/^(\d+)_(.+)\.(ts|js|sql)$/);
@@ -903,7 +905,7 @@ var SeedManager = class {
903
905
  * Load SQL seed from file
904
906
  */
905
907
  loadSqlSeed(seedFile) {
906
- const sql2 = fs3.readFileSync(seedFile.filePath, "utf-8");
908
+ const sql2 = fs4.readFileSync(seedFile.filePath, "utf-8");
907
909
  return {
908
910
  name: seedFile.name,
909
911
  run: /* @__PURE__ */ __name(async () => {
@@ -8267,6 +8269,9 @@ async function createDatabaseService(config) {
8267
8269
  }
8268
8270
  __name(createDatabaseService, "createDatabaseService");
8269
8271
  var JSON_INDENT_SPACES = 2;
8272
+ var VERSION_PAD_LENGTH = 3;
8273
+ var DECIMAL_RADIX = 10;
8274
+ var SEPARATOR_WIDTH = 50;
8270
8275
  async function getUserSchemas(adapter) {
8271
8276
  const result = await adapter.query?.(`
8272
8277
  SELECT schema_name FROM information_schema.schemata
@@ -8327,8 +8332,8 @@ function parseEnvLine(line) {
8327
8332
  }
8328
8333
  __name(parseEnvLine, "parseEnvLine");
8329
8334
  function loadEnvFile(envFilePath) {
8330
- if (!fs3.existsSync(envFilePath)) return;
8331
- const envContent = fs3.readFileSync(envFilePath, "utf-8");
8335
+ if (!fs4.existsSync(envFilePath)) return;
8336
+ const envContent = fs4.readFileSync(envFilePath, "utf-8");
8332
8337
  for (const line of envContent.split("\n")) {
8333
8338
  const parsed = parseEnvLine(line);
8334
8339
  if (parsed) {
@@ -8361,7 +8366,7 @@ __name(loadConfigFromPath, "loadConfigFromPath");
8361
8366
  async function findAndLoadConfig() {
8362
8367
  for (const configName of CONFIG_PATHS) {
8363
8368
  const configFilePath = path4.join(process.cwd(), configName);
8364
- if (fs3.existsSync(configFilePath)) {
8369
+ if (fs4.existsSync(configFilePath)) {
8365
8370
  return loadConfigFromPath(configFilePath);
8366
8371
  }
8367
8372
  }
@@ -8371,7 +8376,7 @@ __name(findAndLoadConfig, "findAndLoadConfig");
8371
8376
  function warnAboutTypeScriptConfigs() {
8372
8377
  for (const tsName of TS_CONFIG_PATHS) {
8373
8378
  const tsPath = path4.join(process.cwd(), tsName);
8374
- if (fs3.existsSync(tsPath)) {
8379
+ if (fs4.existsSync(tsPath)) {
8375
8380
  console.warn(
8376
8381
  `⚠️ Found ${path4.basename(tsPath)} but cannot import TypeScript files directly.`
8377
8382
  );
@@ -8406,7 +8411,7 @@ async function loadConfig(configPath) {
8406
8411
  const explicitPath = configPath ?? globalConfigPath;
8407
8412
  if (explicitPath) {
8408
8413
  const resolvedPath = path4.resolve(process.cwd(), explicitPath);
8409
- if (fs3.existsSync(resolvedPath)) {
8414
+ if (fs4.existsSync(resolvedPath)) {
8410
8415
  return loadConfigFromPath(resolvedPath);
8411
8416
  }
8412
8417
  console.error(`❌ Config file not found: ${resolvedPath}`);
@@ -9226,6 +9231,417 @@ program.command("reset").description(
9226
9231
  process.exit(1);
9227
9232
  }
9228
9233
  });
9234
+ function createReadlineInterface() {
9235
+ return readline.createInterface({
9236
+ input: process.stdin,
9237
+ output: process.stdout
9238
+ });
9239
+ }
9240
+ __name(createReadlineInterface, "createReadlineInterface");
9241
+ async function promptInput(message, defaultValue) {
9242
+ const rl = createReadlineInterface();
9243
+ const prompt = defaultValue ? `${message} (${defaultValue}): ` : `${message}: `;
9244
+ return new Promise((resolve4) => {
9245
+ rl.question(prompt, (answer) => {
9246
+ rl.close();
9247
+ const trimmed = answer.trim();
9248
+ resolve4(trimmed !== "" ? trimmed : defaultValue ?? "");
9249
+ });
9250
+ });
9251
+ }
9252
+ __name(promptInput, "promptInput");
9253
+ async function promptSelect(message, options) {
9254
+ const rl = createReadlineInterface();
9255
+ console.log(message);
9256
+ options.forEach((opt, i) => console.log(` ${i + 1}) ${opt}`));
9257
+ return new Promise((resolve4) => {
9258
+ rl.question("Select (number): ", (answer) => {
9259
+ rl.close();
9260
+ const index = Number.parseInt(answer, DECIMAL_RADIX) - 1;
9261
+ resolve4(options[index] ?? options[0]);
9262
+ });
9263
+ });
9264
+ }
9265
+ __name(promptSelect, "promptSelect");
9266
+ async function promptConfirm(message) {
9267
+ const rl = createReadlineInterface();
9268
+ return new Promise((resolve4) => {
9269
+ rl.question(`${message} (y/N): `, (answer) => {
9270
+ rl.close();
9271
+ resolve4(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
9272
+ });
9273
+ });
9274
+ }
9275
+ __name(promptConfirm, "promptConfirm");
9276
+ async function runInteractiveMigration(config) {
9277
+ console.log();
9278
+ console.log("📦 Create Migration - Interactive Mode");
9279
+ console.log("─".repeat(SEPARATOR_WIDTH));
9280
+ console.log();
9281
+ const name = await promptInput("Migration name (e.g., add_users_table)");
9282
+ if (!name) {
9283
+ console.error("❌ Migration name is required");
9284
+ process.exit(1);
9285
+ }
9286
+ const snakeName = toSnakeCase(name);
9287
+ const tableName = await promptInput("Table name", snakeName);
9288
+ const schema = await promptInput("Database schema", "public");
9289
+ const typeChoice = await promptSelect("File type:", [
9290
+ "SQL (.sql)",
9291
+ "TypeScript (.ts)"
9292
+ ]);
9293
+ const type = typeChoice.includes("TypeScript") ? "ts" : "sql";
9294
+ const gitUser = getGitUsername();
9295
+ const includeAuthor = gitUser ? await promptConfirm(`Include author (${gitUser})?`) : false;
9296
+ const author = includeAuthor ? gitUser : "";
9297
+ console.log();
9298
+ console.log("─".repeat(SEPARATOR_WIDTH));
9299
+ console.log(`Migration: ${name}`);
9300
+ console.log(`Table: ${schema}.${tableName}`);
9301
+ console.log(`Type: ${type.toUpperCase()}`);
9302
+ if (author) console.log(`Author: ${author}`);
9303
+ console.log("─".repeat(SEPARATOR_WIDTH));
9304
+ const confirm = await promptConfirm("Create migration?");
9305
+ if (!confirm) {
9306
+ console.log("Cancelled.");
9307
+ process.exit(0);
9308
+ }
9309
+ const migrationsPath = config.migrationsPath ?? "./migrations";
9310
+ if (!fs4.existsSync(migrationsPath)) {
9311
+ fs4.mkdirSync(migrationsPath, { recursive: true });
9312
+ }
9313
+ const version = getNextMigrationVersion(migrationsPath);
9314
+ const filename = `${version}_${snakeName}.${type}`;
9315
+ const filepath = path4.join(migrationsPath, filename);
9316
+ const content = getMigrationTemplate({
9317
+ name,
9318
+ version,
9319
+ tableName,
9320
+ schema,
9321
+ author,
9322
+ type
9323
+ });
9324
+ fs4.writeFileSync(filepath, content, "utf-8");
9325
+ console.log(`✅ Created: ${filepath}`);
9326
+ }
9327
+ __name(runInteractiveMigration, "runInteractiveMigration");
9328
+ async function runInteractiveSeed(config) {
9329
+ console.log();
9330
+ console.log("🌱 Create Seed - Interactive Mode");
9331
+ console.log("─".repeat(SEPARATOR_WIDTH));
9332
+ console.log();
9333
+ const name = await promptInput("Seed name (e.g., admin_users)");
9334
+ if (!name) {
9335
+ console.error("❌ Seed name is required");
9336
+ process.exit(1);
9337
+ }
9338
+ const snakeName = toSnakeCase(name);
9339
+ const tableName = await promptInput("Table name", snakeName);
9340
+ const schema = await promptInput("Database schema", "public");
9341
+ const typeChoice = await promptSelect("File type:", [
9342
+ "TypeScript (.ts)",
9343
+ "SQL (.sql)",
9344
+ "CSV (.csv)"
9345
+ ]);
9346
+ const typeMap = {
9347
+ "TypeScript (.ts)": "ts",
9348
+ "SQL (.sql)": "sql",
9349
+ "CSV (.csv)": "csv"
9350
+ };
9351
+ const type = typeMap[typeChoice] ?? "ts";
9352
+ let author = "";
9353
+ if (type !== "csv") {
9354
+ const gitUser = getGitUsername();
9355
+ const includeAuthor = gitUser ? await promptConfirm(`Include author (${gitUser})?`) : false;
9356
+ author = includeAuthor ? gitUser : "";
9357
+ }
9358
+ console.log();
9359
+ console.log("─".repeat(SEPARATOR_WIDTH));
9360
+ console.log(`Seed: ${name}`);
9361
+ console.log(`Table: ${schema}.${tableName}`);
9362
+ console.log(`Type: ${type.toUpperCase()}`);
9363
+ if (author) console.log(`Author: ${author}`);
9364
+ console.log("─".repeat(SEPARATOR_WIDTH));
9365
+ const confirm = await promptConfirm("Create seed?");
9366
+ if (!confirm) {
9367
+ console.log("Cancelled.");
9368
+ process.exit(0);
9369
+ }
9370
+ const seedsPath = config.seedsPath ?? "./seeds";
9371
+ if (!fs4.existsSync(seedsPath)) {
9372
+ fs4.mkdirSync(seedsPath, { recursive: true });
9373
+ }
9374
+ const order = getNextSeedOrder(seedsPath);
9375
+ const filename = `${order}_${snakeName}.${type}`;
9376
+ const filepath = path4.join(seedsPath, filename);
9377
+ let content;
9378
+ if (type === "csv") {
9379
+ content = getCsvSeedTemplate({ name, tableName, schema });
9380
+ } else {
9381
+ content = getSeedTemplate({
9382
+ name,
9383
+ order,
9384
+ tableName,
9385
+ schema,
9386
+ author,
9387
+ type
9388
+ });
9389
+ }
9390
+ fs4.writeFileSync(filepath, content, "utf-8");
9391
+ console.log(`✅ Created: ${filepath}`);
9392
+ }
9393
+ __name(runInteractiveSeed, "runInteractiveSeed");
9394
+ function getNextMigrationVersion(migrationsPath) {
9395
+ if (!fs4.existsSync(migrationsPath)) {
9396
+ return "001";
9397
+ }
9398
+ const files = fs4.readdirSync(migrationsPath);
9399
+ const versions = files.map((f) => {
9400
+ const match = f.match(/^(\d+)_/);
9401
+ return match ? Number.parseInt(match[1], DECIMAL_RADIX) : 0;
9402
+ }).filter((v) => v > 0);
9403
+ const maxVersion = versions.length > 0 ? Math.max(...versions) : 0;
9404
+ return String(maxVersion + 1).padStart(VERSION_PAD_LENGTH, "0");
9405
+ }
9406
+ __name(getNextMigrationVersion, "getNextMigrationVersion");
9407
+ function getNextSeedOrder(seedsPath) {
9408
+ if (!fs4.existsSync(seedsPath)) {
9409
+ return "001";
9410
+ }
9411
+ const files = fs4.readdirSync(seedsPath);
9412
+ const orders = files.map((f) => {
9413
+ const match = f.match(/^(\d+)_/);
9414
+ return match ? Number.parseInt(match[1], DECIMAL_RADIX) : 0;
9415
+ }).filter((v) => v > 0);
9416
+ const maxOrder = orders.length > 0 ? Math.max(...orders) : 0;
9417
+ return String(maxOrder + 1).padStart(VERSION_PAD_LENGTH, "0");
9418
+ }
9419
+ __name(getNextSeedOrder, "getNextSeedOrder");
9420
+ function toSnakeCase(name) {
9421
+ return name.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "").replace(/[^a-z0-9_]/g, "_").replace(/_+/g, "_");
9422
+ }
9423
+ __name(toSnakeCase, "toSnakeCase");
9424
+ function toPascalCase(name) {
9425
+ return name.split(/[_\s-]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
9426
+ }
9427
+ __name(toPascalCase, "toPascalCase");
9428
+ function getTemplateDir() {
9429
+ const currentFile = fileURLToPath(import.meta.url);
9430
+ const currentDir = path4.dirname(currentFile);
9431
+ const packageRoot = path4.resolve(currentDir, "..", "..");
9432
+ return path4.join(packageRoot, "template");
9433
+ }
9434
+ __name(getTemplateDir, "getTemplateDir");
9435
+ function loadTemplate(templatePath, vars) {
9436
+ const fullPath = path4.join(getTemplateDir(), templatePath);
9437
+ if (!fs4.existsSync(fullPath)) {
9438
+ throw new Error(`Template not found: ${fullPath}`);
9439
+ }
9440
+ let content = fs4.readFileSync(fullPath, "utf-8");
9441
+ for (const [key, value] of Object.entries(vars)) {
9442
+ const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
9443
+ content = content.replace(regex, value ?? "");
9444
+ }
9445
+ return content;
9446
+ }
9447
+ __name(loadTemplate, "loadTemplate");
9448
+ function getGitUsername() {
9449
+ try {
9450
+ return execSync("git config user.name", { encoding: "utf-8" }).trim();
9451
+ } catch {
9452
+ return "";
9453
+ }
9454
+ }
9455
+ __name(getGitUsername, "getGitUsername");
9456
+ function getMigrationTemplate(options) {
9457
+ const { name, version, tableName, schema, author, type } = options;
9458
+ const description = toPascalCase(name);
9459
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9460
+ const vars = {
9461
+ VERSION: version,
9462
+ DESCRIPTION: description,
9463
+ TABLE_NAME: tableName,
9464
+ SCHEMA: schema,
9465
+ CREATED_DATE: date,
9466
+ AUTHOR: author
9467
+ };
9468
+ const templateFile = type === "ts" ? "migrations/migration.ts.template" : "migrations/migration.sql.template";
9469
+ return loadTemplate(templateFile, vars);
9470
+ }
9471
+ __name(getMigrationTemplate, "getMigrationTemplate");
9472
+ function getSeedTemplate(options) {
9473
+ const { name, order, tableName, schema, author, type } = options;
9474
+ const description = toPascalCase(name);
9475
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9476
+ const vars = {
9477
+ ORDER: order,
9478
+ DESCRIPTION: description,
9479
+ TABLE_NAME: tableName,
9480
+ SCHEMA: schema,
9481
+ CREATED_DATE: date,
9482
+ AUTHOR: author,
9483
+ UUID_1: randomUUID(),
9484
+ UUID_2: randomUUID(),
9485
+ UUID_3: randomUUID()
9486
+ };
9487
+ const templateFile = type === "ts" ? "seeds/seed.ts.template" : "seeds/seed.sql.template";
9488
+ return loadTemplate(templateFile, vars);
9489
+ }
9490
+ __name(getSeedTemplate, "getSeedTemplate");
9491
+ function getCsvSeedTemplate(options) {
9492
+ const { name, tableName, schema } = options;
9493
+ const description = toPascalCase(name);
9494
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
9495
+ const vars = {
9496
+ DESCRIPTION: description,
9497
+ TABLE_NAME: tableName,
9498
+ SCHEMA: schema,
9499
+ CREATED_DATE: date,
9500
+ AUTHOR: "",
9501
+ UUID_1: randomUUID(),
9502
+ UUID_2: randomUUID(),
9503
+ UUID_3: randomUUID()
9504
+ };
9505
+ try {
9506
+ return loadTemplate("seeds/seed.csv.template", vars);
9507
+ } catch {
9508
+ return `id,name,created_at
9509
+ ${randomUUID()},Example 1,${(/* @__PURE__ */ new Date()).toISOString()}
9510
+ ${randomUUID()},Example 2,${(/* @__PURE__ */ new Date()).toISOString()}
9511
+ `;
9512
+ }
9513
+ }
9514
+ __name(getCsvSeedTemplate, "getCsvSeedTemplate");
9515
+ var createCommand = program.command("create").description("Create new migration or seed files");
9516
+ createCommand.command("migration").description("Create a new migration file (interactive if no name provided)").argument("[name]", "Migration name (e.g., add_users_table)").option("-t, --type <type>", "File type: sql or ts (default: sql)", "sql").option(
9517
+ "-T, --table <table>",
9518
+ "Table name (default: derived from migration name)"
9519
+ ).option(
9520
+ "-s, --schema <schema>",
9521
+ "Database schema (default: public)",
9522
+ "public"
9523
+ ).option("--no-author", "Skip adding git username as author").option("-i, --interactive", "Force interactive mode").action(
9524
+ async (name, options) => {
9525
+ try {
9526
+ const config = await loadConfig();
9527
+ if (!name || options.interactive) {
9528
+ await runInteractiveMigration(config);
9529
+ process.exit(0);
9530
+ }
9531
+ const migrationsPath = config.migrationsPath ?? "./migrations";
9532
+ if (!fs4.existsSync(migrationsPath)) {
9533
+ fs4.mkdirSync(migrationsPath, { recursive: true });
9534
+ console.log(`📁 Created directory: ${migrationsPath}`);
9535
+ }
9536
+ const version = getNextMigrationVersion(migrationsPath);
9537
+ const snakeName = toSnakeCase(name);
9538
+ const tableName = options.table ?? snakeName;
9539
+ const schema = options.schema;
9540
+ const author = options.author ? getGitUsername() : "";
9541
+ const extension = options.type === "ts" ? "ts" : "sql";
9542
+ const filename = `${version}_${snakeName}.${extension}`;
9543
+ const filepath = path4.join(migrationsPath, filename);
9544
+ if (fs4.existsSync(filepath)) {
9545
+ console.error(`❌ File already exists: ${filepath}`);
9546
+ process.exit(1);
9547
+ }
9548
+ const content = getMigrationTemplate({
9549
+ name,
9550
+ version,
9551
+ tableName,
9552
+ schema,
9553
+ author,
9554
+ type: options.type === "ts" ? "ts" : "sql"
9555
+ });
9556
+ fs4.writeFileSync(filepath, content, "utf-8");
9557
+ console.log(`✅ Created migration: ${filename}`);
9558
+ console.log(` Path: ${filepath}`);
9559
+ console.log(` Type: ${options.type.toUpperCase()}`);
9560
+ console.log(` Table: ${schema}.${tableName}`);
9561
+ if (author) {
9562
+ console.log(` Author: ${author}`);
9563
+ }
9564
+ console.log("");
9565
+ console.log("📝 Next steps:");
9566
+ console.log(` 1. Edit the migration file to add your schema changes`);
9567
+ console.log(` 2. Run 'plyaz-db migrate up' to apply the migration`);
9568
+ console.log(
9569
+ ` 3. Test rollback with 'plyaz-db migrate down' before deploying`
9570
+ );
9571
+ process.exit(0);
9572
+ } catch (error) {
9573
+ console.error("❌ Error:", error.message);
9574
+ process.exit(1);
9575
+ }
9576
+ }
9577
+ );
9578
+ createCommand.command("seed").description("Create a new seed file (interactive if no name provided)").argument("[name]", "Seed name (e.g., admin_users)").option("-t, --type <type>", "File type: ts, sql, or csv (default: ts)", "ts").option("-T, --table <table>", "Table name (default: derived from seed name)").option(
9579
+ "-s, --schema <schema>",
9580
+ "Database schema (default: public)",
9581
+ "public"
9582
+ ).option("--no-author", "Skip adding git username as author").option("-i, --interactive", "Force interactive mode").action(
9583
+ async (name, options) => {
9584
+ try {
9585
+ const config = await loadConfig();
9586
+ if (!name || options.interactive) {
9587
+ await runInteractiveSeed(config);
9588
+ process.exit(0);
9589
+ }
9590
+ const seedsPath = config.seedsPath ?? "./seeds";
9591
+ if (!fs4.existsSync(seedsPath)) {
9592
+ fs4.mkdirSync(seedsPath, { recursive: true });
9593
+ console.log(`📁 Created directory: ${seedsPath}`);
9594
+ }
9595
+ const order = getNextSeedOrder(seedsPath);
9596
+ const snakeName = toSnakeCase(name);
9597
+ const tableName = options.table ?? snakeName;
9598
+ const schema = options.schema;
9599
+ const author = options.author ? getGitUsername() : "";
9600
+ const typeMap = {
9601
+ ts: "ts",
9602
+ sql: "sql",
9603
+ csv: "csv"
9604
+ };
9605
+ const fileType = typeMap[options.type] ?? "ts";
9606
+ const filename = `${order}_${snakeName}.${fileType}`;
9607
+ const filepath = path4.join(seedsPath, filename);
9608
+ if (fs4.existsSync(filepath)) {
9609
+ console.error(`❌ File already exists: ${filepath}`);
9610
+ process.exit(1);
9611
+ }
9612
+ let content;
9613
+ if (fileType === "csv") {
9614
+ content = getCsvSeedTemplate({ name, tableName, schema });
9615
+ } else {
9616
+ content = getSeedTemplate({
9617
+ name,
9618
+ order,
9619
+ tableName,
9620
+ schema,
9621
+ author,
9622
+ type: fileType
9623
+ });
9624
+ }
9625
+ fs4.writeFileSync(filepath, content, "utf-8");
9626
+ console.log(`✅ Created seed: ${filename}`);
9627
+ console.log(` Path: ${filepath}`);
9628
+ console.log(` Type: ${fileType.toUpperCase()}`);
9629
+ console.log(` Table: ${schema}.${tableName}`);
9630
+ if (author && fileType !== "csv") {
9631
+ console.log(` Author: ${author}`);
9632
+ }
9633
+ console.log("");
9634
+ console.log("📝 Next steps:");
9635
+ console.log(` 1. Edit the seed file to add your data`);
9636
+ console.log(` 2. Run 'plyaz-db seed run' to execute seeds`);
9637
+ console.log(` 3. Use 'plyaz-db seed status' to check seed status`);
9638
+ process.exit(0);
9639
+ } catch (error) {
9640
+ console.error("❌ Error:", error.message);
9641
+ process.exit(1);
9642
+ }
9643
+ }
9644
+ );
9229
9645
  program.parse();
9230
9646
  //# sourceMappingURL=index.js.map
9231
9647
  //# sourceMappingURL=index.js.map