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.
Files changed (92) hide show
  1. package/README.md +110 -16
  2. package/TODO.md +14 -0
  3. package/dbmr.schema.json +333 -0
  4. package/demo/.dockerignore +7 -0
  5. package/demo/.env.example +13 -0
  6. package/demo/Dockerfile +20 -0
  7. package/demo/app.js +37 -0
  8. package/demo/commons/add_migration.js +43 -0
  9. package/demo/commons/db.js +17 -0
  10. package/demo/commons/migrate.js +65 -0
  11. package/demo/commons/security.js +30 -0
  12. package/demo/commons/session.js +13 -0
  13. package/demo/dbmr.schema.json +362 -0
  14. package/demo/docs/llm.md +197 -0
  15. package/demo/llms.txt +70 -0
  16. package/demo/middleware/logger.js +67 -0
  17. package/demo/migrations/20260430155808_create_migrations_table.sql +6 -0
  18. package/demo/migrations/20260430155809_create_tables.sql +207 -0
  19. package/demo/models/addresses.js +22 -0
  20. package/demo/models/cart_items.js +18 -0
  21. package/demo/models/carts.js +16 -0
  22. package/demo/models/categories.js +20 -0
  23. package/demo/models/coupons.js +23 -0
  24. package/demo/models/order_items.js +21 -0
  25. package/demo/models/orders.js +25 -0
  26. package/demo/models/payments.js +21 -0
  27. package/demo/models/product_images.js +18 -0
  28. package/demo/models/product_reviews.js +20 -0
  29. package/demo/models/product_variants.js +20 -0
  30. package/demo/models/products.js +30 -0
  31. package/demo/models/shipments.js +19 -0
  32. package/demo/models/users.js +19 -0
  33. package/demo/models/wishlists.js +15 -0
  34. package/demo/openapi.json +5872 -0
  35. package/demo/package-lock.json +2810 -0
  36. package/demo/package.json +34 -0
  37. package/demo/routes/addresses.js +6 -0
  38. package/demo/routes/carts/cart_items.js +7 -0
  39. package/demo/routes/carts.js +6 -0
  40. package/demo/routes/categories.js +6 -0
  41. package/demo/routes/coupons.js +6 -0
  42. package/demo/routes/docs.js +18 -0
  43. package/demo/routes/health.js +35 -0
  44. package/demo/routes/index.js +39 -0
  45. package/demo/routes/orders/order_items.js +7 -0
  46. package/demo/routes/orders/payments.js +7 -0
  47. package/demo/routes/orders/shipments.js +7 -0
  48. package/demo/routes/orders.js +6 -0
  49. package/demo/routes/products/product_images.js +7 -0
  50. package/demo/routes/products/product_reviews.js +7 -0
  51. package/demo/routes/products/product_variants.js +7 -0
  52. package/demo/routes/products.js +6 -0
  53. package/demo/routes/users.js +6 -0
  54. package/demo/routes/wishlists.js +6 -0
  55. package/docker-compose.yml +1 -1
  56. package/package.json +8 -7
  57. package/scripts/demo-create.js +47 -0
  58. package/skill/SKILL.md +464 -0
  59. package/skill/references/cockroachdb.md +49 -0
  60. package/skill/references/dynamodb.md +53 -0
  61. package/skill/references/mongodb.md +56 -0
  62. package/skill/references/mssql.md +55 -0
  63. package/skill/references/oracle.md +52 -0
  64. package/skill/references/postgres.md +50 -0
  65. package/skill/references/redis.md +53 -0
  66. package/skill/references/sqlite3.md +43 -0
  67. package/src/cli/commands/generate.js +58 -17
  68. package/src/cli/commands/help.js +11 -6
  69. package/src/cli/commands/init.js +2 -2
  70. package/src/cli/commands/inspect.js +1 -0
  71. package/src/cli/diff-engine.js +52 -22
  72. package/src/cli/generate-docs-route.js +31 -0
  73. package/src/cli/generate-migration.js +356 -0
  74. package/src/cli/generate-route.js +52 -24
  75. package/src/cli/init/dependencies.js +3 -0
  76. package/src/cli/init/generators.js +1 -1
  77. package/src/cli/init.js +8 -8
  78. package/src/cockroachdb/db.js +90 -59
  79. package/src/commons/route.js +20 -20
  80. package/src/commons/validator.js +58 -1
  81. package/src/dynamodb/db.js +50 -27
  82. package/src/mongodb/db.js +1 -0
  83. package/src/mssql/db.js +89 -61
  84. package/src/mysql/db.js +1 -0
  85. package/src/oracle/db.js +1 -0
  86. package/src/postgres/db.js +61 -41
  87. package/src/redis/db.js +1 -0
  88. package/src/schema/schema-parser.js +43 -1
  89. package/src/schema/schema-printer.js +7 -0
  90. package/src/schema/schema-validator.js +17 -0
  91. package/src/sqlite3/db.js +1 -0
  92. package/docs/SKILL.md +0 -419
