@dreamtree-org/korm-js 1.0.39 → 1.0.40
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 +720 -158
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,55 +1,58 @@
|
|
|
1
1
|
# KORM-JS
|
|
2
2
|
|
|
3
|
-
**Knowledge Object-Relational Mapping** - A powerful, modular ORM system for Node.js with dynamic database operations, complex queries, relationships, and
|
|
3
|
+
**Knowledge Object-Relational Mapping** - A powerful, modular ORM system for Node.js with dynamic database operations, complex queries, relationships, nested requests, and soft delete support.
|
|
4
4
|
|
|
5
|
-
[](https://badge.fury.io/js/@dreamtree-org%2Fkorm-js)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
10
|
- 🚀 **Multi-Database Support**: MySQL, PostgreSQL, SQLite
|
|
11
|
-
- 🔧 **Dynamic Operations**: Create, Read, Update, Delete
|
|
12
|
-
- 🔍 **Advanced Querying**: Complex queries with relationships
|
|
11
|
+
- 🔧 **Dynamic Operations**: Create, Read, Update, Delete, Replace, Upsert, Sync
|
|
12
|
+
- 🔍 **Advanced Querying**: Complex queries with relationships, joins, and filtering
|
|
13
13
|
- 🛡️ **Data Validation**: Built-in request validation with custom rules
|
|
14
14
|
- 🔄 **Auto-Sync**: Automatic table schema synchronization
|
|
15
15
|
- 📦 **Modular Design**: Use only what you need
|
|
16
16
|
- 🎯 **Express.js Ready**: Perfect integration with Express applications
|
|
17
17
|
- 🔄 **Schema Generation**: Auto-generate schemas from existing databases
|
|
18
|
+
- 🗑️ **Soft Delete**: Built-in soft delete support with automatic filtering
|
|
19
|
+
- 🎣 **Model Hooks**: Before, After, Validate, and Custom action hooks
|
|
18
20
|
|
|
19
21
|
## Installation
|
|
20
22
|
|
|
21
23
|
```bash
|
|
22
|
-
npm install korm-js
|
|
24
|
+
npm install @dreamtree-org/korm-js
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
## Quick Start with Express.js and
|
|
27
|
+
## Quick Start with Express.js and MySQL
|
|
26
28
|
|
|
27
29
|
### 1. Basic Setup
|
|
28
30
|
|
|
29
31
|
```javascript
|
|
30
32
|
require('dotenv').config();
|
|
31
33
|
const express = require('express');
|
|
32
|
-
const { initializeKORM, validate, helperUtility } = require('korm-js');
|
|
34
|
+
const { initializeKORM, validate, helperUtility } = require('@dreamtree-org/korm-js');
|
|
33
35
|
const knex = require('knex');
|
|
34
36
|
|
|
35
37
|
const app = express();
|
|
36
38
|
app.use(express.json());
|
|
37
39
|
|
|
38
|
-
//
|
|
40
|
+
// MySQL database configuration
|
|
39
41
|
const db = knex({
|
|
40
|
-
client: '
|
|
42
|
+
client: 'mysql2',
|
|
41
43
|
connection: {
|
|
42
44
|
host: process.env.DB_HOST || 'localhost',
|
|
43
|
-
user: process.env.DB_USER || '
|
|
44
|
-
password: process.env.DB_PASS || '
|
|
45
|
-
database: process.env.DB_NAME || '
|
|
45
|
+
user: process.env.DB_USER || 'root',
|
|
46
|
+
password: process.env.DB_PASS || 'password',
|
|
47
|
+
database: process.env.DB_NAME || 'my_database',
|
|
48
|
+
port: process.env.DB_PORT || 3306
|
|
46
49
|
}
|
|
47
50
|
});
|
|
48
51
|
|
|
49
|
-
// Initialize KORM
|
|
52
|
+
// Initialize KORM with MySQL
|
|
50
53
|
const korm = initializeKORM({
|
|
51
54
|
db: db,
|
|
52
|
-
dbClient: '
|
|
55
|
+
dbClient: 'mysql'
|
|
53
56
|
});
|
|
54
57
|
|
|
55
58
|
app.listen(3000, () => {
|
|
@@ -63,9 +66,11 @@ app.listen(3000, () => {
|
|
|
63
66
|
async function initApp() {
|
|
64
67
|
// Load existing schema if available
|
|
65
68
|
let syncSchema = helperUtility.file.readJSON('schema/sync.json');
|
|
66
|
-
|
|
69
|
+
if (syncSchema) {
|
|
70
|
+
korm.setSchema(syncSchema);
|
|
71
|
+
}
|
|
67
72
|
|
|
68
|
-
// Sync database with schema
|
|
73
|
+
// Sync database with schema (creates tables if they don't exist)
|
|
69
74
|
await korm.syncDatabase().then(() => {
|
|
70
75
|
console.log('✅ Database synced');
|
|
71
76
|
});
|
|
@@ -103,7 +108,9 @@ app.get('/health', (req, res) => {
|
|
|
103
108
|
});
|
|
104
109
|
```
|
|
105
110
|
|
|
106
|
-
|
|
111
|
+
## Complete CRUD Operations Guide
|
|
112
|
+
|
|
113
|
+
### 1. Create Operation
|
|
107
114
|
|
|
108
115
|
```javascript
|
|
109
116
|
// Create a new record
|
|
@@ -114,11 +121,36 @@ POST /api/Users/crud
|
|
|
114
121
|
"username": "john_doe",
|
|
115
122
|
"email": "john@example.com",
|
|
116
123
|
"first_name": "John",
|
|
117
|
-
"last_name": "Doe"
|
|
124
|
+
"last_name": "Doe",
|
|
125
|
+
"age": 30,
|
|
126
|
+
"is_active": true
|
|
118
127
|
}
|
|
119
128
|
}
|
|
120
129
|
|
|
121
|
-
//
|
|
130
|
+
// Response
|
|
131
|
+
{
|
|
132
|
+
"message": "Record created successfully",
|
|
133
|
+
"data": [
|
|
134
|
+
{
|
|
135
|
+
"id": 1,
|
|
136
|
+
"username": "john_doe",
|
|
137
|
+
"email": "john@example.com",
|
|
138
|
+
"first_name": "John",
|
|
139
|
+
"last_name": "Doe",
|
|
140
|
+
"age": 30,
|
|
141
|
+
"is_active": true,
|
|
142
|
+
"created_at": "2024-01-01T00:00:00.000Z",
|
|
143
|
+
"updated_at": "2024-01-01T00:00:00.000Z"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"success": true
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 2. List Operation (Read Multiple Records)
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
// Get all records with basic filtering
|
|
122
154
|
POST /api/Users/crud
|
|
123
155
|
{
|
|
124
156
|
"action": "list",
|
|
@@ -128,103 +160,491 @@ POST /api/Users/crud
|
|
|
128
160
|
"limit": 10
|
|
129
161
|
}
|
|
130
162
|
|
|
131
|
-
//
|
|
163
|
+
// List with pagination
|
|
164
|
+
POST /api/Users/crud
|
|
165
|
+
{
|
|
166
|
+
"action": "list",
|
|
167
|
+
"select": ["id", "username", "email"],
|
|
168
|
+
"sort": [["created_at", "desc"]],
|
|
169
|
+
"limit": 10,
|
|
170
|
+
"offset": 20
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// List with complex conditions
|
|
174
|
+
POST /api/Users/crud
|
|
175
|
+
{
|
|
176
|
+
"action": "list",
|
|
177
|
+
"where": {
|
|
178
|
+
"first_name": { "like": "%John%" },
|
|
179
|
+
"email": { "like": "%@example.com" },
|
|
180
|
+
"age": { ">=": 18, "<=": 65 },
|
|
181
|
+
"is_active": true
|
|
182
|
+
},
|
|
183
|
+
"select": ["id", "username", "email", "first_name", "last_name"],
|
|
184
|
+
"sort": [["created_at", "desc"], ["last_name", "asc"]],
|
|
185
|
+
"limit": 10
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Response
|
|
189
|
+
{
|
|
190
|
+
"data": [
|
|
191
|
+
{
|
|
192
|
+
"id": 1,
|
|
193
|
+
"username": "john_doe",
|
|
194
|
+
"email": "john@example.com",
|
|
195
|
+
"first_name": "John",
|
|
196
|
+
"last_name": "Doe"
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
"total": 1,
|
|
200
|
+
"page": 1,
|
|
201
|
+
"limit": 10
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 3. Show Operation (Read Single Record)
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
// Get single record by ID
|
|
132
209
|
POST /api/Users/crud
|
|
133
210
|
{
|
|
134
211
|
"action": "show",
|
|
135
212
|
"where": { "id": 1 }
|
|
136
213
|
}
|
|
137
214
|
|
|
138
|
-
//
|
|
215
|
+
// Get single record with multiple conditions
|
|
216
|
+
POST /api/Users/crud
|
|
217
|
+
{
|
|
218
|
+
"action": "show",
|
|
219
|
+
"where": {
|
|
220
|
+
"username": "john_doe",
|
|
221
|
+
"is_active": true
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Response
|
|
226
|
+
{
|
|
227
|
+
"id": 1,
|
|
228
|
+
"username": "john_doe",
|
|
229
|
+
"email": "john@example.com",
|
|
230
|
+
"first_name": "John",
|
|
231
|
+
"last_name": "Doe",
|
|
232
|
+
"age": 30,
|
|
233
|
+
"is_active": true,
|
|
234
|
+
"created_at": "2024-01-01T00:00:00.000Z",
|
|
235
|
+
"updated_at": "2024-01-01T00:00:00.000Z"
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 4. Update Operation
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
// Update record by ID
|
|
139
243
|
POST /api/Users/crud
|
|
140
244
|
{
|
|
141
245
|
"action": "update",
|
|
142
246
|
"where": { "id": 1 },
|
|
143
247
|
"data": {
|
|
144
248
|
"first_name": "Jane",
|
|
145
|
-
"
|
|
249
|
+
"last_name": "Smith",
|
|
250
|
+
"updated_at": new Date().toISOString()
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Update multiple records
|
|
255
|
+
POST /api/Users/crud
|
|
256
|
+
{
|
|
257
|
+
"action": "update",
|
|
258
|
+
"where": { "is_active": false },
|
|
259
|
+
"data": {
|
|
260
|
+
"is_active": true,
|
|
261
|
+
"updated_at": new Date().toISOString()
|
|
146
262
|
}
|
|
147
263
|
}
|
|
148
264
|
|
|
149
|
-
//
|
|
265
|
+
// Response
|
|
266
|
+
{
|
|
267
|
+
"message": "Record updated successfully",
|
|
268
|
+
"data": [
|
|
269
|
+
{
|
|
270
|
+
"id": 1,
|
|
271
|
+
"first_name": "Jane",
|
|
272
|
+
"last_name": "Smith",
|
|
273
|
+
"updated_at": "2024-01-01T00:00:00.000Z"
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
"success": true
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 5. Delete Operation
|
|
281
|
+
|
|
282
|
+
```javascript
|
|
283
|
+
// Hard delete (permanent deletion)
|
|
150
284
|
POST /api/Users/crud
|
|
151
285
|
{
|
|
152
286
|
"action": "delete",
|
|
153
287
|
"where": { "id": 1 }
|
|
154
288
|
}
|
|
155
289
|
|
|
156
|
-
//
|
|
290
|
+
// Delete multiple records
|
|
291
|
+
POST /api/Users/crud
|
|
292
|
+
{
|
|
293
|
+
"action": "delete",
|
|
294
|
+
"where": { "is_active": false }
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Response
|
|
298
|
+
{
|
|
299
|
+
"message": "Record deleted successfully",
|
|
300
|
+
"data": [/* deleted records */],
|
|
301
|
+
"success": true
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 6. Count Operation
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
// Count all records
|
|
309
|
+
POST /api/Users/crud
|
|
310
|
+
{
|
|
311
|
+
"action": "count"
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Count with conditions
|
|
157
315
|
POST /api/Users/crud
|
|
158
316
|
{
|
|
159
317
|
"action": "count",
|
|
160
|
-
"where": {
|
|
318
|
+
"where": {
|
|
319
|
+
"is_active": true,
|
|
320
|
+
"created_at": { ">=": "2024-01-01" }
|
|
321
|
+
}
|
|
161
322
|
}
|
|
323
|
+
|
|
324
|
+
// Response
|
|
325
|
+
42 // Number of matching records
|
|
162
326
|
```
|
|
163
327
|
|
|
164
|
-
###
|
|
328
|
+
### 7. Replace Operation
|
|
165
329
|
|
|
166
330
|
```javascript
|
|
167
|
-
//
|
|
331
|
+
// Replace record (MySQL specific - replaces entire row)
|
|
332
|
+
POST /api/Users/crud
|
|
333
|
+
{
|
|
334
|
+
"action": "replace",
|
|
335
|
+
"data": {
|
|
336
|
+
"id": 1,
|
|
337
|
+
"username": "john_doe_updated",
|
|
338
|
+
"email": "john.updated@example.com",
|
|
339
|
+
"first_name": "John",
|
|
340
|
+
"last_name": "Doe Updated"
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Response
|
|
345
|
+
{
|
|
346
|
+
"message": "Record replaced successfully",
|
|
347
|
+
"data": [/* replaced record */],
|
|
348
|
+
"success": true
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### 8. Upsert Operation (Insert or Update)
|
|
353
|
+
|
|
354
|
+
```javascript
|
|
355
|
+
// Upsert record (insert if not exists, update if exists)
|
|
356
|
+
POST /api/Users/crud
|
|
357
|
+
{
|
|
358
|
+
"action": "upsert",
|
|
359
|
+
"data": {
|
|
360
|
+
"username": "john_doe",
|
|
361
|
+
"email": "john@example.com",
|
|
362
|
+
"first_name": "John",
|
|
363
|
+
"last_name": "Doe"
|
|
364
|
+
},
|
|
365
|
+
"conflict": ["username"] // Conflict columns for MySQL
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Response
|
|
369
|
+
{
|
|
370
|
+
"message": "Record upserted successfully",
|
|
371
|
+
"data": [/* upserted record */],
|
|
372
|
+
"success": true
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### 9. Sync Operation (Upsert + Delete)
|
|
377
|
+
|
|
378
|
+
```javascript
|
|
379
|
+
// Sync operation: upsert records and delete others matching where clause
|
|
380
|
+
POST /api/Users/crud
|
|
381
|
+
{
|
|
382
|
+
"action": "sync",
|
|
383
|
+
"data": {
|
|
384
|
+
"username": "john_doe",
|
|
385
|
+
"email": "john@example.com",
|
|
386
|
+
"first_name": "John",
|
|
387
|
+
"last_name": "Doe"
|
|
388
|
+
},
|
|
389
|
+
"conflict": ["username"],
|
|
390
|
+
"where": {
|
|
391
|
+
"created_at": { "<": "2024-01-01" }
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Response
|
|
396
|
+
{
|
|
397
|
+
"message": "Record synced successfully",
|
|
398
|
+
"data": {
|
|
399
|
+
"insertOrUpdateQuery": [/* upserted records */],
|
|
400
|
+
"deleteQuery": [/* deleted records */]
|
|
401
|
+
},
|
|
402
|
+
"success": true
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Advanced Querying
|
|
407
|
+
|
|
408
|
+
### Complex Where Conditions
|
|
409
|
+
|
|
410
|
+
```javascript
|
|
411
|
+
// Multiple operators
|
|
168
412
|
POST /api/Users/crud
|
|
169
413
|
{
|
|
170
414
|
"action": "list",
|
|
171
415
|
"where": {
|
|
172
|
-
"
|
|
416
|
+
"age": { ">=": 18, "<=": 65 },
|
|
173
417
|
"email": { "like": "%@example.com" },
|
|
174
|
-
"
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
"limit": 10
|
|
418
|
+
"first_name": { "in": ["John", "Jane", "Bob"] },
|
|
419
|
+
"is_active": true,
|
|
420
|
+
"created_at": { ">=": "2024-01-01", "<=": "2024-12-31" }
|
|
421
|
+
}
|
|
179
422
|
}
|
|
180
423
|
|
|
181
|
-
//
|
|
424
|
+
// OR conditions (using arrays)
|
|
182
425
|
POST /api/Users/crud
|
|
183
426
|
{
|
|
184
427
|
"action": "list",
|
|
185
|
-
"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
428
|
+
"where": {
|
|
429
|
+
"or": [
|
|
430
|
+
{ "first_name": "John" },
|
|
431
|
+
{ "last_name": "Doe" }
|
|
432
|
+
]
|
|
433
|
+
}
|
|
189
434
|
}
|
|
190
435
|
|
|
191
|
-
//
|
|
436
|
+
// NULL checks
|
|
192
437
|
POST /api/Users/crud
|
|
193
438
|
{
|
|
194
|
-
"action": "
|
|
439
|
+
"action": "list",
|
|
195
440
|
"where": {
|
|
196
|
-
"
|
|
197
|
-
"created_at": { ">=": "2024-01-01" }
|
|
441
|
+
"deleted_at": null
|
|
198
442
|
}
|
|
199
443
|
}
|
|
444
|
+
```
|
|
200
445
|
|
|
201
|
-
|
|
446
|
+
### Sorting
|
|
447
|
+
|
|
448
|
+
```javascript
|
|
449
|
+
// Single sort
|
|
202
450
|
POST /api/Users/crud
|
|
203
451
|
{
|
|
204
452
|
"action": "list",
|
|
205
|
-
"
|
|
453
|
+
"sort": [["created_at", "desc"]]
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Multiple sorts
|
|
457
|
+
POST /api/Users/crud
|
|
458
|
+
{
|
|
459
|
+
"action": "list",
|
|
460
|
+
"sort": [
|
|
461
|
+
["is_active", "desc"],
|
|
462
|
+
["created_at", "desc"],
|
|
463
|
+
["last_name", "asc"]
|
|
464
|
+
]
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Joins
|
|
469
|
+
|
|
470
|
+
```javascript
|
|
471
|
+
// Inner join
|
|
472
|
+
POST /api/Users/crud
|
|
473
|
+
{
|
|
474
|
+
"action": "list",
|
|
475
|
+
"select": ["users.id", "users.username", "profiles.bio"],
|
|
206
476
|
"join": [
|
|
207
477
|
{
|
|
208
478
|
"table": "user_profiles",
|
|
209
|
-
"
|
|
479
|
+
"as": "profiles",
|
|
480
|
+
"on": "users.id = profiles.user_id",
|
|
481
|
+
"type": "inner"
|
|
210
482
|
}
|
|
211
483
|
],
|
|
212
484
|
"where": { "users.is_active": true }
|
|
213
485
|
}
|
|
486
|
+
|
|
487
|
+
// Left join
|
|
488
|
+
POST /api/Users/crud
|
|
489
|
+
{
|
|
490
|
+
"action": "list",
|
|
491
|
+
"select": ["users.*", "profiles.bio"],
|
|
492
|
+
"join": [
|
|
493
|
+
{
|
|
494
|
+
"table": "user_profiles",
|
|
495
|
+
"as": "profiles",
|
|
496
|
+
"on": "users.id = profiles.user_id",
|
|
497
|
+
"type": "left"
|
|
498
|
+
}
|
|
499
|
+
]
|
|
500
|
+
}
|
|
214
501
|
```
|
|
215
502
|
|
|
216
|
-
|
|
503
|
+
## Soft Delete Support
|
|
504
|
+
|
|
505
|
+
### Enabling Soft Delete
|
|
506
|
+
|
|
507
|
+
Create a model file at `models/Users.model.js`:
|
|
217
508
|
|
|
218
509
|
```javascript
|
|
219
|
-
|
|
510
|
+
class Users {
|
|
511
|
+
// Enable soft delete for this model
|
|
512
|
+
hasSoftDelete = true;
|
|
513
|
+
|
|
514
|
+
// Optional: Custom soft delete hook
|
|
515
|
+
beforeDelete({ model, action, request, context, db, utils, controller }) {
|
|
516
|
+
// Custom logic before soft delete
|
|
517
|
+
console.log('Soft deleting user:', request.where);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Optional: Custom hook after soft delete
|
|
521
|
+
afterDelete({ model, action, data, request, context, db, utils, controller }) {
|
|
522
|
+
// Custom logic after soft delete
|
|
523
|
+
console.log('User soft deleted:', data);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
module.exports = Users;
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Using Soft Delete
|
|
531
|
+
|
|
532
|
+
```javascript
|
|
533
|
+
// When soft delete is enabled, delete action automatically sets deleted_at
|
|
534
|
+
POST /api/Users/crud
|
|
535
|
+
{
|
|
536
|
+
"action": "delete",
|
|
537
|
+
"where": { "id": 1 }
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// List operation automatically filters out soft-deleted records
|
|
541
|
+
POST /api/Users/crud
|
|
542
|
+
{
|
|
543
|
+
"action": "list",
|
|
544
|
+
"where": { "is_active": true }
|
|
545
|
+
// Automatically adds: deleted_at IS NULL
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// To see soft-deleted records, you need to query directly
|
|
549
|
+
// (soft delete only affects list and delete operations)
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
## Model Hooks
|
|
553
|
+
|
|
554
|
+
### Creating Model Hooks
|
|
555
|
+
|
|
556
|
+
Create a model file at `models/Users.model.js`:
|
|
557
|
+
|
|
558
|
+
```javascript
|
|
559
|
+
class Users {
|
|
560
|
+
// Validation hook - runs before any action
|
|
561
|
+
async validate({ model, action, request, context, db, utils, controller }) {
|
|
562
|
+
if (action === 'create' || action === 'update') {
|
|
563
|
+
if (!request.data.email) {
|
|
564
|
+
throw new Error('Email is required');
|
|
565
|
+
}
|
|
566
|
+
// Check if email already exists
|
|
567
|
+
const existing = await db('users')
|
|
568
|
+
.where('email', request.data.email)
|
|
569
|
+
.first();
|
|
570
|
+
if (existing && existing.id !== request.where?.id) {
|
|
571
|
+
throw new Error('Email already exists');
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Before hook - runs before the action executes
|
|
577
|
+
async beforeCreate({ model, action, request, context, db, utils, controller }) {
|
|
578
|
+
// Add timestamps
|
|
579
|
+
request.data.created_at = new Date();
|
|
580
|
+
request.data.updated_at = new Date();
|
|
581
|
+
return request.data;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
async beforeUpdate({ model, action, request, context, db, utils, controller }) {
|
|
585
|
+
// Update timestamp
|
|
586
|
+
request.data.updated_at = new Date();
|
|
587
|
+
return request.data;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// After hook - runs after the action executes
|
|
591
|
+
async afterCreate({ model, action, data, request, context, db, utils, controller }) {
|
|
592
|
+
// Log creation
|
|
593
|
+
console.log('User created:', data);
|
|
594
|
+
// Send welcome email, etc.
|
|
595
|
+
return data;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
async afterUpdate({ model, action, data, request, context, db, utils, controller }) {
|
|
599
|
+
// Log update
|
|
600
|
+
console.log('User updated:', data);
|
|
601
|
+
return data;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Custom action hook
|
|
605
|
+
async onCustomAction({ model, action, request, context, db, utils, controller }) {
|
|
606
|
+
// Handle custom actions like 'activate', 'deactivate', etc.
|
|
607
|
+
if (action === 'activate') {
|
|
608
|
+
return await db('users')
|
|
609
|
+
.where(request.where)
|
|
610
|
+
.update({ is_active: true, updated_at: new Date() });
|
|
611
|
+
}
|
|
612
|
+
throw new Error(`Unknown custom action: ${action}`);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// Soft delete support
|
|
616
|
+
hasSoftDelete = true;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
module.exports = Users;
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Using Custom Actions
|
|
623
|
+
|
|
624
|
+
```javascript
|
|
625
|
+
// Call custom action
|
|
626
|
+
POST /api/Users/crud
|
|
627
|
+
{
|
|
628
|
+
"action": "activate",
|
|
629
|
+
"where": { "id": 1 }
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
## Data Validation
|
|
634
|
+
|
|
635
|
+
### Basic Validation
|
|
636
|
+
|
|
637
|
+
```javascript
|
|
638
|
+
const { validate } = require('@dreamtree-org/korm-js');
|
|
220
639
|
|
|
221
640
|
// Define validation rules
|
|
222
641
|
const userValidationRules = {
|
|
223
|
-
username: 'required|type:string|maxLen:50',
|
|
642
|
+
username: 'required|type:string|minLen:3|maxLen:50',
|
|
224
643
|
email: 'required|type:string|maxLen:255',
|
|
225
644
|
first_name: 'required|type:string|maxLen:100',
|
|
226
645
|
last_name: 'required|type:string|maxLen:100',
|
|
227
|
-
age: 'type:number|min:0|max:150'
|
|
646
|
+
age: 'type:number|min:0|max:150',
|
|
647
|
+
is_active: 'type:boolean'
|
|
228
648
|
};
|
|
229
649
|
|
|
230
650
|
// Validate and create user
|
|
@@ -235,24 +655,20 @@ app.post('/api/users/validate', async (req, res) => {
|
|
|
235
655
|
|
|
236
656
|
const result = await korm.processRequest({
|
|
237
657
|
action: 'create',
|
|
238
|
-
data:
|
|
239
|
-
...validatedData,
|
|
240
|
-
created_at: new Date(),
|
|
241
|
-
updated_at: new Date()
|
|
242
|
-
}
|
|
658
|
+
data: validatedData
|
|
243
659
|
}, 'Users');
|
|
244
660
|
|
|
245
661
|
res.status(201).json({
|
|
246
662
|
success: true,
|
|
247
663
|
message: 'User created successfully',
|
|
248
|
-
data: result
|
|
664
|
+
data: result
|
|
249
665
|
});
|
|
250
666
|
} catch (error) {
|
|
251
667
|
if (error.name === 'ValidationError') {
|
|
252
668
|
return res.status(400).json({
|
|
253
669
|
success: false,
|
|
254
670
|
message: 'Validation failed',
|
|
255
|
-
errors: error.message
|
|
671
|
+
errors: error.message
|
|
256
672
|
});
|
|
257
673
|
}
|
|
258
674
|
|
|
@@ -265,28 +681,102 @@ app.post('/api/users/validate', async (req, res) => {
|
|
|
265
681
|
});
|
|
266
682
|
```
|
|
267
683
|
|
|
268
|
-
###
|
|
684
|
+
### Advanced Validation
|
|
685
|
+
|
|
686
|
+
```javascript
|
|
687
|
+
const { validate } = require('@dreamtree-org/korm-js');
|
|
688
|
+
|
|
689
|
+
// Advanced validation rules
|
|
690
|
+
const advancedRules = {
|
|
691
|
+
username: 'required|type:string|regex:username',
|
|
692
|
+
email: 'required|type:string|regex:email',
|
|
693
|
+
phone: 'regex:phone',
|
|
694
|
+
password: 'required|type:string|minLen:8',
|
|
695
|
+
confirm_password: 'required|type:string|match:password',
|
|
696
|
+
status: 'in:active,inactive,pending',
|
|
697
|
+
user_id: 'exists:users,id'
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
const customRegex = {
|
|
701
|
+
username: /^[a-zA-Z0-9_]+$/,
|
|
702
|
+
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
703
|
+
phone: /^\+?[\d\s-()]{10,15}$/
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
const validatedData = await validate(data, advancedRules, { customRegex });
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
## Nested Requests
|
|
710
|
+
|
|
711
|
+
```javascript
|
|
712
|
+
// Process multiple related requests in one call
|
|
713
|
+
POST /api/Users/crud
|
|
714
|
+
{
|
|
715
|
+
"action": "show",
|
|
716
|
+
"where": { "id": 1 },
|
|
717
|
+
"other_requests": {
|
|
718
|
+
"Posts": {
|
|
719
|
+
"action": "list",
|
|
720
|
+
"where": { "user_id": 1 },
|
|
721
|
+
"limit": 10
|
|
722
|
+
},
|
|
723
|
+
"Comments": {
|
|
724
|
+
"action": "list",
|
|
725
|
+
"where": { "user_id": 1 },
|
|
726
|
+
"limit": 5
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Response includes nested data
|
|
732
|
+
{
|
|
733
|
+
"id": 1,
|
|
734
|
+
"username": "john_doe",
|
|
735
|
+
"email": "john@example.com",
|
|
736
|
+
"other_responses": {
|
|
737
|
+
"Posts": {
|
|
738
|
+
"data": [/* posts */],
|
|
739
|
+
"total": 10
|
|
740
|
+
},
|
|
741
|
+
"Comments": {
|
|
742
|
+
"data": [/* comments */],
|
|
743
|
+
"total": 5
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
## Schema Structure
|
|
750
|
+
|
|
751
|
+
### Example Schema (Auto-generated from MySQL)
|
|
269
752
|
|
|
270
753
|
```javascript
|
|
271
|
-
// Example schema structure (auto-generated)
|
|
272
754
|
{
|
|
273
755
|
"Users": {
|
|
274
756
|
"table": "users",
|
|
275
757
|
"alias": "Users",
|
|
758
|
+
"modelName": "Users",
|
|
276
759
|
"columns": {
|
|
277
|
-
"id": "bigint|size:8|
|
|
278
|
-
"username": "
|
|
279
|
-
"email": "
|
|
280
|
-
"first_name": "
|
|
281
|
-
"last_name": "
|
|
282
|
-
"
|
|
283
|
-
"
|
|
284
|
-
"
|
|
760
|
+
"id": "bigint|size:8|unsigned|auto_increment",
|
|
761
|
+
"username": "varchar|size:255",
|
|
762
|
+
"email": "varchar|size:255",
|
|
763
|
+
"first_name": "varchar|size:255|nullable",
|
|
764
|
+
"last_name": "varchar|size:255|nullable",
|
|
765
|
+
"age": "int|size:4|nullable",
|
|
766
|
+
"is_active": "tinyint|size:1|default:1",
|
|
767
|
+
"created_at": "timestamp|default:CURRENT_TIMESTAMP",
|
|
768
|
+
"updated_at": "timestamp|default:CURRENT_TIMESTAMP|onUpdate:CURRENT_TIMESTAMP",
|
|
769
|
+
"deleted_at": "timestamp|nullable"
|
|
285
770
|
},
|
|
286
|
-
"modelName": "Users",
|
|
287
771
|
"seed": [],
|
|
288
772
|
"hasRelations": {},
|
|
289
|
-
"indexes": [
|
|
773
|
+
"indexes": [
|
|
774
|
+
{
|
|
775
|
+
"name": "idx_users_email",
|
|
776
|
+
"columns": ["email"],
|
|
777
|
+
"unique": true
|
|
778
|
+
}
|
|
779
|
+
]
|
|
290
780
|
}
|
|
291
781
|
}
|
|
292
782
|
```
|
|
@@ -298,12 +788,15 @@ app.post('/api/users/validate', async (req, res) => {
|
|
|
298
788
|
```javascript
|
|
299
789
|
const korm = initializeKORM({
|
|
300
790
|
db: db,
|
|
301
|
-
dbClient: '
|
|
791
|
+
dbClient: 'mysql' // or 'pg', 'sqlite'
|
|
302
792
|
});
|
|
303
793
|
|
|
304
794
|
// Process any CRUD request
|
|
305
795
|
const result = await korm.processRequest(requestBody, modelName);
|
|
306
796
|
|
|
797
|
+
// Process request with nested requests
|
|
798
|
+
const result = await korm.processRequestWithOthers(requestBody, modelName);
|
|
799
|
+
|
|
307
800
|
// Set schema manually
|
|
308
801
|
korm.setSchema(schemaObject);
|
|
309
802
|
|
|
@@ -314,139 +807,100 @@ await korm.syncDatabase();
|
|
|
314
807
|
const schema = await korm.generateSchema();
|
|
315
808
|
```
|
|
316
809
|
|
|
317
|
-
###
|
|
318
|
-
|
|
319
|
-
```javascript
|
|
320
|
-
// List records
|
|
321
|
-
{
|
|
322
|
-
"action": "list",
|
|
323
|
-
"where": { "is_active": true },
|
|
324
|
-
"select": ["id", "name", "email"],
|
|
325
|
-
"sort": [["created_at", "desc"]],
|
|
326
|
-
"limit": 10,
|
|
327
|
-
"offset": 0
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Show single record
|
|
331
|
-
{
|
|
332
|
-
"action": "show",
|
|
333
|
-
"where": { "id": 1 }
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Create record
|
|
337
|
-
{
|
|
338
|
-
"action": "create",
|
|
339
|
-
"data": { "name": "John", "email": "john@example.com" }
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Update record
|
|
343
|
-
{
|
|
344
|
-
"action": "update",
|
|
345
|
-
"where": { "id": 1 },
|
|
346
|
-
"data": { "name": "Jane" }
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// Delete record
|
|
350
|
-
{
|
|
351
|
-
"action": "delete",
|
|
352
|
-
"where": { "id": 1 }
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Count records
|
|
356
|
-
{
|
|
357
|
-
"action": "count",
|
|
358
|
-
"where": { "is_active": true }
|
|
359
|
-
}
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
### Validation Rules
|
|
810
|
+
### ControllerWrapper Static Methods
|
|
363
811
|
|
|
364
812
|
```javascript
|
|
365
|
-
const {
|
|
366
|
-
|
|
367
|
-
// Basic validation rules
|
|
368
|
-
const rules = {
|
|
369
|
-
username: 'required|type:string|minLen:3|maxLen:30',
|
|
370
|
-
email: 'required|type:string|maxLen:255',
|
|
371
|
-
age: 'type:number|min:0|max:150',
|
|
372
|
-
status: 'in:active,inactive,pending'
|
|
373
|
-
};
|
|
813
|
+
const { ControllerWrapper } = require('@dreamtree-org/korm-js');
|
|
374
814
|
|
|
375
|
-
//
|
|
376
|
-
const
|
|
377
|
-
username: 'required|type:string|regex:username',
|
|
378
|
-
email: 'required|type:string|regex:email',
|
|
379
|
-
phone: 'regex:phone',
|
|
380
|
-
user_id: 'exists:users,id'
|
|
381
|
-
};
|
|
815
|
+
// Load model class
|
|
816
|
+
const ModelClass = ControllerWrapper.loadModelClass('Users');
|
|
382
817
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
386
|
-
phone: /^\+?[\d\s-()]{10,15}$/
|
|
387
|
-
};
|
|
818
|
+
// Get model instance
|
|
819
|
+
const modelInstance = ControllerWrapper.getModelInstance(model);
|
|
388
820
|
|
|
389
|
-
|
|
821
|
+
// Generate schema
|
|
822
|
+
const schema = await ControllerWrapper.generateSchema();
|
|
390
823
|
```
|
|
391
824
|
|
|
392
|
-
###
|
|
825
|
+
### ProcessRequest Actions Summary
|
|
393
826
|
|
|
394
|
-
|
|
395
|
-
|
|
827
|
+
| Action | Description | Required Fields |
|
|
828
|
+
|--------|-------------|----------------|
|
|
829
|
+
| `create` | Create new record | `data` |
|
|
830
|
+
| `list` | Get multiple records | None (optional: `where`, `select`, `sort`, `limit`, `offset`) |
|
|
831
|
+
| `show` | Get single record | `where` |
|
|
832
|
+
| `update` | Update record(s) | `where`, `data` |
|
|
833
|
+
| `delete` | Delete record(s) | `where` |
|
|
834
|
+
| `count` | Count records | None (optional: `where`) |
|
|
835
|
+
| `replace` | Replace record (MySQL) | `data` |
|
|
836
|
+
| `upsert` | Insert or update | `data`, `conflict` |
|
|
837
|
+
| `sync` | Upsert + delete | `data`, `conflict`, `where` |
|
|
396
838
|
|
|
397
|
-
|
|
398
|
-
helperUtility.file.readJSON('path/to/file.json');
|
|
399
|
-
helperUtility.file.writeJSON('path/to/file.json', data);
|
|
400
|
-
helperUtility.file.createDirectory('path/to/directory');
|
|
839
|
+
### Validation Rules
|
|
401
840
|
|
|
402
|
-
|
|
403
|
-
|
|
841
|
+
| Rule | Description | Example |
|
|
842
|
+
|------|-------------|---------|
|
|
843
|
+
| `required` | Field is required | `username: 'required'` |
|
|
844
|
+
| `type:string` | Field must be string | `name: 'type:string'` |
|
|
845
|
+
| `type:number` | Field must be number | `age: 'type:number'` |
|
|
846
|
+
| `type:boolean` | Field must be boolean | `is_active: 'type:boolean'` |
|
|
847
|
+
| `minLen:n` | Minimum length | `username: 'minLen:3'` |
|
|
848
|
+
| `maxLen:n` | Maximum length | `email: 'maxLen:255'` |
|
|
849
|
+
| `min:n` | Minimum value | `age: 'min:0'` |
|
|
850
|
+
| `max:n` | Maximum value | `age: 'max:150'` |
|
|
851
|
+
| `in:val1,val2` | Value must be in list | `status: 'in:active,inactive'` |
|
|
852
|
+
| `regex:name` | Custom regex pattern | `email: 'regex:email'` |
|
|
853
|
+
| `match:field` | Must match another field | `confirm_password: 'match:password'` |
|
|
854
|
+
| `exists:table,column` | Value must exist in table | `user_id: 'exists:users,id'` |
|
|
404
855
|
|
|
405
856
|
## Database Support
|
|
406
857
|
|
|
407
|
-
###
|
|
858
|
+
### MySQL (Current Guide)
|
|
859
|
+
|
|
408
860
|
```javascript
|
|
409
861
|
const knex = require('knex');
|
|
410
862
|
|
|
411
863
|
const db = knex({
|
|
412
|
-
client: '
|
|
864
|
+
client: 'mysql2',
|
|
413
865
|
connection: {
|
|
414
866
|
host: process.env.DB_HOST || 'localhost',
|
|
415
|
-
user: process.env.DB_USER || '
|
|
867
|
+
user: process.env.DB_USER || 'root',
|
|
416
868
|
password: process.env.DB_PASS || 'password',
|
|
417
869
|
database: process.env.DB_NAME || 'database_name',
|
|
418
|
-
port: process.env.DB_PORT ||
|
|
870
|
+
port: process.env.DB_PORT || 3306
|
|
419
871
|
}
|
|
420
872
|
});
|
|
421
873
|
|
|
422
874
|
const korm = initializeKORM({
|
|
423
875
|
db: db,
|
|
424
|
-
dbClient: '
|
|
876
|
+
dbClient: 'mysql'
|
|
425
877
|
});
|
|
426
878
|
```
|
|
427
879
|
|
|
428
|
-
###
|
|
880
|
+
### PostgreSQL
|
|
881
|
+
|
|
429
882
|
```javascript
|
|
430
883
|
const knex = require('knex');
|
|
431
884
|
|
|
432
885
|
const db = knex({
|
|
433
|
-
client: '
|
|
886
|
+
client: 'pg',
|
|
434
887
|
connection: {
|
|
435
888
|
host: process.env.DB_HOST || 'localhost',
|
|
436
889
|
user: process.env.DB_USER || 'username',
|
|
437
890
|
password: process.env.DB_PASS || 'password',
|
|
438
891
|
database: process.env.DB_NAME || 'database_name',
|
|
439
|
-
port: process.env.DB_PORT ||
|
|
892
|
+
port: process.env.DB_PORT || 5432
|
|
440
893
|
}
|
|
441
894
|
});
|
|
442
895
|
|
|
443
896
|
const korm = initializeKORM({
|
|
444
897
|
db: db,
|
|
445
|
-
dbClient: '
|
|
898
|
+
dbClient: 'pg'
|
|
446
899
|
});
|
|
447
900
|
```
|
|
448
901
|
|
|
449
902
|
### SQLite
|
|
903
|
+
|
|
450
904
|
```javascript
|
|
451
905
|
const knex = require('knex');
|
|
452
906
|
|
|
@@ -466,15 +920,123 @@ const korm = initializeKORM({
|
|
|
466
920
|
## Error Handling
|
|
467
921
|
|
|
468
922
|
```javascript
|
|
923
|
+
// Global error handler
|
|
469
924
|
app.use((error, req, res, next) => {
|
|
470
925
|
console.error('KORM Error:', error);
|
|
471
926
|
|
|
472
|
-
res.status(500).json({
|
|
927
|
+
res.status(error.status || 500).json({
|
|
473
928
|
success: false,
|
|
474
929
|
message: 'Internal server error',
|
|
475
|
-
error: process.env.NODE_ENV === 'development' ? error.message : 'Something went wrong'
|
|
930
|
+
error: process.env.NODE_ENV === 'development' ? error.message : 'Something went wrong',
|
|
931
|
+
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
|
|
476
932
|
});
|
|
477
933
|
});
|
|
934
|
+
|
|
935
|
+
// Route-specific error handling
|
|
936
|
+
app.post('/api/:model/crud', async (req, res) => {
|
|
937
|
+
try {
|
|
938
|
+
const { model } = req.params;
|
|
939
|
+
const result = await korm.processRequest(req.body, model);
|
|
940
|
+
res.json(result);
|
|
941
|
+
} catch (error) {
|
|
942
|
+
// Handle validation errors
|
|
943
|
+
if (error.name === 'ValidationError') {
|
|
944
|
+
return res.status(400).json({
|
|
945
|
+
success: false,
|
|
946
|
+
message: 'Validation failed',
|
|
947
|
+
errors: error.message
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// Handle not found errors
|
|
952
|
+
if (error.message.includes('not found')) {
|
|
953
|
+
return res.status(404).json({
|
|
954
|
+
success: false,
|
|
955
|
+
message: error.message
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Handle other errors
|
|
960
|
+
res.status(400).json({
|
|
961
|
+
success: false,
|
|
962
|
+
message: error.message
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
## Complete Example Application
|
|
969
|
+
|
|
970
|
+
```javascript
|
|
971
|
+
require('dotenv').config();
|
|
972
|
+
const express = require('express');
|
|
973
|
+
const { initializeKORM, validate, helperUtility } = require('@dreamtree-org/korm-js');
|
|
974
|
+
const knex = require('knex');
|
|
975
|
+
|
|
976
|
+
const app = express();
|
|
977
|
+
app.use(express.json());
|
|
978
|
+
|
|
979
|
+
// MySQL configuration
|
|
980
|
+
const db = knex({
|
|
981
|
+
client: 'mysql2',
|
|
982
|
+
connection: {
|
|
983
|
+
host: process.env.DB_HOST || 'localhost',
|
|
984
|
+
user: process.env.DB_USER || 'root',
|
|
985
|
+
password: process.env.DB_PASS || 'password',
|
|
986
|
+
database: process.env.DB_NAME || 'my_database',
|
|
987
|
+
port: process.env.DB_PORT || 3306
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
// Initialize KORM
|
|
992
|
+
const korm = initializeKORM({
|
|
993
|
+
db: db,
|
|
994
|
+
dbClient: 'mysql'
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
// Initialize app
|
|
998
|
+
async function initApp() {
|
|
999
|
+
try {
|
|
1000
|
+
// Load or generate schema
|
|
1001
|
+
let schema = helperUtility.file.readJSON('schema/schema.json');
|
|
1002
|
+
if (schema) {
|
|
1003
|
+
korm.setSchema(schema);
|
|
1004
|
+
} else {
|
|
1005
|
+
schema = await korm.generateSchema();
|
|
1006
|
+
helperUtility.file.createDirectory('schema');
|
|
1007
|
+
helperUtility.file.writeJSON('schema/schema.json', schema);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// Sync database
|
|
1011
|
+
await korm.syncDatabase();
|
|
1012
|
+
console.log('✅ Database synced');
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
console.error('❌ Initialization error:', error);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// Generic CRUD endpoint
|
|
1019
|
+
app.post('/api/:model/crud', async (req, res) => {
|
|
1020
|
+
try {
|
|
1021
|
+
const { model } = req.params;
|
|
1022
|
+
const result = await korm.processRequest(req.body, model);
|
|
1023
|
+
res.json(result);
|
|
1024
|
+
} catch (error) {
|
|
1025
|
+
res.status(400).json({ error: error.message });
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
// Health check
|
|
1030
|
+
app.get('/health', (req, res) => {
|
|
1031
|
+
res.send('OK');
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
// Start server
|
|
1035
|
+
const PORT = process.env.PORT || 3000;
|
|
1036
|
+
app.listen(PORT, async () => {
|
|
1037
|
+
console.log(`🚀 Server running on http://localhost:${PORT}`);
|
|
1038
|
+
await initApp();
|
|
1039
|
+
});
|
|
478
1040
|
```
|
|
479
1041
|
|
|
480
1042
|
## Contributing
|
|
@@ -491,7 +1053,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
491
1053
|
|
|
492
1054
|
## Support
|
|
493
1055
|
|
|
494
|
-
If you have any questions or need help, please open an issue on GitHub or contact us at [partha.preetham.krishna@gmail.com](mailto:partha
|
|
1056
|
+
If you have any questions or need help, please open an issue on GitHub or contact us at [partha.preetham.krishna@gmail.com](mailto:partha-preetham.krishna@gmail.com).
|
|
495
1057
|
|
|
496
1058
|
---
|
|
497
1059
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dreamtree-org/korm-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.40",
|
|
4
4
|
"description": "Knowledge Object-Relational Mapping - A powerful, modular ORM system for Node.js with dynamic database operations, complex queries, relationships, and nested requests",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Partha Preetham Krishna",
|