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 CHANGED
@@ -2,11 +2,26 @@
2
2
 
3
3
  A database-agnostic REST API generator for Node.js. Works with Express or ultimate-express (a high-performance drop-in replacement). Define a model, get a full CRUD API with filtering, pagination, and bulk operations — backed by any of 9 supported databases.
4
4
 
5
+ ## Build a REST API with AI
6
+
7
+ This library is designed to be driven by an AI assistant. Give it a prompt like this:
8
+
9
+ ```
10
+ Use db-model-router to build a REST API for a task management app with postgres.
11
+ I need: users (name, email, password_hash), projects (name, description, owner_id → users),
12
+ and tasks (title, status, priority, project_id → projects, assignee_id → users).
13
+ Scaffold the project, write the migrations, generate models and routes with parent-child
14
+ relationships for projects.tasks, and make sure everything runs.
15
+ ```
16
+
17
+ For the LLM skill reference, see [SKILL.md](./docs/SKILL.md).
18
+
5
19
  ## Supported Adapters
6
20
 
7
21
  | Adapter | Module Key | Driver | Install |
8
22
  | --------------------------------------------- | ------------- | ------------------------ | ---------------------------------------------------------------------- |
9
23
  | [MySQL](#mysql-example) | `mysql` | mysql2 | `npm i db-model-router mysql2` |
24
+ | MariaDB | `mariadb` | mysql2 | `npm i db-model-router mysql2` |
10
25
  | [PostgreSQL](./docs/adapters/postgres.md) | `postgres` | pg | `npm i db-model-router pg` |
11
26
  | [SQLite3](./docs/adapters/sqlite3.md) | `sqlite3` | better-sqlite3 | `npm i db-model-router better-sqlite3` |
12
27
  | [MongoDB](./docs/adapters/mongodb.md) | `mongodb` | mongodb | `npm i db-model-router mongodb` |
@@ -55,6 +70,306 @@ npm install db-model-router @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
55
70
 
56
71
  Both `express` and `ultimate-express` are optional peer dependencies. The library auto-detects which one is installed (preferring `ultimate-express` when both are present). All database drivers are also optional peer dependencies, so your `node_modules` stays lean.
57
72
 
73
+ ## Quick Start
74
+
75
+ The fastest way to start a new project:
76
+
77
+ ```bash
78
+ # Scaffold a project interactively
79
+ npx db-model-router init
80
+
81
+ # Or fully non-interactive from a schema file
82
+ db-model-router init --from dbmr.schema.json --yes --no-install
83
+ db-model-router generate --from dbmr.schema.json
84
+ ```
85
+
86
+ After scaffolding:
87
+
88
+ ```bash
89
+ # 1. Edit .env with your database credentials
90
+ # 2. Start developing
91
+ npm run dev
92
+ ```
93
+
94
+ ## Schema-Driven Workflow
95
+
96
+ Instead of running multiple CLI commands manually, you can define your entire project in a single `dbmr.schema.json` file and let the CLI generate everything from it.
97
+
98
+ ### The Schema File
99
+
100
+ `dbmr.schema.json` is a declarative JSON file that describes your adapter, framework, tables, columns, relationships, and options — all in one place:
101
+
102
+ ```json
103
+ {
104
+ "adapter": "postgres",
105
+ "framework": "express",
106
+ "options": {
107
+ "session": "redis",
108
+ "rateLimiting": true,
109
+ "helmet": true,
110
+ "logger": true,
111
+ "loki": false
112
+ },
113
+ "tables": {
114
+ "users": {
115
+ "columns": {
116
+ "user_id": "auto_increment",
117
+ "name": "required|string",
118
+ "email": "required|string",
119
+ "age": "integer",
120
+ "is_deleted": "boolean",
121
+ "created_at": "datetime",
122
+ "updated_at": "datetime"
123
+ },
124
+ "pk": "user_id",
125
+ "unique": ["email"],
126
+ "softDelete": "is_deleted",
127
+ "timestamps": {
128
+ "created_at": "created_at",
129
+ "modified_at": "updated_at"
130
+ }
131
+ },
132
+ "posts": {
133
+ "columns": {
134
+ "post_id": "auto_increment",
135
+ "title": "required|string",
136
+ "body": "string",
137
+ "user_id": "required|integer",
138
+ "created_at": "datetime",
139
+ "modified_at": "datetime"
140
+ },
141
+ "pk": "post_id",
142
+ "unique": ["post_id"]
143
+ }
144
+ },
145
+ "relationships": [
146
+ { "parent": "users", "child": "posts", "foreignKey": "user_id" }
147
+ ]
148
+ }
149
+ ```
150
+
151
+ Table entries support these fields:
152
+
153
+ | Field | Required | Description |
154
+ | ------------ | -------- | ------------------------------------------------------------------------ |
155
+ | `columns` | Yes | Object mapping column names to Column_Rule strings (include ALL columns) |
156
+ | `pk` | Yes | Primary key column name (convention: `<table>_id`) |
157
+ | `unique` | No | Array of unique constraint columns (defaults to `[pk]`) |
158
+ | `softDelete` | No | Column name used for soft-delete |
159
+ | `timestamps` | No | Object with `created_at` and `modified_at` column name mapping |
160
+
161
+ Column rules use the format `(required|)?(string|integer|numeric|boolean|object|datetime|auto_increment)`.
162
+
163
+ - `auto_increment` — auto-incrementing PK (SERIAL in Postgres, AUTO_INCREMENT in MySQL/MariaDB)
164
+ - `datetime` — date/time columns (TIMESTAMP, DATETIME, DATE)
165
+ - `required|<type>` — NOT NULL constraint on insert/update
166
+
167
+ ### Unified CLI: `db-model-router`
168
+
169
+ The `db-model-router` command is the unified entry point with five subcommands:
170
+
171
+ ```bash
172
+ db-model-router <subcommand> [flags]
173
+ ```
174
+
175
+ | Subcommand | Description |
176
+ | ---------- | ------------------------------------------------------------------- |
177
+ | `init` | Scaffold a new project (optionally from a schema file) |
178
+ | `inspect` | Introspect a live database and produce a `dbmr.schema.json` |
179
+ | `generate` | Generate models, routes, tests, and OpenAPI spec from the schema |
180
+ | `doctor` | Validate schema, check dependencies, verify generated files in sync |
181
+ | `diff` | Preview what changes regeneration would make (read-only) |
182
+
183
+ #### Universal Flags
184
+
185
+ All subcommands accept these flags:
186
+
187
+ | Flag | Description |
188
+ | -------------- | ----------------------------------------------------------- |
189
+ | `--yes` | Accept all defaults, suppress interactive prompts |
190
+ | `--json` | Output machine-readable JSON instead of human-readable text |
191
+ | `--dry-run` | Preview actions without writing files or running commands |
192
+ | `--no-install` | Skip `npm install` (applies to commands that would run it) |
193
+ | `--help` | Show usage information for the subcommand |
194
+
195
+ #### Quick Workflow Example
196
+
197
+ ```bash
198
+ # 1. Introspect an existing database into a schema file
199
+ db-model-router inspect --type postgres --env .env
200
+
201
+ # 2. (Optional) Edit dbmr.schema.json to add relationships, tweak columns, etc.
202
+
203
+ # 3. Generate all artifacts from the schema
204
+ db-model-router generate --from dbmr.schema.json
205
+
206
+ # 4. Check everything is in sync
207
+ db-model-router doctor --from dbmr.schema.json
208
+
209
+ # 5. Preview what a regeneration would change
210
+ db-model-router diff --from dbmr.schema.json
211
+ ```
212
+
213
+ Or start a brand-new project from a schema file:
214
+
215
+ ```bash
216
+ # Scaffold project + generate everything in one go
217
+ db-model-router init --from dbmr.schema.json --yes --no-install
218
+ db-model-router generate --from dbmr.schema.json
219
+ ```
220
+
221
+ ### Command Reference
222
+
223
+ #### `init`
224
+
225
+ Scaffold a new project from a schema file or interactively. Generates an ESM-based project (`"type": "module"` in package.json) with Docker support.
226
+
227
+ | Flag / Arg | Description |
228
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
229
+ | `--from <path>` | Read adapter, framework, and options from a `dbmr.schema.json` file |
230
+ | `--framework <name>` | Express framework: `express` or `ultimate-express` |
231
+ | `--database <name>` | Database adapter: `mysql`, `mariadb`, `postgres`, `sqlite3`, `mongodb`, `mssql`, `cockroachdb`, `oracle`, `redis`, `dynamodb` |
232
+ | `--db <name>` | Alias for `--database` |
233
+ | `--session <type>` | Session store: `memory`, `redis`, `database` |
234
+ | `--output <dir>` | Directory for backend source files (relative to cwd). `package.json` and `app.js` stay in root; `commons/`, `route/`, `middleware/`, `migrations/` go inside this folder. |
235
+ | `--rateLimiting` | Enable rate limiting via `express-rate-limit` (default: yes) |
236
+ | `--helmet` | Enable Helmet security headers (default: yes) |
237
+ | `--logger` | Enable Winston request logger (default: yes) |
238
+ | `--loki` | Enable Grafana Loki log transport + Loki/Grafana in docker-compose (default: no, only asked when `--logger` is enabled) |
239
+
240
+ ```bash
241
+ # Non-interactive with output directory
242
+ db-model-router init --framework express --database postgres --output backend --yes
243
+
244
+ # With Loki logging
245
+ db-model-router init --database postgres --logger --loki --yes
246
+
247
+ # From schema, skip install
248
+ db-model-router init --from dbmr.schema.json --yes --no-install
249
+
250
+ # Dry run to preview files
251
+ db-model-router init --from dbmr.schema.json --dry-run
252
+ ```
253
+
254
+ Generated project structure (with `--output backend`):
255
+
256
+ ```
257
+ ├── package.json # root (type: "module")
258
+ ├── app.js # ESM entry point
259
+ ├── .env / .env.example
260
+ ├── .gitignore
261
+ ├── Dockerfile # node:alpine production image
262
+ ├── .dockerignore
263
+ ├── docker-compose.yml # database + CloudBeaver + optional Loki/Grafana
264
+ ├── .cloudbeaver/
265
+ │ └── data-sources.json # auto-connects CloudBeaver to your DB
266
+ ├── .grafana/ # (only when --loki)
267
+ │ └── datasources.yml # auto-connects Grafana to Loki
268
+ └── backend/
269
+ ├── commons/
270
+ │ ├── db.js # database init, connect, global.db
271
+ │ ├── session.js # session configuration
272
+ │ ├── security.js # helmet, rate limiting, custom headers
273
+ │ ├── migrate.js # migration runner (importable + standalone script)
274
+ │ └── add_migration.js # migration creator (importable + standalone script)
275
+ ├── middleware/
276
+ │ └── logger.js # Winston logger (+ Loki transport when LOKI_HOST is set)
277
+ ├── route/
278
+ │ ├── index.js # central route mounting
279
+ │ └── health.js # GET /health with DB connectivity check
280
+ └── migrations/
281
+ └── <timestamp>_create_migrations_table.sql
282
+ ```
283
+
284
+ Docker services included automatically:
285
+
286
+ | Service | When | Port | Description |
287
+ | ----------- | ------------------------------------- | ------ | -------------------------------------- |
288
+ | Database | Always (except sqlite3) | Varies | Selected database with random password |
289
+ | Redis | `--session redis` (if DB isn't redis) | 6379 | Session store |
290
+ | CloudBeaver | SQL/MongoDB databases | 8978 | Web-based DB admin, auto-connected |
291
+ | Loki | `--loki` | 3100 | Log aggregation |
292
+ | Grafana | `--loki` | 3001 | Log visualization, Loki pre-configured |
293
+
294
+ npm scripts added: `start`, `dev`, `test`, `migrate`, `add_migration`, `docker:build`, `docker:up`, `docker:down`.
295
+
296
+ #### `inspect`
297
+
298
+ Introspect a live database and produce a `dbmr.schema.json` file.
299
+
300
+ | Flag / Arg | Description |
301
+ | ------------------ | ---------------------------------------------------------------------------------------------------------------------- |
302
+ | `--type <adapter>` | Database adapter to introspect (required): `mysql`, `mariadb`, `postgres`, `sqlite3`, `mssql`, `oracle`, `cockroachdb` |
303
+ | `--env <path>` | Path to `.env` file for database connection parameters |
304
+ | `--out <path>` | Output file path (default: `dbmr.schema.json`) |
305
+ | `--tables <list>` | Comma-separated list of tables to include (omit for all) |
306
+
307
+ ```bash
308
+ db-model-router inspect --type postgres --env .env
309
+ db-model-router inspect --type sqlite3 --out schema.json --tables users,posts
310
+ db-model-router inspect --type mysql --json
311
+ ```
312
+
313
+ #### `generate`
314
+
315
+ Generate models, routes, tests, OpenAPI spec, and LLM docs from a schema file. All generated code is ESM (`import`/`export`).
316
+
317
+ | Flag / Arg | Description |
318
+ | --------------- | ------------------------------------------------------------ |
319
+ | `--from <path>` | Path to schema file (default: `dbmr.schema.json`) |
320
+ | `--models` | Generate only model files |
321
+ | `--routes` | Generate only route files (including child routes and index) |
322
+ | `--openapi` | Generate only OpenAPI spec |
323
+ | `--tests` | Generate only test files |
324
+ | `--llm-docs` | Generate only LLM documentation (`llms.txt` + `docs/llm.md`) |
325
+
326
+ When no artifact flags are provided, all artifact types are generated.
327
+
328
+ ```bash
329
+ db-model-router generate --from dbmr.schema.json
330
+ db-model-router generate --models --dry-run
331
+ db-model-router generate --routes --tests
332
+ db-model-router generate --from dbmr.schema.json --json
333
+ ```
334
+
335
+ #### `doctor`
336
+
337
+ Validate schema, check adapter driver dependencies, and verify generated files are in sync.
338
+
339
+ | Flag / Arg | Description |
340
+ | --------------- | ------------------------------------------------- |
341
+ | `--from <path>` | Path to schema file (default: `dbmr.schema.json`) |
342
+
343
+ ```bash
344
+ db-model-router doctor --from dbmr.schema.json
345
+ db-model-router doctor --json
346
+ ```
347
+
348
+ Reports three checks: schema validation, dependency check, sync check.
349
+
350
+ #### `diff`
351
+
352
+ Preview changes between the current generated files and what the schema would produce. Read-only.
353
+
354
+ | Flag / Arg | Description |
355
+ | --------------- | ------------------------------------------------- |
356
+ | `--from <path>` | Path to schema file (default: `dbmr.schema.json`) |
357
+
358
+ ```bash
359
+ db-model-router diff --from dbmr.schema.json
360
+ db-model-router diff --json
361
+ ```
362
+
363
+ #### `help`
364
+
365
+ Show help for any command.
366
+
367
+ ```bash
368
+ db-model-router help # general overview with per-command flags
369
+ db-model-router help init # detailed help for init
370
+ db-model-router init --help # same as above
371
+ ```
372
+
58
373
  ## MySQL Example
59
374
 
60
375
  ### 1. Connect
@@ -109,13 +424,14 @@ app.use("/users", route(users));
109
424
  app.listen(3000);
110
425
  ```
111
426
 
112
- This creates 8 endpoints:
427
+ This creates 9 endpoints:
113
428
 
114
429
  | Method | Path | Description |
115
430
  | ------ | ------------ | ------------------------------- |
116
431
  | GET | `/users/:id` | Get one record by PK |
117
432
  | POST | `/users/add` | Insert a single record |
118
433
  | PUT | `/users/:id` | Update a single record |
434
+ | PATCH | `/users/:id` | Partial update a single record |
119
435
  | DELETE | `/users/:id` | Delete a single record |
120
436
  | GET | `/users/` | List with pagination |
121
437
  | POST | `/users/` | Bulk insert (`{ data: [...] }`) |
@@ -274,207 +590,6 @@ The model and route APIs remain identical across all adapters. See the individua
274
590
  - [Redis](./docs/adapters/redis.md)
275
591
  - [DynamoDB](./docs/adapters/dynamodb.md)
276
592
 
277
- ## CLI Tools
278
-
279
- Three CLI commands are included to scaffold models, routes, and full apps from an existing database.
280
-
281
- ### generate-app
282
-
283
- The fastest way to go from database to running API. Scaffolds a complete Express REST API project in a single command — introspects your database, generates models and routes (including parent-child relationships), and creates the app entry point, middleware, environment config, and project structure.
284
-
285
- ```bash
286
- # Full app from MySQL
287
- db-model-router-generate-app --type mysql --env .env
288
-
289
- # SQLite3 into a specific directory
290
- db-model-router-generate-app --type sqlite3 --database ./myapp.db --output ./my-api
291
-
292
- # Postgres with specific tables and relationships
293
- db-model-router-generate-app --type postgres --env .env --tables users,posts,posts.comments
294
- ```
295
-
296
- Options:
297
-
298
- | Option | Description |
299
- | ------------ | ------------------------------------------------------------------------------- |
300
- | `--type` | Database type (mysql, postgres, sqlite3, mssql, oracle, cockroachdb) [required] |
301
- | `--output` | Output directory (default: current directory) |
302
- | `--host` | Database host |
303
- | `--port` | Database port |
304
- | `--database` | Database name or file path |
305
- | `--user` | Database user |
306
- | `--password` | Database password |
307
- | `--schema` | Schema name (postgres only) |
308
- | `--tables` | Comma-separated tables, supports `parent.child` notation for relationships |
309
- | `--env` | Path to .env file for DB connection |
310
-
311
- Generated project structure:
312
-
313
- ```
314
- my-api/
315
- app.js # Express app with init(), db.connect(), middleware, error handler, health check
316
- .env.example # Pre-filled environment template for your DB type
317
- .gitignore # node_modules, .env, *.db
318
- middleware/
319
- logger.js # Request logger (method, URL, status, response time)
320
- models/
321
- users.js # Auto-generated from DB introspection
322
- posts.js
323
- index.js
324
- routes/
325
- users.js # Auto-generated route files
326
- posts.js
327
- index.js
328
- openapi.json # OpenAPI 3.0 spec
329
- migrations/
330
- README.md # Placeholder for migration scripts
331
- sessions/
332
- README.md # Placeholder for session config
333
- ```
334
-
335
- When `--tables` includes parent-child notation (e.g., `posts.comments`), the routes directory also includes scoped child route files and nested route mounting — see [Parent-Child Relationships](#parent-child-relationships-foreign-keys) below.
336
-
337
- To start the generated app:
338
-
339
- ```bash
340
- cp .env.example .env # edit with your DB credentials
341
- npm install
342
- node app.js
343
- ```
344
-
345
- ### generate-model
346
-
347
- Connects to your database, introspects all tables, and generates model files with validation rules, primary keys, unique constraints, and auto-detected options (safeDelete, timestamps). This is called automatically by `generate-app`, but can be used standalone.
348
-
349
- ```bash
350
- # Basic usage
351
- db-model-router-generate-model --type mysql --host localhost --database mydb --user root --password secret
352
-
353
- # Using an .env file
354
- db-model-router-generate-model --type postgres --env .env --output ./src/models
355
-
356
- # SQLite3
357
- db-model-router-generate-model --type sqlite3 --database ./myapp.db --output ./models
358
-
359
- # Only specific tables
360
- db-model-router-generate-model --type mysql --env .env --tables users,posts,comments
361
- ```
362
-
363
- Options:
364
-
365
- | Option | Description |
366
- | ------------ | ----------------------------------------------------------------------------- |
367
- | `--type` | Database type (mysql, postgres, sqlite3, mssql, oracle, cockroachdb) |
368
- | `--host` | Database host (default: localhost) |
369
- | `--port` | Database port |
370
- | `--database` | Database name (or file path for sqlite3) |
371
- | `--user` | Database user |
372
- | `--password` | Database password |
373
- | `--schema` | Schema name (postgres only, default: public) |
374
- | `--output` | Output directory (default: ./models) |
375
- | `--tables` | Comma-separated list of tables to generate (supports `parent.child` notation) |
376
- | `--env` | Path to .env file to load |
377
-
378
- Auto-detection:
379
-
380
- - Columns with `DEFAULT` values are marked as optional (not `required`)
381
- - Timestamp columns (`created_at`, `updated_at`, `modified_at`, `createdAt`, etc.) are excluded from the model structure and added to the option object
382
- - Soft-delete columns (`is_deleted`, `deleted`, `is_active`, `archived`, etc.) are excluded from the structure and set as `safeDelete` in the option
383
- - Multi-column unique indexes are correctly grouped for the unique constraint parameter
384
-
385
- Generated output:
386
-
387
- ```
388
- models/
389
- users.js # model(db, "users", {...}, "user_id", ["email"], { safeDelete: "is_deleted", ... })
390
- posts.js # model(db, "posts", {...}, "post_id", ["post_id"])
391
- index.js # exports { users, posts }
392
- ```
393
-
394
- ### generate-route
395
-
396
- Generates Express route files for each model. If models don't exist yet, it auto-generates them first. Also generates an OpenAPI 3.0 spec (`openapi.json`) from the model metadata. This is called automatically by `generate-app`, but can be used standalone.
397
-
398
- ```bash
399
- # From existing models
400
- db-model-router-generate-route --models ./models --output ./routes
401
-
402
- # Auto-generate models + routes in one step
403
- db-model-router-generate-route --type mysql --env .env --models ./models --output ./routes
404
-
405
- # SQLite3 one-liner
406
- db-model-router-generate-route --type sqlite3 --database ./myapp.db
407
- ```
408
-
409
- Options:
410
-
411
- | Option | Description |
412
- | ------------ | -------------------------------------------------------------------------- |
413
- | `--models` | Path to models directory (default: ./models) |
414
- | `--output` | Output directory for routes (default: ./routes) |
415
- | `--type` | Database type — triggers model generation if models are missing |
416
- | `--host` | Database host (passed to model generation) |
417
- | `--port` | Database port (passed to model generation) |
418
- | `--database` | Database name or file path (passed to model generation) |
419
- | `--user` | Database user (passed to model generation) |
420
- | `--password` | Database password (passed to model generation) |
421
- | `--schema` | Schema name (passed to model generation) |
422
- | `--tables` | Comma-separated tables, supports `parent.child` notation for relationships |
423
- | `--env` | Path to .env file (passed to model generation) |
424
-
425
- #### Parent-Child Relationships (Foreign Keys)
426
-
427
- Use dot notation in `--tables` to declare parent-child relationships. This works in `generate-route`, `generate-app`, and `generate-model`. The generator creates nested routes that automatically scope child queries by the parent's foreign key.
428
-
429
- ```bash
430
- # Declare that comments belong to posts
431
- db-model-router-generate-route --type mysql --env .env --tables users,posts,posts.comments
432
-
433
- # Same via generate-app
434
- db-model-router-generate-app --type mysql --env .env --tables users,posts,posts.comments
435
- ```
436
-
437
- The FK column is derived by convention: `<parent_singular>_id` (e.g., `posts.comments` → `post_id`).
438
-
439
- This generates:
440
-
441
- ```
442
- routes/
443
- users.js # route(users)
444
- posts.js # route(posts)
445
- comments.js # route(comments) — direct access
446
- comments_child_of_posts.js # route(comments, { post_id: "params.post_id" }) — scoped
447
- index.js # mounts all routes
448
- openapi.json # OpenAPI 3.0 spec
449
- ```
450
-
451
- The generated `index.js` mounts both nested and top-level routes:
452
-
453
- ```js
454
- // Nested: GET /api/posts/:post_id/comments — returns only comments for that post
455
- router.use("/posts/:post_id/comments", commentsChildRoute);
456
-
457
- // Direct: GET /api/comments — returns all comments
458
- router.use("/comments", commentsRoute);
459
- ```
460
-
461
- The child route file uses payload override to scope every query:
462
-
463
- ```js
464
- // comments_child_of_posts.js
465
- module.exports = route(comments, { post_id: "params.post_id" });
466
- ```
467
-
468
- #### Generated output (without relationships)
469
-
470
- ```
471
- routes/
472
- users.js # route(users)
473
- posts.js # route(posts)
474
- index.js # express.Router() mounting all routes at /users, /posts, etc.
475
- openapi.json # OpenAPI 3.0 spec
476
- ```
477
-
478
593
  ## Environment Setup (Docker)
479
594
 
480
595
  A `docker-compose.yml` is included for running all supported databases locally: