drixio 1.1.9 → 1.1.10
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
|
@@ -28,27 +28,201 @@ var init_types = __esm({
|
|
|
28
28
|
// src/logic/loader.ts
|
|
29
29
|
import fs from "fs/promises";
|
|
30
30
|
import path from "path";
|
|
31
|
+
function parseEnvContent(content) {
|
|
32
|
+
const env = {};
|
|
33
|
+
const lines = content.split(/\r?\n/);
|
|
34
|
+
for (let line of lines) {
|
|
35
|
+
line = line.trim();
|
|
36
|
+
if (!line || line.startsWith("#")) continue;
|
|
37
|
+
if (line.startsWith("export ")) {
|
|
38
|
+
line = line.slice(7).trim();
|
|
39
|
+
}
|
|
40
|
+
const eqIdx = line.indexOf("=");
|
|
41
|
+
if (eqIdx === -1) continue;
|
|
42
|
+
const key = line.slice(0, eqIdx).trim();
|
|
43
|
+
let val = line.slice(eqIdx + 1).trim();
|
|
44
|
+
if (val.startsWith('"')) {
|
|
45
|
+
const endQuote = val.indexOf('"', 1);
|
|
46
|
+
val = endQuote !== -1 ? val.slice(1, endQuote) : val.slice(1);
|
|
47
|
+
} else if (val.startsWith("'")) {
|
|
48
|
+
const endQuote = val.indexOf("'", 1);
|
|
49
|
+
val = endQuote !== -1 ? val.slice(1, endQuote) : val.slice(1);
|
|
50
|
+
} else {
|
|
51
|
+
const commentIdx = val.indexOf("#");
|
|
52
|
+
if (commentIdx !== -1) {
|
|
53
|
+
val = val.slice(0, commentIdx).trim();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (key) {
|
|
57
|
+
env[key] = val;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return env;
|
|
61
|
+
}
|
|
62
|
+
async function loadCascadedEnv(cwd) {
|
|
63
|
+
const envFiles = [
|
|
64
|
+
".env",
|
|
65
|
+
".env.production",
|
|
66
|
+
".env.development",
|
|
67
|
+
".env.local",
|
|
68
|
+
".env.development.local"
|
|
69
|
+
];
|
|
70
|
+
const mergedEnv = {};
|
|
71
|
+
for (const file of envFiles) {
|
|
72
|
+
try {
|
|
73
|
+
const filePath = path.join(cwd, file);
|
|
74
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
75
|
+
const parsed = parseEnvContent(content);
|
|
76
|
+
Object.assign(mergedEnv, parsed);
|
|
77
|
+
} catch {
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
for (const [key, val] of Object.entries(process.env)) {
|
|
81
|
+
if (typeof val === "string" && val.trim() !== "") {
|
|
82
|
+
mergedEnv[key] = val.trim();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return mergedEnv;
|
|
86
|
+
}
|
|
87
|
+
function classifyDatabaseUrl(rawUrl, cwd) {
|
|
88
|
+
let trimmed = rawUrl.trim();
|
|
89
|
+
if (!trimmed) return null;
|
|
90
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
91
|
+
trimmed = trimmed.slice(1, -1).trim();
|
|
92
|
+
}
|
|
93
|
+
if (trimmed.startsWith("postgres://") || trimmed.startsWith("postgresql://")) {
|
|
94
|
+
return { type: "postgres", targetUrl: trimmed };
|
|
95
|
+
}
|
|
96
|
+
if (trimmed.startsWith("mysql://")) {
|
|
97
|
+
return { type: "mysql", targetUrl: trimmed };
|
|
98
|
+
}
|
|
99
|
+
const lower = trimmed.toLowerCase();
|
|
100
|
+
const isSqlitePrefix = lower.startsWith("file:") || lower.startsWith("sqlite://") || lower.startsWith("sqlite:");
|
|
101
|
+
const isSqliteExt = lower.endsWith(".db") || lower.endsWith(".sqlite") || lower.endsWith(".sqlite3") || lower.endsWith(".db3");
|
|
102
|
+
const isMemory = lower === ":memory:";
|
|
103
|
+
if (isSqlitePrefix || isSqliteExt || isMemory) {
|
|
104
|
+
let cleanPath = trimmed.replace(/^sqlite:\/\//i, "").replace(/^sqlite:/i, "").replace(/^file:/i, "");
|
|
105
|
+
if (cleanPath === ":memory:") {
|
|
106
|
+
return { type: "sqlite", targetUrl: ":memory:" };
|
|
107
|
+
}
|
|
108
|
+
if (!path.isAbsolute(cleanPath)) {
|
|
109
|
+
cleanPath = path.resolve(cwd, cleanPath);
|
|
110
|
+
}
|
|
111
|
+
return { type: "sqlite", targetUrl: cleanPath };
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
function buildUrlFromComponentEnv(env) {
|
|
116
|
+
const host = env.DB_HOST || env.DATABASE_HOST || env.MYSQL_HOST || env.POSTGRES_HOST || env.PGHOST;
|
|
117
|
+
const dbName = env.DB_NAME || env.DB_DATABASE || env.DATABASE_NAME || env.MYSQL_DATABASE || env.POSTGRES_DB || env.PGDATABASE;
|
|
118
|
+
if (!host || !dbName) return null;
|
|
119
|
+
const driver = (env.DB_CONNECTION || env.DB_TYPE || env.DB_DRIVER || "").toLowerCase();
|
|
120
|
+
const portStr = env.DB_PORT || env.MYSQL_PORT || env.POSTGRES_PORT || env.PGPORT;
|
|
121
|
+
let type = "mysql";
|
|
122
|
+
if (driver.includes("postgres") || driver.includes("pgsql") || driver.includes("pg") || env.POSTGRES_HOST || env.PGHOST || portStr === "5432") {
|
|
123
|
+
type = "postgres";
|
|
124
|
+
} else if (driver.includes("mysql") || driver.includes("mariadb") || env.MYSQL_HOST || portStr === "3306") {
|
|
125
|
+
type = "mysql";
|
|
126
|
+
}
|
|
127
|
+
const defaultPort = type === "postgres" ? 5432 : 3306;
|
|
128
|
+
const port = portStr ? parseInt(portStr, 10) || defaultPort : defaultPort;
|
|
129
|
+
const user = env.DB_USER || env.DB_USERNAME || env.MYSQL_USER || env.POSTGRES_USER || env.PGUSER || (type === "postgres" ? "postgres" : "root");
|
|
130
|
+
const pass = env.DB_PASSWORD || env.DB_PASS || env.MYSQL_PASSWORD || env.POSTGRES_PASSWORD || env.PGPASSWORD || "";
|
|
131
|
+
const auth = pass ? `${encodeURIComponent(user)}:${encodeURIComponent(pass)}` : encodeURIComponent(user);
|
|
132
|
+
const targetUrl = `${type}://${auth}@${host}:${port}/${dbName}`;
|
|
133
|
+
return { type, targetUrl };
|
|
134
|
+
}
|
|
31
135
|
async function detectDatabase(databaseUrl) {
|
|
32
136
|
const cwd = process.cwd();
|
|
33
137
|
if (databaseUrl) {
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
let targetUrl = databaseUrl.replace("file:", "");
|
|
43
|
-
if (type === "sqlite" && !path.isAbsolute(targetUrl)) {
|
|
44
|
-
targetUrl = path.resolve(cwd, targetUrl);
|
|
138
|
+
const classified = classifyDatabaseUrl(databaseUrl, cwd);
|
|
139
|
+
if (classified) {
|
|
140
|
+
return {
|
|
141
|
+
type: classified.type,
|
|
142
|
+
targetUrl: classified.targetUrl,
|
|
143
|
+
source: "manual"
|
|
144
|
+
};
|
|
45
145
|
}
|
|
46
146
|
return {
|
|
47
|
-
type,
|
|
48
|
-
targetUrl,
|
|
147
|
+
type: "unknown",
|
|
148
|
+
targetUrl: databaseUrl,
|
|
49
149
|
source: "manual"
|
|
50
150
|
};
|
|
51
151
|
}
|
|
152
|
+
const allEnv = await loadCascadedEnv(cwd);
|
|
153
|
+
const prismaPaths = [
|
|
154
|
+
path.join(cwd, "prisma", "schema.prisma"),
|
|
155
|
+
path.join(cwd, "src", "prisma", "schema.prisma")
|
|
156
|
+
];
|
|
157
|
+
for (const schemaPath of prismaPaths) {
|
|
158
|
+
try {
|
|
159
|
+
const schemaContent = await fs.readFile(schemaPath, "utf-8");
|
|
160
|
+
const providerMatch = schemaContent.match(
|
|
161
|
+
/provider\s*=\s*["']([^"']+)["']/
|
|
162
|
+
);
|
|
163
|
+
const urlMatch = schemaContent.match(
|
|
164
|
+
/url\s*=\s*(?:env\(["']([^"']+)["']\)|["']([^"']+)["'])/
|
|
165
|
+
);
|
|
166
|
+
if (providerMatch) {
|
|
167
|
+
let provider = providerMatch[1];
|
|
168
|
+
if (provider === "postgresql") provider = "postgres";
|
|
169
|
+
let rawUrl;
|
|
170
|
+
if (urlMatch) {
|
|
171
|
+
if (urlMatch[1]) {
|
|
172
|
+
rawUrl = allEnv[urlMatch[1]];
|
|
173
|
+
} else if (urlMatch[2]) {
|
|
174
|
+
rawUrl = urlMatch[2];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (rawUrl) {
|
|
178
|
+
if (provider === "sqlite") {
|
|
179
|
+
let cleanPath = rawUrl.replace(/^file:/i, "");
|
|
180
|
+
if (!path.isAbsolute(cleanPath)) {
|
|
181
|
+
cleanPath = path.resolve(
|
|
182
|
+
path.dirname(schemaPath),
|
|
183
|
+
cleanPath
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
type: "sqlite",
|
|
188
|
+
targetUrl: cleanPath,
|
|
189
|
+
source: ".env"
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
const classified = classifyDatabaseUrl(rawUrl, cwd);
|
|
193
|
+
if (classified) {
|
|
194
|
+
return {
|
|
195
|
+
type: classified.type,
|
|
196
|
+
targetUrl: classified.targetUrl,
|
|
197
|
+
source: ".env"
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
for (const key of DB_ENV_KEYS) {
|
|
206
|
+
const candidate = allEnv[key];
|
|
207
|
+
if (candidate) {
|
|
208
|
+
const classified = classifyDatabaseUrl(candidate, cwd);
|
|
209
|
+
if (classified) {
|
|
210
|
+
return {
|
|
211
|
+
type: classified.type,
|
|
212
|
+
targetUrl: classified.targetUrl,
|
|
213
|
+
source: ".env"
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const assembled = buildUrlFromComponentEnv(allEnv);
|
|
219
|
+
if (assembled) {
|
|
220
|
+
return {
|
|
221
|
+
type: assembled.type,
|
|
222
|
+
targetUrl: assembled.targetUrl,
|
|
223
|
+
source: ".env"
|
|
224
|
+
};
|
|
225
|
+
}
|
|
52
226
|
const searchDirs = [
|
|
53
227
|
".",
|
|
54
228
|
"prisma",
|
|
@@ -61,9 +235,10 @@ async function detectDatabase(databaseUrl) {
|
|
|
61
235
|
try {
|
|
62
236
|
const targetDir = path.join(cwd, dir);
|
|
63
237
|
const files = await fs.readdir(targetDir);
|
|
64
|
-
const sqliteFile = files.find(
|
|
65
|
-
|
|
66
|
-
|
|
238
|
+
const sqliteFile = files.find((file) => {
|
|
239
|
+
const lower = file.toLowerCase();
|
|
240
|
+
return lower.endsWith(".db") || lower.endsWith(".sqlite") || lower.endsWith(".sqlite3") || lower.endsWith(".db3");
|
|
241
|
+
});
|
|
67
242
|
if (sqliteFile) {
|
|
68
243
|
return {
|
|
69
244
|
type: "sqlite",
|
|
@@ -74,81 +249,6 @@ async function detectDatabase(databaseUrl) {
|
|
|
74
249
|
} catch {
|
|
75
250
|
}
|
|
76
251
|
}
|
|
77
|
-
const prismaSchemaPath = path.join(cwd, "prisma", "schema.prisma");
|
|
78
|
-
try {
|
|
79
|
-
const schemaContent = await fs.readFile(prismaSchemaPath, "utf-8");
|
|
80
|
-
const providerMatch = schemaContent.match(
|
|
81
|
-
/provider\s*=\s*["']([^"']+)["']/
|
|
82
|
-
);
|
|
83
|
-
const urlMatch = schemaContent.match(
|
|
84
|
-
/url\s*=\s*(?:env\(["']([^"']+)["']\)|["']([^"']+)["'])/
|
|
85
|
-
);
|
|
86
|
-
if (providerMatch) {
|
|
87
|
-
let provider = providerMatch[1];
|
|
88
|
-
if (provider === "postgresql") provider = "postgres";
|
|
89
|
-
let targetUrl = "";
|
|
90
|
-
if (urlMatch && urlMatch[2]) {
|
|
91
|
-
targetUrl = urlMatch[2];
|
|
92
|
-
if (targetUrl.startsWith("file:")) {
|
|
93
|
-
targetUrl = path.join(
|
|
94
|
-
cwd,
|
|
95
|
-
"prisma",
|
|
96
|
-
targetUrl.replace("file:", "")
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (targetUrl && (provider === "sqlite" || provider === "postgres" || provider === "mysql")) {
|
|
101
|
-
return {
|
|
102
|
-
type: provider,
|
|
103
|
-
targetUrl,
|
|
104
|
-
source: ".env"
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
} catch {
|
|
109
|
-
}
|
|
110
|
-
const envPath = path.join(cwd, ".env");
|
|
111
|
-
try {
|
|
112
|
-
const envContent = await fs.readFile(envPath, "utf-8");
|
|
113
|
-
const dbKeys = [
|
|
114
|
-
"DATABASE_URL",
|
|
115
|
-
"DB_URL",
|
|
116
|
-
"POSTGRES_URL",
|
|
117
|
-
"POSTGRES_PRISMA_URL",
|
|
118
|
-
"MYSQL_URL"
|
|
119
|
-
];
|
|
120
|
-
for (const key of dbKeys) {
|
|
121
|
-
const regex = new RegExp(`${key}\\s*=\\s*["']?([^"'\\r\\n]+)["']?`);
|
|
122
|
-
const match = envContent.match(regex);
|
|
123
|
-
if (match) {
|
|
124
|
-
const url = match[1];
|
|
125
|
-
if (url.startsWith("file:") || url.endsWith(".db") || url.includes(".sqlite")) {
|
|
126
|
-
let targetUrl = url.replace("file:", "");
|
|
127
|
-
if (!path.isAbsolute(targetUrl)) {
|
|
128
|
-
targetUrl = path.resolve(cwd, targetUrl);
|
|
129
|
-
}
|
|
130
|
-
return {
|
|
131
|
-
type: "sqlite",
|
|
132
|
-
targetUrl,
|
|
133
|
-
source: ".env"
|
|
134
|
-
};
|
|
135
|
-
} else if (url.startsWith("postgres://") || url.startsWith("postgresql://")) {
|
|
136
|
-
return {
|
|
137
|
-
type: "postgres",
|
|
138
|
-
targetUrl: url,
|
|
139
|
-
source: ".env"
|
|
140
|
-
};
|
|
141
|
-
} else if (url.startsWith("mysql://")) {
|
|
142
|
-
return {
|
|
143
|
-
type: "mysql",
|
|
144
|
-
targetUrl: url,
|
|
145
|
-
source: ".env"
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
} catch (error) {
|
|
151
|
-
}
|
|
152
252
|
return {
|
|
153
253
|
type: "unknown",
|
|
154
254
|
targetUrl: "",
|
|
@@ -161,7 +261,7 @@ async function saveDatabaseUrl(url) {
|
|
|
161
261
|
let envContent = "";
|
|
162
262
|
try {
|
|
163
263
|
envContent = await fs.readFile(envPath, "utf-8");
|
|
164
|
-
} catch
|
|
264
|
+
} catch {
|
|
165
265
|
}
|
|
166
266
|
const regex = /DATABASE_URL\s*=\s*["']?([^"'\r\n]+)["']?/;
|
|
167
267
|
if (regex.test(envContent)) {
|
|
@@ -183,10 +283,27 @@ async function saveDatabaseUrl(url) {
|
|
|
183
283
|
);
|
|
184
284
|
}
|
|
185
285
|
}
|
|
286
|
+
var DB_ENV_KEYS;
|
|
186
287
|
var init_loader = __esm({
|
|
187
288
|
"src/logic/loader.ts"() {
|
|
188
289
|
"use strict";
|
|
189
290
|
init_types();
|
|
291
|
+
DB_ENV_KEYS = [
|
|
292
|
+
"DATABASE_URL",
|
|
293
|
+
"DB_URL",
|
|
294
|
+
"DATABASE_URI",
|
|
295
|
+
"DB_URI",
|
|
296
|
+
"DIRECT_URL",
|
|
297
|
+
"POSTGRES_URL",
|
|
298
|
+
"POSTGRESQL_URL",
|
|
299
|
+
"POSTGRES_PRISMA_URL",
|
|
300
|
+
"POSTGRES_URL_NON_POOLING",
|
|
301
|
+
"SUPABASE_DB_URL",
|
|
302
|
+
"MYSQL_URL",
|
|
303
|
+
"MYSQL_DATABASE_URL",
|
|
304
|
+
"JAWSDB_URL",
|
|
305
|
+
"CLEARDB_DATABASE_URL"
|
|
306
|
+
];
|
|
190
307
|
}
|
|
191
308
|
});
|
|
192
309
|
|
|
@@ -203,10 +320,14 @@ var init_sqlite = __esm({
|
|
|
203
320
|
}
|
|
204
321
|
async getDb() {
|
|
205
322
|
if (!this.db) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
323
|
+
if (this.dbPath !== ":memory:") {
|
|
324
|
+
let modFs = "node:fs";
|
|
325
|
+
const fs19 = await import(modFs);
|
|
326
|
+
if (!fs19.existsSync(this.dbPath)) {
|
|
327
|
+
throw new Error(
|
|
328
|
+
`Failed to found database file at: ${this.dbPath}`
|
|
329
|
+
);
|
|
330
|
+
}
|
|
210
331
|
}
|
|
211
332
|
let mod = "node:sqlite";
|
|
212
333
|
const sqlite = await import(mod);
|
|
@@ -222,12 +343,17 @@ var init_sqlite = __esm({
|
|
|
222
343
|
const db = await this.getDb();
|
|
223
344
|
const vQuery = db.prepare("SELECT sqlite_version() as v");
|
|
224
345
|
const vRow = vQuery.get();
|
|
225
|
-
let
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
346
|
+
let sizeBytes = 0;
|
|
347
|
+
let dbName = ":memory:";
|
|
348
|
+
if (this.dbPath !== ":memory:") {
|
|
349
|
+
let modFs = "node:fs";
|
|
350
|
+
const fs19 = await import(modFs);
|
|
351
|
+
const stats = fs19.statSync(this.dbPath);
|
|
352
|
+
sizeBytes = stats.size;
|
|
353
|
+
let modPath = "node:path";
|
|
354
|
+
const path20 = await import(modPath);
|
|
355
|
+
dbName = path20.basename(this.dbPath);
|
|
356
|
+
}
|
|
231
357
|
return {
|
|
232
358
|
status: "connected",
|
|
233
359
|
dbType: "sqlite",
|
|
@@ -235,7 +361,7 @@ var init_sqlite = __esm({
|
|
|
235
361
|
version: vRow?.v,
|
|
236
362
|
activeConnections: 1,
|
|
237
363
|
// SQLite is single file, essentially 1 active connection for the app
|
|
238
|
-
sizeBytes
|
|
364
|
+
sizeBytes,
|
|
239
365
|
uptime: process.uptime()
|
|
240
366
|
};
|
|
241
367
|
} catch (e) {
|
|
@@ -549,6 +675,31 @@ var init_sqlite = __esm({
|
|
|
549
675
|
|
|
550
676
|
// src/logic/adapters/postgres.ts
|
|
551
677
|
import pg from "pg";
|
|
678
|
+
function buildPgPoolConfig(connectionString) {
|
|
679
|
+
const config = {
|
|
680
|
+
connectionString,
|
|
681
|
+
connectionTimeoutMillis: 1e4
|
|
682
|
+
// 10s timeout to prevent hanging on unreachable hosts
|
|
683
|
+
};
|
|
684
|
+
try {
|
|
685
|
+
const lower = connectionString.toLowerCase();
|
|
686
|
+
const isExplicitSslDisable = lower.includes("sslmode=disable");
|
|
687
|
+
const isExplicitSslRequire = lower.includes("sslmode=require") || lower.includes("sslmode=prefer") || lower.includes("ssl=true") || lower.includes("ssl=1");
|
|
688
|
+
let isCloudProvider = false;
|
|
689
|
+
const match = connectionString.match(/@([^/:?#]+)/);
|
|
690
|
+
if (match && match[1]) {
|
|
691
|
+
const host = match[1].toLowerCase();
|
|
692
|
+
isCloudProvider = host.includes("supabase.") || host.includes("neon.tech") || host.includes("railway.") || host.includes("render.com") || host.includes("cockroach") || host.includes("aiven") || host.includes("rds.amazonaws.com");
|
|
693
|
+
}
|
|
694
|
+
if (!isExplicitSslDisable && (isExplicitSslRequire || isCloudProvider)) {
|
|
695
|
+
config.ssl = {
|
|
696
|
+
rejectUnauthorized: false
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
} catch {
|
|
700
|
+
}
|
|
701
|
+
return config;
|
|
702
|
+
}
|
|
552
703
|
var PostgresAdapter;
|
|
553
704
|
var init_postgres = __esm({
|
|
554
705
|
"src/logic/adapters/postgres.ts"() {
|
|
@@ -561,9 +712,7 @@ var init_postgres = __esm({
|
|
|
561
712
|
}
|
|
562
713
|
getPool() {
|
|
563
714
|
if (!this.pool) {
|
|
564
|
-
this.pool = new pg.Pool(
|
|
565
|
-
connectionString: this.connectionString
|
|
566
|
-
});
|
|
715
|
+
this.pool = new pg.Pool(buildPgPoolConfig(this.connectionString));
|
|
567
716
|
this.pool.on("error", () => {
|
|
568
717
|
});
|
|
569
718
|
}
|
|
@@ -866,7 +1015,8 @@ var init_mysql = __esm({
|
|
|
866
1015
|
if (!this.pool) {
|
|
867
1016
|
this.pool = mysql.createPool({
|
|
868
1017
|
uri: this.connection,
|
|
869
|
-
multipleStatements: true
|
|
1018
|
+
multipleStatements: true,
|
|
1019
|
+
connectTimeout: 1e4
|
|
870
1020
|
});
|
|
871
1021
|
this.pool.on("connection", (connection) => {
|
|
872
1022
|
connection.query("SET SESSION sql_mode = 'ANSI_QUOTES'").catch(() => {
|
|
@@ -1984,6 +2134,9 @@ function inferColumnStrategy(col) {
|
|
|
1984
2134
|
if (name.includes("last_name")) {
|
|
1985
2135
|
return { type: "last_name", label: "Last Name" };
|
|
1986
2136
|
}
|
|
2137
|
+
if (name.includes("username") || name.includes("user_name") || name.includes("handle")) {
|
|
2138
|
+
return { type: "username", label: "Username" };
|
|
2139
|
+
}
|
|
1987
2140
|
if (name.includes("name") || name.includes("author") || name.includes("user")) {
|
|
1988
2141
|
return { type: "full_name", label: "Full Name" };
|
|
1989
2142
|
}
|
|
@@ -2064,6 +2217,11 @@ function generateFieldValue(strategy, fkCache = {}) {
|
|
|
2064
2217
|
return getRandomItem(FIRST_NAMES);
|
|
2065
2218
|
case "last_name":
|
|
2066
2219
|
return getRandomItem(LAST_NAMES);
|
|
2220
|
+
case "username": {
|
|
2221
|
+
const f = getRandomItem(FIRST_NAMES).toLowerCase();
|
|
2222
|
+
const l = getRandomItem(LAST_NAMES).toLowerCase();
|
|
2223
|
+
return `${f}_${l}${getRandomInt(100, 99999)}`;
|
|
2224
|
+
}
|
|
2067
2225
|
case "full_name":
|
|
2068
2226
|
return `${getRandomItem(FIRST_NAMES)} ${getRandomItem(LAST_NAMES)}`;
|
|
2069
2227
|
case "avatar":
|
|
@@ -4116,6 +4274,72 @@ var init_snippets = __esm({
|
|
|
4116
4274
|
}
|
|
4117
4275
|
});
|
|
4118
4276
|
|
|
4277
|
+
// src/logic/version.ts
|
|
4278
|
+
import fs5 from "fs";
|
|
4279
|
+
import path5 from "path";
|
|
4280
|
+
import { fileURLToPath } from "url";
|
|
4281
|
+
function getDrixioVersion() {
|
|
4282
|
+
if (cachedVersion) {
|
|
4283
|
+
return cachedVersion;
|
|
4284
|
+
}
|
|
4285
|
+
if ("1.1.10") {
|
|
4286
|
+
cachedVersion = "1.1.10";
|
|
4287
|
+
return cachedVersion;
|
|
4288
|
+
}
|
|
4289
|
+
try {
|
|
4290
|
+
let currentDir = path5.dirname(fileURLToPath(import.meta.url));
|
|
4291
|
+
for (let i = 0; i < 5; i++) {
|
|
4292
|
+
const candidate = path5.join(currentDir, "package.json");
|
|
4293
|
+
if (fs5.existsSync(candidate)) {
|
|
4294
|
+
const pkg = JSON.parse(fs5.readFileSync(candidate, "utf-8"));
|
|
4295
|
+
if (pkg.name === "drixio" && typeof pkg.version === "string") {
|
|
4296
|
+
cachedVersion = pkg.version;
|
|
4297
|
+
return pkg.version;
|
|
4298
|
+
}
|
|
4299
|
+
}
|
|
4300
|
+
const parent = path5.dirname(currentDir);
|
|
4301
|
+
if (parent === currentDir) break;
|
|
4302
|
+
currentDir = parent;
|
|
4303
|
+
}
|
|
4304
|
+
} catch {
|
|
4305
|
+
}
|
|
4306
|
+
try {
|
|
4307
|
+
const cwdPkgPath = path5.resolve(process.cwd(), "package.json");
|
|
4308
|
+
if (fs5.existsSync(cwdPkgPath)) {
|
|
4309
|
+
const pkg = JSON.parse(fs5.readFileSync(cwdPkgPath, "utf-8"));
|
|
4310
|
+
if (pkg.name === "drixio" && typeof pkg.version === "string") {
|
|
4311
|
+
cachedVersion = pkg.version;
|
|
4312
|
+
return pkg.version;
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
} catch {
|
|
4316
|
+
}
|
|
4317
|
+
if (typeof process.env.npm_package_version === "string") {
|
|
4318
|
+
cachedVersion = process.env.npm_package_version;
|
|
4319
|
+
return cachedVersion;
|
|
4320
|
+
}
|
|
4321
|
+
cachedVersion = "0.0.0";
|
|
4322
|
+
return cachedVersion;
|
|
4323
|
+
}
|
|
4324
|
+
var cachedVersion;
|
|
4325
|
+
var init_version = __esm({
|
|
4326
|
+
"src/logic/version.ts"() {
|
|
4327
|
+
"use strict";
|
|
4328
|
+
}
|
|
4329
|
+
});
|
|
4330
|
+
|
|
4331
|
+
// src/logic/serialization.ts
|
|
4332
|
+
var init_serialization = __esm({
|
|
4333
|
+
"src/logic/serialization.ts"() {
|
|
4334
|
+
"use strict";
|
|
4335
|
+
if (!("toJSON" in BigInt.prototype)) {
|
|
4336
|
+
BigInt.prototype.toJSON = function() {
|
|
4337
|
+
return this.toString();
|
|
4338
|
+
};
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
});
|
|
4342
|
+
|
|
4119
4343
|
// src/logic/index.ts
|
|
4120
4344
|
var init_logic = __esm({
|
|
4121
4345
|
"src/logic/index.ts"() {
|
|
@@ -4134,6 +4358,8 @@ var init_logic = __esm({
|
|
|
4134
4358
|
init_safety();
|
|
4135
4359
|
init_diff();
|
|
4136
4360
|
init_snippets();
|
|
4361
|
+
init_version();
|
|
4362
|
+
init_serialization();
|
|
4137
4363
|
}
|
|
4138
4364
|
});
|
|
4139
4365
|
|
|
@@ -4177,7 +4403,7 @@ function printCustomDashboard(title, rows) {
|
|
|
4177
4403
|
);
|
|
4178
4404
|
}
|
|
4179
4405
|
function printDashboard(dbConfig) {
|
|
4180
|
-
const version =
|
|
4406
|
+
const version = getDrixioVersion();
|
|
4181
4407
|
const headerTitle = ` Lightweight Interactive TUI Database Client \u2022 v${version} `;
|
|
4182
4408
|
let dbTypeVal = "None";
|
|
4183
4409
|
let targetVal = "-";
|
|
@@ -4208,6 +4434,7 @@ var rgb, l1, l2, l3, l4, l5, l6;
|
|
|
4208
4434
|
var init_logo = __esm({
|
|
4209
4435
|
"src/tui/ui/logo.ts"() {
|
|
4210
4436
|
"use strict";
|
|
4437
|
+
init_version();
|
|
4211
4438
|
rgb = (r, g, b) => (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
|
|
4212
4439
|
l1 = rgb(0, 255, 255);
|
|
4213
4440
|
l2 = rgb(0, 230, 245);
|
|
@@ -4526,8 +4753,8 @@ x Error creating table: ${e.message}`));
|
|
|
4526
4753
|
await waitForEnter2();
|
|
4527
4754
|
}
|
|
4528
4755
|
async function waitForEnter2() {
|
|
4529
|
-
const { input:
|
|
4530
|
-
await
|
|
4756
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
4757
|
+
await input11({
|
|
4531
4758
|
message: "Press Enter to continue..."
|
|
4532
4759
|
});
|
|
4533
4760
|
}
|
|
@@ -4600,8 +4827,8 @@ var init_buildTable = __esm({
|
|
|
4600
4827
|
});
|
|
4601
4828
|
|
|
4602
4829
|
// src/tui/views/sqlRunner.ts
|
|
4603
|
-
import
|
|
4604
|
-
import
|
|
4830
|
+
import fs15 from "fs/promises";
|
|
4831
|
+
import path15 from "path";
|
|
4605
4832
|
import { input as input5 } from "@inquirer/prompts";
|
|
4606
4833
|
import pc29 from "picocolors";
|
|
4607
4834
|
async function runSqlRunner(dbConfig) {
|
|
@@ -4622,10 +4849,10 @@ No database connection found. Please setup first.`)
|
|
|
4622
4849
|
message: "Enter the path to your .md or .sql file:"
|
|
4623
4850
|
});
|
|
4624
4851
|
if (filePath && filePath.trim()) {
|
|
4625
|
-
const absolutePath =
|
|
4852
|
+
const absolutePath = path15.resolve(process.cwd(), filePath.trim());
|
|
4626
4853
|
let fileContent = "";
|
|
4627
4854
|
try {
|
|
4628
|
-
fileContent = await
|
|
4855
|
+
fileContent = await fs15.readFile(absolutePath, "utf-8");
|
|
4629
4856
|
} catch (err2) {
|
|
4630
4857
|
console.log(pc29.red(`
|
|
4631
4858
|
x Failed to read file: ${err2.message}`));
|
|
@@ -5160,8 +5387,8 @@ async function handleModifyMenu(dbConfig) {
|
|
|
5160
5387
|
await waitForEnter3();
|
|
5161
5388
|
}
|
|
5162
5389
|
async function waitForEnter3() {
|
|
5163
|
-
const { input:
|
|
5164
|
-
await
|
|
5390
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
5391
|
+
await input11({
|
|
5165
5392
|
message: "Press Enter to continue..."
|
|
5166
5393
|
});
|
|
5167
5394
|
}
|
|
@@ -5179,11 +5406,465 @@ var init_tableManagerFlow = __esm({
|
|
|
5179
5406
|
}
|
|
5180
5407
|
});
|
|
5181
5408
|
|
|
5409
|
+
// src/tui/wizards/ormWizard.ts
|
|
5410
|
+
var ormWizard_exports = {};
|
|
5411
|
+
__export(ormWizard_exports, {
|
|
5412
|
+
runOrmWizard: () => runOrmWizard
|
|
5413
|
+
});
|
|
5414
|
+
import { select as select13, input as input8 } from "@inquirer/prompts";
|
|
5415
|
+
import fs16 from "fs/promises";
|
|
5416
|
+
import path16 from "path";
|
|
5417
|
+
import pc34 from "picocolors";
|
|
5418
|
+
async function runOrmWizard(dbConfig) {
|
|
5419
|
+
if (dbConfig.type === "unknown") {
|
|
5420
|
+
console.log(
|
|
5421
|
+
pc34.yellow(
|
|
5422
|
+
"\nNo database connection found. Please setup database first."
|
|
5423
|
+
)
|
|
5424
|
+
);
|
|
5425
|
+
return;
|
|
5426
|
+
}
|
|
5427
|
+
const adapter = createDBAdapter(dbConfig);
|
|
5428
|
+
try {
|
|
5429
|
+
const allSchemasRes = await getTableSchemas(adapter, void 0, true);
|
|
5430
|
+
if (!allSchemasRes.success) {
|
|
5431
|
+
console.log(
|
|
5432
|
+
pc34.red(`
|
|
5433
|
+
\u2718 Failed to inspect schema: ${allSchemasRes.error}`)
|
|
5434
|
+
);
|
|
5435
|
+
return;
|
|
5436
|
+
}
|
|
5437
|
+
const allTables = allSchemasRes.data;
|
|
5438
|
+
if (allTables.length === 0) {
|
|
5439
|
+
console.log(pc34.yellow("\nNo tables found in this database."));
|
|
5440
|
+
return;
|
|
5441
|
+
}
|
|
5442
|
+
console.log(pc34.cyan("\n--- Modern ORM & Type Definition Generator ---"));
|
|
5443
|
+
console.log(
|
|
5444
|
+
pc34.dim(
|
|
5445
|
+
"Generate production-ready Prisma, Drizzle, or TypeScript definitions.\n"
|
|
5446
|
+
)
|
|
5447
|
+
);
|
|
5448
|
+
const targetFormat = await select13({
|
|
5449
|
+
message: "Select target ORM or definition format:",
|
|
5450
|
+
choices: [
|
|
5451
|
+
{
|
|
5452
|
+
name: "Prisma Schema (schema.prisma)",
|
|
5453
|
+
value: "prisma",
|
|
5454
|
+
description: "Standard Prisma models with data source and generator"
|
|
5455
|
+
},
|
|
5456
|
+
{
|
|
5457
|
+
name: "Drizzle ORM (schema.ts)",
|
|
5458
|
+
value: "drizzle",
|
|
5459
|
+
description: "Type-safe Drizzle table definitions with core packages"
|
|
5460
|
+
},
|
|
5461
|
+
{
|
|
5462
|
+
name: "TypeScript Interfaces (drixio-types.d.ts)",
|
|
5463
|
+
value: "types",
|
|
5464
|
+
description: "Pure TypeScript interface definitions for database records"
|
|
5465
|
+
}
|
|
5466
|
+
]
|
|
5467
|
+
});
|
|
5468
|
+
const scope = await select13({
|
|
5469
|
+
message: "Select generation scope:",
|
|
5470
|
+
choices: [
|
|
5471
|
+
{
|
|
5472
|
+
name: `All Tables (${allTables.length} tables)`,
|
|
5473
|
+
value: "all"
|
|
5474
|
+
},
|
|
5475
|
+
{
|
|
5476
|
+
name: "Single Table",
|
|
5477
|
+
value: "single"
|
|
5478
|
+
}
|
|
5479
|
+
]
|
|
5480
|
+
});
|
|
5481
|
+
let selectedTables = allTables;
|
|
5482
|
+
if (scope === "single") {
|
|
5483
|
+
const chosenTableName = await select13({
|
|
5484
|
+
message: "Select table to generate code for:",
|
|
5485
|
+
choices: allTables.map((t) => ({
|
|
5486
|
+
name: t.tableName,
|
|
5487
|
+
value: t.tableName
|
|
5488
|
+
}))
|
|
5489
|
+
});
|
|
5490
|
+
selectedTables = allTables.filter((t) => t.tableName === chosenTableName);
|
|
5491
|
+
}
|
|
5492
|
+
let generatedCode = "";
|
|
5493
|
+
let defaultFileName = "schema.ts";
|
|
5494
|
+
if (targetFormat === "prisma") {
|
|
5495
|
+
generatedCode = generatePrismaSchema(selectedTables, dbConfig.type);
|
|
5496
|
+
defaultFileName = "schema.prisma";
|
|
5497
|
+
} else if (targetFormat === "drizzle") {
|
|
5498
|
+
generatedCode = generateDrizzleSchema(selectedTables, dbConfig.type);
|
|
5499
|
+
defaultFileName = "schema.ts";
|
|
5500
|
+
} else {
|
|
5501
|
+
generatedCode = generateTypeScriptDefinitions(selectedTables, dbConfig.type);
|
|
5502
|
+
defaultFileName = "drixio-types.d.ts";
|
|
5503
|
+
}
|
|
5504
|
+
const outputAction = await select13({
|
|
5505
|
+
message: "What would you like to do with the generated code?",
|
|
5506
|
+
choices: [
|
|
5507
|
+
{
|
|
5508
|
+
name: `Save to file (${defaultFileName})`,
|
|
5509
|
+
value: "save"
|
|
5510
|
+
},
|
|
5511
|
+
{
|
|
5512
|
+
name: "Print directly to terminal",
|
|
5513
|
+
value: "print"
|
|
5514
|
+
}
|
|
5515
|
+
]
|
|
5516
|
+
});
|
|
5517
|
+
if (outputAction === "print") {
|
|
5518
|
+
console.log(pc34.bold(pc34.cyan(`
|
|
5519
|
+
--- Generated Code ---`)));
|
|
5520
|
+
console.log(generatedCode);
|
|
5521
|
+
console.log(pc34.bold(pc34.cyan(`----------------------
|
|
5522
|
+
`)));
|
|
5523
|
+
} else {
|
|
5524
|
+
const outPath = await input8({
|
|
5525
|
+
message: "Enter destination file path:",
|
|
5526
|
+
default: defaultFileName
|
|
5527
|
+
});
|
|
5528
|
+
const resolvedPath = path16.resolve(process.cwd(), outPath);
|
|
5529
|
+
await fs16.mkdir(path16.dirname(resolvedPath), { recursive: true });
|
|
5530
|
+
await fs16.writeFile(resolvedPath, generatedCode, "utf-8");
|
|
5531
|
+
console.log(
|
|
5532
|
+
pc34.green(
|
|
5533
|
+
`
|
|
5534
|
+
\u2714 Successfully generated and saved to: ${pc34.bold(resolvedPath)}`
|
|
5535
|
+
)
|
|
5536
|
+
);
|
|
5537
|
+
}
|
|
5538
|
+
} catch (e) {
|
|
5539
|
+
console.log(pc34.red(`
|
|
5540
|
+
\u2718 Code generation failed: ${e.message}`));
|
|
5541
|
+
} finally {
|
|
5542
|
+
await adapter.close();
|
|
5543
|
+
}
|
|
5544
|
+
}
|
|
5545
|
+
var init_ormWizard = __esm({
|
|
5546
|
+
"src/tui/wizards/ormWizard.ts"() {
|
|
5547
|
+
"use strict";
|
|
5548
|
+
init_logic();
|
|
5549
|
+
}
|
|
5550
|
+
});
|
|
5551
|
+
|
|
5552
|
+
// src/tui/wizards/snippetsWizard.ts
|
|
5553
|
+
var snippetsWizard_exports = {};
|
|
5554
|
+
__export(snippetsWizard_exports, {
|
|
5555
|
+
runSnippetsWizard: () => runSnippetsWizard
|
|
5556
|
+
});
|
|
5557
|
+
import { select as select14, input as input9 } from "@inquirer/prompts";
|
|
5558
|
+
import pc35 from "picocolors";
|
|
5559
|
+
async function runSnippetsWizard(dbConfig) {
|
|
5560
|
+
if (dbConfig.type === "unknown") {
|
|
5561
|
+
console.log(
|
|
5562
|
+
pc35.yellow(
|
|
5563
|
+
"\nNo database connection found. Please setup database first."
|
|
5564
|
+
)
|
|
5565
|
+
);
|
|
5566
|
+
return;
|
|
5567
|
+
}
|
|
5568
|
+
const snippets = await loadSnippets();
|
|
5569
|
+
if (snippets.length === 0) {
|
|
5570
|
+
console.log(pc35.yellow("\nNo SQL snippets found in workspace."));
|
|
5571
|
+
return;
|
|
5572
|
+
}
|
|
5573
|
+
console.log(pc35.cyan("\n--- SQL Snippets & Operational Templates ---"));
|
|
5574
|
+
console.log(
|
|
5575
|
+
pc35.dim(
|
|
5576
|
+
"Run parameterized diagnostic queries and high-frequency templates.\n"
|
|
5577
|
+
)
|
|
5578
|
+
);
|
|
5579
|
+
const snippetChoices = snippets.map((s) => ({
|
|
5580
|
+
name: `${s.title} ${pc35.dim(`(${s.tags?.join(", ") || "general"})`)}`,
|
|
5581
|
+
value: s.id,
|
|
5582
|
+
description: s.description || s.sql
|
|
5583
|
+
}));
|
|
5584
|
+
const chosenId = await select14({
|
|
5585
|
+
message: "Select a snippet to execute:",
|
|
5586
|
+
choices: snippetChoices
|
|
5587
|
+
});
|
|
5588
|
+
const snippet = snippets.find((s) => s.id === chosenId);
|
|
5589
|
+
if (!snippet) return;
|
|
5590
|
+
console.log(pc35.bold(pc35.cyan(`
|
|
5591
|
+
Template SQL:`)));
|
|
5592
|
+
console.log(pc35.dim(snippet.sql));
|
|
5593
|
+
const params = extractSnippetParams(snippet.sql);
|
|
5594
|
+
const paramValues = {};
|
|
5595
|
+
if (params.length > 0) {
|
|
5596
|
+
console.log(pc35.yellow(`
|
|
5597
|
+
This query requires ${params.length} parameter(s):`));
|
|
5598
|
+
for (const param of params) {
|
|
5599
|
+
let defaultVal = "";
|
|
5600
|
+
if (param === "limit") defaultVal = "20";
|
|
5601
|
+
if (param === "table") defaultVal = "users";
|
|
5602
|
+
const val = await input9({
|
|
5603
|
+
message: `Enter value for :${pc35.bold(param)}:`,
|
|
5604
|
+
default: defaultVal
|
|
5605
|
+
});
|
|
5606
|
+
paramValues[param] = val;
|
|
5607
|
+
}
|
|
5608
|
+
}
|
|
5609
|
+
const finalSql = substituteSnippetParams(
|
|
5610
|
+
snippet.sql,
|
|
5611
|
+
paramValues,
|
|
5612
|
+
dbConfig.type
|
|
5613
|
+
);
|
|
5614
|
+
console.log(pc35.bold(pc35.cyan(`
|
|
5615
|
+
Executing Query:`)));
|
|
5616
|
+
console.log(pc35.white(finalSql));
|
|
5617
|
+
const adapter = createDBAdapter(dbConfig);
|
|
5618
|
+
try {
|
|
5619
|
+
const startTime = performance.now();
|
|
5620
|
+
const result = await adapter.query(finalSql);
|
|
5621
|
+
const elapsed = Math.round(performance.now() - startTime);
|
|
5622
|
+
console.log(
|
|
5623
|
+
pc35.green(
|
|
5624
|
+
`
|
|
5625
|
+
\u2714 Query executed successfully in ${elapsed}ms (${result.rows.length} row(s) returned):
|
|
5626
|
+
`
|
|
5627
|
+
)
|
|
5628
|
+
);
|
|
5629
|
+
if (result.rows.length > 0) {
|
|
5630
|
+
console.table(result.rows.slice(0, 50));
|
|
5631
|
+
if (result.rows.length > 50) {
|
|
5632
|
+
console.log(
|
|
5633
|
+
pc35.dim(`... and ${result.rows.length - 50} more row(s) hidden.`)
|
|
5634
|
+
);
|
|
5635
|
+
}
|
|
5636
|
+
} else {
|
|
5637
|
+
console.log(pc35.dim("(No rows returned)"));
|
|
5638
|
+
}
|
|
5639
|
+
} catch (e) {
|
|
5640
|
+
console.log(pc35.red(`
|
|
5641
|
+
\u2718 Query execution failed: ${e.message}`));
|
|
5642
|
+
} finally {
|
|
5643
|
+
await adapter.close();
|
|
5644
|
+
}
|
|
5645
|
+
}
|
|
5646
|
+
var init_snippetsWizard = __esm({
|
|
5647
|
+
"src/tui/wizards/snippetsWizard.ts"() {
|
|
5648
|
+
"use strict";
|
|
5649
|
+
init_logic();
|
|
5650
|
+
}
|
|
5651
|
+
});
|
|
5652
|
+
|
|
5653
|
+
// src/tui/wizards/diffWizard.ts
|
|
5654
|
+
var diffWizard_exports = {};
|
|
5655
|
+
__export(diffWizard_exports, {
|
|
5656
|
+
runDiffWizard: () => runDiffWizard
|
|
5657
|
+
});
|
|
5658
|
+
import { select as select15, input as input10 } from "@inquirer/prompts";
|
|
5659
|
+
import fs17 from "fs/promises";
|
|
5660
|
+
import { existsSync as existsSync3 } from "fs";
|
|
5661
|
+
import path17 from "path";
|
|
5662
|
+
import pc36 from "picocolors";
|
|
5663
|
+
async function runDiffWizard(dbConfig) {
|
|
5664
|
+
if (dbConfig.type === "unknown") {
|
|
5665
|
+
console.log(
|
|
5666
|
+
pc36.yellow(
|
|
5667
|
+
"\nNo database connection found. Please setup database first."
|
|
5668
|
+
)
|
|
5669
|
+
);
|
|
5670
|
+
return;
|
|
5671
|
+
}
|
|
5672
|
+
console.log(pc36.cyan("\n--- Schema Diff & Migration Wizard ---"));
|
|
5673
|
+
console.log(
|
|
5674
|
+
pc36.dim(
|
|
5675
|
+
"Compare schemas against snapshots or external databases, and generate Up/Down migration SQL.\n"
|
|
5676
|
+
)
|
|
5677
|
+
);
|
|
5678
|
+
const action = await select15({
|
|
5679
|
+
message: "Select diff action:",
|
|
5680
|
+
choices: [
|
|
5681
|
+
{
|
|
5682
|
+
name: "Capture Schema Snapshot (JSON)",
|
|
5683
|
+
value: "snapshot",
|
|
5684
|
+
description: "Save current database structure to a versioned JSON snapshot"
|
|
5685
|
+
},
|
|
5686
|
+
{
|
|
5687
|
+
name: "Compare with Snapshot File (.json)",
|
|
5688
|
+
value: "compare-file",
|
|
5689
|
+
description: "Compare current database with a saved schema snapshot file"
|
|
5690
|
+
},
|
|
5691
|
+
{
|
|
5692
|
+
name: "Compare with Another Database URL",
|
|
5693
|
+
value: "compare-url",
|
|
5694
|
+
description: "Compare current database directly with a remote/local database"
|
|
5695
|
+
}
|
|
5696
|
+
]
|
|
5697
|
+
});
|
|
5698
|
+
const adapter = createDBAdapter(dbConfig);
|
|
5699
|
+
try {
|
|
5700
|
+
if (action === "snapshot") {
|
|
5701
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5702
|
+
const defaultFileName = `.drixio/snapshot_${timestamp}.json`;
|
|
5703
|
+
const outPath = await input10({
|
|
5704
|
+
message: "Enter output file path for snapshot:",
|
|
5705
|
+
default: defaultFileName
|
|
5706
|
+
});
|
|
5707
|
+
const resolvedPath = path17.resolve(process.cwd(), outPath);
|
|
5708
|
+
await fs17.mkdir(path17.dirname(resolvedPath), { recursive: true });
|
|
5709
|
+
console.log(pc36.dim("\nCapturing schema snapshot..."));
|
|
5710
|
+
const snapshotRes = await createSchemaSnapshot(
|
|
5711
|
+
adapter,
|
|
5712
|
+
dbConfig.type,
|
|
5713
|
+
path17.basename(outPath, ".json")
|
|
5714
|
+
);
|
|
5715
|
+
if (!snapshotRes.success) {
|
|
5716
|
+
console.log(pc36.red(`
|
|
5717
|
+
\u2718 Failed to create snapshot: ${snapshotRes.error}`));
|
|
5718
|
+
return;
|
|
5719
|
+
}
|
|
5720
|
+
await fs17.writeFile(
|
|
5721
|
+
resolvedPath,
|
|
5722
|
+
JSON.stringify(snapshotRes.data, null, 2),
|
|
5723
|
+
"utf-8"
|
|
5724
|
+
);
|
|
5725
|
+
console.log(
|
|
5726
|
+
pc36.green(
|
|
5727
|
+
`
|
|
5728
|
+
\u2714 Successfully saved snapshot with ${snapshotRes.data.tables.length} table(s) to: ${pc36.bold(resolvedPath)}`
|
|
5729
|
+
)
|
|
5730
|
+
);
|
|
5731
|
+
return;
|
|
5732
|
+
}
|
|
5733
|
+
let diffResult;
|
|
5734
|
+
if (action === "compare-file") {
|
|
5735
|
+
const defaultPath = existsSync3(path17.resolve(process.cwd(), ".drixio/schema.json")) ? ".drixio/schema.json" : "schema.json";
|
|
5736
|
+
const snapshotPath = await input10({
|
|
5737
|
+
message: "Enter path to snapshot JSON file:",
|
|
5738
|
+
default: defaultPath
|
|
5739
|
+
});
|
|
5740
|
+
const resolvedSnapshot = path17.resolve(process.cwd(), snapshotPath);
|
|
5741
|
+
if (!existsSync3(resolvedSnapshot)) {
|
|
5742
|
+
console.log(pc36.red(`
|
|
5743
|
+
\u2718 Snapshot file not found: ${resolvedSnapshot}`));
|
|
5744
|
+
return;
|
|
5745
|
+
}
|
|
5746
|
+
console.log(pc36.dim("\nComparing current database with snapshot..."));
|
|
5747
|
+
const content = await fs17.readFile(resolvedSnapshot, "utf-8");
|
|
5748
|
+
let snapshot;
|
|
5749
|
+
try {
|
|
5750
|
+
snapshot = JSON.parse(content);
|
|
5751
|
+
} catch {
|
|
5752
|
+
console.log(pc36.red(`
|
|
5753
|
+
\u2718 Invalid JSON content in snapshot file: ${resolvedSnapshot}`));
|
|
5754
|
+
return;
|
|
5755
|
+
}
|
|
5756
|
+
const res = await diffDatabaseWithSnapshot(
|
|
5757
|
+
adapter,
|
|
5758
|
+
snapshot,
|
|
5759
|
+
dbConfig.type,
|
|
5760
|
+
"Current Database",
|
|
5761
|
+
`Snapshot (${path17.basename(resolvedSnapshot)})`
|
|
5762
|
+
);
|
|
5763
|
+
if (!res.success) {
|
|
5764
|
+
console.log(pc36.red(`
|
|
5765
|
+
\u2718 Diff failed: ${res.error}`));
|
|
5766
|
+
return;
|
|
5767
|
+
}
|
|
5768
|
+
diffResult = res.data;
|
|
5769
|
+
} else {
|
|
5770
|
+
const targetUrl = await input10({
|
|
5771
|
+
message: "Enter target database connection URL (e.g. postgres://user:pass@host:5432/other_db):"
|
|
5772
|
+
});
|
|
5773
|
+
if (!targetUrl.trim()) {
|
|
5774
|
+
console.log(pc36.yellow("Target URL cannot be empty."));
|
|
5775
|
+
return;
|
|
5776
|
+
}
|
|
5777
|
+
console.log(pc36.dim("\nConnecting to target database and comparing..."));
|
|
5778
|
+
const targetConfig = await detectDatabase(targetUrl.trim());
|
|
5779
|
+
const targetAdapter = createDBAdapter(targetConfig);
|
|
5780
|
+
try {
|
|
5781
|
+
const res = await diffDatabases(
|
|
5782
|
+
adapter,
|
|
5783
|
+
targetAdapter,
|
|
5784
|
+
dbConfig.type,
|
|
5785
|
+
"Current Database",
|
|
5786
|
+
"Target Database"
|
|
5787
|
+
);
|
|
5788
|
+
if (!res.success) {
|
|
5789
|
+
console.log(pc36.red(`
|
|
5790
|
+
\u2718 Diff failed: ${res.error}`));
|
|
5791
|
+
return;
|
|
5792
|
+
}
|
|
5793
|
+
diffResult = res.data;
|
|
5794
|
+
} finally {
|
|
5795
|
+
await targetAdapter.close();
|
|
5796
|
+
}
|
|
5797
|
+
}
|
|
5798
|
+
if (!diffResult.hasChanges) {
|
|
5799
|
+
console.log(pc36.green("\n\u2714 No schema differences detected. Both schemas are identical!"));
|
|
5800
|
+
return;
|
|
5801
|
+
}
|
|
5802
|
+
console.log(pc36.bold(pc36.yellow(`
|
|
5803
|
+
--- Schema Differences Detected ---`)));
|
|
5804
|
+
console.log(` Added Tables: ${diffResult.stats.addedTablesCount}`);
|
|
5805
|
+
console.log(` Dropped Tables: ${diffResult.stats.droppedTablesCount}`);
|
|
5806
|
+
console.log(` Altered Tables: ${diffResult.stats.alteredTablesCount}`);
|
|
5807
|
+
console.log(` Added Columns: ${diffResult.stats.addedColumnsCount}`);
|
|
5808
|
+
console.log(` Dropped Columns: ${diffResult.stats.droppedColumnsCount}`);
|
|
5809
|
+
console.log(` Added Indexes: ${diffResult.stats.addedIndexesCount}`);
|
|
5810
|
+
console.log(` Dropped Indexes: ${diffResult.stats.droppedIndexesCount}`);
|
|
5811
|
+
const nextStep = await select15({
|
|
5812
|
+
message: "What would you like to inspect?",
|
|
5813
|
+
choices: [
|
|
5814
|
+
{
|
|
5815
|
+
name: "View Forward Migration SQL (Up)",
|
|
5816
|
+
value: "view-up"
|
|
5817
|
+
},
|
|
5818
|
+
{
|
|
5819
|
+
name: "View Rollback SQL (Down)",
|
|
5820
|
+
value: "view-down"
|
|
5821
|
+
},
|
|
5822
|
+
{
|
|
5823
|
+
name: "Save Migration SQL to File",
|
|
5824
|
+
value: "save-sql"
|
|
5825
|
+
}
|
|
5826
|
+
]
|
|
5827
|
+
});
|
|
5828
|
+
if (nextStep === "view-up") {
|
|
5829
|
+
console.log(pc36.bold(pc36.cyan("\n--- Forward Migration SQL (Up) ---")));
|
|
5830
|
+
console.log(diffResult.migrationSql);
|
|
5831
|
+
console.log(pc36.bold(pc36.cyan("----------------------------------\n")));
|
|
5832
|
+
} else if (nextStep === "view-down") {
|
|
5833
|
+
console.log(pc36.bold(pc36.cyan("\n--- Rollback SQL (Down) ---")));
|
|
5834
|
+
console.log(diffResult.rollbackSql);
|
|
5835
|
+
console.log(pc36.bold(pc36.cyan("---------------------------\n")));
|
|
5836
|
+
} else if (nextStep === "save-sql") {
|
|
5837
|
+
const outSqlPath = await input10({
|
|
5838
|
+
message: "Enter destination file path:",
|
|
5839
|
+
default: "migration.sql"
|
|
5840
|
+
});
|
|
5841
|
+
const resolvedOut = path17.resolve(process.cwd(), outSqlPath);
|
|
5842
|
+
await fs17.mkdir(path17.dirname(resolvedOut), { recursive: true });
|
|
5843
|
+
await fs17.writeFile(resolvedOut, diffResult.migrationSql, "utf-8");
|
|
5844
|
+
console.log(
|
|
5845
|
+
pc36.green(`
|
|
5846
|
+
\u2714 Migration SQL successfully saved to: ${pc36.bold(resolvedOut)}`)
|
|
5847
|
+
);
|
|
5848
|
+
}
|
|
5849
|
+
} catch (e) {
|
|
5850
|
+
console.log(pc36.red(`
|
|
5851
|
+
\u2718 Schema diff failed: ${e.message}`));
|
|
5852
|
+
} finally {
|
|
5853
|
+
await adapter.close();
|
|
5854
|
+
}
|
|
5855
|
+
}
|
|
5856
|
+
var init_diffWizard = __esm({
|
|
5857
|
+
"src/tui/wizards/diffWizard.ts"() {
|
|
5858
|
+
"use strict";
|
|
5859
|
+
init_logic();
|
|
5860
|
+
}
|
|
5861
|
+
});
|
|
5862
|
+
|
|
5182
5863
|
// src/studio/api.ts
|
|
5183
5864
|
import { Hono } from "hono";
|
|
5184
5865
|
import { spawn } from "child_process";
|
|
5185
|
-
import
|
|
5186
|
-
import
|
|
5866
|
+
import path18 from "path";
|
|
5867
|
+
import fs18 from "fs";
|
|
5187
5868
|
function nodeToWebStream(nodeStream) {
|
|
5188
5869
|
return new ReadableStream({
|
|
5189
5870
|
start(controller) {
|
|
@@ -5279,15 +5960,37 @@ function registerApiRoutes(app, dbConfig) {
|
|
|
5279
5960
|
return c.json({ success: false, error: e.message }, 500);
|
|
5280
5961
|
}
|
|
5281
5962
|
});
|
|
5963
|
+
const detectHostEnvironment = (cfg) => {
|
|
5964
|
+
if (cfg.type === "sqlite") {
|
|
5965
|
+
return { isRemote: false, host: "local", badgeLabel: "LOCAL (SQLite)" };
|
|
5966
|
+
}
|
|
5967
|
+
if (cfg.type === "mysql" || cfg.type === "postgres") {
|
|
5968
|
+
let host = "localhost";
|
|
5969
|
+
const match = cfg.targetUrl.match(/@([^:/@?]+)/);
|
|
5970
|
+
if (match) host = match[1];
|
|
5971
|
+
const isLocal = host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0" || host === "host.docker.internal";
|
|
5972
|
+
return {
|
|
5973
|
+
isRemote: !isLocal,
|
|
5974
|
+
host,
|
|
5975
|
+
badgeLabel: isLocal ? `LOCAL (${cfg.type.toUpperCase()})` : `REMOTE (${host})`
|
|
5976
|
+
};
|
|
5977
|
+
}
|
|
5978
|
+
return { isRemote: false, host: "", badgeLabel: "DISCONNECTED" };
|
|
5979
|
+
};
|
|
5282
5980
|
api.get("/config", (c) => {
|
|
5283
5981
|
const isConnected = !!currentAdapter && currentDbConfig.type !== "unknown";
|
|
5982
|
+
const envInfo = detectHostEnvironment(currentDbConfig);
|
|
5284
5983
|
return c.json({
|
|
5285
5984
|
success: true,
|
|
5286
5985
|
data: {
|
|
5986
|
+
appVersion: getDrixioVersion(),
|
|
5287
5987
|
connected: isConnected,
|
|
5288
5988
|
dbType: isConnected ? currentDbConfig.type : "none",
|
|
5289
5989
|
dbName: isConnected ? getDbName() : "No Database",
|
|
5290
|
-
targetUrl: currentDbConfig.targetUrl || ""
|
|
5990
|
+
targetUrl: currentDbConfig.targetUrl || "",
|
|
5991
|
+
isRemote: envInfo.isRemote,
|
|
5992
|
+
host: envInfo.host,
|
|
5993
|
+
badgeLabel: isConnected ? envInfo.badgeLabel : "DISCONNECTED"
|
|
5291
5994
|
}
|
|
5292
5995
|
});
|
|
5293
5996
|
});
|
|
@@ -5694,6 +6397,54 @@ function registerApiRoutes(app, dbConfig) {
|
|
|
5694
6397
|
return c.json({ success: false, error: e.message }, 500);
|
|
5695
6398
|
}
|
|
5696
6399
|
});
|
|
6400
|
+
api.post("/query/explain", async (c) => {
|
|
6401
|
+
try {
|
|
6402
|
+
const { sql } = await c.req.json().catch(() => ({}));
|
|
6403
|
+
if (!sql || typeof sql !== "string") {
|
|
6404
|
+
return c.json(
|
|
6405
|
+
{ success: false, error: "SQL query is required for explain" },
|
|
6406
|
+
400
|
|
6407
|
+
);
|
|
6408
|
+
}
|
|
6409
|
+
const adapter = getAdapter();
|
|
6410
|
+
const cleanSql = sql.trim().replace(/;+$/, "");
|
|
6411
|
+
let explainSql = "";
|
|
6412
|
+
if (currentDbConfig.type === "sqlite") {
|
|
6413
|
+
explainSql = `EXPLAIN QUERY PLAN ${cleanSql}`;
|
|
6414
|
+
} else if (currentDbConfig.type === "postgres") {
|
|
6415
|
+
explainSql = `EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS) ${cleanSql}`;
|
|
6416
|
+
} else if (currentDbConfig.type === "mysql") {
|
|
6417
|
+
explainSql = `EXPLAIN ${cleanSql}`;
|
|
6418
|
+
} else {
|
|
6419
|
+
explainSql = `EXPLAIN ${cleanSql}`;
|
|
6420
|
+
}
|
|
6421
|
+
const startTime = performance.now();
|
|
6422
|
+
let res;
|
|
6423
|
+
try {
|
|
6424
|
+
res = await adapter.query(explainSql);
|
|
6425
|
+
} catch (primaryErr) {
|
|
6426
|
+
if (currentDbConfig.type === "postgres") {
|
|
6427
|
+
explainSql = `EXPLAIN ${cleanSql}`;
|
|
6428
|
+
res = await adapter.query(explainSql);
|
|
6429
|
+
} else {
|
|
6430
|
+
throw primaryErr;
|
|
6431
|
+
}
|
|
6432
|
+
}
|
|
6433
|
+
const durationMs = Math.round(performance.now() - startTime);
|
|
6434
|
+
return c.json({
|
|
6435
|
+
success: true,
|
|
6436
|
+
data: {
|
|
6437
|
+
columns: res.columns,
|
|
6438
|
+
rows: res.rows,
|
|
6439
|
+
durationMs,
|
|
6440
|
+
explainSql,
|
|
6441
|
+
dialect: currentDbConfig.type
|
|
6442
|
+
}
|
|
6443
|
+
});
|
|
6444
|
+
} catch (e) {
|
|
6445
|
+
return c.json({ success: false, error: e.message }, 500);
|
|
6446
|
+
}
|
|
6447
|
+
});
|
|
5697
6448
|
api.post("/query/export", async (c) => {
|
|
5698
6449
|
try {
|
|
5699
6450
|
const body = await c.req.json();
|
|
@@ -6284,10 +7035,10 @@ function registerApiRoutes(app, dbConfig) {
|
|
|
6284
7035
|
if (dialect === "sqlite") {
|
|
6285
7036
|
const rawPath = body.url || body.sqlitePath || dbName || "drixio.sqlite";
|
|
6286
7037
|
const cleanPath = rawPath.replace(/^file:/, "").trim();
|
|
6287
|
-
const fullPath =
|
|
7038
|
+
const fullPath = path18.isAbsolute(cleanPath) ? cleanPath : path18.resolve(process.cwd(), cleanPath);
|
|
6288
7039
|
if (mode === "create") {
|
|
6289
|
-
const dir =
|
|
6290
|
-
if (!
|
|
7040
|
+
const dir = path18.dirname(fullPath);
|
|
7041
|
+
if (!fs18.existsSync(dir)) {
|
|
6291
7042
|
return c.json(
|
|
6292
7043
|
{
|
|
6293
7044
|
success: false,
|
|
@@ -6296,18 +7047,18 @@ function registerApiRoutes(app, dbConfig) {
|
|
|
6296
7047
|
400
|
|
6297
7048
|
);
|
|
6298
7049
|
}
|
|
6299
|
-
const exists =
|
|
7050
|
+
const exists = fs18.existsSync(fullPath);
|
|
6300
7051
|
const latencyMs2 = Date.now() - startTime;
|
|
6301
7052
|
return c.json({
|
|
6302
7053
|
success: true,
|
|
6303
7054
|
data: {
|
|
6304
7055
|
latencyMs: latencyMs2,
|
|
6305
|
-
message: exists ? `File already exists at "${
|
|
7056
|
+
message: exists ? `File already exists at "${path18.basename(fullPath)}". Will connect and reuse.` : `Target path is valid. File will be created on connect.`,
|
|
6306
7057
|
fullPath
|
|
6307
7058
|
}
|
|
6308
7059
|
});
|
|
6309
7060
|
} else {
|
|
6310
|
-
if (!
|
|
7061
|
+
if (!fs18.existsSync(fullPath)) {
|
|
6311
7062
|
return c.json(
|
|
6312
7063
|
{
|
|
6313
7064
|
success: false,
|
|
@@ -6316,7 +7067,7 @@ function registerApiRoutes(app, dbConfig) {
|
|
|
6316
7067
|
400
|
|
6317
7068
|
);
|
|
6318
7069
|
}
|
|
6319
|
-
const stats =
|
|
7070
|
+
const stats = fs18.statSync(fullPath);
|
|
6320
7071
|
if (stats.isDirectory()) {
|
|
6321
7072
|
return c.json(
|
|
6322
7073
|
{
|
|
@@ -6435,27 +7186,27 @@ import { serve } from "@hono/node-server";
|
|
|
6435
7186
|
import { Hono as Hono2 } from "hono";
|
|
6436
7187
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
6437
7188
|
import open from "open";
|
|
6438
|
-
import
|
|
6439
|
-
import
|
|
6440
|
-
import { fileURLToPath } from "url";
|
|
7189
|
+
import path19 from "path";
|
|
7190
|
+
import pc38 from "picocolors";
|
|
7191
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6441
7192
|
async function runStudio(dbConfig) {
|
|
6442
7193
|
const app = new Hono2();
|
|
6443
7194
|
registerApiRoutes(app, dbConfig);
|
|
6444
7195
|
const isDev = __dirname.includes("src") || __dirname.includes("studio");
|
|
6445
|
-
const studioDistPath = isDev ?
|
|
6446
|
-
const
|
|
7196
|
+
const studioDistPath = isDev ? path19.resolve(__dirname, "../../dist/studio") : path19.resolve(__dirname, "./studio");
|
|
7197
|
+
const fs19 = await import("fs/promises");
|
|
6447
7198
|
app.use("/*", async (c, next) => {
|
|
6448
7199
|
c.header("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
6449
7200
|
await next();
|
|
6450
7201
|
});
|
|
6451
7202
|
app.use(
|
|
6452
7203
|
"/*",
|
|
6453
|
-
serveStatic({ root:
|
|
7204
|
+
serveStatic({ root: path19.relative(process.cwd(), studioDistPath) })
|
|
6454
7205
|
);
|
|
6455
7206
|
app.get("*", async (c) => {
|
|
6456
|
-
const indexPath =
|
|
7207
|
+
const indexPath = path19.join(studioDistPath, "index.html");
|
|
6457
7208
|
try {
|
|
6458
|
-
const html = await
|
|
7209
|
+
const html = await fs19.readFile(indexPath, "utf-8");
|
|
6459
7210
|
return c.html(html);
|
|
6460
7211
|
} catch (e) {
|
|
6461
7212
|
return c.text(
|
|
@@ -6467,23 +7218,23 @@ async function runStudio(dbConfig) {
|
|
|
6467
7218
|
const defaultPort = process.env.PORT ? parseInt(process.env.PORT, 10) : 51213;
|
|
6468
7219
|
const port = await getAvailablePort(defaultPort);
|
|
6469
7220
|
console.log(
|
|
6470
|
-
|
|
7221
|
+
pc38.cyan(`
|
|
6471
7222
|
Starting Drixio Studio on http://localhost:${port}...`)
|
|
6472
7223
|
);
|
|
6473
7224
|
if (dbConfig.type === "unknown") {
|
|
6474
7225
|
console.log(
|
|
6475
|
-
|
|
7226
|
+
pc38.yellow(
|
|
6476
7227
|
`\u26A0\uFE0F No database detected. Studio started in standalone mode.`
|
|
6477
7228
|
)
|
|
6478
7229
|
);
|
|
6479
7230
|
console.log(
|
|
6480
|
-
|
|
7231
|
+
pc38.dim(
|
|
6481
7232
|
`You can create or connect to a database in the SQL Console.
|
|
6482
7233
|
`
|
|
6483
7234
|
)
|
|
6484
7235
|
);
|
|
6485
7236
|
}
|
|
6486
|
-
console.log(
|
|
7237
|
+
console.log(pc38.dim(`Press Ctrl+C to stop the server.
|
|
6487
7238
|
`));
|
|
6488
7239
|
serve({
|
|
6489
7240
|
fetch: app.fetch,
|
|
@@ -6512,14 +7263,14 @@ var init_studio = __esm({
|
|
|
6512
7263
|
"src/studio/index.ts"() {
|
|
6513
7264
|
"use strict";
|
|
6514
7265
|
init_api();
|
|
6515
|
-
__filename =
|
|
6516
|
-
__dirname =
|
|
7266
|
+
__filename = fileURLToPath2(import.meta.url);
|
|
7267
|
+
__dirname = path19.dirname(__filename);
|
|
6517
7268
|
}
|
|
6518
7269
|
});
|
|
6519
7270
|
|
|
6520
7271
|
// bin/cli.ts
|
|
6521
7272
|
init_logic();
|
|
6522
|
-
import
|
|
7273
|
+
import pc39 from "picocolors";
|
|
6523
7274
|
import { parseArgs } from "util";
|
|
6524
7275
|
|
|
6525
7276
|
// src/commands/query.ts
|
|
@@ -6603,8 +7354,8 @@ async function runQueryCommand(dbConfig, args) {
|
|
|
6603
7354
|
const adapter = createDBAdapter(dbConfig);
|
|
6604
7355
|
let sql = args[0];
|
|
6605
7356
|
if (!sql) {
|
|
6606
|
-
const { input:
|
|
6607
|
-
sql = await
|
|
7357
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
7358
|
+
sql = await input11({
|
|
6608
7359
|
message: "Enter your SQL query:"
|
|
6609
7360
|
});
|
|
6610
7361
|
}
|
|
@@ -6637,8 +7388,8 @@ Query Error: ${e.message}
|
|
|
6637
7388
|
// src/commands/export.ts
|
|
6638
7389
|
init_logic();
|
|
6639
7390
|
import pc3 from "picocolors";
|
|
6640
|
-
import
|
|
6641
|
-
import
|
|
7391
|
+
import fs6 from "fs/promises";
|
|
7392
|
+
import path6 from "path";
|
|
6642
7393
|
async function runExportCommand(dbConfig, args, options) {
|
|
6643
7394
|
if (dbConfig.type === "unknown") {
|
|
6644
7395
|
console.log(
|
|
@@ -6650,7 +7401,7 @@ async function runExportCommand(dbConfig, args, options) {
|
|
|
6650
7401
|
let tableName = args[0];
|
|
6651
7402
|
let format = options.format?.toLowerCase();
|
|
6652
7403
|
const schemaOnly = options["schema-only"];
|
|
6653
|
-
const { select:
|
|
7404
|
+
const { select: select16 } = await import("@inquirer/prompts");
|
|
6654
7405
|
if (!tableName) {
|
|
6655
7406
|
const allTables = await adapter.getTables();
|
|
6656
7407
|
if (allTables.length === 0) {
|
|
@@ -6661,13 +7412,13 @@ async function runExportCommand(dbConfig, args, options) {
|
|
|
6661
7412
|
{ name: "All Tables (*)", value: "*" },
|
|
6662
7413
|
...allTables.map((t) => ({ name: t, value: t }))
|
|
6663
7414
|
];
|
|
6664
|
-
tableName = await
|
|
7415
|
+
tableName = await select16({
|
|
6665
7416
|
message: "Which table do you want to export?",
|
|
6666
7417
|
choices: tableChoices
|
|
6667
7418
|
});
|
|
6668
7419
|
}
|
|
6669
7420
|
if (!format || !["csv", "json"].includes(format)) {
|
|
6670
|
-
format = await
|
|
7421
|
+
format = await select16({
|
|
6671
7422
|
message: "Which format do you want to export?",
|
|
6672
7423
|
choices: [
|
|
6673
7424
|
{ name: "CSV", value: "csv" },
|
|
@@ -6675,8 +7426,8 @@ async function runExportCommand(dbConfig, args, options) {
|
|
|
6675
7426
|
]
|
|
6676
7427
|
});
|
|
6677
7428
|
}
|
|
6678
|
-
const exportDir =
|
|
6679
|
-
await
|
|
7429
|
+
const exportDir = path6.join(process.cwd(), "drixio_exports");
|
|
7430
|
+
await fs6.mkdir(exportDir, { recursive: true });
|
|
6680
7431
|
const tablesToExport = tableName === "*" ? await adapter.getTables() : [tableName];
|
|
6681
7432
|
console.log(pc3.cyan(`
|
|
6682
7433
|
Starting export to ${exportDir}...`));
|
|
@@ -6695,8 +7446,8 @@ Starting export to ${exportDir}...`));
|
|
|
6695
7446
|
const content = exportRes.data;
|
|
6696
7447
|
const suffix = schemaOnly ? "_schema" : "_data";
|
|
6697
7448
|
const ext = format === "json" ? ".json" : ".csv";
|
|
6698
|
-
const fp =
|
|
6699
|
-
await
|
|
7449
|
+
const fp = path6.join(exportDir, `${table}${suffix}${ext}`);
|
|
7450
|
+
await fs6.writeFile(fp, content, "utf-8");
|
|
6700
7451
|
const typeLabel = schemaOnly ? "Schema" : "Data";
|
|
6701
7452
|
console.log(
|
|
6702
7453
|
pc3.green(
|
|
@@ -6715,8 +7466,8 @@ Starting export to ${exportDir}...`));
|
|
|
6715
7466
|
// src/commands/import.ts
|
|
6716
7467
|
init_logic();
|
|
6717
7468
|
import pc4 from "picocolors";
|
|
6718
|
-
import
|
|
6719
|
-
import
|
|
7469
|
+
import fs7 from "fs/promises";
|
|
7470
|
+
import path7 from "path";
|
|
6720
7471
|
async function runImportCommand(dbConfig, args, options) {
|
|
6721
7472
|
if (dbConfig.type === "unknown") {
|
|
6722
7473
|
console.log(
|
|
@@ -6727,15 +7478,15 @@ async function runImportCommand(dbConfig, args, options) {
|
|
|
6727
7478
|
const adapter = createDBAdapter(dbConfig);
|
|
6728
7479
|
let filePath = args[0];
|
|
6729
7480
|
let tableName = options.table;
|
|
6730
|
-
const { input:
|
|
7481
|
+
const { input: input11, select: select16 } = await import("@inquirer/prompts");
|
|
6731
7482
|
if (!filePath) {
|
|
6732
|
-
filePath = await
|
|
7483
|
+
filePath = await input11({
|
|
6733
7484
|
message: "Enter the path to your CSV or JSON file:"
|
|
6734
7485
|
});
|
|
6735
7486
|
}
|
|
6736
|
-
const resolvedPath =
|
|
7487
|
+
const resolvedPath = path7.resolve(process.cwd(), filePath);
|
|
6737
7488
|
try {
|
|
6738
|
-
await
|
|
7489
|
+
await fs7.access(resolvedPath);
|
|
6739
7490
|
} catch {
|
|
6740
7491
|
console.log(pc4.red(`Error: File not found at ${resolvedPath}`));
|
|
6741
7492
|
process.exit(1);
|
|
@@ -6748,14 +7499,14 @@ async function runImportCommand(dbConfig, args, options) {
|
|
|
6748
7499
|
);
|
|
6749
7500
|
process.exit(1);
|
|
6750
7501
|
}
|
|
6751
|
-
tableName = await
|
|
7502
|
+
tableName = await select16({
|
|
6752
7503
|
message: "Which table do you want to import data into?",
|
|
6753
7504
|
choices: allTables.map((t) => ({ name: t, value: t }))
|
|
6754
7505
|
});
|
|
6755
7506
|
}
|
|
6756
7507
|
console.log(pc4.cyan(`
|
|
6757
7508
|
Reading file...`));
|
|
6758
|
-
const fileContent = await
|
|
7509
|
+
const fileContent = await fs7.readFile(resolvedPath, "utf-8");
|
|
6759
7510
|
const isJson = filePath.toLowerCase().endsWith(".json");
|
|
6760
7511
|
const isCsv = filePath.toLowerCase().endsWith(".csv");
|
|
6761
7512
|
if (!isJson && !isCsv) {
|
|
@@ -6808,7 +7559,7 @@ async function runSeedCommand(dbConfig, args) {
|
|
|
6808
7559
|
const adapter = createDBAdapter(dbConfig);
|
|
6809
7560
|
let tableName = args[0];
|
|
6810
7561
|
let countStr = args[1];
|
|
6811
|
-
const { input:
|
|
7562
|
+
const { input: input11, select: select16 } = await import("@inquirer/prompts");
|
|
6812
7563
|
if (!tableName) {
|
|
6813
7564
|
const allTables = await adapter.getTables();
|
|
6814
7565
|
if (allTables.length === 0) {
|
|
@@ -6817,14 +7568,14 @@ async function runSeedCommand(dbConfig, args) {
|
|
|
6817
7568
|
);
|
|
6818
7569
|
process.exit(1);
|
|
6819
7570
|
}
|
|
6820
|
-
tableName = await
|
|
7571
|
+
tableName = await select16({
|
|
6821
7572
|
message: "Which table do you want to seed with realistic fake data?",
|
|
6822
7573
|
choices: allTables.map((t) => ({ name: t, value: t }))
|
|
6823
7574
|
});
|
|
6824
7575
|
}
|
|
6825
7576
|
let count = parseInt(countStr);
|
|
6826
7577
|
if (isNaN(count) || count <= 0) {
|
|
6827
|
-
const res = await
|
|
7578
|
+
const res = await input11({
|
|
6828
7579
|
message: "How many rows to generate?",
|
|
6829
7580
|
default: "50"
|
|
6830
7581
|
});
|
|
@@ -6883,19 +7634,19 @@ async function runTruncateCommand(dbConfig, args) {
|
|
|
6883
7634
|
}
|
|
6884
7635
|
const adapter = createDBAdapter(dbConfig);
|
|
6885
7636
|
let tableName = args[0];
|
|
6886
|
-
const { select:
|
|
7637
|
+
const { select: select16, confirm: confirm8 } = await import("@inquirer/prompts");
|
|
6887
7638
|
if (!tableName) {
|
|
6888
7639
|
const allTables = await adapter.getTables();
|
|
6889
7640
|
if (allTables.length === 0) {
|
|
6890
7641
|
console.log(pc6.yellow("No tables found in the database."));
|
|
6891
7642
|
process.exit(0);
|
|
6892
7643
|
}
|
|
6893
|
-
tableName = await
|
|
7644
|
+
tableName = await select16({
|
|
6894
7645
|
message: "Which table do you want to truncate (empty all data)?",
|
|
6895
7646
|
choices: allTables.map((t) => ({ name: t, value: t }))
|
|
6896
7647
|
});
|
|
6897
7648
|
}
|
|
6898
|
-
const sure = await
|
|
7649
|
+
const sure = await confirm8({
|
|
6899
7650
|
message: `Are you sure you want to TRUNCATE '${tableName}'? This will delete all rows and cannot be undone!`,
|
|
6900
7651
|
default: false
|
|
6901
7652
|
});
|
|
@@ -6921,8 +7672,8 @@ async function runTruncateCommand(dbConfig, args) {
|
|
|
6921
7672
|
// src/commands/exec.ts
|
|
6922
7673
|
init_logic();
|
|
6923
7674
|
import pc7 from "picocolors";
|
|
6924
|
-
import
|
|
6925
|
-
import
|
|
7675
|
+
import fs8 from "fs/promises";
|
|
7676
|
+
import path8 from "path";
|
|
6926
7677
|
async function runExecCommand(dbConfig, args) {
|
|
6927
7678
|
if (dbConfig.type === "unknown") {
|
|
6928
7679
|
console.log(
|
|
@@ -6931,18 +7682,18 @@ async function runExecCommand(dbConfig, args) {
|
|
|
6931
7682
|
process.exit(1);
|
|
6932
7683
|
}
|
|
6933
7684
|
let filePath = args[0];
|
|
6934
|
-
const { input:
|
|
7685
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
6935
7686
|
if (!filePath) {
|
|
6936
|
-
filePath = await
|
|
7687
|
+
filePath = await input11({ message: "Enter the path to your .sql file:" });
|
|
6937
7688
|
}
|
|
6938
|
-
const resolvedPath =
|
|
7689
|
+
const resolvedPath = path8.resolve(process.cwd(), filePath);
|
|
6939
7690
|
try {
|
|
6940
|
-
await
|
|
7691
|
+
await fs8.access(resolvedPath);
|
|
6941
7692
|
} catch {
|
|
6942
7693
|
console.log(pc7.red(`Error: File not found at ${resolvedPath}`));
|
|
6943
7694
|
process.exit(1);
|
|
6944
7695
|
}
|
|
6945
|
-
const sqlContent = await
|
|
7696
|
+
const sqlContent = await fs8.readFile(resolvedPath, "utf-8");
|
|
6946
7697
|
if (!sqlContent.trim()) {
|
|
6947
7698
|
console.log(pc7.yellow("File is empty."));
|
|
6948
7699
|
process.exit(0);
|
|
@@ -7021,8 +7772,8 @@ Backup Error: ${e.message}
|
|
|
7021
7772
|
// src/commands/restore.ts
|
|
7022
7773
|
init_logic();
|
|
7023
7774
|
import pc9 from "picocolors";
|
|
7024
|
-
import
|
|
7025
|
-
import
|
|
7775
|
+
import fs9 from "fs/promises";
|
|
7776
|
+
import path9 from "path";
|
|
7026
7777
|
async function runRestoreCommand(dbConfig, args, options = {}) {
|
|
7027
7778
|
if (dbConfig.type === "unknown") {
|
|
7028
7779
|
console.log(
|
|
@@ -7031,10 +7782,10 @@ async function runRestoreCommand(dbConfig, args, options = {}) {
|
|
|
7031
7782
|
process.exit(1);
|
|
7032
7783
|
}
|
|
7033
7784
|
let targetPath = args[0];
|
|
7034
|
-
const { input:
|
|
7785
|
+
const { input: input11, select: select16, confirm: confirm8 } = await import("@inquirer/prompts");
|
|
7035
7786
|
if (!targetPath) {
|
|
7036
7787
|
try {
|
|
7037
|
-
const entries = await
|
|
7788
|
+
const entries = await fs9.readdir(process.cwd(), {
|
|
7038
7789
|
withFileTypes: true
|
|
7039
7790
|
});
|
|
7040
7791
|
const candidates = [];
|
|
@@ -7056,24 +7807,24 @@ async function runRestoreCommand(dbConfig, args, options = {}) {
|
|
|
7056
7807
|
name: "\u270F\uFE0F Enter a custom path manually...",
|
|
7057
7808
|
value: "__custom__"
|
|
7058
7809
|
});
|
|
7059
|
-
const choice = await
|
|
7810
|
+
const choice = await select16({
|
|
7060
7811
|
message: "Select a backup directory or file to restore:",
|
|
7061
7812
|
choices: candidates
|
|
7062
7813
|
});
|
|
7063
7814
|
if (choice === "__custom__") {
|
|
7064
|
-
targetPath = await
|
|
7815
|
+
targetPath = await input11({
|
|
7065
7816
|
message: "Enter path to backup directory, .sql, or .json file:"
|
|
7066
7817
|
});
|
|
7067
7818
|
} else {
|
|
7068
7819
|
targetPath = choice;
|
|
7069
7820
|
}
|
|
7070
7821
|
} else {
|
|
7071
|
-
targetPath = await
|
|
7822
|
+
targetPath = await input11({
|
|
7072
7823
|
message: "Enter path to backup directory, .sql, or .json file:"
|
|
7073
7824
|
});
|
|
7074
7825
|
}
|
|
7075
7826
|
} catch {
|
|
7076
|
-
targetPath = await
|
|
7827
|
+
targetPath = await input11({
|
|
7077
7828
|
message: "Enter path to backup directory, .sql, or .json file:"
|
|
7078
7829
|
});
|
|
7079
7830
|
}
|
|
@@ -7082,9 +7833,9 @@ async function runRestoreCommand(dbConfig, args, options = {}) {
|
|
|
7082
7833
|
console.log(pc9.yellow("No restore source specified. Aborting."));
|
|
7083
7834
|
process.exit(0);
|
|
7084
7835
|
}
|
|
7085
|
-
const resolvedPath =
|
|
7836
|
+
const resolvedPath = path9.resolve(process.cwd(), targetPath.trim());
|
|
7086
7837
|
try {
|
|
7087
|
-
await
|
|
7838
|
+
await fs9.access(resolvedPath);
|
|
7088
7839
|
} catch {
|
|
7089
7840
|
console.log(pc9.red(`Error: Backup path not found: ${resolvedPath}`));
|
|
7090
7841
|
process.exit(1);
|
|
@@ -7100,7 +7851,7 @@ async function runRestoreCommand(dbConfig, args, options = {}) {
|
|
|
7100
7851
|
console.log(pc9.dim(`Database: ${dbConfig.type} (${dbConfig.targetUrl})`));
|
|
7101
7852
|
console.log(pc9.dim(`Source: ${resolvedPath}
|
|
7102
7853
|
`));
|
|
7103
|
-
const proceed = await
|
|
7854
|
+
const proceed = await confirm8({
|
|
7104
7855
|
message: "Are you sure you want to proceed with the database restore?",
|
|
7105
7856
|
default: false
|
|
7106
7857
|
});
|
|
@@ -7147,8 +7898,8 @@ Starting database restore from: ${resolvedPath}...`));
|
|
|
7147
7898
|
// src/commands/diagram.ts
|
|
7148
7899
|
init_logic();
|
|
7149
7900
|
import pc10 from "picocolors";
|
|
7150
|
-
import
|
|
7151
|
-
import
|
|
7901
|
+
import fs10 from "fs/promises";
|
|
7902
|
+
import path10 from "path";
|
|
7152
7903
|
async function runDiagramCommand(dbConfig) {
|
|
7153
7904
|
if (dbConfig.type === "unknown") {
|
|
7154
7905
|
console.log(
|
|
@@ -7186,8 +7937,8 @@ You can paste this Mermaid code directly into [Draw.io](https://app.diagrams.net
|
|
|
7186
7937
|
${mermaidCode}
|
|
7187
7938
|
\`\`\`
|
|
7188
7939
|
`;
|
|
7189
|
-
const outPath =
|
|
7190
|
-
await
|
|
7940
|
+
const outPath = path10.resolve(process.cwd(), "drixio_schema.md");
|
|
7941
|
+
await fs10.writeFile(outPath, markdownOutput.trim(), "utf-8");
|
|
7191
7942
|
console.log(pc10.green(`
|
|
7192
7943
|
\u2714 Diagram generated successfully!`));
|
|
7193
7944
|
console.log(pc10.white(`Output saved to: ${pc10.bold(outPath)}`));
|
|
@@ -7208,8 +7959,8 @@ ${mermaidCode}
|
|
|
7208
7959
|
// src/commands/generateTypes.ts
|
|
7209
7960
|
init_logic();
|
|
7210
7961
|
import pc11 from "picocolors";
|
|
7211
|
-
import
|
|
7212
|
-
import
|
|
7962
|
+
import fs11 from "fs/promises";
|
|
7963
|
+
import path11 from "path";
|
|
7213
7964
|
async function runGenerateTypesCommand(dbConfig) {
|
|
7214
7965
|
if (dbConfig.type === "unknown") {
|
|
7215
7966
|
console.log(
|
|
@@ -7233,8 +7984,8 @@ Scanning database to generate TypeScript interfaces...`)
|
|
|
7233
7984
|
process.exit(0);
|
|
7234
7985
|
}
|
|
7235
7986
|
const tsCode = generateTypeScriptDefinitions(tableInfos, dbConfig.type);
|
|
7236
|
-
const outPath =
|
|
7237
|
-
await
|
|
7987
|
+
const outPath = path11.resolve(process.cwd(), "drixio-types.d.ts");
|
|
7988
|
+
await fs11.writeFile(outPath, tsCode, "utf-8");
|
|
7238
7989
|
console.log(pc11.green(`\u2714 TypeScript interfaces generated successfully!`));
|
|
7239
7990
|
console.log(pc11.white(`Output saved to: ${pc11.bold(outPath)}`));
|
|
7240
7991
|
} catch (e) {
|
|
@@ -7249,8 +8000,8 @@ Scanning database to generate TypeScript interfaces...`)
|
|
|
7249
8000
|
// src/commands/generateOrm.ts
|
|
7250
8001
|
init_logic();
|
|
7251
8002
|
import pc12 from "picocolors";
|
|
7252
|
-
import
|
|
7253
|
-
import
|
|
8003
|
+
import fs12 from "fs/promises";
|
|
8004
|
+
import path12 from "path";
|
|
7254
8005
|
async function runGenerateOrmCommand(dbConfig, options = {}) {
|
|
7255
8006
|
if (dbConfig.type === "unknown") {
|
|
7256
8007
|
console.log(
|
|
@@ -7306,11 +8057,11 @@ Scanning database to generate ${target === "prisma" ? "Prisma" : "Drizzle"} sche
|
|
|
7306
8057
|
if (options.print) {
|
|
7307
8058
|
console.log("\n" + generatedCode);
|
|
7308
8059
|
} else {
|
|
7309
|
-
const outPath =
|
|
8060
|
+
const outPath = path12.resolve(
|
|
7310
8061
|
process.cwd(),
|
|
7311
8062
|
options.out || defaultFileName
|
|
7312
8063
|
);
|
|
7313
|
-
await
|
|
8064
|
+
await fs12.writeFile(outPath, generatedCode, "utf-8");
|
|
7314
8065
|
console.log(
|
|
7315
8066
|
pc12.green(
|
|
7316
8067
|
`\u2714 ${target === "prisma" ? "Prisma" : "Drizzle"} schema generated successfully!`
|
|
@@ -7331,10 +8082,10 @@ Scanning database to generate ${target === "prisma" ? "Prisma" : "Drizzle"} sche
|
|
|
7331
8082
|
init_logic();
|
|
7332
8083
|
import pc13 from "picocolors";
|
|
7333
8084
|
async function runInitCommand(args) {
|
|
7334
|
-
const { select:
|
|
8085
|
+
const { select: select16, input: input11, password } = await import("@inquirer/prompts");
|
|
7335
8086
|
let dialect = args[0];
|
|
7336
8087
|
if (!dialect || !["sqlite", "mysql", "postgres"].includes(dialect.toLowerCase())) {
|
|
7337
|
-
dialect = await
|
|
8088
|
+
dialect = await select16({
|
|
7338
8089
|
message: "Which database do you want to initialize locally?",
|
|
7339
8090
|
choices: [
|
|
7340
8091
|
{ name: "SQLite (Local File)", value: "sqlite" },
|
|
@@ -7380,15 +8131,15 @@ Initializing a local ${dialect} database...`));
|
|
|
7380
8131
|
"Please provide credentials for your local server (e.g. running via XAMPP, Homebrew, etc.)"
|
|
7381
8132
|
)
|
|
7382
8133
|
);
|
|
7383
|
-
const host = await
|
|
8134
|
+
const host = await input11({
|
|
7384
8135
|
message: "Server Host:",
|
|
7385
8136
|
default: "localhost"
|
|
7386
8137
|
});
|
|
7387
|
-
const port = await
|
|
8138
|
+
const port = await input11({
|
|
7388
8139
|
message: "Server Port:",
|
|
7389
8140
|
default: dialect === "mysql" ? "3306" : "5432"
|
|
7390
8141
|
});
|
|
7391
|
-
const user = await
|
|
8142
|
+
const user = await input11({
|
|
7392
8143
|
message: "Username:",
|
|
7393
8144
|
default: dialect === "mysql" ? "root" : "postgres"
|
|
7394
8145
|
});
|
|
@@ -7397,7 +8148,7 @@ Initializing a local ${dialect} database...`));
|
|
|
7397
8148
|
});
|
|
7398
8149
|
let dbName = args[1];
|
|
7399
8150
|
if (!dbName) {
|
|
7400
|
-
dbName = await
|
|
8151
|
+
dbName = await input11({
|
|
7401
8152
|
message: "New Database Name (e.g. my_project):"
|
|
7402
8153
|
});
|
|
7403
8154
|
}
|
|
@@ -7489,10 +8240,10 @@ Could not connect to the local ${dialect} server on ${host}:${port}.`
|
|
|
7489
8240
|
init_logic();
|
|
7490
8241
|
import pc14 from "picocolors";
|
|
7491
8242
|
async function runDropDbCommand(args) {
|
|
7492
|
-
const { select:
|
|
8243
|
+
const { select: select16, input: input11, password, confirm: confirm8 } = await import("@inquirer/prompts");
|
|
7493
8244
|
let dialect = args[0];
|
|
7494
8245
|
if (!dialect || !["sqlite", "mysql", "postgres"].includes(dialect.toLowerCase())) {
|
|
7495
|
-
dialect = await
|
|
8246
|
+
dialect = await select16({
|
|
7496
8247
|
message: "Which database type do you want to drop?",
|
|
7497
8248
|
choices: [
|
|
7498
8249
|
{ name: "SQLite (Local File)", value: "sqlite" },
|
|
@@ -7505,12 +8256,12 @@ async function runDropDbCommand(args) {
|
|
|
7505
8256
|
let dbName = args[1];
|
|
7506
8257
|
if (dialect === "sqlite") {
|
|
7507
8258
|
if (!dbName) {
|
|
7508
|
-
dbName = await
|
|
8259
|
+
dbName = await input11({
|
|
7509
8260
|
message: "Enter the SQLite filename to delete (e.g. database.sqlite):",
|
|
7510
8261
|
default: "database.sqlite"
|
|
7511
8262
|
});
|
|
7512
8263
|
}
|
|
7513
|
-
const sure = await
|
|
8264
|
+
const sure = await confirm8({
|
|
7514
8265
|
message: `Are you absolutely sure you want to delete ${dbName}? This cannot be undone!`,
|
|
7515
8266
|
default: false
|
|
7516
8267
|
});
|
|
@@ -7535,15 +8286,15 @@ async function runDropDbCommand(args) {
|
|
|
7535
8286
|
`Please provide credentials for your local ${dialect} server to drop a database.`
|
|
7536
8287
|
)
|
|
7537
8288
|
);
|
|
7538
|
-
const host = await
|
|
8289
|
+
const host = await input11({
|
|
7539
8290
|
message: "Server Host:",
|
|
7540
8291
|
default: "localhost"
|
|
7541
8292
|
});
|
|
7542
|
-
const port = await
|
|
8293
|
+
const port = await input11({
|
|
7543
8294
|
message: "Server Port:",
|
|
7544
8295
|
default: dialect === "mysql" ? "3306" : "5432"
|
|
7545
8296
|
});
|
|
7546
|
-
const user = await
|
|
8297
|
+
const user = await input11({
|
|
7547
8298
|
message: "Username:",
|
|
7548
8299
|
default: dialect === "mysql" ? "root" : "postgres"
|
|
7549
8300
|
});
|
|
@@ -7551,11 +8302,11 @@ async function runDropDbCommand(args) {
|
|
|
7551
8302
|
message: "Password (leave empty if none):"
|
|
7552
8303
|
});
|
|
7553
8304
|
if (!dbName) {
|
|
7554
|
-
dbName = await
|
|
8305
|
+
dbName = await input11({
|
|
7555
8306
|
message: "Which Database Name do you want to DROP?"
|
|
7556
8307
|
});
|
|
7557
8308
|
}
|
|
7558
|
-
const sure = await
|
|
8309
|
+
const sure = await confirm8({
|
|
7559
8310
|
message: `Are you absolutely sure you want to DROP DATABASE '${dbName}' from ${host}? All data will be lost!`,
|
|
7560
8311
|
default: false
|
|
7561
8312
|
});
|
|
@@ -7676,8 +8427,8 @@ async function runDescribeCommand(dbConfig, args, options = {}) {
|
|
|
7676
8427
|
if (tables.length === 1) {
|
|
7677
8428
|
tableName = tables[0];
|
|
7678
8429
|
} else {
|
|
7679
|
-
const { select:
|
|
7680
|
-
tableName = await
|
|
8430
|
+
const { select: select16 } = await import("@inquirer/prompts");
|
|
8431
|
+
tableName = await select16({
|
|
7681
8432
|
message: "Select a table to describe:",
|
|
7682
8433
|
choices: tables.map((t) => ({ name: t, value: t }))
|
|
7683
8434
|
});
|
|
@@ -7766,9 +8517,9 @@ Failed to describe table: ${e.message}
|
|
|
7766
8517
|
// src/commands/diff.ts
|
|
7767
8518
|
init_logic();
|
|
7768
8519
|
import pc17 from "picocolors";
|
|
7769
|
-
import
|
|
8520
|
+
import fs13 from "fs/promises";
|
|
7770
8521
|
import { existsSync as existsSync2 } from "fs";
|
|
7771
|
-
import
|
|
8522
|
+
import path13 from "path";
|
|
7772
8523
|
async function runDiffCommand(dbConfig, args, options = {}) {
|
|
7773
8524
|
if (dbConfig.type === "unknown") {
|
|
7774
8525
|
console.log(
|
|
@@ -7789,7 +8540,7 @@ Capturing schema snapshot for ${dbConfig.type.toUpperCase()} database...`
|
|
|
7789
8540
|
const snapshotRes = await createSchemaSnapshot(
|
|
7790
8541
|
adapter,
|
|
7791
8542
|
dbConfig.type,
|
|
7792
|
-
|
|
8543
|
+
path13.basename(outPath, ".json")
|
|
7793
8544
|
);
|
|
7794
8545
|
if (!snapshotRes.success) {
|
|
7795
8546
|
console.log(
|
|
@@ -7797,9 +8548,9 @@ Capturing schema snapshot for ${dbConfig.type.toUpperCase()} database...`
|
|
|
7797
8548
|
);
|
|
7798
8549
|
process.exit(1);
|
|
7799
8550
|
}
|
|
7800
|
-
const resolvedPath =
|
|
7801
|
-
await
|
|
7802
|
-
await
|
|
8551
|
+
const resolvedPath = path13.resolve(process.cwd(), outPath);
|
|
8552
|
+
await fs13.mkdir(path13.dirname(resolvedPath), { recursive: true });
|
|
8553
|
+
await fs13.writeFile(
|
|
7803
8554
|
resolvedPath,
|
|
7804
8555
|
JSON.stringify(snapshotRes.data, null, 2),
|
|
7805
8556
|
"utf-8"
|
|
@@ -7816,9 +8567,9 @@ Capturing schema snapshot for ${dbConfig.type.toUpperCase()} database...`
|
|
|
7816
8567
|
}
|
|
7817
8568
|
let targetArg = args[0];
|
|
7818
8569
|
if (!targetArg) {
|
|
7819
|
-
if (existsSync2(
|
|
8570
|
+
if (existsSync2(path13.resolve(process.cwd(), "schema.json"))) {
|
|
7820
8571
|
targetArg = "schema.json";
|
|
7821
|
-
} else if (existsSync2(
|
|
8572
|
+
} else if (existsSync2(path13.resolve(process.cwd(), ".drixio/schema.json"))) {
|
|
7822
8573
|
targetArg = ".drixio/schema.json";
|
|
7823
8574
|
} else {
|
|
7824
8575
|
console.log(
|
|
@@ -7873,7 +8624,7 @@ Connecting to target database and computing schema diff...`
|
|
|
7873
8624
|
});
|
|
7874
8625
|
}
|
|
7875
8626
|
} else {
|
|
7876
|
-
const filePath =
|
|
8627
|
+
const filePath = path13.resolve(process.cwd(), targetArg);
|
|
7877
8628
|
if (!existsSync2(filePath)) {
|
|
7878
8629
|
console.log(
|
|
7879
8630
|
pc17.red(`\u2718 Target snapshot file not found: ${targetArg}`)
|
|
@@ -7886,7 +8637,7 @@ Connecting to target database and computing schema diff...`
|
|
|
7886
8637
|
Comparing current database with snapshot: ${targetArg}...`
|
|
7887
8638
|
)
|
|
7888
8639
|
);
|
|
7889
|
-
const content = await
|
|
8640
|
+
const content = await fs13.readFile(filePath, "utf-8");
|
|
7890
8641
|
let snapshot;
|
|
7891
8642
|
try {
|
|
7892
8643
|
snapshot = JSON.parse(content);
|
|
@@ -7901,7 +8652,7 @@ Comparing current database with snapshot: ${targetArg}...`
|
|
|
7901
8652
|
snapshot,
|
|
7902
8653
|
dbConfig.type,
|
|
7903
8654
|
"Current Database",
|
|
7904
|
-
`Snapshot (${
|
|
8655
|
+
`Snapshot (${path13.basename(targetArg)})`
|
|
7905
8656
|
);
|
|
7906
8657
|
if (!diffRes.success) {
|
|
7907
8658
|
console.log(pc17.red(`\u2718 Diff failed: ${diffRes.error}`));
|
|
@@ -7916,9 +8667,9 @@ Comparing current database with snapshot: ${targetArg}...`
|
|
|
7916
8667
|
printDiffReport(diffResult, options.reverse);
|
|
7917
8668
|
const targetSql = options.reverse ? diffResult.rollbackSql : diffResult.migrationSql;
|
|
7918
8669
|
if (options.out) {
|
|
7919
|
-
const outResolved =
|
|
7920
|
-
await
|
|
7921
|
-
await
|
|
8670
|
+
const outResolved = path13.resolve(process.cwd(), options.out);
|
|
8671
|
+
await fs13.mkdir(path13.dirname(outResolved), { recursive: true });
|
|
8672
|
+
await fs13.writeFile(outResolved, targetSql, "utf-8");
|
|
7922
8673
|
console.log(
|
|
7923
8674
|
pc17.green(`\u2714 Migration SQL written to: ${pc17.bold(options.out)}`)
|
|
7924
8675
|
);
|
|
@@ -7934,8 +8685,8 @@ Nothing to apply. Schema is already in sync.`)
|
|
|
7934
8685
|
const skipConfirm = options.force || options.y;
|
|
7935
8686
|
let proceed = skipConfirm;
|
|
7936
8687
|
if (!proceed) {
|
|
7937
|
-
const { confirm:
|
|
7938
|
-
proceed = await
|
|
8688
|
+
const { confirm: confirm8 } = await import("@inquirer/prompts");
|
|
8689
|
+
proceed = await confirm8({
|
|
7939
8690
|
message: `Apply this ${options.reverse ? "rollback" : "migration"} to "${dbConfig.type.toUpperCase()}" database?`,
|
|
7940
8691
|
default: false
|
|
7941
8692
|
});
|
|
@@ -8107,8 +8858,8 @@ async function runRunCommand(dbConfig, args, _options) {
|
|
|
8107
8858
|
const targetIdent = args[0];
|
|
8108
8859
|
const paramArgs = args.slice(1);
|
|
8109
8860
|
if (!targetIdent) {
|
|
8110
|
-
const { select:
|
|
8111
|
-
const selectedId = await
|
|
8861
|
+
const { select: select16 } = await import("@inquirer/prompts");
|
|
8862
|
+
const selectedId = await select16({
|
|
8112
8863
|
message: "Select a saved query template to run:",
|
|
8113
8864
|
choices: snippets.map((s) => ({
|
|
8114
8865
|
name: `${s.title} ${pc18.dim(`(${s.id})`)}`,
|
|
@@ -8145,10 +8896,10 @@ async function runRunCommand(dbConfig, args, _options) {
|
|
|
8145
8896
|
}
|
|
8146
8897
|
}
|
|
8147
8898
|
if (requiredParams.length > 0) {
|
|
8148
|
-
const { input:
|
|
8899
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
8149
8900
|
for (const param of requiredParams) {
|
|
8150
8901
|
if (providedParams[param] === void 0) {
|
|
8151
|
-
const val = await
|
|
8902
|
+
const val = await input11({
|
|
8152
8903
|
message: `Enter value for :${param}:`,
|
|
8153
8904
|
validate: (v) => v.trim() !== "" ? true : `:${param} cannot be empty`
|
|
8154
8905
|
});
|
|
@@ -8270,7 +9021,7 @@ async function runQuickCommand(command, args, options, dbConfig) {
|
|
|
8270
9021
|
// src/tui/index.ts
|
|
8271
9022
|
init_logo();
|
|
8272
9023
|
init_logic();
|
|
8273
|
-
import
|
|
9024
|
+
import pc37 from "picocolors";
|
|
8274
9025
|
|
|
8275
9026
|
// src/tui/views/editor.ts
|
|
8276
9027
|
init_logic();
|
|
@@ -8302,8 +9053,8 @@ var selectTable = async (tableChoices) => await select({
|
|
|
8302
9053
|
init_logic();
|
|
8303
9054
|
import { input, select as select2 } from "@inquirer/prompts";
|
|
8304
9055
|
import pc21 from "picocolors";
|
|
8305
|
-
import
|
|
8306
|
-
import
|
|
9056
|
+
import fs14 from "fs/promises";
|
|
9057
|
+
import path14 from "path";
|
|
8307
9058
|
async function runBeginnerAdd(adapter, dbType, tableName, columns) {
|
|
8308
9059
|
console.log(pc21.cyan(`
|
|
8309
9060
|
--- Add Data to [${tableName}] ---`));
|
|
@@ -8423,10 +9174,10 @@ async function runExpertMode(adapter) {
|
|
|
8423
9174
|
message: "Enter the path to your .md or .sql file:"
|
|
8424
9175
|
});
|
|
8425
9176
|
if (filePath && filePath.trim()) {
|
|
8426
|
-
const absolutePath =
|
|
9177
|
+
const absolutePath = path14.resolve(process.cwd(), filePath.trim());
|
|
8427
9178
|
let fileContent = "";
|
|
8428
9179
|
try {
|
|
8429
|
-
fileContent = await
|
|
9180
|
+
fileContent = await fs14.readFile(absolutePath, "utf-8");
|
|
8430
9181
|
} catch (err2) {
|
|
8431
9182
|
console.log(pc21.red(`
|
|
8432
9183
|
x Failed to read file: ${err2.message}`));
|
|
@@ -8543,8 +9294,8 @@ async function viewTables(dbConfig) {
|
|
|
8543
9294
|
Error fetching data: ${e.message}
|
|
8544
9295
|
`));
|
|
8545
9296
|
currentWhere = "";
|
|
8546
|
-
const { input:
|
|
8547
|
-
await
|
|
9297
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
9298
|
+
await input11({ message: "Click Enter to continue..." });
|
|
8548
9299
|
continue;
|
|
8549
9300
|
}
|
|
8550
9301
|
const rows = data.rows;
|
|
@@ -8613,8 +9364,8 @@ Error fetching data: ${e.message}
|
|
|
8613
9364
|
continue;
|
|
8614
9365
|
}
|
|
8615
9366
|
if (action === "search") {
|
|
8616
|
-
const { input:
|
|
8617
|
-
const searchInput = await
|
|
9367
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
9368
|
+
const searchInput = await input11({
|
|
8618
9369
|
message: "Enter Search (e.g. `age > 18` or `John` for fuzzy search):"
|
|
8619
9370
|
});
|
|
8620
9371
|
currentWhere = buildSearchWhereClause(
|
|
@@ -8638,18 +9389,18 @@ Error fetching data: ${e.message}
|
|
|
8638
9389
|
console.log(pc22.red(`
|
|
8639
9390
|
Export Error: ${exportRes.error}`));
|
|
8640
9391
|
} else {
|
|
8641
|
-
const
|
|
8642
|
-
const
|
|
8643
|
-
const exportDir =
|
|
9392
|
+
const fs19 = await import("fs/promises");
|
|
9393
|
+
const path20 = await import("path");
|
|
9394
|
+
const exportDir = path20.join(
|
|
8644
9395
|
process.cwd(),
|
|
8645
9396
|
"drixio_exports"
|
|
8646
9397
|
);
|
|
8647
|
-
await
|
|
8648
|
-
const fp =
|
|
9398
|
+
await fs19.mkdir(exportDir, { recursive: true });
|
|
9399
|
+
const fp = path20.join(
|
|
8649
9400
|
exportDir,
|
|
8650
9401
|
`${selectedTable}.${format}`
|
|
8651
9402
|
);
|
|
8652
|
-
await
|
|
9403
|
+
await fs19.writeFile(fp, exportRes.data, "utf-8");
|
|
8653
9404
|
console.log(pc22.green(`
|
|
8654
9405
|
\u2714 Exported to ${fp}`));
|
|
8655
9406
|
}
|
|
@@ -8657,8 +9408,8 @@ Export Error: ${exportRes.error}`));
|
|
|
8657
9408
|
console.log(pc22.red(`
|
|
8658
9409
|
Export Error: ${e.message}`));
|
|
8659
9410
|
}
|
|
8660
|
-
const { input:
|
|
8661
|
-
await
|
|
9411
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
9412
|
+
await input11({ message: "Click Enter to continue..." });
|
|
8662
9413
|
continue;
|
|
8663
9414
|
}
|
|
8664
9415
|
const mode = await select3({
|
|
@@ -8720,8 +9471,8 @@ x Error: ${error.message}`));
|
|
|
8720
9471
|
await adapter.close();
|
|
8721
9472
|
}
|
|
8722
9473
|
async function waitForEnter() {
|
|
8723
|
-
const { input:
|
|
8724
|
-
await
|
|
9474
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
9475
|
+
await input11({
|
|
8725
9476
|
message: "Press Enter to continue..."
|
|
8726
9477
|
});
|
|
8727
9478
|
}
|
|
@@ -8837,6 +9588,24 @@ var selectAction = async (dbConfig) => await select5({
|
|
|
8837
9588
|
description: "Create new tables, or modify/drop existing tables.",
|
|
8838
9589
|
disabled: dbConfig.type === "unknown"
|
|
8839
9590
|
},
|
|
9591
|
+
{
|
|
9592
|
+
name: "\u26A1 ORM & Type Generator",
|
|
9593
|
+
value: "orm",
|
|
9594
|
+
description: "Generate Prisma Schema, Drizzle models, or TypeScript definitions.",
|
|
9595
|
+
disabled: dbConfig.type === "unknown"
|
|
9596
|
+
},
|
|
9597
|
+
{
|
|
9598
|
+
name: "\u{1F4D1} SQL Snippets & Templates",
|
|
9599
|
+
value: "snippets",
|
|
9600
|
+
description: "Run parameterized diagnostic queries and high-frequency templates.",
|
|
9601
|
+
disabled: dbConfig.type === "unknown"
|
|
9602
|
+
},
|
|
9603
|
+
{
|
|
9604
|
+
name: "\u{1F504} Schema Diff & Migrations",
|
|
9605
|
+
value: "diff",
|
|
9606
|
+
description: "Compare database schemas with snapshots and generate migration SQL.",
|
|
9607
|
+
disabled: dbConfig.type === "unknown"
|
|
9608
|
+
},
|
|
8840
9609
|
new Separator2(),
|
|
8841
9610
|
{
|
|
8842
9611
|
name: dbConfig.type === "unknown" ? " Setup Connection" : " Connection Settings",
|
|
@@ -8858,7 +9627,7 @@ async function runRepl(dbConfig) {
|
|
|
8858
9627
|
if (dbConfig.type === "unknown") return;
|
|
8859
9628
|
const dbAdapter = createDBAdapter(dbConfig);
|
|
8860
9629
|
let running = true;
|
|
8861
|
-
const { input:
|
|
9630
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
8862
9631
|
console.clear();
|
|
8863
9632
|
console.log(
|
|
8864
9633
|
pc25.cyan(
|
|
@@ -8889,7 +9658,7 @@ async function runRepl(dbConfig) {
|
|
|
8889
9658
|
);
|
|
8890
9659
|
while (running) {
|
|
8891
9660
|
try {
|
|
8892
|
-
const queryStr = await
|
|
9661
|
+
const queryStr = await input11({
|
|
8893
9662
|
message: pc25.green(`${dbConfig.type}>`)
|
|
8894
9663
|
});
|
|
8895
9664
|
const sql = queryStr.trim();
|
|
@@ -8935,7 +9704,7 @@ async function runTui(initialConfig, customUrl) {
|
|
|
8935
9704
|
case "editor":
|
|
8936
9705
|
if (dbConfig.type === "unknown") {
|
|
8937
9706
|
console.log(
|
|
8938
|
-
|
|
9707
|
+
pc37.yellow(
|
|
8939
9708
|
`
|
|
8940
9709
|
No database connection found. Please setup database first.`
|
|
8941
9710
|
)
|
|
@@ -8952,6 +9721,24 @@ No database connection found. Please setup database first.`
|
|
|
8952
9721
|
case "repl":
|
|
8953
9722
|
await runRepl(dbConfig);
|
|
8954
9723
|
break;
|
|
9724
|
+
case "orm": {
|
|
9725
|
+
const { runOrmWizard: runOrmWizard2 } = await Promise.resolve().then(() => (init_ormWizard(), ormWizard_exports));
|
|
9726
|
+
await runOrmWizard2(dbConfig);
|
|
9727
|
+
await waitForEnter4();
|
|
9728
|
+
break;
|
|
9729
|
+
}
|
|
9730
|
+
case "snippets": {
|
|
9731
|
+
const { runSnippetsWizard: runSnippetsWizard2 } = await Promise.resolve().then(() => (init_snippetsWizard(), snippetsWizard_exports));
|
|
9732
|
+
await runSnippetsWizard2(dbConfig);
|
|
9733
|
+
await waitForEnter4();
|
|
9734
|
+
break;
|
|
9735
|
+
}
|
|
9736
|
+
case "diff": {
|
|
9737
|
+
const { runDiffWizard: runDiffWizard2 } = await Promise.resolve().then(() => (init_diffWizard(), diffWizard_exports));
|
|
9738
|
+
await runDiffWizard2(dbConfig);
|
|
9739
|
+
await waitForEnter4();
|
|
9740
|
+
break;
|
|
9741
|
+
}
|
|
8955
9742
|
case "setup":
|
|
8956
9743
|
case "re-configure":
|
|
8957
9744
|
dbConfig = await runSetup(dbConfig);
|
|
@@ -8959,32 +9746,19 @@ No database connection found. Please setup database first.`
|
|
|
8959
9746
|
break;
|
|
8960
9747
|
case "exit":
|
|
8961
9748
|
running = false;
|
|
8962
|
-
console.log(
|
|
9749
|
+
console.log(pc37.dim("\nThanks for using Drixio. Goodbye!"));
|
|
8963
9750
|
break;
|
|
8964
9751
|
}
|
|
8965
9752
|
}
|
|
8966
9753
|
async function waitForEnter4() {
|
|
8967
|
-
const { input:
|
|
8968
|
-
await
|
|
9754
|
+
const { input: input11 } = await import("@inquirer/prompts");
|
|
9755
|
+
await input11({
|
|
8969
9756
|
message: "Click Enter to continue..."
|
|
8970
9757
|
});
|
|
8971
9758
|
}
|
|
8972
9759
|
}
|
|
8973
9760
|
|
|
8974
9761
|
// bin/cli.ts
|
|
8975
|
-
import { readFileSync } from "fs";
|
|
8976
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8977
|
-
import { dirname, join } from "path";
|
|
8978
|
-
function getVersion() {
|
|
8979
|
-
try {
|
|
8980
|
-
const __dirname2 = dirname(fileURLToPath2(import.meta.url));
|
|
8981
|
-
const pkgPath = join(__dirname2, "../package.json");
|
|
8982
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
8983
|
-
return pkg.version || "1.1.9";
|
|
8984
|
-
} catch {
|
|
8985
|
-
return "1.1.9";
|
|
8986
|
-
}
|
|
8987
|
-
}
|
|
8988
9762
|
async function main() {
|
|
8989
9763
|
const args = process.argv.slice(2);
|
|
8990
9764
|
let customUrl;
|
|
@@ -9012,80 +9786,80 @@ async function main() {
|
|
|
9012
9786
|
allowPositionals: true
|
|
9013
9787
|
});
|
|
9014
9788
|
if (values.version) {
|
|
9015
|
-
console.log(`drixio v${
|
|
9789
|
+
console.log(`drixio v${getDrixioVersion()}`);
|
|
9016
9790
|
process.exit(0);
|
|
9017
9791
|
}
|
|
9018
9792
|
if (values.help) {
|
|
9019
|
-
console.log(
|
|
9793
|
+
console.log(pc39.cyan(`
|
|
9020
9794
|
Drixio - Modern Database Manager
|
|
9021
9795
|
`));
|
|
9022
|
-
console.log(`${
|
|
9796
|
+
console.log(`${pc39.bold("Usage:")} npx drixio [command] [options]
|
|
9023
9797
|
`);
|
|
9024
|
-
console.log(`${
|
|
9798
|
+
console.log(`${pc39.bold("Tiers & Interfaces:")}`);
|
|
9025
9799
|
console.log(
|
|
9026
|
-
` Interactive TUI: ${
|
|
9800
|
+
` Interactive TUI: ${pc39.green("npx drixio")} (Terminal UI with beginner wizards)`
|
|
9027
9801
|
);
|
|
9028
9802
|
console.log(
|
|
9029
|
-
` Web Studio: ${
|
|
9803
|
+
` Web Studio: ${pc39.green("npx drixio studio")} (Browser UI for bulk inspection)`
|
|
9030
9804
|
);
|
|
9031
9805
|
console.log(`
|
|
9032
|
-
${
|
|
9806
|
+
${pc39.bold("Quick Commands (Headless / Pro):")}`);
|
|
9033
9807
|
console.log(
|
|
9034
|
-
` ${
|
|
9808
|
+
` ${pc39.green("tables")} List all database tables and row counts (alias: ls)`
|
|
9035
9809
|
);
|
|
9036
9810
|
console.log(
|
|
9037
|
-
` ${
|
|
9811
|
+
` ${pc39.green("describe")} [table] Inspect columns, types, PKs, and indexes (alias: desc)`
|
|
9038
9812
|
);
|
|
9039
9813
|
console.log(
|
|
9040
|
-
` ${
|
|
9814
|
+
` ${pc39.green("query")} "<sql>" Run a quick SQL query`
|
|
9041
9815
|
);
|
|
9042
9816
|
console.log(
|
|
9043
|
-
` ${
|
|
9817
|
+
` ${pc39.green("exec")} <file.sql> Execute a SQL script file`
|
|
9044
9818
|
);
|
|
9045
9819
|
console.log(
|
|
9046
|
-
` ${
|
|
9820
|
+
` ${pc39.green("export")} [table] Export table(s) to CSV/JSON`
|
|
9047
9821
|
);
|
|
9048
9822
|
console.log(
|
|
9049
|
-
` ${
|
|
9823
|
+
` ${pc39.green("import")} [file] Import JSON/CSV into a table`
|
|
9050
9824
|
);
|
|
9051
9825
|
console.log(
|
|
9052
|
-
` ${
|
|
9826
|
+
` ${pc39.green("seed")} [table] [count] Generate realistic fake data for a table`
|
|
9053
9827
|
);
|
|
9054
9828
|
console.log(
|
|
9055
|
-
` ${
|
|
9829
|
+
` ${pc39.green("truncate")} [table] Empty all data in a table and reset sequence`
|
|
9056
9830
|
);
|
|
9057
9831
|
console.log(
|
|
9058
|
-
` ${
|
|
9832
|
+
` ${pc39.green("diagram")} Generate a Mermaid ER diagram`
|
|
9059
9833
|
);
|
|
9060
9834
|
console.log(
|
|
9061
|
-
` ${
|
|
9835
|
+
` ${pc39.green("generate-types")} Generate TypeScript interfaces`
|
|
9062
9836
|
);
|
|
9063
9837
|
console.log(
|
|
9064
|
-
` ${
|
|
9838
|
+
` ${pc39.green("generate-orm")} [target] Generate Prisma or Drizzle ORM schema`
|
|
9065
9839
|
);
|
|
9066
9840
|
console.log(
|
|
9067
|
-
` ${
|
|
9841
|
+
` ${pc39.green("diff")} [target] Compare schemas & generate migration SQL`
|
|
9068
9842
|
);
|
|
9069
9843
|
console.log(
|
|
9070
|
-
` ${
|
|
9844
|
+
` ${pc39.green("snippets")} List saved SQL snippets & templates (alias: snip)`
|
|
9071
9845
|
);
|
|
9072
9846
|
console.log(
|
|
9073
|
-
` ${
|
|
9847
|
+
` ${pc39.green("run")} [snippet] Execute a saved snippet or parametric query`
|
|
9074
9848
|
);
|
|
9075
9849
|
console.log(
|
|
9076
|
-
` ${
|
|
9850
|
+
` ${pc39.green("backup")} Backup the entire database`
|
|
9077
9851
|
);
|
|
9078
9852
|
console.log(
|
|
9079
|
-
` ${
|
|
9853
|
+
` ${pc39.green("restore")} [dir|file] Restore database from a backup directory or .sql file`
|
|
9080
9854
|
);
|
|
9081
9855
|
console.log(
|
|
9082
|
-
` ${
|
|
9856
|
+
` ${pc39.green("init")} [db_type] Initialize a local database & .env`
|
|
9083
9857
|
);
|
|
9084
9858
|
console.log(
|
|
9085
|
-
` ${
|
|
9859
|
+
` ${pc39.green("drop-db")} [db_type] Drop a local database`
|
|
9086
9860
|
);
|
|
9087
9861
|
console.log(`
|
|
9088
|
-
${
|
|
9862
|
+
${pc39.bold("Options:")}`);
|
|
9089
9863
|
console.log(` -v, --version Show drixio version`);
|
|
9090
9864
|
console.log(` --help Show this help message`);
|
|
9091
9865
|
console.log(` --json Output results as JSON`);
|