db-model-router 1.0.4 → 1.0.5
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 +110 -16
- package/TODO.md +14 -0
- package/dbmr.schema.json +333 -0
- package/demo/.dockerignore +7 -0
- package/demo/.env.example +13 -0
- package/demo/Dockerfile +20 -0
- package/demo/app.js +37 -0
- package/demo/commons/add_migration.js +43 -0
- package/demo/commons/db.js +17 -0
- package/demo/commons/migrate.js +65 -0
- package/demo/commons/security.js +30 -0
- package/demo/commons/session.js +13 -0
- package/demo/dbmr.schema.json +362 -0
- package/demo/docs/llm.md +197 -0
- package/demo/llms.txt +70 -0
- package/demo/middleware/logger.js +67 -0
- package/demo/migrations/20260430155808_create_migrations_table.sql +6 -0
- package/demo/migrations/20260430155809_create_tables.sql +207 -0
- package/demo/models/addresses.js +22 -0
- package/demo/models/cart_items.js +18 -0
- package/demo/models/carts.js +16 -0
- package/demo/models/categories.js +20 -0
- package/demo/models/coupons.js +23 -0
- package/demo/models/order_items.js +21 -0
- package/demo/models/orders.js +25 -0
- package/demo/models/payments.js +21 -0
- package/demo/models/product_images.js +18 -0
- package/demo/models/product_reviews.js +20 -0
- package/demo/models/product_variants.js +20 -0
- package/demo/models/products.js +30 -0
- package/demo/models/shipments.js +19 -0
- package/demo/models/users.js +19 -0
- package/demo/models/wishlists.js +15 -0
- package/demo/openapi.json +5872 -0
- package/demo/package-lock.json +2810 -0
- package/demo/package.json +34 -0
- package/demo/routes/addresses.js +6 -0
- package/demo/routes/carts/cart_items.js +7 -0
- package/demo/routes/carts.js +6 -0
- package/demo/routes/categories.js +6 -0
- package/demo/routes/coupons.js +6 -0
- package/demo/routes/docs.js +18 -0
- package/demo/routes/health.js +35 -0
- package/demo/routes/index.js +39 -0
- package/demo/routes/orders/order_items.js +7 -0
- package/demo/routes/orders/payments.js +7 -0
- package/demo/routes/orders/shipments.js +7 -0
- package/demo/routes/orders.js +6 -0
- package/demo/routes/products/product_images.js +7 -0
- package/demo/routes/products/product_reviews.js +7 -0
- package/demo/routes/products/product_variants.js +7 -0
- package/demo/routes/products.js +6 -0
- package/demo/routes/users.js +6 -0
- package/demo/routes/wishlists.js +6 -0
- package/docker-compose.yml +1 -1
- package/package.json +8 -7
- package/scripts/demo-create.js +47 -0
- package/skill/SKILL.md +464 -0
- package/skill/references/cockroachdb.md +49 -0
- package/skill/references/dynamodb.md +53 -0
- package/skill/references/mongodb.md +56 -0
- package/skill/references/mssql.md +55 -0
- package/skill/references/oracle.md +52 -0
- package/skill/references/postgres.md +50 -0
- package/skill/references/redis.md +53 -0
- package/skill/references/sqlite3.md +43 -0
- package/src/cli/commands/generate.js +58 -17
- package/src/cli/commands/help.js +11 -6
- package/src/cli/commands/init.js +2 -2
- package/src/cli/commands/inspect.js +1 -0
- package/src/cli/diff-engine.js +52 -22
- package/src/cli/generate-docs-route.js +31 -0
- package/src/cli/generate-migration.js +356 -0
- package/src/cli/generate-route.js +52 -24
- package/src/cli/init/dependencies.js +3 -0
- package/src/cli/init/generators.js +1 -1
- package/src/cli/init.js +8 -8
- package/src/cockroachdb/db.js +90 -59
- package/src/commons/route.js +20 -20
- package/src/commons/validator.js +58 -1
- package/src/dynamodb/db.js +50 -27
- package/src/mongodb/db.js +1 -0
- package/src/mssql/db.js +89 -61
- package/src/mysql/db.js +1 -0
- package/src/oracle/db.js +1 -0
- package/src/postgres/db.js +61 -41
- package/src/redis/db.js +1 -0
- package/src/schema/schema-parser.js +43 -1
- package/src/schema/schema-printer.js +7 -0
- package/src/schema/schema-validator.js +17 -0
- package/src/sqlite3/db.js +1 -0
- package/docs/SKILL.md +0 -419
package/docs/SKILL.md
DELETED
|
@@ -1,419 +0,0 @@
|
|
|
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
|
-
|
|
6
|
-
# db-model-router — LLM Skill Reference
|
|
7
|
-
|
|
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.
|
|
20
|
-
|
|
21
|
-
## Install
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install db-model-router <framework> <driver>
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Frameworks: `express` or `ultimate-express` (auto-detected, prefers ultimate-express)
|
|
28
|
-
Drivers: `mysql2`, `pg`, `better-sqlite3`, `mongodb`, `mssql`, `oracledb`, `ioredis`, `@aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb`
|
|
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
|
-
|
|
45
|
-
## Init → Connect → Model → Route
|
|
46
|
-
|
|
47
|
-
```js
|
|
48
|
-
const { init, db, model, route } = require("db-model-router");
|
|
49
|
-
init("postgres"); // mysql|postgres|sqlite3|mongodb|mssql|cockroachdb|oracle|redis|dynamodb
|
|
50
|
-
db.connect({ host, port: 5432, user, password, database });
|
|
51
|
-
|
|
52
|
-
const users = model(
|
|
53
|
-
db,
|
|
54
|
-
"users",
|
|
55
|
-
{
|
|
56
|
-
name: "required|string",
|
|
57
|
-
email: "required|string",
|
|
58
|
-
age: "integer",
|
|
59
|
-
meta: "object",
|
|
60
|
-
},
|
|
61
|
-
"id",
|
|
62
|
-
["email"],
|
|
63
|
-
{
|
|
64
|
-
safeDelete: "is_deleted",
|
|
65
|
-
created_at: "created_at",
|
|
66
|
-
modified_at: "updated_at",
|
|
67
|
-
},
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
app.use("/users", route(users));
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
**Critical**: call `init()` before `db.connect()`. Default adapter is mysql. Do NOT destructure `db` before `init()`.
|
|
74
|
-
|
|
75
|
-
## model(db, table, structure, pk, unique, option)
|
|
76
|
-
|
|
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 |
|
|
83
|
-
|
|
84
|
-
## Model Methods (all async)
|
|
85
|
-
|
|
86
|
-
```js
|
|
87
|
-
// INSERT — single returns record, bulk returns {rows, message, type}
|
|
88
|
-
await m.insert({ name: "Alice", email: "a@b.com", age: 30 }) // → {id:1, name:"Alice", ...}
|
|
89
|
-
await m.insert({ data: [{...}, {...}] }) // → {rows:2, message, type:"success"}
|
|
90
|
-
|
|
91
|
-
// UPDATE — PK required in payload
|
|
92
|
-
await m.update({ id: 1, name: "Alice V2", email: "a@b.com", age: 31 })
|
|
93
|
-
await m.update({ data: [{id:1,...}, {id:2,...}] })
|
|
94
|
-
|
|
95
|
-
// PATCH — partial update, only sends changed fields, PK required
|
|
96
|
-
await m.patch({ id: 1, age: 35 }) // → full merged record
|
|
97
|
-
|
|
98
|
-
// UPSERT — PK optional, uses unique cols for conflict
|
|
99
|
-
await m.upsert({ email: "new@b.com", name: "New", age: 20 })
|
|
100
|
-
|
|
101
|
-
// READ
|
|
102
|
-
await m.byId(1) // → record or null
|
|
103
|
-
await m.find({ name: "Alice" }) // → {data:[], count}
|
|
104
|
-
await m.findOne({ email: "a@b.com" }) // → record or false
|
|
105
|
-
await m.list({ page: 0, size: 10, sort: ["-age"] }) // → {data:[], count}
|
|
106
|
-
|
|
107
|
-
// DELETE — with safeDelete: sets column=1; without: hard delete
|
|
108
|
-
await m.remove(1)
|
|
109
|
-
await m.remove({ name: "Bob" })
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## Filter Syntax
|
|
113
|
-
|
|
114
|
-
Structure: `[OR_groups[AND_conditions[col, op, val]]]`
|
|
115
|
-
Ops: `= != < > <= >= like not like in not in`
|
|
116
|
-
|
|
117
|
-
```js
|
|
118
|
-
// AND: age > 25 AND type = 1
|
|
119
|
-
[
|
|
120
|
-
[
|
|
121
|
-
["age", ">", 25],
|
|
122
|
-
["type", "=", 1],
|
|
123
|
-
],
|
|
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 %)
|
|
132
|
-
[["name", "like", "Ali"]]
|
|
133
|
-
];
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## route(model, override?)
|
|
137
|
-
|
|
138
|
-
Generates Express Router with 9 endpoints:
|
|
139
|
-
|
|
140
|
-
| Method | Path | Action |
|
|
141
|
-
| ------ | ------ | -------------------------------- |
|
|
142
|
-
| GET | `/:pk` | Get by PK |
|
|
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 |
|
|
147
|
-
| GET | `/` | List (page, size, sort, filters) |
|
|
148
|
-
| POST | `/` | Bulk insert `{data:[...]}` |
|
|
149
|
-
| PUT | `/` | Bulk update `{data:[...]}` |
|
|
150
|
-
| DELETE | `/` | Bulk delete |
|
|
151
|
-
|
|
152
|
-
**Payload override** (multi-tenancy): `route(m, { tenant_id: "user.tenant_id" })` — maps cols to `req` paths via lodash.get.
|
|
153
|
-
|
|
154
|
-
**Query params**: `select_columns=name,email`, `output_content_type=csv|xml|json`, `sort=-age,name`
|
|
155
|
-
|
|
156
|
-
## CLI Tools
|
|
157
|
-
|
|
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
|
|
232
|
-
|
|
233
|
-
```bash
|
|
234
|
-
db-model-router inspect --type postgres --env .env [--out schema.json] [--tables t1,t2]
|
|
235
|
-
```
|
|
236
|
-
|
|
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 |
|
|
243
|
-
|
|
244
|
-
#### `generate` — Code Generation
|
|
245
|
-
|
|
246
|
-
```bash
|
|
247
|
-
db-model-router generate --from dbmr.schema.json [--models] [--routes] [--openapi] [--tests] [--llm-docs]
|
|
248
|
-
```
|
|
249
|
-
|
|
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.
|
|
260
|
-
|
|
261
|
-
#### `doctor` — Validation
|
|
262
|
-
|
|
263
|
-
```bash
|
|
264
|
-
db-model-router doctor [--from dbmr.schema.json] [--json]
|
|
265
|
-
```
|
|
266
|
-
|
|
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`
|
|
280
|
-
|
|
281
|
-
## Connection Configs
|
|
282
|
-
|
|
283
|
-
```js
|
|
284
|
-
// MySQL (default)
|
|
285
|
-
db.connect({
|
|
286
|
-
host,
|
|
287
|
-
port: 3306,
|
|
288
|
-
user,
|
|
289
|
-
password,
|
|
290
|
-
database,
|
|
291
|
-
connectionLimit: 100,
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
// PostgreSQL / CockroachDB
|
|
295
|
-
init("postgres"); // cockroachdb port: 26257
|
|
296
|
-
db.connect({ host, port: 5432, user, password, database });
|
|
297
|
-
|
|
298
|
-
// SQLite3
|
|
299
|
-
init("sqlite3");
|
|
300
|
-
db.connect({ database: "./file.db" }); // or ":memory:"
|
|
301
|
-
|
|
302
|
-
// MongoDB
|
|
303
|
-
init("mongodb");
|
|
304
|
-
db.connect({ host, port: 27017, username, password, database });
|
|
305
|
-
// or: db.connect({ uri: "mongodb://user:pass@host:27017/db" })
|
|
306
|
-
|
|
307
|
-
// MSSQL
|
|
308
|
-
init("mssql");
|
|
309
|
-
await db.connect({
|
|
310
|
-
server: host,
|
|
311
|
-
port: 1433,
|
|
312
|
-
user,
|
|
313
|
-
password,
|
|
314
|
-
database,
|
|
315
|
-
options: { encrypt: false, trustServerCertificate: true },
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
// Oracle
|
|
319
|
-
init("oracle");
|
|
320
|
-
db.connect({ host, port: 1521, user, password, database });
|
|
321
|
-
|
|
322
|
-
// Redis
|
|
323
|
-
init("redis");
|
|
324
|
-
db.connect({ host, port: 6379, password });
|
|
325
|
-
|
|
326
|
-
// DynamoDB
|
|
327
|
-
init("dynamodb");
|
|
328
|
-
db.connect({ region, endpoint, accessKeyId, secretAccessKey });
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
## Rules
|
|
332
|
-
|
|
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
|