db-model-router 1.0.2 → 1.0.4
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 +317 -202
- package/docs/SKILL.md +250 -33
- 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 +12 -6
- 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/help.js +180 -0
- package/src/cli/commands/init.js +181 -0
- package/src/cli/commands/inspect.js +222 -0
- package/src/cli/diff-engine.js +198 -0
- package/src/cli/flags.js +112 -0
- package/src/cli/generate-model.js +5 -4
- package/src/cli/generate-route.js +255 -14
- package/src/cli/init/dependencies.js +92 -0
- package/src/cli/init/generators.js +1791 -0
- package/src/cli/init/prompt.js +191 -0
- package/src/cli/init.js +404 -0
- package/src/cli/main.js +175 -0
- package/src/commons/model.js +5 -6
- package/src/commons/route.js +24 -0
- package/src/index.js +2 -0
- package/src/schema/schema-parser.js +78 -0
- package/src/schema/schema-printer.js +77 -0
- package/src/schema/schema-to-meta.js +78 -0
- package/src/schema/schema-validator.js +255 -0
- package/src/serve.js +5 -3
- package/docs/README.md +0 -208
- package/src/cli/generate-app.js +0 -359
package/docs/SKILL.md
CHANGED
|
@@ -1,15 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: db-model-router
|
|
3
|
+
description: Database-agnostic REST API generator for Node.js/Express. Define model → get CRUD API + Express routes. 10 adapters, identical API. Works with express or ultimate-express.
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# db-model-router — LLM Skill Reference
|
|
2
7
|
|
|
3
|
-
Database-agnostic REST API generator for Node.js/Express. Define model → get CRUD API + Express routes.
|
|
8
|
+
Database-agnostic REST API generator for Node.js/Express. Define model → get CRUD API + Express routes. 10 adapters, identical API. Works with `express` or `ultimate-express`. Generated projects use ESM (`import`/`export`).
|
|
9
|
+
|
|
10
|
+
## LLM Workflow (follow this order)
|
|
11
|
+
|
|
12
|
+
1. **Scaffold**: `db-model-router init --framework express --database postgres --session redis --rateLimiting --helmet --logger --yes` (all flags → zero prompts)
|
|
13
|
+
2. **Start infra**: `npm run docker:up` (starts DB + CloudBeaver + optional Loki/Grafana)
|
|
14
|
+
3. **Migrations**: Write SQL/JS migration files into `migrations/`, then `npm run migrate`
|
|
15
|
+
4. **Generate models**: `db-model-router generate --from dbmr.schema.json --models`
|
|
16
|
+
5. **Generate routes + tests**: `db-model-router generate --from dbmr.schema.json --routes --tests`
|
|
17
|
+
6. **Run**: `npm run dev`
|
|
18
|
+
|
|
19
|
+
Step 1 creates the project with ESM, Docker, and all infrastructure. Step 2 starts containers. Steps 3-5 define schema and generate code. Step 6 starts the server.
|
|
4
20
|
|
|
5
21
|
## Install
|
|
6
22
|
|
|
7
23
|
```bash
|
|
8
|
-
npm install db-model-router <driver>
|
|
24
|
+
npm install db-model-router <framework> <driver>
|
|
9
25
|
```
|
|
10
26
|
|
|
27
|
+
Frameworks: `express` or `ultimate-express` (auto-detected, prefers ultimate-express)
|
|
11
28
|
Drivers: `mysql2`, `pg`, `better-sqlite3`, `mongodb`, `mssql`, `oracledb`, `ioredis`, `@aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb`
|
|
12
29
|
|
|
30
|
+
## Adapters
|
|
31
|
+
|
|
32
|
+
| Module Key | Driver | Default Port |
|
|
33
|
+
| ------------- | ------------------------------------------------ | ------------ |
|
|
34
|
+
| `mysql` | mysql2 | 3306 |
|
|
35
|
+
| `mariadb` | mysql2 | 3306 |
|
|
36
|
+
| `postgres` | pg | 5432 |
|
|
37
|
+
| `sqlite3` | better-sqlite3 | — |
|
|
38
|
+
| `mongodb` | mongodb | 27017 |
|
|
39
|
+
| `mssql` | mssql | 1433 |
|
|
40
|
+
| `cockroachdb` | pg | 26257 |
|
|
41
|
+
| `oracle` | oracledb | 1521 |
|
|
42
|
+
| `redis` | ioredis | 6379 |
|
|
43
|
+
| `dynamodb` | @aws-sdk/client-dynamodb + @aws-sdk/lib-dynamodb | — |
|
|
44
|
+
|
|
13
45
|
## Init → Connect → Model → Route
|
|
14
46
|
|
|
15
47
|
```js
|
|
@@ -42,12 +74,12 @@ app.use("/users", route(users));
|
|
|
42
74
|
|
|
43
75
|
## model(db, table, structure, pk, unique, option)
|
|
44
76
|
|
|
45
|
-
| Param | Type | Description
|
|
46
|
-
| --------- | --------------- |
|
|
47
|
-
| structure | `{col: "rule"}` | Types: `string\|integer\|numeric\|object`. Prefix `required\|` for NOT NULL.
|
|
48
|
-
| pk | string | Primary key column.
|
|
49
|
-
| unique | string[] | Columns for upsert conflict resolution
|
|
50
|
-
| option | object | `{ safeDelete, created_at, modified_at }` — column names or null
|
|
77
|
+
| Param | Type | Description |
|
|
78
|
+
| --------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
79
|
+
| structure | `{col: "rule"}` | Types: `string\|integer\|numeric\|boolean\|object\|datetime\|auto_increment`. Prefix `required\|` for NOT NULL. PK, timestamps, soft-delete cols are auto-excluded by the code generator |
|
|
80
|
+
| pk | string | Primary key column. Convention: `<table>_id` |
|
|
81
|
+
| unique | string[] | Columns for upsert conflict resolution |
|
|
82
|
+
| option | object | `{ safeDelete, created_at, modified_at }` — column names or null |
|
|
51
83
|
|
|
52
84
|
## Model Methods (all async)
|
|
53
85
|
|
|
@@ -83,14 +115,22 @@ Structure: `[OR_groups[AND_conditions[col, op, val]]]`
|
|
|
83
115
|
Ops: `= != < > <= >= like not like in not in`
|
|
84
116
|
|
|
85
117
|
```js
|
|
118
|
+
// AND: age > 25 AND type = 1
|
|
86
119
|
[
|
|
87
120
|
[
|
|
88
121
|
["age", ">", 25],
|
|
89
122
|
["type", "=", 1],
|
|
90
123
|
],
|
|
91
|
-
][
|
|
124
|
+
][
|
|
125
|
+
// OR: name = "A" OR name = "B"
|
|
126
|
+
([["name", "=", "A"]], [["name", "=", "B"]])
|
|
127
|
+
][
|
|
128
|
+
// IN
|
|
129
|
+
[["type", "in", [1, 2, 3]]]
|
|
130
|
+
][
|
|
131
|
+
// LIKE (auto-wraps with %)
|
|
92
132
|
[["name", "like", "Ali"]]
|
|
93
|
-
];
|
|
133
|
+
];
|
|
94
134
|
```
|
|
95
135
|
|
|
96
136
|
## route(model, override?)
|
|
@@ -100,14 +140,14 @@ Generates Express Router with 9 endpoints:
|
|
|
100
140
|
| Method | Path | Action |
|
|
101
141
|
| ------ | ------ | -------------------------------- |
|
|
102
142
|
| GET | `/:pk` | Get by PK |
|
|
103
|
-
| POST |
|
|
104
|
-
| PUT | `/:
|
|
105
|
-
| PATCH | `/:
|
|
106
|
-
| DELETE | `/:
|
|
143
|
+
| POST | `/add` | Insert single |
|
|
144
|
+
| PUT | `/:pk` | Update single (PK from URL) |
|
|
145
|
+
| PATCH | `/:pk` | Partial update (PK from URL) |
|
|
146
|
+
| DELETE | `/:pk` | Delete single |
|
|
107
147
|
| GET | `/` | List (page, size, sort, filters) |
|
|
108
148
|
| POST | `/` | Bulk insert `{data:[...]}` |
|
|
109
149
|
| PUT | `/` | Bulk update `{data:[...]}` |
|
|
110
|
-
| DELETE | `/` | Bulk delete
|
|
150
|
+
| DELETE | `/` | Bulk delete |
|
|
111
151
|
|
|
112
152
|
**Payload override** (multi-tenancy): `route(m, { tenant_id: "user.tenant_id" })` — maps cols to `req` paths via lodash.get.
|
|
113
153
|
|
|
@@ -115,29 +155,128 @@ Generates Express Router with 9 endpoints:
|
|
|
115
155
|
|
|
116
156
|
## CLI Tools
|
|
117
157
|
|
|
118
|
-
###
|
|
158
|
+
### Unified CLI: `db-model-router`
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
db-model-router <command> [options]
|
|
162
|
+
db-model-router help <command> # detailed help for any command
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
#### `init` — Project Scaffold
|
|
166
|
+
|
|
167
|
+
Scaffolds a complete ESM-based Express REST API project with Docker support.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Fully non-interactive (LLM-friendly — zero prompts)
|
|
171
|
+
db-model-router init --framework express --database postgres --session redis \
|
|
172
|
+
--rateLimiting --helmet --logger --yes
|
|
173
|
+
|
|
174
|
+
# With Loki logging + Grafana
|
|
175
|
+
db-model-router init --database postgres --logger --loki --yes
|
|
176
|
+
|
|
177
|
+
# With output directory
|
|
178
|
+
db-model-router init --database mysql --output backend --yes
|
|
179
|
+
|
|
180
|
+
# From schema file
|
|
181
|
+
db-model-router init --from dbmr.schema.json --yes --no-install
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
| Flag | Description | Default |
|
|
185
|
+
| -------------------- | ----------------------------------------------------------------------------------------------------------- | ---------- |
|
|
186
|
+
| `--from <path>` | Read config from schema file | |
|
|
187
|
+
| `--framework <name>` | `express` or `ultimate-express` | (prompted) |
|
|
188
|
+
| `--database <name>` | `mysql`, `mariadb`, `postgres`, `sqlite3`, `mongodb`, `mssql`, `cockroachdb`, `oracle`, `redis`, `dynamodb` | (prompted) |
|
|
189
|
+
| `--db <name>` | Alias for `--database` | |
|
|
190
|
+
| `--session <type>` | `memory`, `redis`, `database` | (prompted) |
|
|
191
|
+
| `--output <dir>` | Backend source directory (relative to cwd) | (root) |
|
|
192
|
+
| `--rateLimiting` | Enable rate limiting | yes |
|
|
193
|
+
| `--helmet` | Enable Helmet security headers | yes |
|
|
194
|
+
| `--logger` | Enable Winston request logger | yes |
|
|
195
|
+
| `--loki` | Enable Loki transport + Loki/Grafana in docker-compose | no |
|
|
196
|
+
|
|
197
|
+
Generated files (ESM, `"type": "module"`):
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
app.js Express entry point
|
|
201
|
+
.env / .env.example Environment config (random passwords)
|
|
202
|
+
Dockerfile node:alpine production image
|
|
203
|
+
docker-compose.yml DB + CloudBeaver + optional Loki/Grafana
|
|
204
|
+
.cloudbeaver/data-sources.json Auto-connects CloudBeaver to DB
|
|
205
|
+
.grafana/datasources.yml Auto-connects Grafana to Loki (when --loki)
|
|
206
|
+
<output>/commons/db.js Database init, connect, global.db
|
|
207
|
+
<output>/commons/session.js Session configuration
|
|
208
|
+
<output>/commons/security.js Helmet, rate limiting, custom headers
|
|
209
|
+
<output>/commons/migrate.js Migration runner (importable + standalone)
|
|
210
|
+
<output>/commons/add_migration.js Migration creator (importable + standalone)
|
|
211
|
+
<output>/middleware/logger.js Winston logger (+ Loki when LOKI_HOST is set)
|
|
212
|
+
<output>/route/index.js Central route mounting
|
|
213
|
+
<output>/route/health.js GET /health with DB connectivity check
|
|
214
|
+
<output>/migrations/ Initial migration files
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Docker services (auto-generated in docker-compose.yml):
|
|
218
|
+
|
|
219
|
+
| Service | When | Port | Notes |
|
|
220
|
+
| ----------- | --------------------------- | ------ | ------------------------------------- |
|
|
221
|
+
| Database | Always (except sqlite3) | Varies | Random password, bind mount `./data/` |
|
|
222
|
+
| Redis | `session=redis`, DB ≠ redis | 6379 | Session store |
|
|
223
|
+
| CloudBeaver | SQL/MongoDB databases | 8978 | Web DB admin, auto-connected |
|
|
224
|
+
| Loki | `--loki` | 3100 | Log aggregation |
|
|
225
|
+
| Grafana | `--loki` | 3001 | Log visualization |
|
|
226
|
+
|
|
227
|
+
Scripts: `start`, `dev`, `test`, `migrate`, `add_migration`, `docker:build`, `docker:up`, `docker:down`.
|
|
228
|
+
|
|
229
|
+
**Critical**: `db-model-router` is CJS. Generated ESM code must use: `import dbModelRouter from "db-model-router"; const { init, db } = dbModelRouter;` — NOT named imports.
|
|
230
|
+
|
|
231
|
+
#### `inspect` — DB Introspection
|
|
119
232
|
|
|
120
233
|
```bash
|
|
121
|
-
db-model-router
|
|
234
|
+
db-model-router inspect --type postgres --env .env [--out schema.json] [--tables t1,t2]
|
|
122
235
|
```
|
|
123
236
|
|
|
124
|
-
|
|
237
|
+
| Flag | Description |
|
|
238
|
+
| ------------------ | --------------------------------------- |
|
|
239
|
+
| `--type <adapter>` | Database adapter (required) |
|
|
240
|
+
| `--env <path>` | Path to .env file |
|
|
241
|
+
| `--out <path>` | Output file (default: dbmr.schema.json) |
|
|
242
|
+
| `--tables <list>` | Comma-separated table filter |
|
|
125
243
|
|
|
126
|
-
|
|
244
|
+
#### `generate` — Code Generation
|
|
127
245
|
|
|
128
246
|
```bash
|
|
129
|
-
db-model-router
|
|
247
|
+
db-model-router generate --from dbmr.schema.json [--models] [--routes] [--openapi] [--tests] [--llm-docs]
|
|
130
248
|
```
|
|
131
249
|
|
|
132
|
-
|
|
250
|
+
| Flag | Description |
|
|
251
|
+
| --------------- | --------------------------------------- |
|
|
252
|
+
| `--from <path>` | Schema file (default: dbmr.schema.json) |
|
|
253
|
+
| `--models` | Generate only model files |
|
|
254
|
+
| `--routes` | Generate only route files + index |
|
|
255
|
+
| `--openapi` | Generate only OpenAPI spec |
|
|
256
|
+
| `--tests` | Generate only test files |
|
|
257
|
+
| `--llm-docs` | Generate only LLM docs |
|
|
258
|
+
|
|
259
|
+
No flags = generate all. Generated routes/tests use ESM imports.
|
|
133
260
|
|
|
134
|
-
|
|
261
|
+
#### `doctor` — Validation
|
|
135
262
|
|
|
136
263
|
```bash
|
|
137
|
-
db-model-router
|
|
264
|
+
db-model-router doctor [--from dbmr.schema.json] [--json]
|
|
138
265
|
```
|
|
139
266
|
|
|
140
|
-
|
|
267
|
+
Checks: schema validation, dependency check, file sync.
|
|
268
|
+
|
|
269
|
+
#### `diff` — Preview Changes
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
db-model-router diff [--from dbmr.schema.json] [--json]
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Shows added/modified/deleted files without writing.
|
|
276
|
+
|
|
277
|
+
#### Universal Flags (all commands)
|
|
278
|
+
|
|
279
|
+
`--yes`, `--json`, `--dry-run`, `--no-install`, `--help`
|
|
141
280
|
|
|
142
281
|
## Connection Configs
|
|
143
282
|
|
|
@@ -191,12 +330,90 @@ db.connect({ region, endpoint, accessKeyId, secretAccessKey });
|
|
|
191
330
|
|
|
192
331
|
## Rules
|
|
193
332
|
|
|
194
|
-
1. `init()` before `db.connect()`. Don't destructure `db` before `init()
|
|
195
|
-
2. `
|
|
196
|
-
3. `
|
|
197
|
-
4. `
|
|
198
|
-
5.
|
|
199
|
-
6.
|
|
200
|
-
7.
|
|
201
|
-
8. `
|
|
202
|
-
9.
|
|
333
|
+
1. `init()` before `db.connect()`. Don't destructure `db` before `init()` — it's a getter.
|
|
334
|
+
2. Generated projects are ESM (`"type": "module"`). The library itself is CJS. Use default import: `import dbModelRouter from "db-model-router"; const { init, db } = dbModelRouter;`
|
|
335
|
+
3. `model structure` excludes: PK col, timestamp cols, soft-delete cols.
|
|
336
|
+
4. `update()`/`patch()` require PK in payload. `upsert()` PK is optional.
|
|
337
|
+
5. `findOne()` returns `false` on no match. `byId()` returns `null`.
|
|
338
|
+
6. Bulk ops wrap in `{ data: [...] }`. Single ops use flat object.
|
|
339
|
+
7. Timestamps auto-stripped from payloads. DB handles defaults/triggers.
|
|
340
|
+
8. `safeDelete` makes `remove()` soft-delete; all reads auto-filter deleted rows.
|
|
341
|
+
9. `list()` defaults: page=0, size=30. `sort` array: `["-col"]` for DESC.
|
|
342
|
+
10. Use the unified `db-model-router` CLI with `dbmr.schema.json` for new projects.
|
|
343
|
+
11. `generate` auto-generates test files alongside routes. Tests use `supertest`.
|
|
344
|
+
12. `global.db` is set by `commons/db.js` — accessible anywhere without imports.
|
|
345
|
+
13. Logger dynamically loads `winston-loki` only when `LOKI_HOST` env var is set.
|
|
346
|
+
14. Docker passwords are randomly generated and shared between `.env` and `docker-compose.yml`.
|
|
347
|
+
|
|
348
|
+
## Environment Variables by Database
|
|
349
|
+
|
|
350
|
+
| Database | Variables |
|
|
351
|
+
| ----------- | ---------------------------------------------------------------------- |
|
|
352
|
+
| mysql | `PORT DB_HOST DB_PORT=3306 DB_NAME DB_USER DB_PASS` |
|
|
353
|
+
| mariadb | `PORT DB_HOST DB_PORT=3306 DB_NAME DB_USER DB_PASS` |
|
|
354
|
+
| postgres | `PORT DB_HOST DB_PORT=5432 DB_NAME DB_USER DB_PASS` |
|
|
355
|
+
| cockroachdb | `PORT DB_HOST DB_PORT=26257 DB_NAME DB_USER DB_PASS` |
|
|
356
|
+
| sqlite3 | `PORT DB_NAME=./data/data.db` |
|
|
357
|
+
| mongodb | `PORT DB_HOST DB_PORT=27017 DB_NAME DB_USER DB_PASS` |
|
|
358
|
+
| mssql | `PORT DB_HOST DB_PORT=1433 DB_NAME DB_USER DB_PASS` |
|
|
359
|
+
| oracle | `PORT DB_HOST DB_PORT=1521 DB_NAME DB_USER DB_PASS` |
|
|
360
|
+
| redis | `PORT DB_HOST DB_PORT=6379 DB_PASS` |
|
|
361
|
+
| dynamodb | `PORT AWS_REGION AWS_ENDPOINT AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY` |
|
|
362
|
+
|
|
363
|
+
When `session=redis` and database ≠ redis: adds `REDIS_HOST REDIS_PORT REDIS_PASS`.
|
|
364
|
+
When `logger=true`: adds `APP_NAME LOG_LEVEL LOKI_HOST` (LOKI_HOST empty unless `--loki`).
|
|
365
|
+
|
|
366
|
+
## Schema-Driven Workflow
|
|
367
|
+
|
|
368
|
+
The `db-model-router` command uses `dbmr.schema.json` as the source of truth.
|
|
369
|
+
|
|
370
|
+
### LLM Workflow (schema-driven)
|
|
371
|
+
|
|
372
|
+
1. **Inspect** (existing DB): `db-model-router inspect --type postgres --env .env` → writes `dbmr.schema.json`
|
|
373
|
+
2. **Edit** `dbmr.schema.json` — add relationships, tweak columns, set options
|
|
374
|
+
3. **Generate**: `db-model-router generate --from dbmr.schema.json` → models, routes, tests, OpenAPI
|
|
375
|
+
4. **Doctor**: `db-model-router doctor --from dbmr.schema.json` → validate schema + check sync
|
|
376
|
+
5. **Run**: `npm run dev`
|
|
377
|
+
|
|
378
|
+
### dbmr.schema.json Format
|
|
379
|
+
|
|
380
|
+
```json
|
|
381
|
+
{
|
|
382
|
+
"adapter": "postgres",
|
|
383
|
+
"framework": "express",
|
|
384
|
+
"options": {
|
|
385
|
+
"session": "redis",
|
|
386
|
+
"rateLimiting": true,
|
|
387
|
+
"helmet": true,
|
|
388
|
+
"logger": true,
|
|
389
|
+
"loki": false
|
|
390
|
+
},
|
|
391
|
+
"tables": {
|
|
392
|
+
"users": {
|
|
393
|
+
"columns": {
|
|
394
|
+
"user_id": "auto_increment",
|
|
395
|
+
"name": "required|string",
|
|
396
|
+
"email": "required|string",
|
|
397
|
+
"age": "integer",
|
|
398
|
+
"is_deleted": "boolean",
|
|
399
|
+
"created_at": "datetime",
|
|
400
|
+
"updated_at": "datetime"
|
|
401
|
+
},
|
|
402
|
+
"pk": "user_id",
|
|
403
|
+
"unique": ["email"],
|
|
404
|
+
"softDelete": "is_deleted",
|
|
405
|
+
"timestamps": { "created_at": "created_at", "modified_at": "updated_at" }
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
"relationships": [
|
|
409
|
+
{ "parent": "users", "child": "posts", "foreignKey": "user_id" }
|
|
410
|
+
]
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Fields per table: `columns` (required, include ALL columns), `pk` (required, convention: `<table>_id`), `unique` (default `[pk]`), `softDelete`, `timestamps`.
|
|
415
|
+
Column rules: `(required|)?(string|integer|numeric|boolean|object|datetime|auto_increment)`.
|
|
416
|
+
|
|
417
|
+
- `auto_increment` — auto-incrementing PK (SERIAL in Postgres, AUTO_INCREMENT in MySQL/MariaDB)
|
|
418
|
+
- `datetime` — date/time columns (TIMESTAMP, DATETIME, DATE)
|
|
419
|
+
- `required|<type>` — NOT NULL constraint
|
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.4",
|
|
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",
|
|
@@ -21,7 +19,8 @@
|
|
|
21
19
|
"test:cockroachdb": "dotenv -e env/.env.cockroachdb -- mocha test/adapters/cockroachdb.*.test.js --timeout 15000 --exit",
|
|
22
20
|
"test:mssql": "dotenv -e env/.env.mssql -- mocha test/adapters/mssql.*.test.js --timeout 30000 --exit",
|
|
23
21
|
"test:properties": "mocha test/properties/*.property.test.js --timeout 30000 --exit",
|
|
24
|
-
"test:all": "mocha test/adapters/*.test.js test/properties/*.property.test.js test/function.test.js --timeout 30000 --exit"
|
|
22
|
+
"test:all": "mocha test/adapters/*.test.js test/properties/*.property.test.js test/function.test.js --timeout 30000 --exit",
|
|
23
|
+
"clean:demo": "rm -rf demo/* demo/.*"
|
|
25
24
|
},
|
|
26
25
|
"repository": {
|
|
27
26
|
"type": "git",
|
|
@@ -29,6 +28,13 @@
|
|
|
29
28
|
},
|
|
30
29
|
"keywords": [
|
|
31
30
|
"mysql2",
|
|
31
|
+
"sqlite3",
|
|
32
|
+
"oracledb",
|
|
33
|
+
"postgres",
|
|
34
|
+
"pg",
|
|
35
|
+
"dynamodb",
|
|
36
|
+
"mongodb",
|
|
37
|
+
"mssql",
|
|
32
38
|
"express",
|
|
33
39
|
"ultimate-express",
|
|
34
40
|
"generative",
|
|
@@ -43,6 +49,7 @@
|
|
|
43
49
|
"homepage": "https://github.com/AvinashSKaranth/db-model-router#readme",
|
|
44
50
|
"dependencies": {
|
|
45
51
|
"dotenv": "^10.0.0",
|
|
52
|
+
"inquirer": "^8.2.6",
|
|
46
53
|
"lodash": "^4.17.21",
|
|
47
54
|
"node-input-validator": "^4.5.0"
|
|
48
55
|
},
|
|
@@ -95,7 +102,6 @@
|
|
|
95
102
|
}
|
|
96
103
|
},
|
|
97
104
|
"devDependencies": {
|
|
98
|
-
"better-sqlite3": "^12.9.0",
|
|
99
105
|
"dotenv-cli": "^11.0.0",
|
|
100
106
|
"express": "^4.21.0",
|
|
101
107
|
"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;
|