db-model-router 1.0.4 → 1.0.6

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 (46) hide show
  1. package/README.md +110 -16
  2. package/TODO.md +15 -0
  3. package/dbmr.schema.json +333 -0
  4. package/docker-compose.yml +1 -1
  5. package/package.json +8 -7
  6. package/scripts/demo-create.js +47 -0
  7. package/skill/SKILL.md +464 -0
  8. package/skill/references/cockroachdb.md +49 -0
  9. package/skill/references/dynamodb.md +53 -0
  10. package/skill/references/mongodb.md +56 -0
  11. package/skill/references/mssql.md +55 -0
  12. package/skill/references/oracle.md +52 -0
  13. package/skill/references/postgres.md +50 -0
  14. package/skill/references/redis.md +53 -0
  15. package/skill/references/sqlite3.md +43 -0
  16. package/src/cli/commands/generate.js +95 -31
  17. package/src/cli/commands/help.js +12 -7
  18. package/src/cli/commands/init.js +2 -2
  19. package/src/cli/commands/inspect.js +1 -0
  20. package/src/cli/diff-engine.js +54 -23
  21. package/src/cli/generate-db-manager.js +1573 -0
  22. package/src/cli/generate-docs-route.js +31 -0
  23. package/src/cli/generate-migration.js +356 -0
  24. package/src/cli/generate-model.js +9 -4
  25. package/src/cli/generate-openapi.js +40 -13
  26. package/src/cli/generate-route.js +55 -27
  27. package/src/cli/init/dependencies.js +3 -0
  28. package/src/cli/init/generators.js +37 -31
  29. package/src/cli/init.js +8 -8
  30. package/src/cli/main.js +2 -2
  31. package/src/cockroachdb/db.js +90 -59
  32. package/src/commons/route.js +20 -20
  33. package/src/commons/validator.js +58 -1
  34. package/src/dynamodb/db.js +50 -27
  35. package/src/mongodb/db.js +1 -0
  36. package/src/mssql/db.js +89 -61
  37. package/src/mysql/db.js +1 -0
  38. package/src/oracle/db.js +1 -0
  39. package/src/postgres/db.js +61 -41
  40. package/src/redis/db.js +1 -0
  41. package/src/schema/schema-parser.js +43 -1
  42. package/src/schema/schema-printer.js +7 -0
  43. package/src/schema/schema-validator.js +17 -0
  44. package/src/sqlite3/db.js +12 -0
  45. package/docs/SKILL.md +0 -419
  46. package/src/cli/commands/generate-llm-docs.js +0 -418
package/README.md CHANGED
@@ -14,7 +14,11 @@ Scaffold the project, write the migrations, generate models and routes with pare
14
14
  relationships for projects.tasks, and make sure everything runs.
15
15
  ```
16
16
 
17
- For the LLM skill reference, see [SKILL.md](./docs/SKILL.md).
17
+ For the LLM skill reference, see [SKILL.md](./skill/SKILL.md). You can also add it directly to your AI assistant:
18
+
19
+ ```bash
20
+ npx skills add https://github.com/AvinashSKaranth/db-model-router/skill
21
+ ```
18
22
 
19
23
  ## Supported Adapters
20
24
 
@@ -97,7 +101,31 @@ Instead of running multiple CLI commands manually, you can define your entire pr
97
101
 
98
102
  ### The Schema File
99
103
 
100
- `dbmr.schema.json` is a declarative JSON file that describes your adapter, framework, tables, columns, relationships, and options — all in one place:
104
+ `dbmr.schema.json` is a declarative JSON file that describes your adapter, framework, tables, columns, module hierarchy, and options — all in one place.
105
+
106
+ #### Modules and the `parent` Field
107
+
108
+ Each table in the schema represents a **module**. Modules are either top-level or nested under a parent module using the `parent` field:
109
+
110
+ - `"parent": null` — top-level module, routes mount at `/<table>/`
111
+ - `"parent": "posts"` — child module, routes mount at `/posts/:post_id/comments/:comment_id`
112
+
113
+ When a table has `parent` set, the CLI automatically:
114
+
115
+ 1. Creates a child route file scoped by the parent's PK as a URL parameter
116
+ 2. Mounts the child routes under the parent path
117
+ 3. Also mounts the child as a top-level route for direct access
118
+
119
+ #### Best Practice: Don't Use System Tables as Parents
120
+
121
+ Tables like `users`, `tenants`, `roles`, `permissions`, `sessions`, and `role_permissions` are cross-cutting concerns — they are referenced by almost every feature module via foreign key columns (e.g. `user_id`, `tenant_id`). Making them route parents would nest every feature module under them, which is not the intent.
122
+
123
+ Keep system tables as top-level modules (`"parent": null`) and reference them via FK columns in your feature tables. Only use `parent` for true domain hierarchies like `posts → comments`, `orders → order_items`, or `projects → tasks`.
124
+
125
+ Examples of tables that should stay top-level (not be parents of feature modules):
126
+ `users`, `tenants`, `roles`, `role_permissions`, `permissions`, `sessions`, `accounts`, `auth_tokens`
127
+
128
+ #### Example Schema
101
129
 
102
130
  ```json
