db-model-router 1.0.0
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/.env +7 -0
- package/LICENSE +201 -0
- package/README.md +505 -0
- package/docker-compose.yml +141 -0
- package/docs/README.md +208 -0
- package/docs/SKILL.md +202 -0
- package/docs/adapters/cockroachdb.md +49 -0
- package/docs/adapters/dynamodb.md +53 -0
- package/docs/adapters/mongodb.md +56 -0
- package/docs/adapters/mssql.md +55 -0
- package/docs/adapters/oracle.md +52 -0
- package/docs/adapters/postgres.md +50 -0
- package/docs/adapters/redis.md +53 -0
- package/docs/adapters/sqlite3.md +43 -0
- package/package.json +109 -0
- package/src/cli/generate-app.js +359 -0
- package/src/cli/generate-model.js +760 -0
- package/src/cli/generate-openapi.js +237 -0
- package/src/cli/generate-route.js +346 -0
- package/src/cockroachdb/db.js +563 -0
- package/src/commons/function.js +165 -0
- package/src/commons/model.js +444 -0
- package/src/commons/route.js +214 -0
- package/src/commons/validator.js +172 -0
- package/src/dynamodb/db.js +552 -0
- package/src/index.js +57 -0
- package/src/mongodb/db.js +381 -0
- package/src/mssql/db.js +461 -0
- package/src/mysql/db.js +527 -0
- package/src/oracle/db.js +855 -0
- package/src/oracle/sql_translator.js +406 -0
- package/src/postgres/db.js +666 -0
- package/src/postgres/ddl_translator.js +69 -0
- package/src/postgres/sql_translator.js +396 -0
- package/src/redis/db.js +448 -0
- package/src/serve.js +90 -0
- package/src/sqlite3/db.js +346 -0
package/docs/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# rest-router
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
## Supported Adapters
|
|
6
|
+
|
|
7
|
+
| Adapter | Module Key | Driver | Install |
|
|
8
|
+
| ---------------------------------------- | ------------- | ------------------------ | ---------------------------------------------------------------------- |
|
|
9
|
+
| [MySQL](#mysql-example) | `mysql` | mysql2 | `npm i db-model-router mysql2` |
|
|
10
|
+
| [PostgreSQL](./adapters/postgres.md) | `postgres` | pg | `npm i db-model-router pg` |
|
|
11
|
+
| [SQLite3](./adapters/sqlite3.md) | `sqlite3` | better-sqlite3 | `npm i db-model-router better-sqlite3` |
|
|
12
|
+
| [MongoDB](./adapters/mongodb.md) | `mongodb` | mongodb | `npm i db-model-router mongodb` |
|
|
13
|
+
| [MSSQL](./adapters/mssql.md) | `mssql` | mssql | `npm i db-model-router mssql` |
|
|
14
|
+
| [CockroachDB](./adapters/cockroachdb.md) | `cockroachdb` | pg | `npm i db-model-router pg` |
|
|
15
|
+
| [Oracle](./adapters/oracle.md) | `oracle` | oracledb | `npm i db-model-router oracledb` |
|
|
16
|
+
| [Redis](./adapters/redis.md) | `redis` | ioredis | `npm i db-model-router ioredis` |
|
|
17
|
+
| [DynamoDB](./adapters/dynamodb.md) | `dynamodb` | @aws-sdk/client-dynamodb | `npm i db-model-router @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb` |
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
Install the core package, your preferred Express framework, and the driver for your database:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Pick your Express framework (one of the two)
|
|
25
|
+
npm install express
|
|
26
|
+
# OR for ~6x faster performance:
|
|
27
|
+
npm install ultimate-express
|
|
28
|
+
|
|
29
|
+
# Then install db-model-router + your database driver
|
|
30
|
+
npm install db-model-router <driver>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
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.
|
|
34
|
+
|
|
35
|
+
## MySQL Example
|
|
36
|
+
|
|
37
|
+
### 1. Connect
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
const { init, db, model, route } = require("db-model-router");
|
|
41
|
+
|
|
42
|
+
// Default adapter is mysql, so init() is optional
|
|
43
|
+
db.connect({
|
|
44
|
+
host: "localhost",
|
|
45
|
+
port: 3306,
|
|
46
|
+
user: "root",
|
|
47
|
+
password: "password",
|
|
48
|
+
database: "my_app",
|
|
49
|
+
connectionLimit: 100,
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Define a Model
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
const users = model(
|
|
57
|
+
db,
|
|
58
|
+
"users",
|
|
59
|
+
{
|
|
60
|
+
name: "required|string",
|
|
61
|
+
email: "required|string",
|
|
62
|
+
age: "required|integer",
|
|
63
|
+
meta: "object",
|
|
64
|
+
},
|
|
65
|
+
"id",
|
|
66
|
+
["email"],
|
|
67
|
+
{ safeDelete: "is_deleted" },
|
|
68
|
+
);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Schema types: `string`, `integer`, `numeric`, `object`. Prefix with `required|` to enforce on insert/update.
|
|
72
|
+
|
|
73
|
+
### 3. Mount REST Routes
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
// Works with either express or ultimate-express
|
|
77
|
+
const express = require("express"); // or require("ultimate-express")
|
|
78
|
+
const app = express();
|
|
79
|
+
app.use(express.json());
|
|
80
|
+
app.use("/users", route(users));
|
|
81
|
+
app.listen(3000);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
This creates 9 endpoints:
|
|
85
|
+
|
|
86
|
+
| Method | Path | Description |
|
|
87
|
+
| ------ | ------------ | ------------------------------- |
|
|
88
|
+
| GET | `/users/:id` | Get one record by PK |
|
|
89
|
+
| POST | `/users/:id` | Insert a single record |
|
|
90
|
+
| PUT | `/users/:id` | Update a single record |
|
|
91
|
+
| PATCH | `/users/:id` | Partial update (changed fields) |
|
|
92
|
+
| DELETE | `/users/:id` | Delete a single record |
|
|
93
|
+
| GET | `/users/` | List with pagination |
|
|
94
|
+
| POST | `/users/` | Bulk insert (`{ data: [...] }`) |
|
|
95
|
+
| PUT | `/users/` | Bulk update (`{ data: [...] }`) |
|
|
96
|
+
| DELETE | `/users/` | Bulk delete |
|
|
97
|
+
|
|
98
|
+
### 4. Payload Override
|
|
99
|
+
|
|
100
|
+
Inject values from the request into every payload (useful for multi-tenant apps):
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
app.use("/users", route(users, { user_id: "user.user_id" }));
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Model API
|
|
107
|
+
|
|
108
|
+
All model methods are async.
|
|
109
|
+
|
|
110
|
+
### insert / update / patch / upsert
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
const user = await users.insert({ name: "Alice", email: "a@b.com", age: 30 });
|
|
114
|
+
const bulk = await users.insert({ data: [{ ... }, { ... }] });
|
|
115
|
+
const updated = await users.update({ id: 1, name: "Alice V2", email: "a@b.com", age: 31 });
|
|
116
|
+
const patched = await users.patch({ id: 1, age: 35 }); // partial — only updates age
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### byId / find / findOne / list
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
await users.byId(1); // record or null
|
|
123
|
+
await users.find({ name: "Alice" }); // { data: [...], count }
|
|
124
|
+
await users.findOne({ email: "a@b.com" }); // record or false
|
|
125
|
+
await users.list({ page: 0, size: 10, sort: ["-age"] }); // { data: [...], count }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### remove
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
await users.remove(1);
|
|
132
|
+
await users.remove({ name: "Bob" });
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Filter System
|
|
136
|
+
|
|
137
|
+
Structure: `[OR_groups[AND_conditions[column, operator, value]]]`
|
|
138
|
+
|
|
139
|
+
Operators: `=`, `like`, `not like`, `in`, `not in`, `<`, `>`, `<=`, `>=`, `!=`
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
// Alice AND age 30
|
|
143
|
+
await db.get("users", [
|
|
144
|
+
[
|
|
145
|
+
["name", "=", "Alice"],
|
|
146
|
+
["age", "=", 30],
|
|
147
|
+
],
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
// Alice OR age > 30
|
|
151
|
+
await db.get("users", [[["name", "=", "Alice"]], [["age", ">", 30]]]);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Switching Adapters
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
const { init, db, model, route } = require("db-model-router");
|
|
158
|
+
init("postgres"); // or "mongodb", "sqlite3", "mssql", etc.
|
|
159
|
+
db.connect({
|
|
160
|
+
host: "localhost",
|
|
161
|
+
port: 5432,
|
|
162
|
+
user: "postgres",
|
|
163
|
+
password: "password",
|
|
164
|
+
database: "my_app",
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The model and route APIs remain identical across all adapters.
|
|
169
|
+
|
|
170
|
+
## CLI Tools
|
|
171
|
+
|
|
172
|
+
### generate-app
|
|
173
|
+
|
|
174
|
+
Scaffolds a complete Express REST API from an existing database.
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
rest-router-generate-app --type mysql --env .env
|
|
178
|
+
rest-router-generate-app --type sqlite3 --database ./myapp.db --output ./my-api
|
|
179
|
+
rest-router-generate-app --type postgres --env .env --tables users,posts,posts.comments
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Creates: `app.js`, `models/`, `routes/`, `middleware/logger.js`, `.env.example`, `openapi.json`
|
|
183
|
+
|
|
184
|
+
### generate-model
|
|
185
|
+
|
|
186
|
+
Introspects DB → generates model files with auto-detected PK, unique indexes, timestamps, soft-delete.
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
rest-router-generate-model --type mysql --env .env --output ./models [--tables users,posts]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### generate-route
|
|
193
|
+
|
|
194
|
+
Generates route files + OpenAPI spec from models. Supports parent-child via dot notation.
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
rest-router-generate-route --models ./models --output ./routes [--tables posts,posts.comments]
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`posts.comments` → nested route `posts/:post_id/comments` with FK scoping.
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
Apache-2.0
|
|
205
|
+
|
|
206
|
+
## LLM Skill Reference
|
|
207
|
+
|
|
208
|
+
For AI/LLM integration, see the [Skill Reference](./SKILL.md).
|
package/docs/SKILL.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# db-model-router — LLM Skill Reference
|
|
2
|
+
|
|
3
|
+
Database-agnostic REST API generator for Node.js/Express. Define model → get CRUD API + Express routes. 9 adapters, identical API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install db-model-router <driver>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Drivers: `mysql2`, `pg`, `better-sqlite3`, `mongodb`, `mssql`, `oracledb`, `ioredis`, `@aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb`
|
|
12
|
+
|
|
13
|
+
## Init → Connect → Model → Route
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
const { init, db, model, route } = require("db-model-router");
|
|
17
|
+
init("postgres"); // mysql|postgres|sqlite3|mongodb|mssql|cockroachdb|oracle|redis|dynamodb
|
|
18
|
+
db.connect({ host, port: 5432, user, password, database });
|
|
19
|
+
|
|
20
|
+
const users = model(
|
|
21
|
+
db,
|
|
22
|
+
"users",
|
|
23
|
+
{
|
|
24
|
+
name: "required|string",
|
|
25
|
+
email: "required|string",
|
|
26
|
+
age: "integer",
|
|
27
|
+
meta: "object",
|
|
28
|
+
},
|
|
29
|
+
"id",
|
|
30
|
+
["email"],
|
|
31
|
+
{
|
|
32
|
+
safeDelete: "is_deleted",
|
|
33
|
+
created_at: "created_at",
|
|
34
|
+
modified_at: "updated_at",
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
app.use("/users", route(users));
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Critical**: call `init()` before `db.connect()`. Default adapter is mysql. Do NOT destructure `db` before `init()`.
|
|
42
|
+
|
|
43
|
+
## model(db, table, structure, pk, unique, option)
|
|
44
|
+
|
|
45
|
+
| Param | Type | Description |
|
|
46
|
+
| --------- | --------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
47
|
+
| structure | `{col: "rule"}` | Types: `string\|integer\|numeric\|object`. Prefix `required\|` for NOT NULL. Exclude PK, timestamps, soft-delete cols |
|
|
48
|
+
| pk | string | Primary key column. Default `"id"` |
|
|
49
|
+
| unique | string[] | Columns for upsert conflict resolution |
|
|
50
|
+
| option | object | `{ safeDelete, created_at, modified_at }` — column names or null |
|
|
51
|
+
|
|
52
|
+
## Model Methods (all async)
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
// INSERT — single returns record, bulk returns {rows, message, type}
|
|
56
|
+
await m.insert({ name: "Alice", email: "a@b.com", age: 30 }) // → {id:1, name:"Alice", ...}
|
|
57
|
+
await m.insert({ data: [{...}, {...}] }) // → {rows:2, message, type:"success"}
|
|
58
|
+
|
|
59
|
+
// UPDATE — PK required in payload
|
|
60
|
+
await m.update({ id: 1, name: "Alice V2", email: "a@b.com", age: 31 })
|
|
61
|
+
await m.update({ data: [{id:1,...}, {id:2,...}] })
|
|
62
|
+
|
|
63
|
+
// PATCH — partial update, only sends changed fields, PK required
|
|
64
|
+
await m.patch({ id: 1, age: 35 }) // → full merged record
|
|
65
|
+
|
|
66
|
+
// UPSERT — PK optional, uses unique cols for conflict
|
|
67
|
+
await m.upsert({ email: "new@b.com", name: "New", age: 20 })
|
|
68
|
+
|
|
69
|
+
// READ
|
|
70
|
+
await m.byId(1) // → record or null
|
|
71
|
+
await m.find({ name: "Alice" }) // → {data:[], count}
|
|
72
|
+
await m.findOne({ email: "a@b.com" }) // → record or false
|
|
73
|
+
await m.list({ page: 0, size: 10, sort: ["-age"] }) // → {data:[], count}
|
|
74
|
+
|
|
75
|
+
// DELETE — with safeDelete: sets column=1; without: hard delete
|
|
76
|
+
await m.remove(1)
|
|
77
|
+
await m.remove({ name: "Bob" })
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Filter Syntax
|
|
81
|
+
|
|
82
|
+
Structure: `[OR_groups[AND_conditions[col, op, val]]]`
|
|
83
|
+
Ops: `= != < > <= >= like not like in not in`
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
[
|
|
87
|
+
[
|
|
88
|
+
["age", ">", 25],
|
|
89
|
+
["type", "=", 1],
|
|
90
|
+
],
|
|
91
|
+
][([["name", "=", "A"]], [["name", "=", "B"]])][[["type", "in", [1, 2, 3]]]][ // AND // OR // IN
|
|
92
|
+
[["name", "like", "Ali"]]
|
|
93
|
+
]; // LIKE %Ali%
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## route(model, override?)
|
|
97
|
+
|
|
98
|
+
Generates Express Router with 9 endpoints:
|
|
99
|
+
|
|
100
|
+
| Method | Path | Action |
|
|
101
|
+
| ------ | ------ | -------------------------------- |
|
|
102
|
+
| GET | `/:pk` | Get by PK |
|
|
103
|
+
| POST | `/:id` | Insert single |
|
|
104
|
+
| PUT | `/:id` | Update single (PK from URL) |
|
|
105
|
+
| PATCH | `/:id` | Partial update |
|
|
106
|
+
| DELETE | `/:id` | Delete single |
|
|
107
|
+
| GET | `/` | List (page, size, sort, filters) |
|
|
108
|
+
| POST | `/` | Bulk insert `{data:[...]}` |
|
|
109
|
+
| PUT | `/` | Bulk update `{data:[...]}` |
|
|
110
|
+
| DELETE | `/` | Bulk delete `{data:[...]}` |
|
|
111
|
+
|
|
112
|
+
**Payload override** (multi-tenancy): `route(m, { tenant_id: "user.tenant_id" })` — maps cols to `req` paths via lodash.get.
|
|
113
|
+
|
|
114
|
+
**Query params**: `select_columns=name,email`, `output_content_type=csv|xml|json`, `sort=-age,name`
|
|
115
|
+
|
|
116
|
+
## CLI Tools
|
|
117
|
+
|
|
118
|
+
### generate-app (full scaffold)
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
rest-router-generate-app --type mysql --env .env [--output ./dir] [--tables users,posts,posts.comments]
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Creates: `app.js`, `models/`, `routes/`, `middleware/logger.js`, `.env.example`, `.gitignore`, `migrations/`, `sessions/`, `openapi.json`
|
|
125
|
+
|
|
126
|
+
### generate-model (DB introspection → model files)
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
rest-router-generate-model --type <db> --env .env [--output ./models] [--tables t1,t2] [--schema public]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Auto-detects: PK, unique indexes, DEFAULT→optional, timestamp cols, soft-delete cols.
|
|
133
|
+
|
|
134
|
+
### generate-route (model files → route files + OpenAPI)
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
rest-router-generate-route --models ./models --output ./routes [--tables posts,posts.comments]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Dot notation `parent.child` creates nested routes: `parent/:parent_id/child` with FK scoping via `<parent_singular>_id`.
|
|
141
|
+
|
|
142
|
+
## Connection Configs
|
|
143
|
+
|
|
144
|
+
```js
|
|
145
|
+
// MySQL (default)
|
|
146
|
+
db.connect({
|
|
147
|
+
host,
|
|
148
|
+
port: 3306,
|
|
149
|
+
user,
|
|
150
|
+
password,
|
|
151
|
+
database,
|
|
152
|
+
connectionLimit: 100,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// PostgreSQL / CockroachDB
|
|
156
|
+
init("postgres"); // cockroachdb port: 26257
|
|
157
|
+
db.connect({ host, port: 5432, user, password, database });
|
|
158
|
+
|
|
159
|
+
// SQLite3
|
|
160
|
+
init("sqlite3");
|
|
161
|
+
db.connect({ database: "./file.db" }); // or ":memory:"
|
|
162
|
+
|
|
163
|
+
// MongoDB
|
|
164
|
+
init("mongodb");
|
|
165
|
+
db.connect({ host, port: 27017, username, password, database });
|
|
166
|
+
// or: db.connect({ uri: "mongodb://user:pass@host:27017/db" })
|
|
167
|
+
|
|
168
|
+
// MSSQL
|
|
169
|
+
init("mssql");
|
|
170
|
+
await db.connect({
|
|
171
|
+
server: host,
|
|
172
|
+
port: 1433,
|
|
173
|
+
user,
|
|
174
|
+
password,
|
|
175
|
+
database,
|
|
176
|
+
options: { encrypt: false, trustServerCertificate: true },
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Oracle
|
|
180
|
+
init("oracle");
|
|
181
|
+
db.connect({ host, port: 1521, user, password, database });
|
|
182
|
+
|
|
183
|
+
// Redis
|
|
184
|
+
init("redis");
|
|
185
|
+
db.connect({ host, port: 6379, password });
|
|
186
|
+
|
|
187
|
+
// DynamoDB
|
|
188
|
+
init("dynamodb");
|
|
189
|
+
db.connect({ region, endpoint, accessKeyId, secretAccessKey });
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Rules
|
|
193
|
+
|
|
194
|
+
1. `init()` before `db.connect()`. Don't destructure `db` before `init()`.
|
|
195
|
+
2. `modelStructure` excludes: PK col, timestamp cols, soft-delete cols.
|
|
196
|
+
3. `update()`/`patch()` require PK in payload. `upsert()` PK is optional.
|
|
197
|
+
4. `findOne()` returns `false` on no match. `byId()` returns `null`.
|
|
198
|
+
5. Bulk ops wrap in `{ data: [...] }`. Single ops use flat object.
|
|
199
|
+
6. Timestamps auto-stripped from payloads. DB handles defaults/triggers.
|
|
200
|
+
7. `safeDelete` makes `remove()` soft-delete; all reads auto-filter deleted rows.
|
|
201
|
+
8. `list()` defaults: page=0, size=30. `sort` array: `["-col"]` for DESC.
|
|
202
|
+
9. CommonJS only (`require`). Use dynamic `import()` for ESM.
|
|
@@ -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)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Oracle Adapter
|
|
2
|
+
|
|
3
|
+
Uses [oracledb](https://www.npmjs.com/package/oracledb) (Oracle Instant Client required).
|
|
4
|
+
|
|
5
|
+
## Connection
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
const { init, db, model, route } = require("db-model-router");
|
|
9
|
+
init("oracle");
|
|
10
|
+
|
|
11
|
+
db.connect({
|
|
12
|
+
host: "localhost",
|
|
13
|
+
port: 1521,
|
|
14
|
+
database: "XEPDB1",
|
|
15
|
+
user: "system",
|
|
16
|
+
password: "oracle",
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Environment Variables
|
|
21
|
+
|
|
22
|
+
```env
|
|
23
|
+
ORACLE_HOST=localhost
|
|
24
|
+
ORACLE_PORT=1521
|
|
25
|
+
ORACLE_DB=XEPDB1
|
|
26
|
+
ORACLE_USER=system
|
|
27
|
+
ORACLE_PASSWORD=oracle
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Notes
|
|
31
|
+
|
|
32
|
+
- Requires Oracle Instant Client installed on the host
|
|
33
|
+
- Uses connection pooling with session callbacks for NLS date format
|
|
34
|
+
- MySQL-style `?` placeholders are auto-translated to `:1, :2, ...`
|
|
35
|
+
- Includes a SQL translator that converts MySQL DDL/DML to Oracle syntax
|
|
36
|
+
- `MERGE INTO ... USING DUAL` is used for upsert operations
|
|
37
|
+
- `RETURNING ... INTO :pk_out` is used to retrieve auto-generated IDs
|
|
38
|
+
- Oracle reserved words in column names are auto-quoted
|
|
39
|
+
- `CLOB` values are fetched as strings
|
|
40
|
+
|
|
41
|
+
## Table Creation
|
|
42
|
+
|
|
43
|
+
```sql
|
|
44
|
+
CREATE TABLE users (
|
|
45
|
+
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
46
|
+
name VARCHAR2(255) NOT NULL,
|
|
47
|
+
email VARCHAR2(255) NOT NULL,
|
|
48
|
+
age NUMBER NOT NULL
|
|
49
|
+
);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
[← Back to main docs](../README.md)
|