@dreamtree-org/korm-js 1.0.45 → 1.0.46
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 +211 -83
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,7 +156,7 @@ POST /api/Users/crud
|
|
|
156
156
|
"action": "list",
|
|
157
157
|
"where": { "is_active": true },
|
|
158
158
|
"select": ["id", "username", "email", "first_name", "last_name"],
|
|
159
|
-
"
|
|
159
|
+
"orderBy": { "column": "created_at", "direction": "desc" },
|
|
160
160
|
"limit": 10
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -165,7 +165,7 @@ POST /api/Users/crud
|
|
|
165
165
|
{
|
|
166
166
|
"action": "list",
|
|
167
167
|
"select": ["id", "username", "email"],
|
|
168
|
-
"
|
|
168
|
+
"orderBy": { "column": "created_at", "direction": "desc" },
|
|
169
169
|
"limit": 10,
|
|
170
170
|
"offset": 20
|
|
171
171
|
}
|
|
@@ -181,7 +181,10 @@ POST /api/Users/crud
|
|
|
181
181
|
"is_active": true
|
|
182
182
|
},
|
|
183
183
|
"select": ["id", "username", "email", "first_name", "last_name"],
|
|
184
|
-
"
|
|
184
|
+
"orderBy": [
|
|
185
|
+
{ "column": "created_at", "direction": "desc" },
|
|
186
|
+
{ "column": "last_name", "direction": "asc" }
|
|
187
|
+
],
|
|
185
188
|
"limit": 10
|
|
186
189
|
}
|
|
187
190
|
|
|
@@ -584,63 +587,98 @@ POST /api/Users/crud
|
|
|
584
587
|
// AND role IN ('admin', 'moderator', 'editor') AND score BETWEEN 50 AND 100
|
|
585
588
|
```
|
|
586
589
|
|
|
587
|
-
### Sorting
|
|
590
|
+
### Sorting (orderBy)
|
|
588
591
|
|
|
589
592
|
```javascript
|
|
590
|
-
// Single sort
|
|
593
|
+
// Single sort with object
|
|
591
594
|
POST /api/Users/crud
|
|
592
595
|
{
|
|
593
596
|
"action": "list",
|
|
594
|
-
"
|
|
597
|
+
"orderBy": { "column": "created_at", "direction": "desc" }
|
|
595
598
|
}
|
|
596
599
|
|
|
597
|
-
//
|
|
600
|
+
// Single sort with string (default: ascending)
|
|
598
601
|
POST /api/Users/crud
|
|
599
602
|
{
|
|
600
603
|
"action": "list",
|
|
601
|
-
"
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
604
|
+
"orderBy": "created_at"
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Multiple sorts with array of objects
|
|
608
|
+
POST /api/Users/crud
|
|
609
|
+
{
|
|
610
|
+
"action": "list",
|
|
611
|
+
"orderBy": [
|
|
612
|
+
{ "column": "is_active", "direction": "desc" },
|
|
613
|
+
{ "column": "created_at", "direction": "desc" },
|
|
614
|
+
{ "column": "last_name", "direction": "asc" }
|
|
605
615
|
]
|
|
606
616
|
}
|
|
617
|
+
|
|
618
|
+
// Multiple sorts with array of strings (all ascending)
|
|
619
|
+
POST /api/Users/crud
|
|
620
|
+
{
|
|
621
|
+
"action": "list",
|
|
622
|
+
"orderBy": ["is_active", "created_at", "last_name"]
|
|
623
|
+
}
|
|
607
624
|
```
|
|
608
625
|
|
|
609
626
|
### Joins
|
|
610
627
|
|
|
611
628
|
```javascript
|
|
612
|
-
// Inner join
|
|
629
|
+
// Inner join (using innerJoin parameter)
|
|
613
630
|
POST /api/Users/crud
|
|
614
631
|
{
|
|
615
632
|
"action": "list",
|
|
616
|
-
"select": ["users.id", "users.username", "
|
|
617
|
-
"
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
"on": "users.id = profiles.user_id",
|
|
622
|
-
"type": "inner"
|
|
623
|
-
}
|
|
624
|
-
],
|
|
633
|
+
"select": ["users.id", "users.username", "user_profiles.bio"],
|
|
634
|
+
"innerJoin": {
|
|
635
|
+
"table": "user_profiles",
|
|
636
|
+
"on": "users.id = user_profiles.user_id"
|
|
637
|
+
},
|
|
625
638
|
"where": { "users.is_active": true }
|
|
626
639
|
}
|
|
627
640
|
|
|
628
|
-
// Left join
|
|
641
|
+
// Left join (using leftJoin parameter)
|
|
629
642
|
POST /api/Users/crud
|
|
630
643
|
{
|
|
631
644
|
"action": "list",
|
|
632
|
-
"select": ["users.*", "
|
|
633
|
-
"
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
645
|
+
"select": ["users.*", "user_profiles.bio"],
|
|
646
|
+
"leftJoin": {
|
|
647
|
+
"table": "user_profiles",
|
|
648
|
+
"on": "users.id = user_profiles.user_id"
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Multiple joins (array format)
|
|
653
|
+
POST /api/Users/crud
|
|
654
|
+
{
|
|
655
|
+
"action": "list",
|
|
656
|
+
"select": ["users.*", "profiles.bio", "roles.name"],
|
|
657
|
+
"leftJoin": [
|
|
658
|
+
{ "table": "user_profiles", "on": "users.id = user_profiles.user_id" },
|
|
659
|
+
{ "table": "roles", "on": "users.role_id = roles.id" }
|
|
640
660
|
]
|
|
641
661
|
}
|
|
662
|
+
|
|
663
|
+
// Join with explicit columns
|
|
664
|
+
POST /api/Users/crud
|
|
665
|
+
{
|
|
666
|
+
"action": "list",
|
|
667
|
+
"innerJoin": {
|
|
668
|
+
"table": "orders",
|
|
669
|
+
"first": "users.id",
|
|
670
|
+
"operator": "=",
|
|
671
|
+
"second": "orders.user_id"
|
|
672
|
+
}
|
|
673
|
+
}
|
|
642
674
|
```
|
|
643
675
|
|
|
676
|
+
**Available join types:**
|
|
677
|
+
- `join` - Regular join
|
|
678
|
+
- `innerJoin` - Inner join
|
|
679
|
+
- `leftJoin` - Left join
|
|
680
|
+
- `rightJoin` - Right join
|
|
681
|
+
|
|
644
682
|
## Relational Support with hasRelations
|
|
645
683
|
|
|
646
684
|
### Understanding hasRelations Structure
|
|
@@ -900,6 +938,9 @@ Create a model file at `models/Users.model.js`:
|
|
|
900
938
|
|
|
901
939
|
```javascript
|
|
902
940
|
class Users {
|
|
941
|
+
// Soft delete support (property, not method)
|
|
942
|
+
hasSoftDelete = true;
|
|
943
|
+
|
|
903
944
|
// Validation hook - runs before any action
|
|
904
945
|
async validate({ model, action, request, context, db, utils, controller }) {
|
|
905
946
|
if (action === 'create' || action === 'update') {
|
|
@@ -916,61 +957,91 @@ class Users {
|
|
|
916
957
|
}
|
|
917
958
|
}
|
|
918
959
|
|
|
919
|
-
// Before
|
|
960
|
+
// Before hooks - run before the action executes
|
|
961
|
+
// Method naming: before{Action} (e.g., beforeCreate, beforeUpdate, beforeList, beforeDelete)
|
|
920
962
|
async beforeCreate({ model, action, request, context, db, utils, controller }) {
|
|
921
|
-
//
|
|
963
|
+
// Modify request data before insert
|
|
922
964
|
request.data.created_at = new Date();
|
|
923
965
|
request.data.updated_at = new Date();
|
|
924
966
|
return request.data;
|
|
925
967
|
}
|
|
926
968
|
|
|
927
969
|
async beforeUpdate({ model, action, request, context, db, utils, controller }) {
|
|
928
|
-
//
|
|
970
|
+
// Modify request data before update
|
|
929
971
|
request.data.updated_at = new Date();
|
|
930
972
|
return request.data;
|
|
931
973
|
}
|
|
932
974
|
|
|
933
|
-
|
|
975
|
+
async beforeDelete({ model, action, request, context, db, utils, controller }) {
|
|
976
|
+
// Logic before delete (works with both hard and soft delete)
|
|
977
|
+
console.log('Deleting user:', request.where);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// After hooks - run after the action executes
|
|
981
|
+
// Method naming: after{Action} (e.g., afterCreate, afterUpdate, afterList, afterDelete)
|
|
934
982
|
async afterCreate({ model, action, data, request, context, db, utils, controller }) {
|
|
935
|
-
//
|
|
983
|
+
// data contains the result of the action
|
|
936
984
|
console.log('User created:', data);
|
|
937
|
-
// Send welcome email, etc.
|
|
985
|
+
// Send welcome email, trigger notifications, etc.
|
|
938
986
|
return data;
|
|
939
987
|
}
|
|
940
988
|
|
|
941
989
|
async afterUpdate({ model, action, data, request, context, db, utils, controller }) {
|
|
942
|
-
// Log update
|
|
943
990
|
console.log('User updated:', data);
|
|
944
991
|
return data;
|
|
945
992
|
}
|
|
946
993
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
if (action === 'activate') {
|
|
951
|
-
return await db('users')
|
|
952
|
-
.where(request.where)
|
|
953
|
-
.update({ is_active: true, updated_at: new Date() });
|
|
954
|
-
}
|
|
955
|
-
throw new Error(`Unknown custom action: ${action}`);
|
|
994
|
+
async afterList({ model, action, data, request, context, db, utils, controller }) {
|
|
995
|
+
// Modify list results before returning
|
|
996
|
+
return data;
|
|
956
997
|
}
|
|
957
998
|
|
|
958
|
-
//
|
|
959
|
-
|
|
999
|
+
// Custom action hooks
|
|
1000
|
+
// Method naming: on{Action}Action (e.g., onActivateAction, onDeactivateAction)
|
|
1001
|
+
async onActivateAction({ model, action, request, context, db, utils, controller }) {
|
|
1002
|
+
return await db('users')
|
|
1003
|
+
.where(request.where)
|
|
1004
|
+
.update({ is_active: true, updated_at: new Date() });
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
async onDeactivateAction({ model, action, request, context, db, utils, controller }) {
|
|
1008
|
+
return await db('users')
|
|
1009
|
+
.where(request.where)
|
|
1010
|
+
.update({ is_active: false, updated_at: new Date() });
|
|
1011
|
+
}
|
|
960
1012
|
}
|
|
961
1013
|
|
|
962
1014
|
module.exports = Users;
|
|
963
1015
|
```
|
|
964
1016
|
|
|
1017
|
+
### Hook Arguments Reference
|
|
1018
|
+
|
|
1019
|
+
| Argument | Description |
|
|
1020
|
+
|----------|-------------|
|
|
1021
|
+
| `model` | Model definition object with table, columns, relations |
|
|
1022
|
+
| `action` | Current action being performed (create, update, delete, etc.) |
|
|
1023
|
+
| `request` | The request object containing where, data, etc. |
|
|
1024
|
+
| `context` | Custom context passed from the controller |
|
|
1025
|
+
| `db` | Knex database instance for direct queries |
|
|
1026
|
+
| `utils` | Utility functions |
|
|
1027
|
+
| `controller` | ControllerWrapper instance |
|
|
1028
|
+
| `data` | (After hooks only) Result of the action |
|
|
1029
|
+
|
|
965
1030
|
### Using Custom Actions
|
|
966
1031
|
|
|
967
1032
|
```javascript
|
|
968
|
-
// Call custom action
|
|
1033
|
+
// Call custom action - triggers on{Action}Action hook
|
|
969
1034
|
POST /api/Users/crud
|
|
970
1035
|
{
|
|
971
1036
|
"action": "activate",
|
|
972
1037
|
"where": { "id": 1 }
|
|
973
1038
|
}
|
|
1039
|
+
|
|
1040
|
+
POST /api/Users/crud
|
|
1041
|
+
{
|
|
1042
|
+
"action": "deactivate",
|
|
1043
|
+
"where": { "id": 1 }
|
|
1044
|
+
}
|
|
974
1045
|
```
|
|
975
1046
|
|
|
976
1047
|
## Data Validation
|
|
@@ -1128,49 +1199,67 @@ POST /api/Users/crud
|
|
|
1128
1199
|
### KORM Instance Methods
|
|
1129
1200
|
|
|
1130
1201
|
```javascript
|
|
1202
|
+
const { initializeKORM } = require('@dreamtree-org/korm-js');
|
|
1203
|
+
|
|
1131
1204
|
const korm = initializeKORM({
|
|
1132
|
-
db: db,
|
|
1133
|
-
dbClient: 'mysql'
|
|
1205
|
+
db: db, // Knex database instance
|
|
1206
|
+
dbClient: 'mysql', // 'mysql', 'mysql2', 'pg', 'postgresql', 'sqlite', 'sqlite3'
|
|
1207
|
+
schema: null, // Optional: initial schema object
|
|
1208
|
+
resolverPath: null // Optional: path to models directory (default: process.cwd())
|
|
1134
1209
|
});
|
|
1135
1210
|
|
|
1136
|
-
// Process any CRUD request
|
|
1137
|
-
const result = await korm.processRequest(requestBody, modelName);
|
|
1211
|
+
// Process any CRUD request (automatically handles other_requests if present)
|
|
1212
|
+
const result = await korm.processRequest(requestBody, modelName, context);
|
|
1138
1213
|
|
|
1139
|
-
// Process request with nested requests
|
|
1140
|
-
const result = await korm.processRequestWithOthers(requestBody, modelName);
|
|
1214
|
+
// Process request with nested requests (legacy - now same as processRequest)
|
|
1215
|
+
const result = await korm.processRequestWithOthers(requestBody, modelName, context);
|
|
1141
1216
|
|
|
1142
1217
|
// Set schema manually
|
|
1143
1218
|
korm.setSchema(schemaObject);
|
|
1144
1219
|
|
|
1145
|
-
// Sync database with schema
|
|
1220
|
+
// Sync database with schema (creates/updates tables)
|
|
1146
1221
|
await korm.syncDatabase();
|
|
1147
1222
|
|
|
1148
1223
|
// Generate schema from existing database
|
|
1149
1224
|
const schema = await korm.generateSchema();
|
|
1150
|
-
```
|
|
1151
|
-
|
|
1152
|
-
### ControllerWrapper Static Methods
|
|
1153
1225
|
|
|
1154
|
-
|
|
1155
|
-
const
|
|
1156
|
-
|
|
1157
|
-
// Load model class
|
|
1158
|
-
const ModelClass = ControllerWrapper.loadModelClass('Users');
|
|
1226
|
+
// Load model class from models/{ModelName}.model.js
|
|
1227
|
+
const ModelClass = korm.loadModelClass('Users');
|
|
1159
1228
|
|
|
1160
1229
|
// Get model instance
|
|
1161
|
-
const modelInstance =
|
|
1162
|
-
|
|
1163
|
-
// Generate schema
|
|
1164
|
-
const schema = await ControllerWrapper.generateSchema();
|
|
1230
|
+
const modelInstance = korm.getModelInstance(modelDef);
|
|
1165
1231
|
```
|
|
1166
1232
|
|
|
1233
|
+
### ProcessRequest Options
|
|
1234
|
+
|
|
1235
|
+
| Parameter | Type | Description |
|
|
1236
|
+
|-----------|------|-------------|
|
|
1237
|
+
| `action` | string | Action to perform (list, show, create, update, delete, count, replace, upsert, sync) |
|
|
1238
|
+
| `where` | object/array | Filter conditions |
|
|
1239
|
+
| `data` | object/array | Data for create/update operations |
|
|
1240
|
+
| `select` | array/string | Columns to select |
|
|
1241
|
+
| `orderBy` | object/array/string | Sorting configuration |
|
|
1242
|
+
| `limit` | number | Maximum records to return |
|
|
1243
|
+
| `offset` | number | Records to skip |
|
|
1244
|
+
| `page` | number | Page number (alternative to offset) |
|
|
1245
|
+
| `with` | array | Related models to eager load |
|
|
1246
|
+
| `groupBy` | array/string | Group by columns |
|
|
1247
|
+
| `having` | object | Having conditions |
|
|
1248
|
+
| `distinct` | boolean/array/string | Distinct results |
|
|
1249
|
+
| `join` | object/array | Join configuration |
|
|
1250
|
+
| `leftJoin` | object/array | Left join configuration |
|
|
1251
|
+
| `rightJoin` | object/array | Right join configuration |
|
|
1252
|
+
| `innerJoin` | object/array | Inner join configuration |
|
|
1253
|
+
| `conflict` | array | Conflict columns for upsert |
|
|
1254
|
+
| `other_requests` | object | Nested requests for related models |
|
|
1255
|
+
|
|
1167
1256
|
### ProcessRequest Actions Summary
|
|
1168
1257
|
|
|
1169
1258
|
| Action | Description | Required Fields |
|
|
1170
1259
|
|--------|-------------|----------------|
|
|
1171
|
-
| `
|
|
1172
|
-
| `list` | Get multiple records | None (optional: `where`, `select`, `sort`, `limit`, `offset`) |
|
|
1260
|
+
| `list` | Get multiple records | None (optional: `where`, `select`, `orderBy`, `limit`, `offset`) |
|
|
1173
1261
|
| `show` | Get single record | `where` |
|
|
1262
|
+
| `create` | Create new record | `data` |
|
|
1174
1263
|
| `update` | Update record(s) | `where`, `data` |
|
|
1175
1264
|
| `delete` | Delete record(s) | `where` |
|
|
1176
1265
|
| `count` | Count records | None (optional: `where`) |
|
|
@@ -1182,19 +1271,58 @@ const schema = await ControllerWrapper.generateSchema();
|
|
|
1182
1271
|
|
|
1183
1272
|
| Rule | Description | Example |
|
|
1184
1273
|
|------|-------------|---------|
|
|
1185
|
-
| `required` | Field is required | `
|
|
1186
|
-
| `type:string` | Field must be string | `
|
|
1187
|
-
| `type:number` | Field must be number | `
|
|
1188
|
-
| `type:boolean` | Field must be boolean | `
|
|
1189
|
-
| `
|
|
1190
|
-
| `
|
|
1191
|
-
| `
|
|
1192
|
-
| `
|
|
1193
|
-
| `
|
|
1194
|
-
| `
|
|
1195
|
-
| `
|
|
1196
|
-
| `
|
|
1197
|
-
| `
|
|
1274
|
+
| `required` | Field is required | `'required'` |
|
|
1275
|
+
| `type:string` | Field must be string | `'type:string'` |
|
|
1276
|
+
| `type:number` | Field must be number | `'type:number'` |
|
|
1277
|
+
| `type:boolean` | Field must be boolean | `'type:boolean'` |
|
|
1278
|
+
| `type:array` | Field must be array | `'type:array'` |
|
|
1279
|
+
| `type:object` | Field must be object | `'type:object'` |
|
|
1280
|
+
| `type:longText` | Field must be string > 255 chars | `'type:longText'` |
|
|
1281
|
+
| `minLen:n` | Minimum string/array length | `'minLen:3'` |
|
|
1282
|
+
| `maxLen:n` | Maximum string/array length | `'maxLen:255'` |
|
|
1283
|
+
| `min:n` | Minimum numeric value | `'min:0'` |
|
|
1284
|
+
| `max:n` | Maximum numeric value | `'max:150'` |
|
|
1285
|
+
| `in:val1,val2` | Value must be in list | `'in:active,inactive,pending'` |
|
|
1286
|
+
| `regex:name` | Custom regex pattern (define in options) | `'regex:email'` |
|
|
1287
|
+
| `call:name` | Custom callback function (define in options) | `'call:myValidator'` |
|
|
1288
|
+
| `exists:table,column` | Value must exist in database table | `'exists:users,id'` |
|
|
1289
|
+
| `default:value` | Default value if not provided | `'default:active'` |
|
|
1290
|
+
|
|
1291
|
+
**Rule Chaining:** Combine multiple rules with `|` pipe character:
|
|
1292
|
+
```javascript
|
|
1293
|
+
{
|
|
1294
|
+
username: 'required|type:string|minLen:3|maxLen:50',
|
|
1295
|
+
email: 'required|type:string|regex:email',
|
|
1296
|
+
age: 'type:number|min:0|max:150',
|
|
1297
|
+
status: 'in:active,inactive|default:active'
|
|
1298
|
+
}
|
|
1299
|
+
```
|
|
1300
|
+
|
|
1301
|
+
### Library Exports
|
|
1302
|
+
|
|
1303
|
+
```javascript
|
|
1304
|
+
const {
|
|
1305
|
+
initializeKORM, // Initialize KORM with database connection
|
|
1306
|
+
helperUtility, // Utility functions (file operations, string manipulation)
|
|
1307
|
+
emitter, // Event emitter instance
|
|
1308
|
+
validate, // Validation function
|
|
1309
|
+
lib, // Additional utilities
|
|
1310
|
+
LibClasses // Library classes (Emitter)
|
|
1311
|
+
} = require('@dreamtree-org/korm-js');
|
|
1312
|
+
|
|
1313
|
+
// lib contains:
|
|
1314
|
+
// - createValidationMiddleware(rules, options) - Express middleware
|
|
1315
|
+
// - validateEmail(email) - Email validation
|
|
1316
|
+
// - validatePassword(password) - Password strength validation
|
|
1317
|
+
// - validatePhone(phone) - Phone number validation
|
|
1318
|
+
// - validatePAN(pan) - PAN validation (India)
|
|
1319
|
+
// - validateAadhaar(aadhaar) - Aadhaar validation (India)
|
|
1320
|
+
|
|
1321
|
+
// helperUtility.file contains:
|
|
1322
|
+
// - readJSON(path) - Read JSON file
|
|
1323
|
+
// - writeJSON(path, data) - Write JSON file
|
|
1324
|
+
// - createDirectory(path) - Create directory
|
|
1325
|
+
```
|
|
1198
1326
|
|
|
1199
1327
|
## Database Support
|
|
1200
1328
|
|
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.46",
|
|
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",
|