forge-sql-orm-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -0
- package/dist-cli/actions/generate-models.d.ts +19 -0
- package/dist-cli/actions/migrations-create.d.ts +46 -0
- package/dist-cli/actions/migrations-drops.d.ts +6 -0
- package/dist-cli/actions/migrations-update.d.ts +6 -0
- package/dist-cli/cli.d.ts +3 -0
- package/dist-cli/cli.js +862 -0
- package/dist-cli/cli.js.map +1 -0
- package/dist-cli/cli.mjs +862 -0
- package/dist-cli/cli.mjs.map +1 -0
- package/package.json +64 -0
- package/src/.env +7 -0
- package/src/actions/generate-models.ts +267 -0
- package/src/actions/migrations-create.ts +213 -0
- package/src/actions/migrations-drops.ts +139 -0
- package/src/actions/migrations-update.ts +659 -0
- package/src/cli.ts +302 -0
- package/tsconfig.json +17 -0
package/src/cli.ts
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import dotenv from "dotenv";
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { generateModels } from "./actions/generate-models";
|
|
9
|
+
import { createMigration } from "./actions/migrations-create";
|
|
10
|
+
import { updateMigration } from "./actions/migrations-update";
|
|
11
|
+
import { dropMigration } from "./actions/migrations-drops";
|
|
12
|
+
|
|
13
|
+
const ENV_PATH = path.resolve(process.cwd(), ".env");
|
|
14
|
+
// 🔄 Load environment variables from `.env` file
|
|
15
|
+
dotenv.config({ path: ENV_PATH });
|
|
16
|
+
|
|
17
|
+
const saveEnvFile = (config: any) => {
|
|
18
|
+
let envContent = "";
|
|
19
|
+
const envFilePath = ENV_PATH;
|
|
20
|
+
|
|
21
|
+
if (fs.existsSync(envFilePath)) {
|
|
22
|
+
envContent = fs.readFileSync(envFilePath, "utf8");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const envVars = envContent
|
|
26
|
+
.split("\n")
|
|
27
|
+
.filter((line) => line.trim() !== "" && !line.startsWith("#"))
|
|
28
|
+
.reduce((acc: any, line) => {
|
|
29
|
+
const [key, ...value] = line.split("=");
|
|
30
|
+
acc[key] = value.join("=");
|
|
31
|
+
return acc;
|
|
32
|
+
}, {});
|
|
33
|
+
|
|
34
|
+
Object.entries(config).forEach(([key, value]) => {
|
|
35
|
+
envVars[`FORGE_SQL_ORM_${key.toUpperCase()}`] = value;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const updatedEnvContent = Object.entries(envVars)
|
|
39
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
40
|
+
.join("\n");
|
|
41
|
+
|
|
42
|
+
fs.writeFileSync(envFilePath, updatedEnvContent, { encoding: "utf8" });
|
|
43
|
+
|
|
44
|
+
console.log("✅ Configuration saved to .env without overwriting other variables.");
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Prompts the user for missing parameters using Inquirer.js.
|
|
49
|
+
* @param config - The current configuration object.
|
|
50
|
+
* @param defaultOutput - Default output path.
|
|
51
|
+
* @param customAskMissingParams - Optional function for additional prompts.
|
|
52
|
+
* @returns Updated configuration with user input.
|
|
53
|
+
*/
|
|
54
|
+
const askMissingParams = async (
|
|
55
|
+
config: any,
|
|
56
|
+
defaultOutput: string,
|
|
57
|
+
customAskMissingParams?: (cfg: any, questions: unknown[]) => void,
|
|
58
|
+
) => {
|
|
59
|
+
const questions: unknown[] = [];
|
|
60
|
+
|
|
61
|
+
if (!config.host)
|
|
62
|
+
questions.push({
|
|
63
|
+
type: "input",
|
|
64
|
+
name: "host",
|
|
65
|
+
message: "Enter database host:",
|
|
66
|
+
default: "localhost",
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (!config.port)
|
|
70
|
+
questions.push({
|
|
71
|
+
type: "input",
|
|
72
|
+
name: "port",
|
|
73
|
+
message: "Enter database port:",
|
|
74
|
+
default: "3306",
|
|
75
|
+
validate: (input: string) => !isNaN(parseInt(input, 10)),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!config.user)
|
|
79
|
+
questions.push({
|
|
80
|
+
type: "input",
|
|
81
|
+
name: "user",
|
|
82
|
+
message: "Enter database user:",
|
|
83
|
+
default: "root",
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (!config.password)
|
|
87
|
+
questions.push({
|
|
88
|
+
type: "password",
|
|
89
|
+
name: "password",
|
|
90
|
+
message: "Enter database password:",
|
|
91
|
+
mask: "*",
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (!config.dbName)
|
|
95
|
+
questions.push({
|
|
96
|
+
type: "input",
|
|
97
|
+
name: "dbName",
|
|
98
|
+
message: "Enter database name:",
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (!config.output)
|
|
102
|
+
questions.push({
|
|
103
|
+
type: "input",
|
|
104
|
+
name: "output",
|
|
105
|
+
message: "Enter output path:",
|
|
106
|
+
default: defaultOutput,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Allow additional questions from the caller
|
|
110
|
+
if (customAskMissingParams) {
|
|
111
|
+
customAskMissingParams(config, questions);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// If there are missing parameters, prompt the user
|
|
115
|
+
if (questions.length > 0) {
|
|
116
|
+
// @ts-ignore - Ignore TypeScript warning for dynamic question type
|
|
117
|
+
const answers = await inquirer.prompt(questions);
|
|
118
|
+
return { ...config, ...answers, port: parseInt(config.port ?? answers.port, 10) };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return config;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Retrieves configuration parameters from command-line arguments and environment variables.
|
|
126
|
+
* If any required parameters are missing, prompts the user for input.
|
|
127
|
+
* @param cmd - The command object containing CLI options.
|
|
128
|
+
* @param defaultOutput - Default output directory.
|
|
129
|
+
* @param customConfig - Optional function for additional configuration parameters.
|
|
130
|
+
* @param customAskMissingParams - Optional function for additional prompts.
|
|
131
|
+
* @returns A fully resolved configuration object.
|
|
132
|
+
*/
|
|
133
|
+
const getConfig = async (
|
|
134
|
+
cmd: any,
|
|
135
|
+
defaultOutput: string,
|
|
136
|
+
customConfig?: () => any,
|
|
137
|
+
customAskMissingParams?: (cfg: any, questions: unknown[]) => void,
|
|
138
|
+
) => {
|
|
139
|
+
let config = {
|
|
140
|
+
host: cmd.host || process.env.FORGE_SQL_ORM_HOST,
|
|
141
|
+
port: cmd.port
|
|
142
|
+
? parseInt(cmd.port, 10)
|
|
143
|
+
: process.env.FORGE_SQL_ORM_PORT
|
|
144
|
+
? parseInt(process.env.FORGE_SQL_ORM_PORT, 10)
|
|
145
|
+
: undefined,
|
|
146
|
+
user: cmd.user || process.env.FORGE_SQL_ORM_USER,
|
|
147
|
+
password: cmd.password || process.env.FORGE_SQL_ORM_PASSWORD,
|
|
148
|
+
dbName: cmd.dbName || process.env.FORGE_SQL_ORM_DBNAME,
|
|
149
|
+
output: cmd.output || process.env.FORGE_SQL_ORM_OUTPUT,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Merge additional configurations if provided
|
|
153
|
+
if (customConfig) {
|
|
154
|
+
config = { ...config, ...customConfig() };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const conf = await askMissingParams(config, defaultOutput, customAskMissingParams);
|
|
158
|
+
if (cmd.saveEnv) {
|
|
159
|
+
saveEnvFile(conf);
|
|
160
|
+
}
|
|
161
|
+
return conf;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// 📌 Initialize CLI
|
|
165
|
+
export const program = new Command();
|
|
166
|
+
program.version("1.0.0");
|
|
167
|
+
|
|
168
|
+
// ✅ Command: Generate database models (Entities)
|
|
169
|
+
program
|
|
170
|
+
.command("generate:model")
|
|
171
|
+
.description("Generate MikroORM models from the database.")
|
|
172
|
+
.option("--host <string>", "Database host")
|
|
173
|
+
.option("--port <number>", "Database port")
|
|
174
|
+
.option("--user <string>", "Database user")
|
|
175
|
+
.option("--password <string>", "Database password")
|
|
176
|
+
.option("--dbName <string>", "Database name")
|
|
177
|
+
.option("--output <string>", "Output path for entities")
|
|
178
|
+
.option("--versionField <string>", "Field name for versioning")
|
|
179
|
+
.option("--saveEnv", "Save configuration to .env file")
|
|
180
|
+
.action(async (cmd) => {
|
|
181
|
+
const config = await getConfig(
|
|
182
|
+
cmd,
|
|
183
|
+
"./database/entities",
|
|
184
|
+
() => ({
|
|
185
|
+
versionField: cmd.versionField || process.env.FORGE_SQL_ORM_VERSIONFIELD,
|
|
186
|
+
}),
|
|
187
|
+
(cfg, questions: unknown[]) => {
|
|
188
|
+
if (!cfg.versionField) {
|
|
189
|
+
questions.push({
|
|
190
|
+
type: "input",
|
|
191
|
+
name: "versionField",
|
|
192
|
+
message: "Enter the field name for versioning (leave empty to skip):",
|
|
193
|
+
default: "",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
);
|
|
198
|
+
await generateModels(config);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// ✅ Command: Create initial database migration
|
|
202
|
+
program
|
|
203
|
+
.command("migrations:create")
|
|
204
|
+
.description("Generate an initial migration for the entire database.")
|
|
205
|
+
.option("--host <string>", "Database host")
|
|
206
|
+
.option("--port <number>", "Database port")
|
|
207
|
+
.option("--user <string>", "Database user")
|
|
208
|
+
.option("--password <string>", "Database password")
|
|
209
|
+
.option("--dbName <string>", "Database name")
|
|
210
|
+
.option("--output <string>", "Output path for migrations")
|
|
211
|
+
.option("--entitiesPath <string>", "Path to the folder containing entities")
|
|
212
|
+
.option("--force", "Force creation even if migrations exist")
|
|
213
|
+
.option("--saveEnv", "Save configuration to .env file")
|
|
214
|
+
.action(async (cmd) => {
|
|
215
|
+
const config = await getConfig(
|
|
216
|
+
cmd,
|
|
217
|
+
"./database/migration",
|
|
218
|
+
() => ({
|
|
219
|
+
entitiesPath: cmd.entitiesPath || process.env.FORGE_SQL_ORM_ENTITIESPATH,
|
|
220
|
+
force: cmd.force || false,
|
|
221
|
+
}),
|
|
222
|
+
(cfg, questions: unknown[]) => {
|
|
223
|
+
if (!cfg.entitiesPath)
|
|
224
|
+
questions.push({
|
|
225
|
+
type: "input",
|
|
226
|
+
name: "entitiesPath",
|
|
227
|
+
message: "Enter the path to entities:",
|
|
228
|
+
default: "./database/entities",
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
);
|
|
232
|
+
await createMigration(config);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// ✅ Command: Update migration for schema changes
|
|
236
|
+
program
|
|
237
|
+
.command("migrations:update")
|
|
238
|
+
.description("Generate a migration to update the database schema.")
|
|
239
|
+
.option("--host <string>", "Database host")
|
|
240
|
+
.option("--port <number>", "Database port")
|
|
241
|
+
.option("--user <string>", "Database user")
|
|
242
|
+
.option("--password <string>", "Database password")
|
|
243
|
+
.option("--dbName <string>", "Database name")
|
|
244
|
+
.option("--output <string>", "Output path for migrations")
|
|
245
|
+
.option("--entitiesPath <string>", "Path to the folder containing entities")
|
|
246
|
+
.option("--saveEnv", "Save configuration to .env file")
|
|
247
|
+
.action(async (cmd) => {
|
|
248
|
+
const config = await getConfig(
|
|
249
|
+
cmd,
|
|
250
|
+
"./database/migration",
|
|
251
|
+
() => ({
|
|
252
|
+
entitiesPath: cmd.entitiesPath || process.env.FORGE_SQL_ORM_ENTITIESPATH,
|
|
253
|
+
}),
|
|
254
|
+
(cfg, questions: unknown[]) => {
|
|
255
|
+
if (!cfg.entitiesPath)
|
|
256
|
+
questions.push({
|
|
257
|
+
type: "input",
|
|
258
|
+
name: "entitiesPath",
|
|
259
|
+
message: "Enter the path to entities:",
|
|
260
|
+
default: "./database/entities",
|
|
261
|
+
});
|
|
262
|
+
},
|
|
263
|
+
);
|
|
264
|
+
await updateMigration(config);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// ✅ Command: Drop all migrations
|
|
268
|
+
program
|
|
269
|
+
.command("migrations:drop")
|
|
270
|
+
.description("Generate a migration to drop all tables and clear migrations history.")
|
|
271
|
+
.option("--host <string>", "Database host")
|
|
272
|
+
.option("--port <number>", "Database port")
|
|
273
|
+
.option("--user <string>", "Database user")
|
|
274
|
+
.option("--password <string>", "Database password")
|
|
275
|
+
.option("--dbName <string>", "Database name")
|
|
276
|
+
.option("--output <string>", "Output path for migrations")
|
|
277
|
+
.option("--entitiesPath <string>", "Path to the folder containing entities")
|
|
278
|
+
.option("--saveEnv", "Save configuration to .env file")
|
|
279
|
+
.action(async (cmd) => {
|
|
280
|
+
const config = await getConfig(
|
|
281
|
+
cmd,
|
|
282
|
+
"./database/migration",
|
|
283
|
+
() => ({
|
|
284
|
+
entitiesPath: cmd.entitiesPath || process.env.FORGE_SQL_ORM_ENTITIESPATH,
|
|
285
|
+
}),
|
|
286
|
+
(cfg, questions: unknown[]) => {
|
|
287
|
+
if (!cfg.entitiesPath)
|
|
288
|
+
questions.push({
|
|
289
|
+
type: "input",
|
|
290
|
+
name: "entitiesPath",
|
|
291
|
+
message: "Enter the path to entities:",
|
|
292
|
+
default: "./database/entities",
|
|
293
|
+
});
|
|
294
|
+
},
|
|
295
|
+
);
|
|
296
|
+
await dropMigration(config);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// 🔥 Execute CLI
|
|
300
|
+
if (require.main === module) {
|
|
301
|
+
program.parse(process.argv);
|
|
302
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist-cli",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"moduleResolution": "node"
|
|
14
|
+
},
|
|
15
|
+
"include": ["src/**/*"],
|
|
16
|
+
"exclude": ["node_modules", "dist-cli"]
|
|
17
|
+
}
|