103
131
  {
@@ -127,7 +155,8 @@ Instead of running multiple CLI commands manually, you can define your entire pr
127
155
  "timestamps": {
128
156
  "created_at": "created_at",
129
157
  "modified_at": "updated_at"
130
- }
158
+ },
159
+ "parent": null
131
160
  },
132
161
  "posts": {
133
162
  "columns": {
@@ -139,16 +168,35 @@ Instead of running multiple CLI commands manually, you can define your entire pr
139
168
  "modified_at": "datetime"
140
169
  },
141
170
  "pk": "post_id",
142
- "unique": ["post_id"]
171
+ "unique": ["post_id"],
172
+ "parent": null
173
+ },
174
+ "comments": {
175
+ "columns": {
176
+ "comment_id": "auto_increment",
177
+ "post_id": "required|integer",
178
+ "user_id": "required|integer",
179
+ "body": "required|string",
180
+ "created_at": "datetime"
181
+ },
182
+ "pk": "comment_id",
183
+ "unique": ["comment_id"],
184
+ "parent": "posts"
143
185
  }
144
- },
145
- "relationships": [
146
- { "parent": "users", "child": "posts", "foreignKey": "user_id" }
147
- ]
186
+ }
148
187
  }
149
188
  ```
150
189
 
151
- Table entries support these fields:
190
+ This generates routes:
191
+
192
+ - `GET /users/`, `GET /users/:user_id` — top-level
193
+ - `GET /posts/`, `GET /posts/:post_id` — top-level
194
+ - `GET /posts/:post_id/comments/`, `GET /posts/:post_id/comments/:comment_id` — nested under posts
195
+ - `GET /comments/`, `GET /comments/:comment_id` — also available as top-level
196
+
197
+ Note: `comments` has `user_id` as a foreign key column but `users` is NOT its parent — `posts` is. The `user_id` is just a data reference, not a route hierarchy.
198
+
199
+ #### Table Fields
152
200
 
153
201
  | Field | Required | Description |
154
202
  | ------------ | -------- | ------------------------------------------------------------------------ |
@@ -157,12 +205,23 @@ Table entries support these fields:
157
205
  | `unique` | No | Array of unique constraint columns (defaults to `[pk]`) |
158
206
  | `softDelete` | No | Column name used for soft-delete |
159
207
  | `timestamps` | No | Object with `created_at` and `modified_at` column name mapping |
208
+ | `parent` | No | Parent table name for route nesting, or `null` for top-level |
209
+
210
+ #### Column Rules
160
211
 
161
- Column rules use the format `(required|)?(string|integer|numeric|boolean|object|datetime|auto_increment)`.
212
+ Format: `(required|)?(string|integer|numeric|boolean|object|datetime|auto_increment)`
162
213
 
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
214
+ | Type | Description |
215
+ | ---------------- | ------------------------------------------------------------------ |
216
+ | `auto_increment` | Auto-incrementing PK (SERIAL in Postgres, AUTO_INCREMENT in MySQL) |
217
+ | `datetime` | Date/time columns (TIMESTAMP, DATETIME, DATE) |
218
+ | `string` | Text columns (VARCHAR, TEXT, CHAR, UUID) |
219
+ | `integer` | Integer columns (INT, BIGINT, SMALLINT) |
220
+ | `numeric` | Decimal columns (DECIMAL, FLOAT, DOUBLE, MONEY) |
221
+ | `boolean` | Boolean columns (BOOLEAN, BIT) |
222
+ | `object` | JSON columns (JSON, JSONB) |
223
+
224
+ Prefix with `required|` for NOT NULL constraint (e.g. `"required|string"`).
166
225
 
167
226
  ### Unified CLI: `db-model-router`
168
227
 
@@ -436,7 +495,7 @@ This creates 9 endpoints:
436
495
  | GET | `/users/` | List with pagination |
437
496
  | POST | `/users/` | Bulk insert (`{ data: [...] }`) |
438
497
  | PUT | `/users/` | Bulk update (`{ data: [...] }`) |
439
- | DELETE | `/users/` | Bulk delete |
498
+ | DELETE | `/users/` | Bulk delete `{ name: "Bob" }` |
440
499
 
441
500
  ### 4. Payload Override
442
501
 
@@ -543,7 +602,7 @@ await users.remove({ name: "Bob" });
543
602
 
544
603
  Filters use a nested array structure: `[OR_groups[AND_conditions[column, operator, value]]]`
545
604
 
546
- Supported operators: `=`, `like`, `not like`, `in`, `not in`, `<`, `>`, `<=`, `>=`, `!=`
605
+ Supported operators: `=`, `!=`, `<`, `>`, `<=`, `>=`, `LIKE`, `NOT LIKE`, `IN`, `NOT IN`
547
606
 
548
607
  ```js