package/skill/SKILL.md ADDED
@@ -0,0 +1,464 @@
1
+ ---
2
+ name: db-model-router
3
+ description: Use this skill whenever the user wants to build a REST API with Node.js/Express backed by any database — including MySQL, PostgreSQL, SQLite, MongoDB, MSSQL, Oracle, Redis, DynamoDB, or CockroachDB. Trigger on any mention of db-model-router, or when the user asks to scaffold, generate, or wire up a CRUD API, models, or routes for a Node/Express backend. Also trigger when the user asks about connecting to a specific database with db-model-router, model definitions, filter syntax, bulk operations, schema-driven generation, or CLI commands like init/generate/inspect/doctor/diff.
4
+ ---
5
+
6
+ # db-model-router — LLM Skill Reference
7
+
8
+ Database-agnostic REST API generator for Node.js/Express. Define a model → get full CRUD + Express routes. 10 adapters, identical API. Generated projects use ESM (`import`/`export`).
9
+
10
+ ## Adapter Reference Files
11
+
12
+ For adapter-specific connection options, env vars, upsert behavior, and table creation SQL, read the relevant file **on demand** (only when the user's task involves that adapter):
13
+
14
+ | Adapter | Reference File |
15
+ | ------------- | --------------------------- |
16
+ | `postgres` | `references/postgres.md` |
17
+ | `cockroachdb` | `references/cockroachdb.md` |
18
+ | `sqlite3` | `references/sqlite3.md` |
19
+ | `mongodb` | `references/mongodb.md` |
20
+ | `mssql` | `references/mssql.md` |
21
+ | `oracle` | `references/oracle.md` |
22
+ | `redis` | `references/redis.md` |
23
+ | `dynamodb` | `references/dynamodb.md` |
24
+
25
+ MySQL/MariaDB use `mysql2` — no separate reference file needed (see Connection Configs below).
26
+
27
+ ---
28
+
29
+ ## LLM Workflow (follow this order for new projects)
30
+
31
+ 1. **Scaffold**: `db-model-router init --framework express --database postgres --session redis --rateLimiting --helmet --logger --yes`
32
+ 2. **Start infra**: `npm run docker:up`
33
+ 3. **Migrations**: Write SQL/JS files into `migrations/`, then `npm run migrate`
34
+ 4. **Generate models**: `db-model-router generate --from dbmr.schema.json --models`
35
+ 5. **Generate routes + tests**: `db-model-router generate --from dbmr.schema.json --routes --tests`
36
+ 6. **Run**: `npm run dev`
37
+
38
+ For existing databases, use `inspect` first:
39
+
40
+ ```bash
41
+ db-model-router inspect --type postgres --env .env # → writes dbmr.schema.json
42
+ db-model-router generate --from dbmr.schema.json # → models, routes, tests, OpenAPI
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ npm install db-model-router <framework> <driver>
51
+ ```
52
+
53
+ Frameworks: `express` or `ultimate-express` (auto-detected; prefers ultimate-express when both present).
54
+
55
+ | Adapter | Driver | Install |
56
+ | ------------- | ------------------------------------------------ | ---------------------------------------------------------------------- |
57
+ | `mysql` | mysql2 | `npm i db-model-router mysql2` |
58
+ | `mariadb` | mysql2 | `npm i db-model-router mysql2` |
59
+ | `postgres` | pg | `npm i db-model-router pg` |
60
+ | `sqlite3` | better-sqlite3 | `npm i db-model-router better-sqlite3` |
61
+ | `mongodb` | mongodb | `npm i db-model-router mongodb` |
62
+ | `mssql` | mssql | `npm i db-model-router mssql` |
63
+ | `cockroachdb` | pg | `npm i db-model-router pg` |
64
+ | `oracle` | oracledb | `npm i db-model-router oracledb` |
65
+ | `redis` | ioredis | `npm i db-model-router ioredis` |
66
+ | `dynamodb` | @aws-sdk/client-dynamodb + @aws-sdk/lib-dynamodb | `npm i db-model-router @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb` |
67
+
68
+ ---
69
+
70
+ ## Init → Connect → Model → Route
71
+
72
+ ```js
73
+ // CJS
74
+ const { init, db, model, route } = require("db-model-router");
75
+
76
+ // ESM (generated projects)
77
+ import dbModelRouter from "db-model-router";
78
+ const { init, db, model, route } = dbModelRouter;
79
+
80
+ init("postgres"); // call BEFORE db.connect() — do NOT destructure db before init()
81
+ db.connect({ host, port: 5432, user, password, database });
82
+
83
+ const users = model(
84
+ db,
85
+ "users",
86
+ {
87
+ name: "required|string",
88
+ email: "required|string",
89
+ age: "integer",
90
+ meta: "object",
91
+ },
92
+ "id", // primary key column
93
+ ["email"], // unique columns (for upsert conflict)
94
+ {
95
+ safeDelete: "is_deleted", // soft-delete column
96
+ created_at: "created_at", // auto-managed timestamp
97
+ modified_at: "updated_at", // auto-managed timestamp
98
+ },
99
+ );
100
+
101
+ app.use("/users", route(users));
102
+ ```
103
+
104
+ > **Critical**: Call `init()` before `db.connect()`. Default adapter is `mysql`. Do NOT destructure `db` before `init()` — it is a getter.
105
+ > **ESM note**: The library is CJS. Generated ESM projects must use default import (above) — NOT named `import { init }`.
106
+
107
+ For adapter-specific connect options (ports, env vars, upsert behavior), read the relevant file from `references/`.
108
+
109
+ ---
110
+
111
+ ## model(db, table, structure, pk, unique, option)
112
+
113
+ | Param | Type | Description |
114
+ | ----------- | --------------- | --------------------------------------------------------------------------------------------------------------- |
115
+ | `structure` | `{col: "rule"}` | Types: `string\|integer\|numeric\|boolean\|object\|datetime\|auto_increment`. Prefix `required\|` for NOT NULL. |
116
+ | `pk` | string | Primary key column. Convention: `<table>_id` |
117
+ | `unique` | string[] | Columns for upsert conflict resolution |
118
+ | `option` | object | `{ safeDelete, created_at, modified_at }` — column names or null |
119
+
120
+ > PK, timestamp, soft-delete, and `auto_increment` cols are auto-excluded from insert/update payloads.
121
+
122
+ ---
123
+
124
+ ## Model Methods (all async)
125
+
126
+ ```js
127
+ // INSERT
128
+ await m.insert({ name: "Alice", email: "a@b.com", age: 30 }) // → {id:1, name:"Alice", ...}
129
+ await m.insert({ data: [{...}, {...}] }) // → {rows:2, message, type:"success"}
130
+
131
+ // UPDATE — PK required in payload
132
+ await m.update({ id: 1, name: "Alice V2", email: "a@b.com", age: 31 })
133
+ await m.update({ data: [{id:1,...}, {id:2,...}] })
134
+
135
+ // PATCH — partial update, only sends changed fields, PK required
136
+ await m.patch({ id: 1, age: 35 }) // → full merged record
137
+
138
+ // UPSERT — PK optional, uses unique cols for conflict
139
+ await m.upsert({ email: "new@b.com", name: "New", age: 20 })
140
+
141
+ // READ
142
+ await m.byId(1) // → record or null
143
+ await m.find({ name: "Alice" }) // → {data:[], count}
144
+ await m.findOne({ email: "a@b.com" }) // → record or false
145
+ await m.list({ page: 0, size: 10, sort: ["-age"] }) // → {data:[], count}
146
+
147
+ // DELETE — safeDelete: sets column=1; without: hard delete
148
+ await m.remove(1)
149
+ await m.remove({ name: "Bob" })
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Filter Syntax
155
+
156
+ Structure: `[OR_groups[AND_conditions[col, op, val]]]`
157
+ Operators: `= != < > <= >= LIKE NOT LIKE IN NOT IN`
158
+
159
+ ```js
160
+ // AND: age > 25 AND type = 1
161
+ [
162
+ [
163
+ ["age", ">", 25],
164
+ ["type", "=", 1],
165
+ ],
166
+ ][
167
+ // OR: name = "A" OR name = "B"
168
+ ([["name", "=", "A"]], [["name", "=", "B"]])
169
+ ][
170
+ // IN
171
+ [["type", "in", [1, 2, 3]]]
172
+ ][
173
+ // LIKE (auto-wraps with %)
174
+ [["name", "like", "Ali"]]
175
+ ];
176
+ ```
177
+
178
+ ### Query Parameter Filter Operators
179
+
180
+ When using `GET /` (list endpoint), query parameters are automatically parsed into filter conditions. Special value prefixes and patterns control the operator:
181
+
182
+ | Query Param Value | Operator | Example | Resulting Filter |
183
+ | ------------------ | ---------- | ----------------------------- | ------------------------------------ |
184
+ | `value` | `=` | `?name=john` | `name = 'john'` |
185
+ | `!value` | `!=` | `?name=!john` | `name != 'john'` |
186
+ | `>value` | `>` | `?age=>25` | `age > 25` |
187
+ | `>=value` (`>%3D`) | `>=` | `?age=>%3D25` | `age >= 25` |
188
+ | `<value` | `<` | `?age=<25` | `age < 25` |
189
+ | `<=value` (`<%3D`) | `<=` | `?age=<%3D25` | `age <= 25` |
190
+ | `%value%` (`%25`) | `LIKE` | `?name=%25john%25` | `name LIKE '%john%'` |
191
+ | `!%value%` | `NOT LIKE` | `?name=!%25john%25` | `name NOT LIKE '%john%'` |
192
+ | `in(a,b,c)` | `IN` | `?status=in(active,pending)` | `status IN ('active','pending')` |
193
+ | `!in(a,b,c)` | `NOT IN` | `?status=!in(active,pending)` | `status NOT IN ('active','pending')` |
194
+
195
+ `%` is URL-encoded as `%25`; `=` in `>=`/`<=` is URL-encoded as `%3D`. `LIKE` patterns follow SQL conventions: `%25john%25` → contains, `%25john` → ends with, `john%25` → starts with. `IN`/`NOT IN` values are comma-separated inside parentheses.
196
+
197
+ ---
198
+
199
+ ## route(model, override?)
200
+
201
+ Generates an Express Router with 9 endpoints:
202
+
203
+ | Method | Path | Action |
204
+ | ------ | ------ | -------------------------------- |
205
+ | GET | `/:pk` | Get by PK |
206
+ | POST | `/add` | Insert single |
207
+ | PUT | `/:pk` | Update single (PK from URL) |
208
+ | PATCH | `/:pk` | Partial update (PK from URL) |
209
+ | DELETE | `/:pk` | Delete single |
210
+ | GET | `/` | List (page, size, sort, filters) |
211
+ | POST | `/` | Bulk insert `{data:[...]}` |
212
+ | PUT | `/` | Bulk update `{data:[...]}` |
213
+ | DELETE | `/` | Bulk delete `{filter_object}` |
214
+
215
+ **Payload override** (multi-tenancy): `route(m, { tenant_id: "user.tenant_id" })` — maps columns to `req` paths via lodash.get.
216
+
217
+ **Query params**: `select_columns=name,email`, `output_content_type=csv|xml|json`, `sort=-age,name`
218
+
219
+ ---
220
+
221
+ ## CLI Reference
222
+
223
+ ```bash
224
+ db-model-router <command> [options]
225
+ db-model-router help <command>
226
+ ```
227
+
228
+ ### `init` — Scaffold project
229
+
230
+ ```bash
231
+ # Fully non-interactive (LLM-friendly)
232
+ db-model-router init --framework express --database postgres --session redis \
233
+ --rateLimiting --helmet --logger --yes
234
+
235
+ # With Loki/Grafana logging
236
+ db-model-router init --database postgres --logger --loki --yes
237
+
238
+ # From schema file
239
+ db-model-router init --from dbmr.schema.json --yes --no-install
240
+ ```
241
+
242
+ Key flags: `--framework`, `--database` (or `--db`), `--session`, `--output`, `--rateLimiting`, `--helmet`, `--logger`, `--loki`, `--yes`, `--no-install`
243
+
244
+ Generated structure (ESM, `"type":"module"`):
245
+
246
+ ```
247
+ app.js Express entry point
248
+ .env / .env.example Env config (random passwords)
249
+ docker-compose.yml DB + CloudBeaver + optional Loki/Grafana
250
+ <output>/commons/db.js Database init + global.db
251
+ <output>/commons/migrate.js Migration runner
252
+ <output>/route/index.js Central route mounting
253
+ <output>/route/health.js GET /health endpoint
254
+ <output>/migrations/ Initial migration files
255
+ ```
256
+
257
+ Docker services auto-generated: database, Redis (if session=redis), CloudBeaver (SQL/MongoDB, port 8978), Loki + Grafana (if --loki).
258
+
259
+ Scripts: `start`, `dev`, `test`, `migrate`, `add_migration`, `docker:build`, `docker:up`, `docker:down`.
260
+
261
+ ### `inspect` — Introspect existing DB → schema
262
+
263
+ ```bash
264
+ db-model-router inspect --type postgres --env .env [--out schema.json] [--tables t1,t2]
265
+ ```
266
+
267
+ ### `generate` — Generate code from schema
268
+
269
+ ```bash
270
+ db-model-router generate --from dbmr.schema.json [--models] [--routes] [--openapi] [--tests] [--llm-docs]
271
+ ```
272
+
273
+ No flags = generate all.
274
+
275
+ ### `doctor` — Validate schema + check file sync
276
+
277
+ ```bash
278
+ db-model-router doctor [--from dbmr.schema.json] [--json]
279
+ ```
280
+
281
+ ### `diff` — Preview changes without writing
282
+
283
+ ```bash
284
+ db-model-router diff [--from dbmr.schema.json] [--json]
285
+ ```
286
+
287
+ Universal flags (all commands): `--yes`, `--json`, `--dry-run`, `--no-install`, `--help`
288
+
289
+ ---
290
+
291
+ ## Schema-Driven Workflow (dbmr.schema.json)
292
+
293
+ ```json
294
+ {
295
+ "adapter": "postgres",
296
+ "framework": "express",
297
+ "options": {
298
+ "session": "redis",
299
+ "rateLimiting": true,
300
+ "helmet": true,
301
+ "logger": true
302
+ },
303
+ "tables": {
304
+ "users": {
305
+ "columns": {
306
+ "user_id": "auto_increment",
307
+ "name": "required|string",
308
+ "email": "required|string",
309
+ "is_deleted": "boolean",
310
+ "created_at": "datetime",
311
+ "updated_at": "datetime"
312
+ },
313
+ "pk": "user_id",
314
+ "unique": ["email"],
315
+ "softDelete": "is_deleted",
316
+ "timestamps": { "created_at": "created_at", "modified_at": "updated_at" },
317
+ "parent": null
318
+ },
319
+ "posts": {
320
+ "columns": {
321
+ "post_id": "auto_increment",
322
+ "title": "required|string",
323
+ "user_id": "required|integer",
324
+ "created_at": "datetime"
325
+ },
326
+ "pk": "post_id",
327
+ "unique": ["post_id"],
328
+ "parent": null
329
+ },
330
+ "comments": {
331
+ "columns": {
332
+ "comment_id": "auto_increment",
333
+ "post_id": "required|integer",
334
+ "user_id": "required|integer",
335
+ "body": "required|string"
336
+ },
337
+ "pk": "comment_id",
338
+ "unique": ["comment_id"],
339
+ "parent": "posts"
340
+ }
341
+ }
342
+ }
343
+ ```
344
+
345
+ ### `parent` field rules
346
+
347
+ - `"parent": null` → top-level route: `/comments/`
348
+ - `"parent": "posts"` → nested route: `/posts/:post_id/comments/` (also mounted at top-level for direct access)
349
+ - **Do NOT use system tables as parents** (`users`, `tenants`, `roles`, `permissions`, `sessions`, `accounts`, `auth_tokens`). They are cross-cutting and referenced via FK columns — not route hierarchies. Only use `parent` for true domain hierarchies: `posts → comments`, `orders → order_items`, `projects → tasks`.
350
+
351
+ ### Column Rules
352
+
353
+ Format: `(required|)?(string|integer|numeric|boolean|object|datetime|auto_increment)`
354
+
355
+ Include ALL columns in schema (PK, timestamps, softDelete). The generator auto-excludes them from model `structure`.
356
+
357
+ ### Table Fields
358
+
359
+ | Field | Required | Description |
360
+ | ------------ | -------- | ------------------------------------------------ |
361
+ | `columns` | Yes | All columns including PK, timestamps, softDelete |
362
+ | `pk` | Yes | Primary key (convention: `<table>_id`) |
363
+ | `unique` | No | Unique constraint columns (default: `[pk]`) |
364
+ | `softDelete` | No | Column name for soft-delete |
365
+ | `timestamps` | No | `{ created_at, modified_at }` column mapping |
366
+ | `parent` | No | Parent table for route nesting, or `null` |
367
+
368
+ ---
369
+
370
+ ## Connection Configs (quick reference)
371
+
372
+ For full details (env vars, upsert behavior, notes), read the adapter reference file.
373
+
374
+ ```js
375
+ // MySQL / MariaDB (default adapter)
376
+ init("mysql");
377
+ db.connect({
378
+ host,
379
+ port: 3306,
380
+ user,
381
+ password,
382
+ database,
383
+ connectionLimit: 100,
384
+ });
385
+
386
+ // PostgreSQL — see references/postgres.md
387
+ init("postgres");
388
+ db.connect({ host, port: 5432, user, password, database });
389
+
390
+ // SQLite3 — see references/sqlite3.md
391
+ init("sqlite3");
392
+ db.connect({ database: "./file.db" }); // or ":memory:"
393
+
394
+ // MongoDB — see references/mongodb.md
395
+ init("mongodb");
396
+ db.connect({ host, port: 27017, username, password, database });
397
+ // or: db.connect({ uri: "mongodb://user:pass@host:27017/db" })
398
+
399
+ // MSSQL — see references/mssql.md (db.connect is async — use await)
400
+ init("mssql");
401
+ await db.connect({
402
+ server: host,
403
+ port: 1433,
404
+ user,
405
+ password,
406
+ database,
407
+ options: { encrypt: false, trustServerCertificate: true },
408
+ });
409
+
410
+ // Oracle — see references/oracle.md
411
+ init("oracle");
412
+ db.connect({ host, port: 1521, user, password, database });
413
+
414
+ // Redis — see references/redis.md
415
+ init("redis");
416
+ db.connect({ host, port: 6379, password });
417
+
418
+ // DynamoDB — see references/dynamodb.md
419
+ init("dynamodb");
420
+ db.connect({ region, endpoint, accessKeyId, secretAccessKey });
421
+
422
+ // CockroachDB — see references/cockroachdb.md
423
+ init("cockroachdb");
424
+ db.connect({ host, port: 26257, user, password, database });
425
+ ```
426
+
427
+ ---
428
+
429
+ ## Environment Variables by Database
430
+
431
+ | Database | Variables |
432
+ | ----------- | ---------------------------------------------------------------------- |
433
+ | mysql | `PORT DB_HOST DB_PORT=3306 DB_NAME DB_USER DB_PASS` |
434
+ | mariadb | `PORT DB_HOST DB_PORT=3306 DB_NAME DB_USER DB_PASS` |
435
+ | postgres | `PORT DB_HOST DB_PORT=5432 DB_NAME DB_USER DB_PASS` |
436
+ | cockroachdb | `PORT DB_HOST DB_PORT=26257 DB_NAME DB_USER DB_PASS` |
437
+ | sqlite3 | `PORT DB_NAME=./data/data.db` |
438
+ | mongodb | `PORT DB_HOST DB_PORT=27017 DB_NAME DB_USER DB_PASS` |
439
+ | mssql | `PORT DB_HOST DB_PORT=1433 DB_NAME DB_USER DB_PASS` |
440
+ | oracle | `PORT DB_HOST DB_PORT=1521 DB_NAME DB_USER DB_PASS` |
441
+ | redis | `PORT DB_HOST DB_PORT=6379 DB_PASS` |
442
+ | dynamodb | `PORT AWS_REGION AWS_ENDPOINT AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY` |
443
+
444
+ When `session=redis` and database ≠ redis: adds `REDIS_HOST REDIS_PORT REDIS_PASS`.
445
+ When `logger=true`: adds `APP_NAME LOG_LEVEL LOKI_HOST`.
446
+
447
+ ---
448
+
449
+ ## Rules
450
+
451
+ 1. `init()` before `db.connect()`. Don't destructure `db` before `init()` — it's a getter.
452
+ 2. Generated projects are ESM. The library is CJS. Use default import: `import dbModelRouter from "db-model-router"; const { init, db } = dbModelRouter;`
453
+ 3. `model structure` excludes: PK, timestamps, soft-delete, and `auto_increment` cols — the generator handles this.
454
+ 4. `update()`/`patch()` require PK in payload. `upsert()` PK is optional.
455
+ 5. `findOne()` returns `false` on no match. `byId()` returns `null`.
456
+ 6. Bulk ops wrap in `{ data: [...] }`. Single ops use flat object.
457
+ 7. Timestamps auto-stripped from payloads — DB handles defaults/triggers.
458
+ 8. `safeDelete` makes `remove()` soft-delete; all reads auto-filter deleted rows.
459
+ 9. `list()` defaults: page=0, size=30. `sort` array: `["-col"]` for DESC.
460
+ 10. `global.db` is set by `commons/db.js` — accessible anywhere without imports.
461
+ 11. Logger dynamically loads `winston-loki` only when `LOKI_HOST` env var is set.
462
+ 12. Docker passwords are randomly generated and shared between `.env` and `docker-compose.yml`.
463
+ 13. PK convention: `<table>_id` (e.g. `user_id`, `post_id`). Include ALL columns in schema.
464
+ 14. Use `parent` only for domain hierarchies (e.g. `posts → comments`), not system tables.
@@ -0,0 +1,49 @@
1
+ # CockroachDB Adapter
2
+
3
+ Uses the [pg](https://www.npmjs.com/package/pg) driver (CockroachDB is PostgreSQL wire-compatible).
4
+
5
+ ## Connection
6
+
7
+ ```js
8
+ const { init, db, model, route } = require("db-model-router");
9
+ init("cockroachdb");
10
+
11
+ db.connect({
12
+ host: "localhost",
13
+ port: 26257,
14
+ database: "defaultdb",
15
+ user: "root",
16
+ password: "",
17
+ });
18
+ ```
19
+
20
+ ## Environment Variables
21
+
22
+ ```env
23
+ CRDB_HOST=localhost
24
+ CRDB_PORT=26257
25
+ CRDB_NAME=defaultdb
26
+ CRDB_USER=root
27
+ CRDB_PASS=
28
+ ```
29
+
30
+ ## Notes
31
+
32
+ - `SERIAL` columns use CockroachDB's `unique_rowid()` which generates INT8 values
33
+ - Large INT8 values that exceed `Number.MAX_SAFE_INTEGER` are kept as strings to preserve precision
34
+ - Includes automatic retry logic for transient connection errors
35
+ - Uses `ON CONFLICT` for upsert operations
36
+ - Run with `--insecure` flag for local development (see docker-compose.yml)
37
+
38
+ ## Table Creation
39
+
40
+ ```sql
41
+ CREATE TABLE users (
42
+ id SERIAL PRIMARY KEY,
43
+ name VARCHAR NOT NULL,
44
+ email VARCHAR NOT NULL,
45
+ age INTEGER NOT NULL
46
+ );
47
+ ```
48
+
49
+ [← Back to main docs](../../README.md)
@@ -0,0 +1,53 @@
1
+ # DynamoDB Adapter
2
+
3
+ Uses [@aws-sdk/client-dynamodb](https://www.npmjs.com/package/@aws-sdk/client-dynamodb) and [@aws-sdk/lib-dynamodb](https://www.npmjs.com/package/@aws-sdk/lib-dynamodb).
4
+
5
+ ## Connection
6
+
7
+ ```js
8
+ const { init, db, model, route } = require("db-model-router");
9
+ init("dynamodb");
10
+
11
+ db.connect({
12
+ region: "us-east-1",
13
+ // For local development (DynamoDB Local):
14
+ endpoint: "http://localhost:8000",
15
+ accessKeyId: "fakeAccessKey",
16
+ secretAccessKey: "fakeSecretKey",
17
+ primaryKey: "id",
18
+ });
19
+ ```
20
+
21
+ ## Environment Variables
22
+
23
+ ```env
24
+ DYNAMODB_HOST=localhost
25
+ DYNAMODB_PORT=8000
26
+ DYNAMODB_REGION=us-east-1
27
+ DYNAMODB_ACCESS_KEY=fakeAccessKey
28
+ DYNAMODB_SECRET_KEY=fakeSecretKey
29
+ ```
30
+
31
+ ## Notes
32
+
33
+ - Tables must be created beforehand (the adapter does not create tables)
34
+ - Auto-generates UUID primary keys for records missing the PK field
35
+ - Filter operators are mapped to DynamoDB FilterExpression syntax
36
+ - `like` uses `contains()`, `in` uses `IN ()`
37
+ - All filtering and pagination happen via `Scan` with in-memory post-processing
38
+ - Batch writes are chunked into groups of 25 (DynamoDB limit)
39
+ - `UpdateCommand` is used for upsert operations
40
+ - Best suited for serverless / AWS-native architectures
41
+
42
+ ## Table Creation (AWS CLI)
43
+
44
+ ```bash
45
+ aws dynamodb create-table \
46
+ --table-name users \
47
+ --attribute-definitions AttributeName=id,AttributeType=S \
48
+ --key-schema AttributeName=id,KeyType=HASH \
49
+ --billing-mode PAY_PER_REQUEST \
50
+ --endpoint-url http://localhost:8000
51
+ ```
52
+
53
+ [← Back to main docs](../../README.md)
@@ -0,0 +1,56 @@
1
+ # MongoDB Adapter
2
+
3
+ Uses the official [mongodb](https://www.npmjs.com/package/mongodb) Node.js driver.
4
+
5
+ ## Connection
6
+
7
+ ```js
8
+ const { init, db, model, route } = require("db-model-router");
9
+ init("mongodb");
10
+
11
+ db.connect({
12
+ host: "localhost",
13
+ port: 27017,
14
+ database: "my_app",
15
+ // or with auth:
16
+ username: "admin",
17
+ password: "secret",
18
+ // or with a full URI:
19
+ uri: "mongodb://admin:secret@localhost:27017",
20
+ });
21
+ ```
22
+
23
+ ## Environment Variables
24
+
25
+ ```env
26
+ MONGO_HOST=localhost
27
+ MONGO_PORT=27017
28
+ MONGO_DB=test_db
29
+ ```
30
+
31
+ ## Notes
32
+
33
+ - Primary key is `_id` (MongoDB's default ObjectId)
34
+ - String `_id` values matching the 24-char hex format are auto-converted to `ObjectId`
35
+ - Filter operators are mapped to MongoDB query operators (`$eq`, `$regex`, `$in`, etc.)
36
+ - `like` uses `$regex` with case-insensitive matching
37
+ - No schema/table creation needed — collections are created on first insert
38
+
39
+ ## Model Definition
40
+
41
+ ```js
42
+ const users = model(
43
+ db,
44
+ "users",
45
+ {
46
+ _id: "string",
47
+ name: "required|string",
48
+ email: "required|string",
49
+ age: "required|integer",
50
+ },
51
+ "_id",
52
+ ["_id"],
53
+ );
54
+ ```
55
+
56
+ [← Back to main docs](../../README.md)
@@ -0,0 +1,55 @@
1
+ # MSSQL (SQL Server) Adapter
2
+
3
+ Uses the [mssql](https://www.npmjs.com/package/mssql) driver with tedious.
4
+
5
+ ## Connection
6
+
7
+ ```js
8
+ const { init, db, model, route } = require("db-model-router");
9
+ init("mssql");
10
+
11
+ await db.connect({
12
+ server: "localhost",
13
+ port: 1433,
14
+ database: "master",
15
+ user: "sa",
16
+ password: "Password123!",
17
+ options: {
18
+ encrypt: false,
19
+ trustServerCertificate: true,
20
+ },
21
+ });
22
+ ```
23
+
24
+ Note: `db.connect()` is async for MSSQL — use `await`.
25
+
26
+ ## Environment Variables
27
+
28
+ ```env
29
+ MSSQL_HOST=localhost
30
+ MSSQL_PORT=1433
31
+ MSSQL_DB=master
32
+ MSSQL_USER=sa
33
+ MSSQL_PASSWORD=Password123!
34
+ ```
35
+
36
+ ## Notes
37
+
38
+ - Column names are escaped with `[brackets]`
39
+ - Uses `MERGE` statements for upsert operations
40
+ - IDENTITY columns are auto-excluded from INSERT in MERGE statements
41
+ - Pagination uses `OFFSET ... ROWS FETCH NEXT ... ROWS ONLY`
42
+ - `OUTPUT INSERTED.*` is used to return inserted rows
43
+
44
+ ## Table Creation
45
+
46
+ ```sql
47
+ CREATE TABLE users (
48
+ id INT IDENTITY(1,1) PRIMARY KEY,
49
+ name NVARCHAR(255),
50
+ email NVARCHAR(255),
51
+ age INT
52
+ );
53
+ ```
54
+
55
+ [← Back to main docs](../../README.md)