db-model-router 1.0.2 → 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 +153 -202
- package/docs/SKILL.md +194 -22
- 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 +3 -5
- 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-route.js +237 -2
- 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 +5 -3
- package/docs/README.md +0 -208
- package/src/cli/generate-app.js +0 -359
package/docs/adapters/mongodb.md
CHANGED
package/docs/adapters/mssql.md
CHANGED
package/docs/adapters/oracle.md
CHANGED
package/docs/adapters/redis.md
CHANGED
package/docs/adapters/sqlite3.md
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "db-model-router",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Generative API Creation using mysql2 and express libraries in node js",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"db-model-router
|
|
8
|
-
"db-model-router-generate-route": "src/cli/generate-route.js",
|
|
9
|
-
"db-model-router-generate-app": "src/cli/generate-app.js"
|
|
7
|
+
"db-model-router": "src/cli/main.js"
|
|
10
8
|
},
|
|
11
9
|
"scripts": {
|
|
12
10
|
"dev": "nodemon src/serve.js",
|
|
@@ -43,6 +41,7 @@
|
|
|
43
41
|
"homepage": "https://github.com/AvinashSKaranth/db-model-router#readme",
|
|
44
42
|
"dependencies": {
|
|
45
43
|
"dotenv": "^10.0.0",
|
|
44
|
+
"inquirer": "^8.2.6",
|
|
46
45
|
"lodash": "^4.17.21",
|
|
47
46
|
"node-input-validator": "^4.5.0"
|
|
48
47
|
},
|
|
@@ -95,7 +94,6 @@
|
|
|
95
94
|
}
|
|
96
95
|
},
|
|
97
96
|
"devDependencies": {
|
|
98
|
-
"better-sqlite3": "^12.9.0",
|
|
99
97
|
"dotenv-cli": "^11.0.0",
|
|
100
98
|
"express": "^4.21.0",
|
|
101
99
|
"faker": "^5.5.3",
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { parseSchema } = require("../../schema/schema-parser");
|
|
6
|
+
const { SchemaValidationError } = require("../../schema/schema-validator");
|
|
7
|
+
const { schemaToModelMeta } = require("../../schema/schema-to-meta");
|
|
8
|
+
const { computeDiff } = require("../diff-engine");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Diff command handler for the unified CLI.
|
|
12
|
+
*
|
|
13
|
+
* Compares the current generated files against what the schema would produce,
|
|
14
|
+
* reporting additions, modifications (with line diffs), and deletions.
|
|
15
|
+
* Does NOT modify any files on disk.
|
|
16
|
+
*
|
|
17
|
+
* Supported flags:
|
|
18
|
+
* --from Path to schema file (default: dbmr.schema.json)
|
|
19
|
+
* --json Output JSON result via ctx
|
|
20
|
+
*
|
|
21
|
+
* @param {object} args - Parsed key-value args
|
|
22
|
+
* @param {object} flags - Universal flags: { yes, json, dryRun, noInstall, help }
|
|
23
|
+
* @param {import('../flags').OutputContext} ctx - Output context
|
|
24
|
+
*/
|
|
25
|
+
async function diff(args, flags, ctx) {
|
|
26
|
+
const schemaFile = args.from || "dbmr.schema.json";
|
|
27
|
+
const schemaPath = path.resolve(schemaFile);
|
|
28
|
+
const baseDir = process.cwd();
|
|
29
|
+
|
|
30
|
+
// --- 1. Read and parse schema ---
|
|
31
|
+
if (!fs.existsSync(schemaPath)) {
|
|
32
|
+
const msg = `Schema file not found: ${schemaFile}`;
|
|
33
|
+
if (flags.json) {
|
|
34
|
+
ctx.result({ error: true, code: "SCHEMA_NOT_FOUND", message: msg });
|
|
35
|
+
} else {
|
|
36
|
+
ctx.log(`Error: ${msg}`);
|
|
37
|
+
}
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let schema;
|
|
43
|
+
try {
|
|
44
|
+
const raw = fs.readFileSync(schemaPath, "utf8");
|
|
45
|
+
schema = parseSchema(raw);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
const msg = `Schema parse error: ${err.message}`;
|
|
48
|
+
if (flags.json) {
|
|
49
|
+
ctx.result({
|
|
50
|
+
error: true,
|
|
51
|
+
code: "SCHEMA_VALIDATION",
|
|
52
|
+
message: msg,
|
|
53
|
+
errors: err.errors || [],
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
ctx.log(`Error: ${msg}`);
|
|
57
|
+
}
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// --- 2. Compute diff ---
|
|
63
|
+
const meta = schemaToModelMeta(schema);
|
|
64
|
+
const relationships = schema.relationships || [];
|
|
65
|
+
const result = computeDiff(baseDir, meta, relationships);
|
|
66
|
+
|
|
67
|
+
// --- 3. Output results ---
|
|
68
|
+
if (flags.json) {
|
|
69
|
+
ctx.result({
|
|
70
|
+
added: result.added,
|
|
71
|
+
modified: result.modified,
|
|
72
|
+
deleted: result.deleted,
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
const total =
|
|
76
|
+
result.added.length + result.modified.length + result.deleted.length;
|
|
77
|
+
|
|
78
|
+
if (total === 0) {
|
|
79
|
+
ctx.log("All generated files are up to date.");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (result.added.length > 0) {
|
|
84
|
+
ctx.log("Added (new files to create):");
|
|
85
|
+
for (const f of result.added) {
|
|
86
|
+
ctx.log(` + ${f}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (result.modified.length > 0) {
|
|
91
|
+
ctx.log("Modified (files with changes):");
|
|
92
|
+
for (const m of result.modified) {
|
|
93
|
+
ctx.log(` ~ ${m.file}`);
|
|
94
|
+
// Display line diffs indented
|
|
95
|
+
for (const line of m.diff.split("\n")) {
|
|
96
|
+
if (line) {
|
|
97
|
+
ctx.log(` ${line}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (result.deleted.length > 0) {
|
|
104
|
+
ctx.log("Deleted (extra files to remove):");
|
|
105
|
+
for (const f of result.deleted) {
|
|
106
|
+
ctx.log(` - ${f}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
ctx.log(`\n${total} file(s) differ.`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
module.exports = diff;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { parseSchema } = require("../../schema/schema-parser");
|
|
6
|
+
const { SchemaValidationError } = require("../../schema/schema-validator");
|
|
7
|
+
const { schemaToModelMeta } = require("../../schema/schema-to-meta");
|
|
8
|
+
const { computeDiff } = require("../diff-engine");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Adapter-to-driver mapping.
|
|
12
|
+
* Maps each supported adapter to the npm package name required.
|
|
13
|
+
*/
|
|
14
|
+
const ADAPTER_DRIVER_MAP = {
|
|
15
|
+
mysql: "mysql2",
|
|
16
|
+
postgres: "pg",
|
|
17
|
+
sqlite3: "better-sqlite3",
|
|
18
|
+
mongodb: "mongodb",
|
|
19
|
+
mssql: "tedious",
|
|
20
|
+
cockroachdb: "pg",
|
|
21
|
+
oracle: "oracledb",
|
|
22
|
+
redis: "redis",
|
|
23
|
+
dynamodb: "@aws-sdk/client-dynamodb",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Doctor command handler for the unified CLI.
|
|
28
|
+
*
|
|
29
|
+
* Validates the schema, checks adapter driver dependencies in package.json,
|
|
30
|
+
* and verifies generated files are in sync with the schema.
|
|
31
|
+
*
|
|
32
|
+
* Supported flags:
|
|
33
|
+
* --from Path to schema file (default: dbmr.schema.json)
|
|
34
|
+
* --json Output JSON result via ctx
|
|
35
|
+
*
|
|
36
|
+
* @param {object} args - Parsed key-value args
|
|
37
|
+
* @param {object} flags - Universal flags: { yes, json, dryRun, noInstall, help }
|
|
38
|
+
* @param {import('../flags').OutputContext} ctx - Output context
|
|
39
|
+
*/
|
|
40
|
+
async function doctor(args, flags, ctx) {
|
|
41
|
+
const schemaFile = args.from || "dbmr.schema.json";
|
|
42
|
+
const schemaPath = path.resolve(schemaFile);
|
|
43
|
+
const baseDir = process.cwd();
|
|
44
|
+
|
|
45
|
+
// --- 1. Schema validation ---
|
|
46
|
+
const validation = { valid: true, errors: [] };
|
|
47
|
+
let schema = null;
|
|
48
|
+
|
|
49
|
+
if (!fs.existsSync(schemaPath)) {
|
|
50
|
+
validation.valid = false;
|
|
51
|
+
validation.errors.push({
|
|
52
|
+
path: "",
|
|
53
|
+
message: `Schema file not found: ${schemaFile}`,
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
try {
|
|
57
|
+
const raw = fs.readFileSync(schemaPath, "utf8");
|
|
58
|
+
schema = parseSchema(raw);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
validation.valid = false;
|
|
61
|
+
if (err instanceof SchemaValidationError) {
|
|
62
|
+
validation.errors = err.errors;
|
|
63
|
+
} else {
|
|
64
|
+
validation.errors.push({ path: "", message: err.message });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// --- 2. Dependency check ---
|
|
70
|
+
const dependencies = { ok: true, missing: [] };
|
|
71
|
+
|
|
72
|
+
if (schema) {
|
|
73
|
+
const driver = ADAPTER_DRIVER_MAP[schema.adapter];
|
|
74
|
+
if (driver) {
|
|
75
|
+
const pkgPath = path.join(baseDir, "package.json");
|
|
76
|
+
if (fs.existsSync(pkgPath)) {
|
|
77
|
+
try {
|
|
78
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
79
|
+
const allDeps = Object.assign(
|
|
80
|
+
{},
|
|
81
|
+
pkg.dependencies || {},
|
|
82
|
+
pkg.devDependencies || {},
|
|
83
|
+
);
|
|
84
|
+
if (!allDeps[driver]) {
|
|
85
|
+
dependencies.ok = false;
|
|
86
|
+
dependencies.missing.push({
|
|
87
|
+
adapter: schema.adapter,
|
|
88
|
+
driver,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
} catch (_) {
|
|
92
|
+
// If package.json is unreadable, report driver as missing
|
|
93
|
+
dependencies.ok = false;
|
|
94
|
+
dependencies.missing.push({
|
|
95
|
+
adapter: schema.adapter,
|
|
96
|
+
driver,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
dependencies.ok = false;
|
|
101
|
+
dependencies.missing.push({
|
|
102
|
+
adapter: schema.adapter,
|
|
103
|
+
driver,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// --- 3. Sync check ---
|
|
110
|
+
const sync = { ok: true, outOfSync: [] };
|
|
111
|
+
|
|
112
|
+
if (schema) {
|
|
113
|
+
const meta = schemaToModelMeta(schema);
|
|
114
|
+
const relationships = schema.relationships || [];
|
|
115
|
+
const diff = computeDiff(baseDir, meta, relationships);
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
diff.added.length > 0 ||
|
|
119
|
+
diff.modified.length > 0 ||
|
|
120
|
+
diff.deleted.length > 0
|
|
121
|
+
) {
|
|
122
|
+
sync.ok = false;
|
|
123
|
+
for (const f of diff.added) {
|
|
124
|
+
sync.outOfSync.push({ file: f, status: "missing" });
|
|
125
|
+
}
|
|
126
|
+
for (const m of diff.modified) {
|
|
127
|
+
sync.outOfSync.push({ file: m.file, status: "modified" });
|
|
128
|
+
}
|
|
129
|
+
for (const f of diff.deleted) {
|
|
130
|
+
sync.outOfSync.push({ file: f, status: "extra" });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// --- 4. Report results ---
|
|
136
|
+
const allPass = validation.valid && dependencies.ok && sync.ok;
|
|
137
|
+
const report = { validation, dependencies, sync };
|
|
138
|
+
|
|
139
|
+
if (flags.json) {
|
|
140
|
+
ctx.result(report);
|
|
141
|
+
} else {
|
|
142
|
+
// Validation
|
|
143
|
+
if (validation.valid) {
|
|
144
|
+
ctx.log("✓ Schema validation passed");
|
|
145
|
+
} else {
|
|
146
|
+
ctx.log("✗ Schema validation failed:");
|
|
147
|
+
for (const e of validation.errors) {
|
|
148
|
+
const loc = e.path ? ` (${e.path})` : "";
|
|
149
|
+
ctx.log(` ${e.message}${loc}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Dependencies
|
|
154
|
+
if (dependencies.ok) {
|
|
155
|
+
ctx.log("✓ Dependencies OK");
|
|
156
|
+
} else {
|
|
157
|
+
ctx.log("✗ Missing dependencies:");
|
|
158
|
+
for (const m of dependencies.missing) {
|
|
159
|
+
ctx.log(` ${m.adapter} requires "${m.driver}" in package.json`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Sync
|
|
164
|
+
if (sync.ok) {
|
|
165
|
+
ctx.log("✓ Generated files in sync");
|
|
166
|
+
} else {
|
|
167
|
+
ctx.log("✗ Files out of sync:");
|
|
168
|
+
for (const s of sync.outOfSync) {
|
|
169
|
+
ctx.log(` ${s.file} (${s.status})`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// --- 5. Exit code ---
|
|
175
|
+
if (!allPass) {
|
|
176
|
+
process.exitCode = 1;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = doctor;
|
|
181
|
+
module.exports.ADAPTER_DRIVER_MAP = ADAPTER_DRIVER_MAP;
|