549
608
  // Find users named Alice OR aged > 30
@@ -561,6 +620,31 @@ const result = await db.get("users", [
561
620
  ]);
562
621
  ```
563
622
 
623
+ ### Query Parameter Filter Operators
624
+
625
+ When using `GET /` (list endpoint), query parameters are automatically parsed into filter conditions. Special value prefixes and patterns control the SQL operator used:
626
+
627
+ | Query Param Value | Operator | Example URL | Resulting Filter |
628
+ | ---------------------- | ---------- | ----------------------------- | ------------------------------------ |
629
+ | `value` | `=` | `?name=john` | `name = 'john'` |
630
+ | `!value` | `!=` | `?name=!john` | `name != 'john'` |
631
+ | `>value` | `>` | `?age=>25` | `age > 25` |
632
+ | `>=value` (use `>%3D`) | `>=` | `?age=>%3D25` | `age >= 25` |
633
+ | `<value` | `<` | `?age=<25` | `age < 25` |
634
+ | `<=value` (use `<%3D`) | `<=` | `?age=<%3D25` | `age <= 25` |
635
+ | `%value%` (use `%25`) | `LIKE` | `?name=%25john%25` | `name LIKE '%john%'` |
636
+ | `!%value%` | `NOT LIKE` | `?name=!%25john%25` | `name NOT LIKE '%john%'` |
637
+ | `in(a,b,c)` | `IN` | `?status=in(active,pending)` | `status IN ('active','pending')` |
638
+ | `!in(a,b,c)` | `NOT IN` | `?status=!in(active,pending)` | `status NOT IN ('active','pending')` |
639
+
640
+ **Notes:**
641
+
642
+ - `%` must be URL-encoded as `%25` in query strings. After URL decoding, the `%` character triggers `LIKE` detection.
643
+ - `=` in `>=` and `<=` must be URL-encoded as `%3D` (e.g. `>%3D25` for `>=25`).
644
+ - `LIKE` patterns follow SQL conventions: `%25john%25` → contains "john", `%25john` → ends with "john", `john%25` → starts with "john".
645
+ - `IN` and `NOT IN` values are comma-separated inside parentheses.
646
+ Operators are detected in order of specificity: `!in(...)` → `in(...)` → `!%...%` → `%...%` → `>=` → `<=` → `>` → `<` → `!value` → `=` (default).
647
+
564
648
  ## Switching Adapters
565
649
 
566
650
  To use a different database, call `init()` before `db.connect()`:
@@ -617,4 +701,14 @@ Apache-2.0
617
701
 
618
702
  ## LLM Skill Reference
619
703
 
620
- For AI/LLM integration, see the [Skill Reference](./docs/SKILL.md) — a structured document covering the full API surface, patterns, constraints, and connection configs for all adapters.
704
+ For AI/LLM integration, see the [Skill Reference](./skill/SKILL.md) — a structured document covering the full API surface, patterns, constraints, and connection configs for all adapters.
705
+
706
+ ### Add the Skill to Your AI Assistant
707
+
708
+ You can install the db-model-router skill directly into any compatible AI assistant using:
709
+
710
+ ```bash
711
+ npx skills add https://github.com/AvinashSKaranth/db-model-router/skill
712
+ ```
713
+
714
+ Once installed, your AI assistant will automatically know how to scaffold projects, generate models and routes, write migrations, and work with all 10 supported database adapters.
package/TODO.md ADDED
@@ -0,0 +1,15 @@
1
+ in generate --db-manager should generate
2
+ DB manager using ejs db manager in the generated codebase (dark theme)
3
+ There is login page with just password -> Needs to login status in session (req.session["db-manager"])
4
+ the password will be in .env as DATABASE_MANAGER_PASSWORD
5
+ Then db manager page
6
+ Left sidebar will have list of tables with local search
7
+ Main page will have 3 tabs
8
+
9
+ 1. Table Structure
10
+ 2. Data top 30 rows with filter,sort,pagenation
11
+ 3. Query page where user can type the raw query
12
+ This needs to added in route like /database
13
+
14
+ The api that this will use is POST /database/login, GET /database/tables, GET /database/tables/:table_name?sort=1&size=30&post_name=%title%
15
+ the UI should be able to filter,sort and move through the pages
@@ -0,0 +1,333 @@
1
+ {
2
+ "adapter": "sqlite3",
3
+ "framework": "express",
4
+ "options": {
5
+ "session": "memory",
6
+ "rateLimiting": true,
7
+ "helmet": true,
8
+ "logger": true,
9
+ "loki": false
10
+ },
11
+ "tables": {
12
+ "users": {
13
+ "columns": {
14
+ "user_id": "auto_increment",
15
+ "name": "required|string",
16
+ "email": "required|string",
17
+ "password_hash": "required|string",
18
+ "phone": "string",
19
+ "avatar_url": "string",
20
+ "role": "required|string",
21
+ "is_deleted": "boolean",
22
+ "created_at": "datetime",
23
+ "updated_at": "datetime"
24
+ },
25
+ "pk": "user_id",
26
+ "unique": ["email"],
27
+ "softDelete": "is_deleted",
28
+ "timestamps": {
29
+ "created_at": "created_at",
30
+ "modified_at": "updated_at"
31
+ },
32
+ "parent": null
33
+ },
34
+ "addresses": {
35
+ "columns": {
36
+ "address_id": "auto_increment",
37
+ "user_id": "required|integer",
38
+ "label": "string",
39
+ "line1": "required|string",
40
+ "line2": "string",
41
+ "city": "required|string",
42
+ "state": "required|string",
43
+ "postal_code": "required|string",
44
+ "country": "required|string",
45
+ "is_default": "boolean",
46
+ "created_at": "datetime",
47
+ "updated_at": "datetime"
48
+ },
49
+ "pk": "address_id",
50
+ "unique": ["address_id"],
51
+ "timestamps": {
52
+ "created_at": "created_at",
53
+ "modified_at": "updated_at"
54
+ },
55
+ "parent": null
56
+ },
57
+ "categories": {
58
+ "columns": {
59
+ "category_id": "auto_increment",
60
+ "name": "required|string",
61
+ "slug": "required|string",
62
+ "description": "string",
63
+ "parent_category_id": "integer",
64
+ "image_url": "string",
65
+ "sort_order": "integer",
66
+ "is_active": "boolean",
67
+ "created_at": "datetime",
68
+ "updated_at": "datetime"
69
+ },
70
+ "pk": "category_id",
71
+ "unique": ["slug"],
72
+ "timestamps": {
73
+ "created_at": "created_at",
74
+ "modified_at": "updated_at"
75
+ },
76
+ "parent": null
77
+ },
78
+ "products": {
79
+ "columns": {
80
+ "product_id": "auto_increment",
81
+ "category_id": "required|integer",
82
+ "name": "required|string",
83
+ "slug": "required|string",
84
+ "description": "string",
85
+ "short_description": "string",
86
+ "sku": "required|string",
87
+ "price": "required|numeric",
88
+ "compare_at_price": "numeric",
89
+ "cost_price": "numeric",
90
+ "currency": "required|string",
91
+ "stock_quantity": "required|integer",
92
+ "low_stock_threshold": "integer",
93
+ "weight": "numeric",
94
+ "weight_unit": "string",
95
+ "is_active": "boolean",
96
+ "is_featured": "boolean",
97
+ "is_deleted": "boolean",
98
+ "meta": "object",
99
+ "created_at": "datetime",
100
+ "updated_at": "datetime"
101
+ },
102
+ "pk": "product_id",
103
+ "unique": ["sku", "slug"],
104
+ "softDelete": "is_deleted",
105
+ "timestamps": {
106
+ "created_at": "created_at",
107
+ "modified_at": "updated_at"
108
+ },
109
+ "parent": null
110
+ },
111
+ "product_images": {
112
+ "columns": {
113
+ "product_image_id": "auto_increment",
114
+ "product_id": "required|integer",
115
+ "url": "required|string",
116
+ "alt_text": "string",
117
+ "sort_order": "integer",
118
+ "is_primary": "boolean",
119
+ "created_at": "datetime"
120
+ },
121
+ "pk": "product_image_id",
122
+ "unique": ["product_image_id"],
123
+ "timestamps": {
124
+ "created_at": "created_at"
125
+ },
126
+ "parent": "products"
127
+ },
128
+ "product_variants": {
129
+ "columns": {
130
+ "variant_id": "auto_increment",
131
+ "product_id": "required|integer",
132
+ "name": "required|string",
133
+ "sku": "required|string",
134
+ "price": "required|numeric",
135
+ "stock_quantity": "required|integer",
136
+ "attributes": "object",
137
+ "is_active": "boolean",
138
+ "created_at": "datetime",
139
+ "updated_at": "datetime"
140
+ },
141
+ "pk": "variant_id",
142
+ "unique": ["sku"],
143
+ "timestamps": {
144
+ "created_at": "created_at",
145
+ "modified_at": "updated_at"
146
+ },
147
+ "parent": "products"
148
+ },
149
+ "product_reviews": {
150
+ "columns": {
151
+ "review_id": "auto_increment",
152
+ "product_id": "required|integer",
153
+ "user_id": "required|integer",
154
+ "rating": "required|integer",
155
+ "title": "string",
156
+ "body": "string",
157
+ "is_verified": "boolean",
158
+ "is_approved": "boolean",
159
+ "created_at": "datetime",
160
+ "updated_at": "datetime"
161
+ },
162
+ "pk": "review_id",
163
+ "unique": ["review_id"],
164
+ "timestamps": {
165
+ "created_at": "created_at",
166
+ "modified_at": "updated_at"
167
+ },
168
+ "parent": "products"
169
+ },
170
+ "carts": {
171
+ "columns": {
172
+ "cart_id": "auto_increment",
173
+ "user_id": "integer",
174
+ "session_id": "string",
175
+ "currency": "required|string",
176
+ "created_at": "datetime",
177
+ "updated_at": "datetime"
178
+ },
179
+ "pk": "cart_id",
180
+ "unique": ["cart_id"],
181
+ "timestamps": {
182
+ "created_at": "created_at",
183
+ "modified_at": "updated_at"
184
+ },
185
+ "parent": null
186
+ },
187
+ "cart_items": {
188
+ "columns": {
189
+ "cart_item_id": "auto_increment",
190
+ "cart_id": "required|integer",
191
+ "product_id": "required|integer",
192
+ "variant_id": "integer",
193
+ "quantity": "required|integer",
194
+ "unit_price": "required|numeric",
195
+ "created_at": "datetime",
196
+ "updated_at": "datetime"
197
+ },
198
+ "pk": "cart_item_id",
199
+ "unique": ["cart_item_id"],
200
+ "timestamps": {
201
+ "created_at": "created_at",
202
+ "modified_at": "updated_at"
203
+ },
204
+ "parent": "carts"
205
+ },
206
+ "orders": {
207
+ "columns": {
208
+ "order_id": "auto_increment",
209
+ "user_id": "required|integer",
210
+ "order_number": "required|string",
211
+ "status": "required|string",
212
+ "subtotal": "required|numeric",
213
+ "tax_amount": "required|numeric",
214
+ "shipping_amount": "required|numeric",
215
+ "discount_amount": "numeric",
216
+ "total": "required|numeric",
217
+ "currency": "required|string",
218
+ "shipping_address_id": "integer",
219
+ "billing_address_id": "integer",
220
+ "notes": "string",
221
+ "created_at": "datetime",
222
+ "updated_at": "datetime"
223
+ },
224
+ "pk": "order_id",
225
+ "unique": ["order_number"],
226
+ "timestamps": {
227
+ "created_at": "created_at",
228
+ "modified_at": "updated_at"
229
+ },
230
+ "parent": null
231
+ },
232
+ "order_items": {
233
+ "columns": {
234
+ "order_item_id": "auto_increment",
235
+ "order_id": "required|integer",
236
+ "product_id": "required|integer",
237
+ "variant_id": "integer",
238
+ "product_name": "required|string",
239
+ "sku": "required|string",
240
+ "quantity": "required|integer",
241
+ "unit_price": "required|numeric",
242
+ "total_price": "required|numeric",
243
+ "created_at": "datetime"
244
+ },
245
+ "pk": "order_item_id",
246
+ "unique": ["order_item_id"],
247
+ "timestamps": {
248
+ "created_at": "created_at"
249
+ },
250
+ "parent": "orders"
251
+ },
252
+ "payments": {
253
+ "columns": {
254
+ "payment_id": "auto_increment",
255
+ "order_id": "required|integer",
256
+ "method": "required|string",
257
+ "provider": "string",
258
+ "provider_transaction_id": "string",
259
+ "amount": "required|numeric",
260
+ "currency": "required|string",
261
+ "status": "required|string",
262
+ "paid_at": "datetime",
263
+ "created_at": "datetime",
264
+ "updated_at": "datetime"
265
+ },
266
+ "pk": "payment_id",
267
+ "unique": ["payment_id"],
268
+ "timestamps": {
269
+ "created_at": "created_at",
270
+ "modified_at": "updated_at"
271
+ },
272
+ "parent": "orders"
273
+ },
274
+ "shipments": {
275
+ "columns": {
276
+ "shipment_id": "auto_increment",
277
+ "order_id": "required|integer",
278
+ "carrier": "required|string",
279
+ "tracking_number": "string",
280
+ "status": "required|string",
281
+ "shipped_at": "datetime",
282
+ "delivered_at": "datetime",
283
+ "created_at": "datetime",
284
+ "updated_at": "datetime"
285
+ },
286
+ "pk": "shipment_id",
287
+ "unique": ["shipment_id"],
288
+ "timestamps": {
289
+ "created_at": "created_at",
290
+ "modified_at": "updated_at"
291
+ },
292
+ "parent": "orders"
293
+ },
294
+ "coupons": {
295
+ "columns": {
296
+ "coupon_id": "auto_increment",
297
+ "code": "required|string",
298
+ "description": "string",
299
+ "discount_type": "required|string",
300
+ "discount_value": "required|numeric",
301
+ "min_order_amount": "numeric",
302
+ "max_uses": "integer",
303
+ "used_count": "integer",
304
+ "starts_at": "datetime",
305
+ "expires_at": "datetime",
306
+ "is_active": "boolean",
307
+ "created_at": "datetime",
308
+ "updated_at": "datetime"
309
+ },
310
+ "pk": "coupon_id",
311
+ "unique": ["code"],
312
+ "timestamps": {
313
+ "created_at": "created_at",
314
+ "modified_at": "updated_at"
315
+ },
316
+ "parent": null
317
+ },
318
+ "wishlists": {
319
+ "columns": {
320
+ "wishlist_id": "auto_increment",
321
+ "user_id": "required|integer",
322
+ "product_id": "required|integer",
323
+ "created_at": "datetime"
324
+ },
325
+ "pk": "wishlist_id",
326
+ "unique": ["wishlist_id"],
327
+ "timestamps": {
328
+ "created_at": "created_at"
329
+ },
330
+ "parent": null
331
+ }
332
+ }
333
+ }
@@ -128,7 +128,7 @@ services:
128
128
  - db-network
129
129
 
130
130
  oracle:
131
- image: gvenzl/oracle-xe:21-slim
131
+ image: gvenzl/oracle-free
132
132
  container_name: db-model-router-oracle
133
133
  restart: unless-stopped
134
134
  ports:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "db-model-router",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Generative API Creation using mysql2 and express libraries in node js",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -20,7 +20,8 @@
20
20
  "test:mssql": "dotenv -e env/.env.mssql -- mocha test/adapters/mssql.*.test.js --timeout 30000 --exit",
21
21
  "test:properties": "mocha test/properties/*.property.test.js --timeout 30000 --exit",
22
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/.*"
23
+ "demo:clear": "node -e \"var fs=require('fs'),p=require('path'),d=p.join(__dirname,'demo');fs.existsSync(d)&&fs.rmSync(d,{recursive:true,force:true});fs.mkdirSync(d,{recursive:true})\"",
24
+ "demo:create": "node scripts/demo-create.js"
24
25
  },
25
26
  "repository": {
26
27
  "type": "git",
@@ -54,14 +55,14 @@
54
55
  "node-input-validator": "^4.5.0"
55
56
  },
56
57
  "peerDependencies": {
57
- "@aws-sdk/client-dynamodb": "^3.1029.0",
58
- "@aws-sdk/lib-dynamodb": "^3.1029.0",
58
+ "@aws-sdk/client-dynamodb": "^3.1039.0",
59
+ "@aws-sdk/lib-dynamodb": "^3.1039.0",
59
60
  "better-sqlite3": "^12.9.0",
60
61
  "express": "^4.17.2 || ^5.0.0",
61
62
  "ioredis": "^5.10.1",
62
- "mongodb": "^7.1.1",
63
- "mssql": "^12.2.1",
64
- "mysql2": "^3.14.4",
63
+ "mongodb": "^7.2.0",
64
+ "mssql": "^12.5.0",
65
+ "mysql2": "^3.22.3",
65
66
  "oracledb": "^6.10.0",
66
67
  "pg": "^8.20.0",
67
68
  "ultimate-express": "^2.0.0"
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+ const { execSync } = require("child_process");
7
+
8
+ const ROOT = path.resolve(__dirname, "..");
9
+ const DEMO = path.join(ROOT, "demo");
10
+
11
+ // 1. Clear demo folder
12
+ if (fs.existsSync(DEMO)) {
13
+ fs.rmSync(DEMO, { recursive: true, force: true });
14
+ }
15
+ fs.mkdirSync(DEMO, { recursive: true });
16
+
17
+ const run = (cmd, cwd) => {
18
+ console.log(`\n> ${cmd}`);
19
+ execSync(cmd, { cwd, stdio: "inherit" });
20
+ };
21
+
22
+ // 2. Scaffold project with sqlite3
23
+ run("node ../src/cli/main.js init --database sqlite3 --yes --no-install", DEMO);
24
+
25
+ // 3. Copy schema and patch adapter to sqlite3
26
+ const schema = JSON.parse(
27
+ fs.readFileSync(path.join(ROOT, "dbmr.schema.json"), "utf8"),
28
+ );
29
+ schema.adapter = "sqlite3";
30
+ if (schema.options) {
31
+ delete schema.options.session;
32
+ delete schema.options.loki;
33
+ }
34
+ fs.writeFileSync(
35
+ path.join(DEMO, "dbmr.schema.json"),
36
+ JSON.stringify(schema, null, 2) + "\n",
37
+ );
38
+ console.log("\n> Copied and patched dbmr.schema.json (adapter → sqlite3)");
39
+
40
+ // 4. Generate models, routes, tests, openapi from schema
41
+ run("node ../src/cli/main.js generate --from dbmr.schema.json", DEMO);
42
+
43
+ // 5. Install dependencies
44
+ run("npm install", DEMO);
45
+
46
+ console.log("\n✔ Demo project ready in ./demo");
47
+ console.log(" cd demo && npm run dev\n");