@dwtechs/antity 0.2.0 → 0.4.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/README.md +52 -18
- package/dist/antity.cjs.js +71 -31
- package/dist/antity.d.ts +49 -18
- package/dist/antity.js +72 -32
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -50,15 +50,16 @@ $ npm i @dwtechs/antity
|
|
|
50
50
|
import { Entity } from "@dwtechs/antity";
|
|
51
51
|
import { normalizeName, normalizeNickname } from "@dwtechs/checkard";
|
|
52
52
|
|
|
53
|
-
const entity = new Entity("
|
|
53
|
+
const entity = new Entity("consumers", [
|
|
54
54
|
{
|
|
55
55
|
key: "id",
|
|
56
56
|
type: "integer",
|
|
57
57
|
min: 0,
|
|
58
58
|
max: 120,
|
|
59
59
|
typeCheck: true,
|
|
60
|
-
|
|
60
|
+
operations: ["select", "update", "delete"],
|
|
61
61
|
required: true,
|
|
62
|
+
safe: true,
|
|
62
63
|
sanitize: true,
|
|
63
64
|
normalize: true,
|
|
64
65
|
control: true,
|
|
@@ -72,8 +73,9 @@ const entity = new Entity("consumer", "consumers", [
|
|
|
72
73
|
min: 0,
|
|
73
74
|
max: 255,
|
|
74
75
|
typeCheck: true,
|
|
75
|
-
|
|
76
|
+
operations: ["select", "insert", "update", "delete"],
|
|
76
77
|
required: true,
|
|
78
|
+
safe: true,
|
|
77
79
|
sanitize: true,
|
|
78
80
|
normalize: true,
|
|
79
81
|
control: true,
|
|
@@ -87,8 +89,9 @@ const entity = new Entity("consumer", "consumers", [
|
|
|
87
89
|
min: 0,
|
|
88
90
|
max: 255,
|
|
89
91
|
typeCheck: true,
|
|
90
|
-
|
|
92
|
+
operations: ["select", "insert", "update", "delete"],
|
|
91
93
|
required: true,
|
|
94
|
+
safe: true,
|
|
92
95
|
sanitize: true,
|
|
93
96
|
normalize: true,
|
|
94
97
|
control: true,
|
|
@@ -102,8 +105,9 @@ const entity = new Entity("consumer", "consumers", [
|
|
|
102
105
|
min: 0,
|
|
103
106
|
max: 255,
|
|
104
107
|
typeCheck: true,
|
|
105
|
-
|
|
108
|
+
operations: ["select", "insert", "update", "delete"],
|
|
106
109
|
required: true,
|
|
110
|
+
safe: true,
|
|
107
111
|
sanitize: true,
|
|
108
112
|
normalize: true,
|
|
109
113
|
control: true,
|
|
@@ -113,8 +117,9 @@ const entity = new Entity("consumer", "consumers", [
|
|
|
113
117
|
},
|
|
114
118
|
]);
|
|
115
119
|
|
|
116
|
-
req.body = entity.normalize(req.body);
|
|
117
|
-
const check = entity.validate(req.body,
|
|
120
|
+
req.body = entity.normalize(req.body); // will also sanitize if true
|
|
121
|
+
const check = entity.validate(req.body, "select");
|
|
122
|
+
const unsafeProps = entity.getUnsafeProps();
|
|
118
123
|
|
|
119
124
|
```
|
|
120
125
|
|
|
@@ -152,6 +157,7 @@ type Type = "boolean" |
|
|
|
152
157
|
"node" |
|
|
153
158
|
"object";
|
|
154
159
|
|
|
160
|
+
type Operation = "select" | "insert" | "update" | "merge" | "delete";
|
|
155
161
|
type Method = "GET" | "PATCH" | "PUT" | "POST" | "DELETE";
|
|
156
162
|
|
|
157
163
|
class Property {
|
|
@@ -160,8 +166,9 @@ class Property {
|
|
|
160
166
|
min: number | Date;
|
|
161
167
|
max: number | Date;
|
|
162
168
|
required: boolean;
|
|
169
|
+
safe: boolean;
|
|
163
170
|
typeCheck: boolean;
|
|
164
|
-
|
|
171
|
+
operations: Operation[];
|
|
165
172
|
sanitize: boolean;
|
|
166
173
|
normalize: boolean;
|
|
167
174
|
control: boolean;
|
|
@@ -171,15 +178,41 @@ class Property {
|
|
|
171
178
|
};
|
|
172
179
|
|
|
173
180
|
class Entity {
|
|
174
|
-
name: string;
|
|
175
181
|
table: string;
|
|
182
|
+
cols: Record<Operation, string[]>;
|
|
176
183
|
properties: Property[];
|
|
177
|
-
normalize(rows: Record<string, any>[]): Record<string, any>[];
|
|
178
|
-
validate(rows: Record<string, any>[],
|
|
184
|
+
normalize(rows: Record<string, any>[]): Record<string, any>[]; // will also sanitize if true
|
|
185
|
+
validate(rows: Record<string, any>[], operation: Operation | Method): string | null;
|
|
186
|
+
getTable(): string;
|
|
187
|
+
// if pagination is true for a select operation, it will return cols + a total column
|
|
188
|
+
getCols(operation: Operation, stringify?: boolean, pagination?: boolean): string[] | string;
|
|
189
|
+
getUnsafeProps(): string[];
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
```
|
|
182
193
|
|
|
194
|
+
### REST Methods mapping
|
|
195
|
+
|
|
196
|
+
When validating request inputs, you can use REST methods or SQL operations as second parameter
|
|
197
|
+
|
|
198
|
+
| REST method | SQL operation |
|
|
199
|
+
| :---------- | :------------ |
|
|
200
|
+
| GET | select |
|
|
201
|
+
| PATCH | update |
|
|
202
|
+
| PUT | update |
|
|
203
|
+
| POST | insert |
|
|
204
|
+
| DELETE | delete |
|
|
205
|
+
|
|
206
|
+
examples :
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
|
|
210
|
+
entity.validate(req.body, "GET"); // will validate "select" properties
|
|
211
|
+
entity.validate(req.body, "PUT"); // will validate "update" properties
|
|
212
|
+
entity.validate(req.body, "DELETE"); // will validate "delete" properties
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
|
|
183
216
|
|
|
184
217
|
### Available options for a property
|
|
185
218
|
|
|
@@ -188,17 +221,18 @@ Any of these can be passed into the options object for each function.
|
|
|
188
221
|
| Name | Type | Description | Default value |
|
|
189
222
|
| :-------------- | :------------------------ | :------------------------------------------------ | :-------------- |
|
|
190
223
|
| key | string | Name of the property |
|
|
191
|
-
| type | Type | Type of the property
|
|
192
|
-
| min | number
|
|
193
|
-
| max | number
|
|
194
|
-
| required | boolean | Is this property required
|
|
224
|
+
| type | Type | Type of the property |
|
|
225
|
+
| min | number \| Date | Minimum value | 0 \| 1900-01-01
|
|
226
|
+
| max | number \| Date | Maximum value | 999999999 \| 2200-12-31
|
|
227
|
+
| required | boolean | Is this property required on insert | false
|
|
228
|
+
| safe | boolean | Is this property safe to send to the client | true
|
|
195
229
|
| typeCheck | boolean | Type is checked if true | false
|
|
196
|
-
|
|
|
230
|
+
| operations | Operation[] | SQL DML operations concerned by the property | [ "select", "insert", "update", "merge", "delete" ]
|
|
197
231
|
| sanitize | boolean | Sanitize the property if true | true
|
|
198
232
|
| normalize | boolean | Normalize the property if true | false
|
|
199
233
|
| control | boolean | Control the property if true | true
|
|
200
|
-
| sanitizer | ((v:any) => any) \| null
|
|
201
|
-
| normalizer | ((v:any) => any) \| null
|
|
234
|
+
| sanitizer | ((v:any) => any) \| null | Sanitizer function if sanitize is true | null
|
|
235
|
+
| normalizer | ((v:any) => any) \| null | Normalizer function if normalize is true | null
|
|
202
236
|
| controller | ((v:any, min:number, max:number, typeCheck:boolean) => any) \| null | Controller function if control is true | null
|
|
203
237
|
|
|
204
238
|
* *Min and max parameters are not used for boolean type*
|
package/dist/antity.cjs.js
CHANGED
|
@@ -331,7 +331,7 @@ function isValidTimestamp(t, min = -2208989361000, max = 7258114800000, type = t
|
|
|
331
331
|
return isTimestamp(t, type) && t >= min && t <= max;
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
-
const
|
|
334
|
+
const Operations = ["select", "insert", "update", "merge", "delete"];
|
|
335
335
|
|
|
336
336
|
const Types = {
|
|
337
337
|
boolean: {
|
|
@@ -421,24 +421,25 @@ const Required = {
|
|
|
421
421
|
};
|
|
422
422
|
|
|
423
423
|
class Property {
|
|
424
|
-
constructor(key, type, min, max, required, typeCheck,
|
|
424
|
+
constructor(key, type, min, max, required, safe, typeCheck, operations, sanitize, normalize, control, sanitizer, normalizer, controller) {
|
|
425
425
|
if (!isString(key, true))
|
|
426
|
-
throw new Error(`Property
|
|
426
|
+
throw new Error(`Property"key" must be a string. Received ${key}`);
|
|
427
427
|
if (!isProperty(type, Types))
|
|
428
|
-
throw new Error(`Property type must be a valid type. Received ${type}`);
|
|
429
|
-
if (isArray(
|
|
430
|
-
for (const
|
|
431
|
-
if (!isIn(
|
|
432
|
-
throw new Error(`Property
|
|
428
|
+
throw new Error(`Property "type" must be a valid type. Received ${type}`);
|
|
429
|
+
if (isArray(operations)) {
|
|
430
|
+
for (const o of operations) {
|
|
431
|
+
if (!isIn(o, Operations))
|
|
432
|
+
throw new Error(`Property "operations" must be an array of SQL operations. Received ${o}`);
|
|
433
433
|
}
|
|
434
434
|
}
|
|
435
435
|
this.key = key;
|
|
436
436
|
this.type = type;
|
|
437
|
-
this.min =
|
|
438
|
-
this.max =
|
|
437
|
+
this.min = this.interval(min, type, 0, "1900-01-01T00:00:00Z");
|
|
438
|
+
this.max = this.interval(max, type, 999999999, "2200-12-31T00:00:00Z");
|
|
439
439
|
this.required = isBoolean(required) ? required : false;
|
|
440
|
+
this.safe = isBoolean(safe) ? safe : true;
|
|
440
441
|
this.typeCheck = isBoolean(typeCheck) ? typeCheck : false;
|
|
441
|
-
this.
|
|
442
|
+
this.operations = operations || Operations;
|
|
442
443
|
this.sanitize = isBoolean(sanitize) ? sanitize : true;
|
|
443
444
|
this.normalize = isBoolean(normalize) ? normalize : false;
|
|
444
445
|
this.control = isBoolean(control) ? control : true;
|
|
@@ -446,6 +447,11 @@ class Property {
|
|
|
446
447
|
this.normalizer = isFunction(normalizer) ? normalizer : null;
|
|
447
448
|
this.controller = isFunction(controller) ? controller : null;
|
|
448
449
|
}
|
|
450
|
+
interval(val, type, integerDefault, dateDefault) {
|
|
451
|
+
if (type === "date")
|
|
452
|
+
return isDate(val) ? val : new Date(dateDefault);
|
|
453
|
+
return isInteger(val, true) ? val : integerDefault;
|
|
454
|
+
}
|
|
449
455
|
}
|
|
450
456
|
|
|
451
457
|
const Messages = {
|
|
@@ -453,47 +459,67 @@ const Messages = {
|
|
|
453
459
|
invalid: (key, type) => `Invalid ${key}, must be of type ${type}`,
|
|
454
460
|
};
|
|
455
461
|
|
|
462
|
+
const Methods = ["GET", "PATCH", "PUT", "POST", "DELETE"];
|
|
463
|
+
|
|
456
464
|
class Entity {
|
|
457
|
-
constructor(
|
|
458
|
-
this.name = name;
|
|
465
|
+
constructor(table, properties) {
|
|
459
466
|
this.table = table;
|
|
460
|
-
this.properties =
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
467
|
+
this.properties = [];
|
|
468
|
+
this.cols = {
|
|
469
|
+
select: [],
|
|
470
|
+
insert: [],
|
|
471
|
+
update: [],
|
|
472
|
+
merge: [],
|
|
473
|
+
delete: []
|
|
474
|
+
};
|
|
475
|
+
this.unsafeProps = [];
|
|
464
476
|
for (const p of properties) {
|
|
465
|
-
|
|
477
|
+
const prop = new Property(p.key, p.type, p.min, p.max, p.required, p.safe, p.typeCheck, p.operations, p.sanitize, p.normalize, p.control, p.sanitizer, p.normalizer, p.controller);
|
|
478
|
+
this.properties.push(prop);
|
|
479
|
+
for (const o of p.operations) {
|
|
480
|
+
if (o === "update")
|
|
481
|
+
this.cols[o].push(`${p.key} = $${this.cols[o].length + 1}`);
|
|
482
|
+
else
|
|
483
|
+
this.cols[o].push(p.key);
|
|
484
|
+
}
|
|
485
|
+
if (!prop.safe)
|
|
486
|
+
this.unsafeProps.push(prop.key);
|
|
466
487
|
}
|
|
467
|
-
return props;
|
|
468
488
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
489
|
+
getTable() {
|
|
490
|
+
return this.table;
|
|
491
|
+
}
|
|
492
|
+
getCols(operation, stringify, pagination) {
|
|
493
|
+
const cols = pagination && operation === "select" ? [...this.cols[operation], "COUNT(*) OVER () AS total"] : this.cols[operation];
|
|
494
|
+
return stringify ? cols.join(', ') : cols;
|
|
495
|
+
}
|
|
496
|
+
getUnsafeProps() {
|
|
497
|
+
return this.unsafeProps;
|
|
476
498
|
}
|
|
477
499
|
normalize(rows) {
|
|
478
500
|
for (const r of rows) {
|
|
479
501
|
for (const { key, sanitize, normalize, sanitizer, normalizer, } of this.properties) {
|
|
480
502
|
let v = r[key];
|
|
481
503
|
if (v) {
|
|
482
|
-
if (sanitize)
|
|
504
|
+
if (sanitize) {
|
|
483
505
|
v = this.sanitize(v, sanitizer);
|
|
484
|
-
|
|
506
|
+
}
|
|
507
|
+
if (normalize && normalizer) {
|
|
485
508
|
v = normalizer(v);
|
|
509
|
+
}
|
|
486
510
|
r[key] = v;
|
|
487
511
|
}
|
|
488
512
|
}
|
|
489
513
|
}
|
|
490
514
|
return rows;
|
|
491
515
|
}
|
|
492
|
-
validate(rows,
|
|
516
|
+
validate(rows, operation) {
|
|
517
|
+
if (isIn(operation, Methods))
|
|
518
|
+
operation = this.mapMethods(operation);
|
|
493
519
|
for (const r of rows) {
|
|
494
|
-
for (const { key, type, min, max, required, typeCheck,
|
|
520
|
+
for (const { key, type, min, max, required, typeCheck, operations, control, controller } of this.properties) {
|
|
495
521
|
const v = r[key];
|
|
496
|
-
if (
|
|
522
|
+
if (isIn(operation, operations)) {
|
|
497
523
|
if (required) {
|
|
498
524
|
const rq = this.require(v, key);
|
|
499
525
|
if (rq)
|
|
@@ -543,6 +569,20 @@ class Entity {
|
|
|
543
569
|
return v;
|
|
544
570
|
}
|
|
545
571
|
}
|
|
572
|
+
mapMethods(method) {
|
|
573
|
+
switch (method) {
|
|
574
|
+
case "GET":
|
|
575
|
+
return Operations[0];
|
|
576
|
+
case "PATCH":
|
|
577
|
+
return Operations[2];
|
|
578
|
+
case "PUT":
|
|
579
|
+
return Operations[2];
|
|
580
|
+
case "POST":
|
|
581
|
+
return Operations[1];
|
|
582
|
+
case "DELETE":
|
|
583
|
+
return Operations[4];
|
|
584
|
+
}
|
|
585
|
+
}
|
|
546
586
|
}
|
|
547
587
|
|
|
548
588
|
exports.Entity = Entity;
|
package/dist/antity.d.ts
CHANGED
|
@@ -25,30 +25,59 @@ https://github.com/DWTechs/Antity.js
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
type
|
|
28
|
+
type Operation = typeof Operations[number];
|
|
29
29
|
type Method = typeof Methods[number];
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
type Type =
|
|
32
|
+
"boolean" |
|
|
33
|
+
"string" |
|
|
34
|
+
"number" |
|
|
35
|
+
"integer" |
|
|
36
|
+
"float" |
|
|
37
|
+
"even" |
|
|
38
|
+
"odd" |
|
|
39
|
+
"positive" |
|
|
40
|
+
"negative" |
|
|
41
|
+
"powerOfTwo" |
|
|
42
|
+
"ascii" |
|
|
43
|
+
"array" |
|
|
44
|
+
"jwt" |
|
|
45
|
+
"symbol" |
|
|
46
|
+
"email" |
|
|
47
|
+
"regex" |
|
|
48
|
+
"json" |
|
|
49
|
+
"ipAddress" |
|
|
50
|
+
"slug" |
|
|
51
|
+
"hexadecimal" |
|
|
52
|
+
"date" |
|
|
53
|
+
"timestamp" |
|
|
54
|
+
"function" |
|
|
55
|
+
"htmlElement" |
|
|
56
|
+
"htmlEventAttribute" |
|
|
57
|
+
"node" |
|
|
58
|
+
"object";
|
|
32
59
|
|
|
33
|
-
declare const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
60
|
+
declare const Operations: readonly [ "select", "insert", "update", "merge", "delete" ];
|
|
61
|
+
declare const Methods: readonly [ "GET", "PATCH", "PUT", "POST", "DELETE" ];
|
|
62
|
+
|
|
63
|
+
declare const Types: Record<Type, {
|
|
64
|
+
validate: (v: any, min: number | Date, max: number | Date, typeCheck: boolean) => boolean;
|
|
65
|
+
}>;
|
|
38
66
|
|
|
39
67
|
declare const Required: {
|
|
40
68
|
validate: (v: any) => boolean;
|
|
41
69
|
};
|
|
42
70
|
|
|
43
71
|
declare class Entity {
|
|
44
|
-
name: string;
|
|
45
72
|
table: string;
|
|
73
|
+
cols: Record<Operation, string[]>;
|
|
46
74
|
properties: Property[];
|
|
47
|
-
constructor(
|
|
48
|
-
|
|
49
|
-
|
|
75
|
+
constructor(table: string, properties: Property[]);
|
|
76
|
+
getTable(): string;
|
|
77
|
+
getCols(operation: Operation, stringify?: boolean, pagination?: boolean): string[] | string;
|
|
78
|
+
getUnsafeProps(): string[];
|
|
50
79
|
normalize(rows: Record<string, any>[]): Record<string, any>[];
|
|
51
|
-
validate(rows: Record<string, any>[],
|
|
80
|
+
validate(rows: Record<string, any>[], operation: Operation | Method): string | null;
|
|
52
81
|
private require;
|
|
53
82
|
private control;
|
|
54
83
|
private sanitize;
|
|
@@ -63,11 +92,12 @@ declare const Messages: {
|
|
|
63
92
|
declare class Property {
|
|
64
93
|
key: string;
|
|
65
94
|
type: Type;
|
|
66
|
-
min: number;
|
|
67
|
-
max: number;
|
|
95
|
+
min: number | Date;
|
|
96
|
+
max: number | Date;
|
|
68
97
|
required: boolean;
|
|
98
|
+
safe: boolean;
|
|
69
99
|
typeCheck: boolean;
|
|
70
|
-
|
|
100
|
+
operations: Operation[];
|
|
71
101
|
sanitize: boolean;
|
|
72
102
|
normalize: boolean;
|
|
73
103
|
control: boolean;
|
|
@@ -79,8 +109,9 @@ declare class Property {
|
|
|
79
109
|
min: number | Date,
|
|
80
110
|
max: number | Date,
|
|
81
111
|
required: boolean,
|
|
112
|
+
safe: boolean,
|
|
82
113
|
typeCheck: boolean,
|
|
83
|
-
|
|
114
|
+
operations: Operation[],
|
|
84
115
|
sanitize: boolean,
|
|
85
116
|
normalize: boolean,
|
|
86
117
|
control: boolean,
|
|
@@ -90,13 +121,13 @@ declare class Property {
|
|
|
90
121
|
);
|
|
91
122
|
}
|
|
92
123
|
|
|
93
|
-
export type { Type, Method };
|
|
124
|
+
export type { Type, Operation, Method };
|
|
94
125
|
export {
|
|
95
126
|
Entity,
|
|
96
127
|
Property,
|
|
97
128
|
Messages,
|
|
98
129
|
Types,
|
|
99
130
|
Required,
|
|
100
|
-
|
|
131
|
+
Operations
|
|
101
132
|
};
|
|
102
133
|
|
package/dist/antity.js
CHANGED
|
@@ -24,9 +24,9 @@ SOFTWARE.
|
|
|
24
24
|
https://github.com/DWTechs/Antity.js
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
import { isBoolean, isStringOfLength, isValidNumber, isValidInteger, isValidFloat, isEven, isOdd, isPositive, isNegative, isPowerOfTwo, isAscii, isArrayOfLength, isEmail, isRegex, isJson, isJWT, isSymbol, isIpAddress, isSlug, isHexadecimal, isValidDate, isValidTimestamp, isFunction, isHtmlElement, isHtmlEventAttribute, isNode, isObject, isNil, isString, isProperty, isArray, isIn, isInteger } from '@dwtechs/checkard';
|
|
27
|
+
import { isBoolean, isStringOfLength, isValidNumber, isValidInteger, isValidFloat, isEven, isOdd, isPositive, isNegative, isPowerOfTwo, isAscii, isArrayOfLength, isEmail, isRegex, isJson, isJWT, isSymbol, isIpAddress, isSlug, isHexadecimal, isValidDate, isValidTimestamp, isFunction, isHtmlElement, isHtmlEventAttribute, isNode, isObject, isNil, isString, isProperty, isArray, isIn, isDate, isInteger } from '@dwtechs/checkard';
|
|
28
28
|
|
|
29
|
-
const
|
|
29
|
+
const Operations = ["select", "insert", "update", "merge", "delete"];
|
|
30
30
|
|
|
31
31
|
const Types = {
|
|
32
32
|
boolean: {
|
|
@@ -116,24 +116,25 @@ const Required = {
|
|
|
116
116
|
};
|
|
117
117
|
|
|
118
118
|
class Property {
|
|
119
|
-
constructor(key, type, min, max, required, typeCheck,
|
|
119
|
+
constructor(key, type, min, max, required, safe, typeCheck, operations, sanitize, normalize, control, sanitizer, normalizer, controller) {
|
|
120
120
|
if (!isString(key, true))
|
|
121
|
-
throw new Error(`Property
|
|
121
|
+
throw new Error(`Property"key" must be a string. Received ${key}`);
|
|
122
122
|
if (!isProperty(type, Types))
|
|
123
|
-
throw new Error(`Property type must be a valid type. Received ${type}`);
|
|
124
|
-
if (isArray(
|
|
125
|
-
for (const
|
|
126
|
-
if (!isIn(
|
|
127
|
-
throw new Error(`Property
|
|
123
|
+
throw new Error(`Property "type" must be a valid type. Received ${type}`);
|
|
124
|
+
if (isArray(operations)) {
|
|
125
|
+
for (const o of operations) {
|
|
126
|
+
if (!isIn(o, Operations))
|
|
127
|
+
throw new Error(`Property "operations" must be an array of SQL operations. Received ${o}`);
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
this.key = key;
|
|
131
131
|
this.type = type;
|
|
132
|
-
this.min =
|
|
133
|
-
this.max =
|
|
132
|
+
this.min = this.interval(min, type, 0, "1900-01-01T00:00:00Z");
|
|
133
|
+
this.max = this.interval(max, type, 999999999, "2200-12-31T00:00:00Z");
|
|
134
134
|
this.required = isBoolean(required) ? required : false;
|
|
135
|
+
this.safe = isBoolean(safe) ? safe : true;
|
|
135
136
|
this.typeCheck = isBoolean(typeCheck) ? typeCheck : false;
|
|
136
|
-
this.
|
|
137
|
+
this.operations = operations || Operations;
|
|
137
138
|
this.sanitize = isBoolean(sanitize) ? sanitize : true;
|
|
138
139
|
this.normalize = isBoolean(normalize) ? normalize : false;
|
|
139
140
|
this.control = isBoolean(control) ? control : true;
|
|
@@ -141,6 +142,11 @@ class Property {
|
|
|
141
142
|
this.normalizer = isFunction(normalizer) ? normalizer : null;
|
|
142
143
|
this.controller = isFunction(controller) ? controller : null;
|
|
143
144
|
}
|
|
145
|
+
interval(val, type, integerDefault, dateDefault) {
|
|
146
|
+
if (type === "date")
|
|
147
|
+
return isDate(val) ? val : new Date(dateDefault);
|
|
148
|
+
return isInteger(val, true) ? val : integerDefault;
|
|
149
|
+
}
|
|
144
150
|
}
|
|
145
151
|
|
|
146
152
|
const Messages = {
|
|
@@ -148,47 +154,67 @@ const Messages = {
|
|
|
148
154
|
invalid: (key, type) => `Invalid ${key}, must be of type ${type}`,
|
|
149
155
|
};
|
|
150
156
|
|
|
157
|
+
const Methods = ["GET", "PATCH", "PUT", "POST", "DELETE"];
|
|
158
|
+
|
|
151
159
|
class Entity {
|
|
152
|
-
constructor(
|
|
153
|
-
this.name = name;
|
|
160
|
+
constructor(table, properties) {
|
|
154
161
|
this.table = table;
|
|
155
|
-
this.properties =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
this.properties = [];
|
|
163
|
+
this.cols = {
|
|
164
|
+
select: [],
|
|
165
|
+
insert: [],
|
|
166
|
+
update: [],
|
|
167
|
+
merge: [],
|
|
168
|
+
delete: []
|
|
169
|
+
};
|
|
170
|
+
this.unsafeProps = [];
|
|
159
171
|
for (const p of properties) {
|
|
160
|
-
|
|
172
|
+
const prop = new Property(p.key, p.type, p.min, p.max, p.required, p.safe, p.typeCheck, p.operations, p.sanitize, p.normalize, p.control, p.sanitizer, p.normalizer, p.controller);
|
|
173
|
+
this.properties.push(prop);
|
|
174
|
+
for (const o of p.operations) {
|
|
175
|
+
if (o === "update")
|
|
176
|
+
this.cols[o].push(`${p.key} = $${this.cols[o].length + 1}`);
|
|
177
|
+
else
|
|
178
|
+
this.cols[o].push(p.key);
|
|
179
|
+
}
|
|
180
|
+
if (!prop.safe)
|
|
181
|
+
this.unsafeProps.push(prop.key);
|
|
161
182
|
}
|
|
162
|
-
return props;
|
|
163
183
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
184
|
+
getTable() {
|
|
185
|
+
return this.table;
|
|
186
|
+
}
|
|
187
|
+
getCols(operation, stringify, pagination) {
|
|
188
|
+
const cols = pagination && operation === "select" ? [...this.cols[operation], "COUNT(*) OVER () AS total"] : this.cols[operation];
|
|
189
|
+
return stringify ? cols.join(', ') : cols;
|
|
190
|
+
}
|
|
191
|
+
getUnsafeProps() {
|
|
192
|
+
return this.unsafeProps;
|
|
171
193
|
}
|
|
172
194
|
normalize(rows) {
|
|
173
195
|
for (const r of rows) {
|
|
174
196
|
for (const { key, sanitize, normalize, sanitizer, normalizer, } of this.properties) {
|
|
175
197
|
let v = r[key];
|
|
176
198
|
if (v) {
|
|
177
|
-
if (sanitize)
|
|
199
|
+
if (sanitize) {
|
|
178
200
|
v = this.sanitize(v, sanitizer);
|
|
179
|
-
|
|
201
|
+
}
|
|
202
|
+
if (normalize && normalizer) {
|
|
180
203
|
v = normalizer(v);
|
|
204
|
+
}
|
|
181
205
|
r[key] = v;
|
|
182
206
|
}
|
|
183
207
|
}
|
|
184
208
|
}
|
|
185
209
|
return rows;
|
|
186
210
|
}
|
|
187
|
-
validate(rows,
|
|
211
|
+
validate(rows, operation) {
|
|
212
|
+
if (isIn(operation, Methods))
|
|
213
|
+
operation = this.mapMethods(operation);
|
|
188
214
|
for (const r of rows) {
|
|
189
|
-
for (const { key, type, min, max, required, typeCheck,
|
|
215
|
+
for (const { key, type, min, max, required, typeCheck, operations, control, controller } of this.properties) {
|
|
190
216
|
const v = r[key];
|
|
191
|
-
if (
|
|
217
|
+
if (isIn(operation, operations)) {
|
|
192
218
|
if (required) {
|
|
193
219
|
const rq = this.require(v, key);
|
|
194
220
|
if (rq)
|
|
@@ -238,6 +264,20 @@ class Entity {
|
|
|
238
264
|
return v;
|
|
239
265
|
}
|
|
240
266
|
}
|
|
267
|
+
mapMethods(method) {
|
|
268
|
+
switch (method) {
|
|
269
|
+
case "GET":
|
|
270
|
+
return Operations[0];
|
|
271
|
+
case "PATCH":
|
|
272
|
+
return Operations[2];
|
|
273
|
+
case "PUT":
|
|
274
|
+
return Operations[2];
|
|
275
|
+
case "POST":
|
|
276
|
+
return Operations[1];
|
|
277
|
+
case "DELETE":
|
|
278
|
+
return Operations[4];
|
|
279
|
+
}
|
|
280
|
+
}
|
|
241
281
|
}
|
|
242
282
|
|
|
243
283
|
export { Entity };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dwtechs/antity",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Open source library for easy entity management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"entities"
|
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
"dist/"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@dwtechs/checkard": "2.29.2"
|
|
38
|
+
"@dwtechs/checkard": "2.29.2",
|
|
39
|
+
"@dwtechs/winstan": "0.2.1",
|
|
40
|
+
"pg": "8.13.1"
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@babel/core": "7.26.0",
|
|
@@ -43,6 +45,7 @@
|
|
|
43
45
|
"@rollup/plugin-commonjs": "28.0.1",
|
|
44
46
|
"@rollup/plugin-node-resolve": "15.3.0",
|
|
45
47
|
"@types/jest": "29.5.14",
|
|
48
|
+
"@types/node": "22.10.1",
|
|
46
49
|
"babel-jest": "29.7.0",
|
|
47
50
|
"core-js": "3.33.0",
|
|
48
51
|
"jest": "29.7.0",
|