@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 +435 -19
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import * as
|
|
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
|
|
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 =
|
|
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 (!
|
|
73
|
+
if (!fs4.existsSync(migrationsPath)) {
|
|
72
74
|
console.error(`Migration directory not found: ${migrationsPath}`);
|
|
73
75
|
return;
|
|
74
76
|
}
|
|
75
|
-
const files =
|
|
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 =
|
|
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
|
-
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
775
|
+
if (!fs4.existsSync(this.seedsPath)) {
|
|
774
776
|
return [];
|
|
775
777
|
}
|
|
776
|
-
const files =
|
|
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 =
|
|
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 (!
|
|
8331
|
-
const envContent =
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|