db-model-router 1.0.0 → 1.0.3
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 +154 -203
- package/docker-compose.yml +13 -9
- package/docs/SKILL.md +196 -24
- package/docs/adapters/cockroachdb.md +1 -1
- package/docs/adapters/dynamodb.md +1 -1
- package/docs/adapters/mongodb.md +1 -1
- package/docs/adapters/mssql.md +1 -1
- package/docs/adapters/oracle.md +1 -1
- package/docs/adapters/postgres.md +1 -1
- package/docs/adapters/redis.md +1 -1
- package/docs/adapters/sqlite3.md +1 -1
- package/package.json +7 -12
- package/src/cli/commands/diff.js +114 -0
- package/src/cli/commands/doctor.js +181 -0
- package/src/cli/commands/generate-llm-docs.js +418 -0
- package/src/cli/commands/generate.js +240 -0
- package/src/cli/commands/init.js +153 -0
- package/src/cli/commands/inspect.js +205 -0
- package/src/cli/diff-engine.js +198 -0
- package/src/cli/flags.js +112 -0
- package/src/cli/generate-model.js +4 -4
- package/src/cli/generate-openapi.js +5 -1
- package/src/cli/generate-route.js +242 -7
- package/src/cli/init/dependencies.js +83 -0
- package/src/cli/init/generators.js +782 -0
- package/src/cli/init/prompt.js +159 -0
- package/src/cli/init.js +281 -0
- package/src/cli/main.js +95 -0
- package/src/commons/model.js +5 -6
- package/src/commons/route.js +24 -0
- package/src/schema/schema-parser.js +78 -0
- package/src/schema/schema-printer.js +81 -0
- package/src/schema/schema-to-meta.js +74 -0
- package/src/schema/schema-validator.js +253 -0
- package/src/serve.js +7 -10
- package/docs/README.md +0 -208
- package/src/cli/generate-app.js +0 -359
package/src/cli/generate-app.js
DELETED
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const path = require("path");
|
|
4
|
-
const fs = require("fs");
|
|
5
|
-
const { execFileSync } = require("child_process");
|
|
6
|
-
|
|
7
|
-
const DB_TYPE_MAP = {
|
|
8
|
-
mysql: "mysql",
|
|
9
|
-
postgres: "postgres",
|
|
10
|
-
postgresql: "postgres",
|
|
11
|
-
sqlite3: "sqlite3",
|
|
12
|
-
mssql: "mssql",
|
|
13
|
-
oracle: "oracle",
|
|
14
|
-
cockroachdb: "cockroachdb",
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const SUPPORTED_TYPES = Object.keys(DB_TYPE_MAP);
|
|
18
|
-
|
|
19
|
-
function ensureDir(dir) {
|
|
20
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function generateAppJs(dbType) {
|
|
24
|
-
return `let express;
|
|
25
|
-
try { express = require("ultimate-express"); } catch (_) { express = require("express"); }
|
|
26
|
-
const { init, db } = require("db-model-router");
|
|
27
|
-
const logger = require("./middleware/logger");
|
|
28
|
-
const routes = require("./routes");
|
|
29
|
-
|
|
30
|
-
// Load environment variables
|
|
31
|
-
require("dotenv").config();
|
|
32
|
-
|
|
33
|
-
// Initialize database adapter
|
|
34
|
-
init("${dbType}");
|
|
35
|
-
db.connect({
|
|
36
|
-
host: process.env.DB_HOST || "localhost",
|
|
37
|
-
port: process.env.DB_PORT,
|
|
38
|
-
database: process.env.DB_NAME,
|
|
39
|
-
user: process.env.DB_USER,
|
|
40
|
-
password: process.env.DB_PASS,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const app = express();
|
|
44
|
-
const PORT = process.env.PORT || 3000;
|
|
45
|
-
|
|
46
|
-
// Middleware
|
|
47
|
-
app.use(express.json());
|
|
48
|
-
app.use(express.urlencoded({ extended: true }));
|
|
49
|
-
app.use(logger);
|
|
50
|
-
|
|
51
|
-
// Routes
|
|
52
|
-
app.use("/api", routes);
|
|
53
|
-
|
|
54
|
-
// Health check
|
|
55
|
-
app.get("/health", (req, res) => {
|
|
56
|
-
res.json({ status: "ok", timestamp: new Date().toISOString() });
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Error handler
|
|
60
|
-
app.use((err, req, res, next) => {
|
|
61
|
-
console.error(err.stack);
|
|
62
|
-
res.status(500).json({ type: "danger", message: "Internal Server Error" });
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
app.listen(PORT, () => {
|
|
66
|
-
console.log(\`Server running on port \${PORT}\`);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
module.exports = app;
|
|
70
|
-
`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function generateLoggerMiddleware() {
|
|
74
|
-
return `/**
|
|
75
|
-
* Simple request logger middleware.
|
|
76
|
-
* Logs method, URL, status code, and response time.
|
|
77
|
-
*/
|
|
78
|
-
module.exports = function logger(req, res, next) {
|
|
79
|
-
const start = Date.now();
|
|
80
|
-
const { method, originalUrl } = req;
|
|
81
|
-
|
|
82
|
-
res.on("finish", () => {
|
|
83
|
-
const duration = Date.now() - start;
|
|
84
|
-
const status = res.statusCode;
|
|
85
|
-
const level = status >= 400 ? "WARN" : "INFO";
|
|
86
|
-
console.log(
|
|
87
|
-
\`[\${new Date().toISOString()}] [\${level}] \${method} \${originalUrl} \${status} \${duration}ms\`,
|
|
88
|
-
);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
next();
|
|
92
|
-
};
|
|
93
|
-
`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function generateEnvExample(dbType) {
|
|
97
|
-
const lines = [
|
|
98
|
-
"# Server",
|
|
99
|
-
"PORT=3000",
|
|
100
|
-
"",
|
|
101
|
-
"# Database",
|
|
102
|
-
`DB_TYPE=${dbType}`,
|
|
103
|
-
];
|
|
104
|
-
switch (dbType) {
|
|
105
|
-
case "mysql":
|
|
106
|
-
lines.push(
|
|
107
|
-
"DB_HOST=localhost",
|
|
108
|
-
"DB_PORT=3306",
|
|
109
|
-
"DB_NAME=my_app",
|
|
110
|
-
"DB_USER=root",
|
|
111
|
-
"DB_PASS=password",
|
|
112
|
-
);
|
|
113
|
-
break;
|
|
114
|
-
case "postgres":
|
|
115
|
-
case "cockroachdb":
|
|
116
|
-
lines.push(
|
|
117
|
-
"DB_HOST=localhost",
|
|
118
|
-
`DB_PORT=${dbType === "cockroachdb" ? 26257 : 5432}`,
|
|
119
|
-
"DB_NAME=my_app",
|
|
120
|
-
"DB_USER=postgres",
|
|
121
|
-
"DB_PASS=password",
|
|
122
|
-
);
|
|
123
|
-
break;
|
|
124
|
-
case "sqlite3":
|
|
125
|
-
lines.push("DB_NAME=./data.db");
|
|
126
|
-
break;
|
|
127
|
-
case "mssql":
|
|
128
|
-
lines.push(
|
|
129
|
-
"DB_HOST=localhost",
|
|
130
|
-
"DB_PORT=1433",
|
|
131
|
-
"DB_NAME=my_app",
|
|
132
|
-
"DB_USER=sa",
|
|
133
|
-
"DB_PASS=password",
|
|
134
|
-
);
|
|
135
|
-
break;
|
|
136
|
-
case "oracle":
|
|
137
|
-
lines.push(
|
|
138
|
-
"DB_HOST=localhost",
|
|
139
|
-
"DB_PORT=1521",
|
|
140
|
-
"DB_NAME=my_app",
|
|
141
|
-
"DB_USER=system",
|
|
142
|
-
"DB_PASS=password",
|
|
143
|
-
);
|
|
144
|
-
break;
|
|
145
|
-
case "mongodb":
|
|
146
|
-
lines.push(
|
|
147
|
-
"DB_HOST=localhost",
|
|
148
|
-
"DB_PORT=27017",
|
|
149
|
-
"DB_NAME=my_app",
|
|
150
|
-
"DB_USER=",
|
|
151
|
-
"DB_PASS=",
|
|
152
|
-
);
|
|
153
|
-
break;
|
|
154
|
-
case "redis":
|
|
155
|
-
lines.push("DB_HOST=localhost", "DB_PORT=6379", "DB_PASS=");
|
|
156
|
-
break;
|
|
157
|
-
case "dynamodb":
|
|
158
|
-
lines.push(
|
|
159
|
-
"AWS_REGION=us-east-1",
|
|
160
|
-
"AWS_ENDPOINT=http://localhost:8000",
|
|
161
|
-
"AWS_ACCESS_KEY_ID=local",
|
|
162
|
-
"AWS_SECRET_ACCESS_KEY=local",
|
|
163
|
-
);
|
|
164
|
-
break;
|
|
165
|
-
default:
|
|
166
|
-
lines.push(
|
|
167
|
-
"DB_HOST=localhost",
|
|
168
|
-
"DB_PORT=3306",
|
|
169
|
-
"DB_NAME=my_app",
|
|
170
|
-
"DB_USER=root",
|
|
171
|
-
"DB_PASS=password",
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
return lines.join("\n") + "\n";
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function generateGitignore() {
|
|
178
|
-
return `node_modules/
|
|
179
|
-
.env
|
|
180
|
-
*.db
|
|
181
|
-
`;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
async function main() {
|
|
185
|
-
const args = parseArgs(process.argv.slice(2));
|
|
186
|
-
|
|
187
|
-
if (args.help) {
|
|
188
|
-
printUsage();
|
|
189
|
-
process.exit(0);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const dbType = DB_TYPE_MAP[(args.type || "").toLowerCase()];
|
|
193
|
-
if (!dbType) {
|
|
194
|
-
console.error(
|
|
195
|
-
`Error: --type is required. Supported: ${SUPPORTED_TYPES.join(", ")}`,
|
|
196
|
-
);
|
|
197
|
-
process.exit(1);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const outputDir = path.resolve(args.output || ".");
|
|
201
|
-
const modelsDir = path.join(outputDir, "models");
|
|
202
|
-
const routesDir = path.join(outputDir, "routes");
|
|
203
|
-
const middlewareDir = path.join(outputDir, "middleware");
|
|
204
|
-
const migrationsDir = path.join(outputDir, "migrations");
|
|
205
|
-
const sessionsDir = path.join(outputDir, "sessions");
|
|
206
|
-
|
|
207
|
-
console.log(`Scaffolding app in ${outputDir}...\n`);
|
|
208
|
-
|
|
209
|
-
// Create directories
|
|
210
|
-
for (const dir of [outputDir, middlewareDir, migrationsDir, sessionsDir]) {
|
|
211
|
-
ensureDir(dir);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Generate models via generate-model CLI
|
|
215
|
-
const generateModelArgs = ["--type", dbType, "--output", modelsDir];
|
|
216
|
-
if (args.host) generateModelArgs.push("--host", args.host);
|
|
217
|
-
if (args.port) generateModelArgs.push("--port", args.port);
|
|
218
|
-
if (args.database) generateModelArgs.push("--database", args.database);
|
|
219
|
-
if (args.user) generateModelArgs.push("--user", args.user);
|
|
220
|
-
if (args.password) generateModelArgs.push("--password", args.password);
|
|
221
|
-
if (args.schema) generateModelArgs.push("--schema", args.schema);
|
|
222
|
-
if (args.env) generateModelArgs.push("--env", args.env);
|
|
223
|
-
if (args.tables) generateModelArgs.push("--tables", args.tables);
|
|
224
|
-
|
|
225
|
-
try {
|
|
226
|
-
execFileSync(
|
|
227
|
-
process.execPath,
|
|
228
|
-
[path.join(__dirname, "generate-model.js"), ...generateModelArgs],
|
|
229
|
-
{ stdio: "inherit" },
|
|
230
|
-
);
|
|
231
|
-
} catch (err) {
|
|
232
|
-
console.error("Model generation failed.");
|
|
233
|
-
process.exit(1);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Generate routes via generate-route CLI
|
|
237
|
-
const generateRouteArgs = ["--models", modelsDir, "--output", routesDir];
|
|
238
|
-
if (args.tables) generateRouteArgs.push("--tables", args.tables);
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
execFileSync(
|
|
242
|
-
process.execPath,
|
|
243
|
-
[path.join(__dirname, "generate-route.js"), ...generateRouteArgs],
|
|
244
|
-
{ stdio: "inherit" },
|
|
245
|
-
);
|
|
246
|
-
} catch (err) {
|
|
247
|
-
console.error("Route generation failed.");
|
|
248
|
-
process.exit(1);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Write app.js
|
|
252
|
-
const appPath = path.join(outputDir, "app.js");
|
|
253
|
-
if (!fs.existsSync(appPath)) {
|
|
254
|
-
fs.writeFileSync(appPath, generateAppJs(dbType));
|
|
255
|
-
console.log(` Created ${appPath}`);
|
|
256
|
-
} else {
|
|
257
|
-
console.log(` Skipped ${appPath} (already exists)`);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Write middleware/logger.js
|
|
261
|
-
const loggerPath = path.join(middlewareDir, "logger.js");
|
|
262
|
-
if (!fs.existsSync(loggerPath)) {
|
|
263
|
-
fs.writeFileSync(loggerPath, generateLoggerMiddleware());
|
|
264
|
-
console.log(` Created ${loggerPath}`);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Write .env.example
|
|
268
|
-
const envPath = path.join(outputDir, ".env.example");
|
|
269
|
-
if (!fs.existsSync(envPath)) {
|
|
270
|
-
fs.writeFileSync(envPath, generateEnvExample(dbType));
|
|
271
|
-
console.log(` Created ${envPath}`);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Write .gitignore
|
|
275
|
-
const gitignorePath = path.join(outputDir, ".gitignore");
|
|
276
|
-
if (!fs.existsSync(gitignorePath)) {
|
|
277
|
-
fs.writeFileSync(gitignorePath, generateGitignore());
|
|
278
|
-
console.log(` Created ${gitignorePath}`);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Write placeholder files
|
|
282
|
-
const migrationReadme = path.join(migrationsDir, "README.md");
|
|
283
|
-
if (!fs.existsSync(migrationReadme)) {
|
|
284
|
-
fs.writeFileSync(
|
|
285
|
-
migrationReadme,
|
|
286
|
-
"# Migrations\n\nPlace your database migration scripts here.\n",
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
const sessionReadme = path.join(sessionsDir, "README.md");
|
|
290
|
-
if (!fs.existsSync(sessionReadme)) {
|
|
291
|
-
fs.writeFileSync(
|
|
292
|
-
sessionReadme,
|
|
293
|
-
"# Sessions\n\nSession configuration and store setup.\n",
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
console.log("\nApp scaffolded. To start:");
|
|
298
|
-
console.log(` cp .env.example .env`);
|
|
299
|
-
console.log(` npm install`);
|
|
300
|
-
console.log(` node app.js`);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function parseArgs(argv) {
|
|
304
|
-
const args = {};
|
|
305
|
-
for (let i = 0; i < argv.length; i++) {
|
|
306
|
-
const arg = argv[i];
|
|
307
|
-
if (arg.startsWith("--")) {
|
|
308
|
-
const key = arg.slice(2);
|
|
309
|
-
const next = argv[i + 1];
|
|
310
|
-
if (next && !next.startsWith("--")) {
|
|
311
|
-
args[key] = next;
|
|
312
|
-
i++;
|
|
313
|
-
} else {
|
|
314
|
-
args[key] = true;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return args;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
function printUsage() {
|
|
322
|
-
console.log(`
|
|
323
|
-
Usage: rest-router-generate-app --type <db_type> [options]
|
|
324
|
-
|
|
325
|
-
Scaffolds a complete Express REST API app from an existing database.
|
|
326
|
-
Creates: app.js, models/, routes/, middleware/logger.js, migrations/, sessions/, .env.example
|
|
327
|
-
|
|
328
|
-
Options:
|
|
329
|
-
--type Database type (${SUPPORTED_TYPES.join(", ")}) [required]
|
|
330
|
-
--output Output directory (default: current directory)
|
|
331
|
-
--host Database host
|
|
332
|
-
--port Database port
|
|
333
|
-
--database Database name or file path
|
|
334
|
-
--user Database user
|
|
335
|
-
--password Database password
|
|
336
|
-
--schema Schema name (postgres only)
|
|
337
|
-
--tables Comma-separated tables (supports parent.child notation)
|
|
338
|
-
--env Path to .env file for DB connection
|
|
339
|
-
--help Show this help message
|
|
340
|
-
|
|
341
|
-
Examples:
|
|
342
|
-
rest-router-generate-app --type mysql --env .env
|
|
343
|
-
rest-router-generate-app --type sqlite3 --database ./myapp.db --output ./my-api
|
|
344
|
-
rest-router-generate-app --type postgres --env .env --tables users,posts,posts.comments
|
|
345
|
-
`);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (require.main === module) {
|
|
349
|
-
main().catch((err) => {
|
|
350
|
-
console.error("Error:", err.message);
|
|
351
|
-
process.exit(1);
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
module.exports = {
|
|
356
|
-
generateAppJs,
|
|
357
|
-
generateLoggerMiddleware,
|
|
358
|
-
generateEnvExample,
|
|
359
|
-
};
|