@dwtechs/antity 0.4.0 → 0.6.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 CHANGED
@@ -57,7 +57,7 @@ const entity = new Entity("consumers", [
57
57
  min: 0,
58
58
  max: 120,
59
59
  typeCheck: true,
60
- operations: ["select", "update", "delete"],
60
+ operations: ["GET", "PUT", "DELETE"],
61
61
  required: true,
62
62
  safe: true,
63
63
  sanitize: true,
@@ -73,7 +73,7 @@ const entity = new Entity("consumers", [
73
73
  min: 0,
74
74
  max: 255,
75
75
  typeCheck: true,
76
- operations: ["select", "insert", "update", "delete"],
76
+ operations: ["GET", "POST", "PUT", "DELETE"],
77
77
  required: true,
78
78
  safe: true,
79
79
  sanitize: true,
@@ -89,7 +89,7 @@ const entity = new Entity("consumers", [
89
89
  min: 0,
90
90
  max: 255,
91
91
  typeCheck: true,
92
- operations: ["select", "insert", "update", "delete"],
92
+ operations: ["GET", "POST", "PUT", "DELETE"],
93
93
  required: true,
94
94
  safe: true,
95
95
  sanitize: true,
@@ -105,7 +105,7 @@ const entity = new Entity("consumers", [
105
105
  min: 0,
106
106
  max: 255,
107
107
  typeCheck: true,
108
- operations: ["select", "insert", "update", "delete"],
108
+ operations: ["GET", "POST", "PUT", "DELETE"],
109
109
  required: true,
110
110
  safe: true,
111
111
  sanitize: true,
@@ -118,7 +118,7 @@ const entity = new Entity("consumers", [
118
118
  ]);
119
119
 
120
120
  req.body = entity.normalize(req.body); // will also sanitize if true
121
- const check = entity.validate(req.body, "select");
121
+ const check = entity.validate(req.body, "GET");
122
122
  const unsafeProps = entity.getUnsafeProps();
123
123
 
124
124
  ```
@@ -129,35 +129,35 @@ const unsafeProps = entity.getUnsafeProps();
129
129
 
130
130
  ```javascript
131
131
 
132
- type Type = "boolean" |
133
- "string" |
134
- "number" |
135
- "integer" |
136
- "float" |
137
- "even" |
138
- "odd" |
139
- "positve" |
140
- "negative" |
141
- "powerOfTwo" |
142
- "ascii" |
143
- "array" |
144
- "jwt" |
145
- "symbol" |
146
- "email" |
147
- "regex" |
148
- "json" |
149
- "ipAddress" |
150
- "slug" |
151
- "hexadecimal" |
152
- "date" |
153
- "timestamp" |
154
- "function" |
155
- "htmlElement" |
156
- "htmlEventAttribute" |
157
- "node" |
158
- "object";
132
+ type Type =
133
+ "boolean" |
134
+ "string" |
135
+ "number" |
136
+ "integer" |
137
+ "float" |
138
+ "even" |
139
+ "odd" |
140
+ "positive" |
141
+ "negative" |
142
+ "powerOfTwo" |
143
+ "ascii" |
144
+ "array" |
145
+ "jwt" |
146
+ "symbol" |
147
+ "email" |
148
+ "regex" |
149
+ "json" |
150
+ "ipAddress" |
151
+ "slug" |
152
+ "hexadecimal" |
153
+ "date" |
154
+ "timestamp" |
155
+ "function" |
156
+ "htmlElement" |
157
+ "htmlEventAttribute" |
158
+ "node" |
159
+ "object";
159
160
 
160
- type Operation = "select" | "insert" | "update" | "merge" | "delete";
161
161
  type Method = "GET" | "PATCH" | "PUT" | "POST" | "DELETE";
162
162
 
163
163
  class Property {
@@ -168,7 +168,7 @@ class Property {
168
168
  required: boolean;
169
169
  safe: boolean;
170
170
  typeCheck: boolean;
171
- operations: Operation[];
171
+ methods: Method[];
172
172
  sanitize: boolean;
173
173
  normalize: boolean;
174
174
  control: boolean;
@@ -178,38 +178,55 @@ class Property {
178
178
  };
179
179
 
180
180
  class Entity {
181
- table: string;
182
- cols: Record<Operation, string[]>;
183
- properties: Property[];
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[];
181
+ constructor(name: string, properties: Property[]);
182
+ get name(): string;
183
+ get unsafeProps(): string[];
184
+ get properties(): Property[];
185
+ set name(name: string);
186
+
187
+ /**
188
+ * Retrieves a property from the `properties` array that matches the specified key.
189
+ *
190
+ * @param {string} key - The key of the property to retrieve.
191
+ * @returns {Property | undefined} - The property object if found, otherwise `undefined`.
192
+ */
193
+ getProp(key: string): Property | undefined;
194
+
195
+ /**
196
+ * Normalizes an array of records by applying sanitization and normalization
197
+ * rules defined in the `properties` of the class.
198
+ *
199
+ * @param rows - An array of records where each record is a key-value pair.
200
+ * The keys represent property names, and the values are the data
201
+ * to be sanitized and normalized.
202
+ * @returns An array of records with sanitized and normalized values.
203
+ */
204
+ normalize(rows: Record<string, unknown>[]): Record<string, unknown>[];
205
+
206
+ /**
207
+ * Validates a set of rows against the defined properties and operation/method.
208
+ *
209
+ * @param rows - An array of objects where each object represents a row to validate.
210
+ * Each row is a record with string keys and unknown values.
211
+ * @param operation - The operation or method to validate against. It can be of type `Operation` or `Method`.
212
+ *
213
+ * @returns A string containing the validation error message if validation fails, or `null` if validation passes.
214
+ *
215
+ * If a property is required and missing, or if it fails the control checks, the function returns an error message.
216
+ * Otherwise, it returns `null` indicating successful validation.
217
+ */
218
+ validate(rows: Record<string, unknown>[], method: Method): string | null;
190
219
  }
191
220
 
192
221
  ```
193
222
 
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
223
  examples :
207
224
 
208
225
  ```javascript
209
226
 
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
227
+ entity.validate(req.body, "GET"); // will validate properties for GET requests
228
+ entity.validate(req.body, "PUT"); // will validate properties for PUT requests
229
+ entity.validate(req.body, "DELETE"); // will validate properties for DELETE requests
213
230
 
214
231
  ```
215
232
 
package/dist/antity.d.ts CHANGED
@@ -25,9 +25,7 @@ https://github.com/DWTechs/Antity.js
25
25
  */
26
26
 
27
27
 
28
- type Operation = typeof Operations[number];
29
28
  type Method = typeof Methods[number];
30
-
31
29
  type Type =
32
30
  "boolean" |
33
31
  "string" |
@@ -57,11 +55,15 @@ type Type =
57
55
  "node" |
58
56
  "object";
59
57
 
60
- declare const Operations: readonly [ "select", "insert", "update", "merge", "delete" ];
61
58
  declare const Methods: readonly [ "GET", "PATCH", "PUT", "POST", "DELETE" ];
62
59
 
63
60
  declare const Types: Record<Type, {
64
- validate: (v: any, min: number | Date, max: number | Date, typeCheck: boolean) => boolean;
61
+ validate: (
62
+ v: any,
63
+ min: number | Date,
64
+ max: number | Date,
65
+ typeCheck: boolean
66
+ ) => boolean;
65
67
  }>;
66
68
 
67
69
  declare const Required: {
@@ -69,24 +71,22 @@ declare const Required: {
69
71
  };
70
72
 
71
73
  declare class Entity {
72
- table: string;
73
- cols: Record<Operation, string[]>;
74
- properties: Property[];
75
- constructor(table: string, properties: Property[]);
76
- getTable(): string;
77
- getCols(operation: Operation, stringify?: boolean, pagination?: boolean): string[] | string;
78
- getUnsafeProps(): string[];
79
- normalize(rows: Record<string, any>[]): Record<string, any>[];
80
- validate(rows: Record<string, any>[], operation: Operation | Method): string | null;
81
- private require;
82
- private control;
83
- private sanitize;
84
- private trim;
74
+ private _name;
75
+ private _unsafeProps;
76
+ private _properties;
77
+ constructor(name: string, properties: Property[]);
78
+ get name(): string;
79
+ get unsafeProps(): string[];
80
+ get properties(): Property[];
81
+ set name(name: string);
82
+ getProp(key: string): Property | undefined;
83
+ normalize(rows: Record<string, unknown>[]): Record<string, unknown>[];
84
+ validate(rows: Record<string, unknown>[], method: Method): string | null;
85
85
  }
86
86
 
87
87
  declare const Messages: {
88
- missing: (key: string) => string;
89
- invalid: (key: string, type: Type) => string;
88
+ missing: (key: string) => string;
89
+ invalid: (key: string, type: Type) => string;
90
90
  };
91
91
 
92
92
  declare class Property {
@@ -97,21 +97,22 @@ declare class Property {
97
97
  required: boolean;
98
98
  safe: boolean;
99
99
  typeCheck: boolean;
100
- operations: Operation[];
100
+ methods: Method[];
101
101
  sanitize: boolean;
102
102
  normalize: boolean;
103
103
  control: boolean;
104
104
  sanitizer: ((v: any) => any) | null;
105
105
  normalizer: ((v: any) => any) | null;
106
106
  controller: ((v: any) => any) | null;
107
- constructor(key: string,
107
+ constructor(
108
+ key: string,
108
109
  type: Type,
109
110
  min: number | Date,
110
111
  max: number | Date,
111
112
  required: boolean,
112
113
  safe: boolean,
113
114
  typeCheck: boolean,
114
- operations: Operation[],
115
+ methods: Method[],
115
116
  sanitize: boolean,
116
117
  normalize: boolean,
117
118
  control: boolean,
@@ -121,13 +122,13 @@ declare class Property {
121
122
  );
122
123
  }
123
124
 
124
- export type { Type, Operation, Method };
125
+ export type { Type, Method };
125
126
  export {
126
127
  Entity,
127
128
  Property,
128
129
  Messages,
129
130
  Types,
130
131
  Required,
131
- Operations
132
+ Methods,
132
133
  };
133
134
 
package/dist/antity.js CHANGED
@@ -24,9 +24,10 @@ 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, isDate, 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, isString, isProperty, isArray, isIn, isDate, isNumber, isInteger, isNil } from '@dwtechs/checkard';
28
+ import { log } from '@dwtechs/winstan';
28
29
 
29
- const Operations = ["select", "insert", "update", "merge", "delete"];
30
+ const Methods = ["GET", "PATCH", "PUT", "POST", "DELETE"];
30
31
 
31
32
  const Types = {
32
33
  boolean: {
@@ -111,20 +112,17 @@ const Types = {
111
112
  validate: (v, _min, _max, _typeCheck) => isObject(v)
112
113
  }
113
114
  };
114
- const Required = {
115
- validate: (v) => !isNil(v)
116
- };
117
115
 
118
116
  class Property {
119
- constructor(key, type, min, max, required, safe, typeCheck, operations, sanitize, normalize, control, sanitizer, normalizer, controller) {
120
- if (!isString(key, true))
121
- throw new Error(`Property"key" must be a string. Received ${key}`);
122
- if (!isProperty(type, Types))
117
+ constructor(key, type, min, max, required, safe, typeCheck, methods, sanitize, normalize, control, sanitizer, normalizer, controller) {
118
+ if (!isString(key, "!0"))
119
+ throw new Error(`Property "key" must be a string. Received ${key}`);
120
+ if (!isProperty(Types, type))
123
121
  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}`);
122
+ if (isArray(methods)) {
123
+ for (const m of methods) {
124
+ if (!isIn(Methods, m))
125
+ throw new Error(`Property "methods" must be an array of REST methods. Received ${m}`);
128
126
  }
129
127
  }
130
128
  this.key = key;
@@ -134,7 +132,7 @@ class Property {
134
132
  this.required = isBoolean(required) ? required : false;
135
133
  this.safe = isBoolean(safe) ? safe : true;
136
134
  this.typeCheck = isBoolean(typeCheck) ? typeCheck : false;
137
- this.operations = operations || Operations;
135
+ this.methods = methods || Methods;
138
136
  this.sanitize = isBoolean(sanitize) ? sanitize : true;
139
137
  this.normalize = isBoolean(normalize) ? normalize : false;
140
138
  this.control = isBoolean(control) ? control : true;
@@ -145,7 +143,7 @@ class Property {
145
143
  interval(val, type, integerDefault, dateDefault) {
146
144
  if (type === "date")
147
145
  return isDate(val) ? val : new Date(dateDefault);
148
- return isInteger(val, true) ? val : integerDefault;
146
+ return (isNumber(val, true) && isInteger(val, true)) ? val : integerDefault;
149
147
  }
150
148
  }
151
149
 
@@ -154,52 +152,46 @@ const Messages = {
154
152
  invalid: (key, type) => `Invalid ${key}, must be of type ${type}`,
155
153
  };
156
154
 
157
- const Methods = ["GET", "PATCH", "PUT", "POST", "DELETE"];
158
-
159
155
  class Entity {
160
- constructor(table, properties) {
161
- this.table = table;
162
- this.properties = [];
163
- this.cols = {
164
- select: [],
165
- insert: [],
166
- update: [],
167
- merge: [],
168
- delete: []
169
- };
170
- this.unsafeProps = [];
156
+ constructor(name, properties) {
157
+ this._name = name;
158
+ this._properties = [];
159
+ this._unsafeProps = [];
171
160
  for (const p of properties) {
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
- }
161
+ const prop = new Property(p.key, p.type, p.min, p.max, p.required, p.safe, p.typeCheck, p.methods, p.sanitize, p.normalize, p.control, p.sanitizer, p.normalizer, p.controller);
162
+ this._properties.push(prop);
180
163
  if (!prop.safe)
181
- this.unsafeProps.push(prop.key);
164
+ this._unsafeProps.push(prop.key);
182
165
  }
183
166
  }
184
- getTable() {
185
- return this.table;
167
+ get name() {
168
+ return this._name;
169
+ }
170
+ get unsafeProps() {
171
+ return this._unsafeProps;
186
172
  }
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;
173
+ get properties() {
174
+ return this._properties;
190
175
  }
191
- getUnsafeProps() {
192
- return this.unsafeProps;
176
+ set name(name) {
177
+ if (!isString(name, "!0"))
178
+ throw new Error('name must be a string of length > 0');
179
+ this._name = name;
180
+ }
181
+ getProp(key) {
182
+ return this.properties.find(p => p.key === key);
193
183
  }
194
184
  normalize(rows) {
195
185
  for (const r of rows) {
196
- for (const { key, sanitize, normalize, sanitizer, normalizer, } of this.properties) {
186
+ for (const { key, type, sanitize, normalize, sanitizer, normalizer, } of this.properties) {
197
187
  let v = r[key];
198
188
  if (v) {
199
189
  if (sanitize) {
190
+ log.debug(`sanitize ${key}: ${type} = ${v}`);
200
191
  v = this.sanitize(v, sanitizer);
201
192
  }
202
193
  if (normalize && normalizer) {
194
+ log.debug(`normalize ${key}: ${type} = ${v}`);
203
195
  v = normalizer(v);
204
196
  }
205
197
  r[key] = v;
@@ -208,15 +200,15 @@ class Entity {
208
200
  }
209
201
  return rows;
210
202
  }
211
- validate(rows, operation) {
212
- if (isIn(operation, Methods))
213
- operation = this.mapMethods(operation);
203
+ validate(rows, method) {
204
+ if (!isIn(Methods, method))
205
+ return `Invalid REST method. Received: ${method}. Must be one of: ${Methods.toString()}`;
214
206
  for (const r of rows) {
215
- for (const { key, type, min, max, required, typeCheck, operations, control, controller } of this.properties) {
207
+ for (const { key, type, min, max, required, typeCheck, methods, control, controller } of this.properties) {
216
208
  const v = r[key];
217
- if (isIn(operation, operations)) {
209
+ if (isIn(methods, method)) {
218
210
  if (required) {
219
- const rq = this.require(v, key);
211
+ const rq = this.require(v, key, type);
220
212
  if (rq)
221
213
  return rq;
222
214
  }
@@ -230,13 +222,16 @@ class Entity {
230
222
  }
231
223
  return null;
232
224
  }
233
- require(v, key) {
234
- return Required.validate(v) ? null : Messages.missing(key);
225
+ require(v, key, type) {
226
+ log.debug(`require ${key}: ${type} = ${v}`);
227
+ return isNil(v) ? Messages.missing(key) : null;
235
228
  }
236
229
  control(v, key, type, min, max, typeCheck, cb) {
230
+ log.debug(`control ${key}: ${type} = ${v}`);
237
231
  if (cb)
238
232
  return cb(v) ? null : Messages.invalid(key, type);
239
- return Types[type].validate(v, min, max, typeCheck) ? null : Messages.invalid(key, type);
233
+ const val = Types[type].validate(v, min, max, typeCheck);
234
+ return val ? null : Messages.invalid(key, type);
240
235
  }
241
236
  sanitize(v, cb) {
242
237
  if (cb)
@@ -250,33 +245,18 @@ class Entity {
250
245
  return this.trim(v);
251
246
  }
252
247
  trim(v) {
253
- if (isString(v, true))
248
+ if (isString(v, "!0"))
254
249
  return v.trim();
255
250
  if (isObject(v, true)) {
256
- if (v.has)
257
- for (const p in v) {
258
- if (v.prototype.hasOwnProperty.call(p)) {
259
- let o = v[p];
260
- if (isString(o, true))
261
- o = o.trim();
262
- }
251
+ for (const k in v) {
252
+ if (Object.prototype.hasOwnProperty.call(v, k)) {
253
+ let o = v[k];
254
+ if (isString(o, "!0", null))
255
+ o = o.trim();
263
256
  }
264
- return v;
265
- }
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];
257
+ }
279
258
  }
259
+ return v;
280
260
  }
281
261
  }
282
262
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dwtechs/antity",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Open source library for easy entity management",
5
5
  "keywords": [
6
6
  "entities"
@@ -25,18 +25,20 @@
25
25
  "contributors": [],
26
26
  "scripts": {
27
27
  "start": "",
28
+ "prebuild": "npm install",
28
29
  "build": "node ./scripts/clear && tsc && npm run rollup && node ./scripts/copy && npm run test",
29
30
  "rollup:mjs": "rollup --config rollup.config.mjs",
30
31
  "rollup:cjs": "rollup --config rollup.config.cjs.mjs",
31
- "rollup": "npm run rollup:mjs && npm run rollup:cjs",
32
+ "rollup": "npm run rollup:mjs",
32
33
  "test": "jest --coverage"
33
34
  },
34
35
  "files": [
35
36
  "dist/"
36
37
  ],
37
38
  "dependencies": {
38
- "@dwtechs/checkard": "2.29.2",
39
- "@dwtechs/winstan": "0.2.1",
39
+ "@dwtechs/checkard": "3.2.3",
40
+ "@dwtechs/winstan": "0.4.0",
41
+ "@dwtechs/sparray": "0.1.1",
40
42
  "pg": "8.13.1"
41
43
  },
42
44
  "devDependencies": {
@@ -1,588 +0,0 @@
1
- /*
2
- MIT License
3
-
4
- Copyright (c) 2024 DWTechs
5
-
6
- Permission is hereby granted, free of charge, to any person obtaining a copy
7
- of this software and associated documentation files (the "Software"), to deal
8
- in the Software without restriction, including without limitation the rights
9
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- copies of the Software, and to permit persons to whom the Software is
11
- furnished to do so, subject to the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be included in all
14
- copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- SOFTWARE.
23
-
24
- https://github.com/DWTechs/Antity.js
25
- */
26
-
27
- 'use strict';
28
-
29
- /*
30
- MIT License
31
-
32
- Copyright (c) 2009 DWTechs
33
-
34
- Permission is hereby granted, free of charge, to any person obtaining a copy
35
- of this software and associated documentation files (the "Software"), to deal
36
- in the Software without restriction, including without limitation the rights
37
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38
- copies of the Software, and to permit persons to whom the Software is
39
- furnished to do so, subject to the following conditions:
40
-
41
- The above copyright notice and this permission notice shall be included in all
42
- copies or substantial portions of the Software.
43
-
44
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
50
- SOFTWARE.
51
-
52
- https://github.com/DWTechs/Checkard.js
53
- */
54
-
55
- function isNumeric(n) {
56
- return !isNaN(n - parseFloat(n));
57
- }
58
- function getTag(t) {
59
- return t == null ? t === undefined ? '[object Undefined]' : '[object Null]' : toString.call(t);
60
- }
61
-
62
- function isBoolean(b) {
63
- return typeof b === "boolean";
64
- }
65
- function isNumber(n, type = true) {
66
- return !isSymbol(n) && !((n === null || n === void 0 ? void 0 : n.constructor) === Array) && (type ? Number(n) === n : isNumeric(n));
67
- }
68
- function isSymbol(s) {
69
- const type = typeof s;
70
- return type === 'symbol' || (type === 'object' && s != null && getTag(s) === '[object Symbol]');
71
- }
72
- function isNil(n) {
73
- return n == null;
74
- }
75
-
76
- function isFunction(func) {
77
- return Boolean(func && getTag(func) === "[object Function]");
78
- }
79
-
80
- const comparisons = {
81
- '=': (a, b) => a == b,
82
- '<': (a, b) => a < b,
83
- '>': (a, b) => a > b,
84
- '<=': (a, b) => a <= b,
85
- '>=': (a, b) => a >= b
86
- };
87
-
88
- function isAscii(c, ext = true) {
89
- return isInteger(c, false) && ((ext && c >= 0 && c <= 255) || (c >= 0 && c <= 127));
90
- }
91
- function isInteger(n, type = true) {
92
- if (!isNumber(n, type))
93
- return false;
94
- const int = Number.parseInt(String(n), 10);
95
- return type ? n === int : n == int;
96
- }
97
- function isFloat(n, type = true) {
98
- if (isSymbol(n))
99
- return false;
100
- const modulo = n % 1 !== 0;
101
- return type ? (Number(n) === n && modulo) : (Number(n) == n && modulo);
102
- }
103
- function isEven(n, type = true) {
104
- return isInteger(n, type) && !(n & 1);
105
- }
106
- function isOdd(n, type = true) {
107
- return isInteger(n, type) && Boolean(n & 1);
108
- }
109
- function isOrigin(n, type = true) {
110
- return type ? n === 0 : n == 0;
111
- }
112
- function isPositive(n, type = true) {
113
- return isNumber(n, type) && n > 0;
114
- }
115
- function isNegative(n, type = true) {
116
- return isNumber(n, type) && n < 0;
117
- }
118
- function isPowerOfTwo(n, type = true) {
119
- return isInteger(n, type) && !isOrigin(n, type) && (n & (n - 1)) === 0;
120
- }
121
-
122
- function isValidNumber(n, min = -999999999, max = 999999999, type = true) {
123
- return isNumber(n, type) && n >= min && n <= max;
124
- }
125
- function isValidInteger(n, min = -999999999, max = 999999999, type = true) {
126
- return isInteger(n, type) && n >= min && n <= max;
127
- }
128
- function isValidFloat(n, min = -999999999.9, max = 999999999.9, type = true) {
129
- return isFloat(n, type) && n >= min && n <= max;
130
- }
131
-
132
- function isArray(a, comp, len) {
133
- return (a === null || a === void 0 ? void 0 : a.constructor) === Array ? (comp && isValidInteger(len, 0, 999999999)) ? comparisons.hasOwnProperty(comp) ? comparisons[comp](a.length, len) : false : true : false;
134
- }
135
- function isArrayOfLength(a, min = -999999999, max = 999999999) {
136
- if (isArray(a, null, null)) {
137
- const n = a.length;
138
- return n >= min && n <= max;
139
- }
140
- return false;
141
- }
142
- function isIn(val, arr) {
143
- return isArray(arr, '>', 0) ? arr.includes(val) : false;
144
- }
145
-
146
- function isString(s, required = false) {
147
- return typeof s === "string" && (required ? !!s : true);
148
- }
149
- function isStringOfLength(s, min = 0, max = 999999999) {
150
- if (isString(s, false)) {
151
- const l = s.length;
152
- return l >= min && l <= max;
153
- }
154
- return false;
155
- }
156
- function isJson(s) {
157
- if (!isString(s))
158
- return false;
159
- try {
160
- JSON.parse(s);
161
- }
162
- catch (e) {
163
- return false;
164
- }
165
- return true;
166
- }
167
- function isRegex(r, type = true) {
168
- if (type)
169
- return r instanceof RegExp;
170
- try {
171
- new RegExp(r);
172
- }
173
- catch (e) {
174
- return false;
175
- }
176
- return true;
177
- }
178
- const emailReg = /^(?=[a-z0-9@.!$%&'*+\/=?^_‘{|}~-]{6,254}$)(?=[a-z0-9.!#$%&'*+\/=?^_‘{|}~-]{1,64}@)[a-z0-9!#$%&'*+\/=?^‘{|}~]+(?:[\._-][a-z0-9!#$%&'*+\/=?^‘{|}~]+)*@(?:(?=[a-z0-9-]{1,63}\.)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?=[a-z0-9-]{2,63}$)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
179
- function isEmail(e) {
180
- return !isSymbol(e) && emailReg.test(String(e).toLowerCase());
181
- }
182
- const ipReg = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
183
- function isIpAddress(i) {
184
- return !isSymbol(i) && ipReg.test(i);
185
- }
186
- const b64Reg = /^[A-Za-z0-9\-_]+={0,2}$/;
187
- function isJWT(t) {
188
- if (!isString(t))
189
- return false;
190
- const p = t.split('.');
191
- if (p.length !== 3)
192
- return false;
193
- const header = p[0];
194
- const payload = p[1];
195
- const signature = p[3];
196
- if (b64Reg.test(header) && b64Reg.test(payload) && b64Reg.test(signature)) {
197
- try {
198
- return isJson(atob(header)) && isJson(atob(payload));
199
- }
200
- catch (e) {
201
- return false;
202
- }
203
- }
204
- return false;
205
- }
206
- const slugReg = /^[^\s-_](?!.*?[-_]{2,})[a-z0-9-\\][^\s]*[^-_\s]$/;
207
- function isSlug(s) {
208
- return isString(s) && slugReg.test(s);
209
- }
210
- const hexadecimal = /^(#|0x|0h)?[0-9A-F]+$/i;
211
- function isHexadecimal(s) {
212
- return isString(s) && hexadecimal.test(s);
213
- }
214
-
215
- function isObject(o, empty = false) {
216
- return o !== null && typeof o === "object" && !isArray(o) && (empty ? !!Object.keys(o).length : true);
217
- }
218
- function isProperty(val, obj) {
219
- const v = String(val);
220
- return isString(v, true) && isObject(obj) ? Object.keys(obj).includes(v) : false;
221
- }
222
-
223
- function isHtmlElement(h) {
224
- return Boolean(typeof HTMLElement === "object"
225
- ? h instanceof HTMLElement
226
- : h &&
227
- typeof h === "object" &&
228
- h.nodeType === 1 &&
229
- typeof h.nodeName === "string");
230
- }
231
- function isHtmlEventAttribute(h) {
232
- switch (h) {
233
- case "onafterprint":
234
- case "onbeforeprint":
235
- case "onbeforeunload":
236
- case "onerror":
237
- case "onhashchange":
238
- case "onload":
239
- case "onmessage":
240
- case "onoffline":
241
- case "ononline":
242
- case "onpagehide":
243
- case "onpageshow":
244
- case "onpopstate":
245
- case "onresize":
246
- case "onstorage":
247
- case "onunload":
248
- case "onblur":
249
- case "onchange":
250
- case "oncontextmenu":
251
- case "onfocus":
252
- case "oninput":
253
- case "oninvalid":
254
- case "onreset":
255
- case "onsearch":
256
- case "onselect":
257
- case "onsubmit":
258
- case "onkeydown":
259
- case "onkeypress":
260
- case "onkeyup":
261
- case "onclick":
262
- case "ondblclick":
263
- case "onmousedown":
264
- case "onmousemove":
265
- case "onmouseout":
266
- case "onmouseover":
267
- case "onmouseup":
268
- case "onmousewheel":
269
- case "onwheel":
270
- case "ondrag":
271
- case "ondragend":
272
- case "ondragenter":
273
- case "ondragleave":
274
- case "ondragover":
275
- case "ondragstart":
276
- case "ondrop":
277
- case "onscroll":
278
- case "oncopy":
279
- case "oncut":
280
- case "onpaste":
281
- case "onabort":
282
- case "oncanplay":
283
- case "oncanplaythrough":
284
- case "oncuechange":
285
- case "ondurationchange":
286
- case "onemptied":
287
- case "onended":
288
- case "onerror":
289
- case "onloadeddata":
290
- case "onloadedmetadata":
291
- case "onloadstart":
292
- case "onpause":
293
- case "onplay":
294
- case "onplaying":
295
- case "onprogress":
296
- case "onratechange":
297
- case "onseeked":
298
- case "onseeking":
299
- case "onstalled":
300
- case "onsuspend":
301
- case "ontimeupdate":
302
- case "onvolumechange":
303
- case "onwaiting":
304
- case "ontoggle":
305
- return true;
306
- default:
307
- return false;
308
- }
309
- }
310
- function isNode(n) {
311
- return Boolean(typeof Node === "object"
312
- ? n instanceof Node
313
- : n &&
314
- typeof n === "object" &&
315
- typeof n.nodeType === "number" &&
316
- typeof n.nodeName === "string");
317
- }
318
-
319
- function isDate(d) {
320
- return !isNaN(d) && d instanceof Date;
321
- }
322
- const minDate = new Date('1/1/1900');
323
- const maxDate = new Date('1/1/2200');
324
- function isValidDate(d, min = minDate, max = maxDate) {
325
- return isDate(d) && d >= min && d <= max;
326
- }
327
- function isTimestamp(t, type = true) {
328
- return isInteger(t, type) && isNumeric(new Date(parseInt(t + '')).getTime());
329
- }
330
- function isValidTimestamp(t, min = -2208989361000, max = 7258114800000, type = true) {
331
- return isTimestamp(t, type) && t >= min && t <= max;
332
- }
333
-
334
- const Operations = ["select", "insert", "update", "merge", "delete"];
335
-
336
- const Types = {
337
- boolean: {
338
- validate: (v, _min, _max, _typeCheck) => isBoolean(v)
339
- },
340
- string: {
341
- validate: (v, min, max, _typeCheck) => isStringOfLength(v, min, max)
342
- },
343
- number: {
344
- validate: (v, min, max, typeCheck) => isValidNumber(v, min || undefined, max || undefined, typeCheck || undefined)
345
- },
346
- integer: {
347
- validate: (v, min, max, typeCheck) => isValidInteger(v, min || undefined, max || undefined, typeCheck || undefined)
348
- },
349
- float: {
350
- validate: (v, min, max, typeCheck) => isValidFloat(v, min || undefined, max || undefined, typeCheck || undefined)
351
- },
352
- even: {
353
- validate: (v, _min, _max, typeCheck) => isEven(v, typeCheck || undefined)
354
- },
355
- odd: {
356
- validate: (v, _min, _max, typeCheck) => isOdd(v, typeCheck || undefined)
357
- },
358
- positive: {
359
- validate: (v, _min, _max, typeCheck) => isPositive(v, typeCheck || undefined)
360
- },
361
- negative: {
362
- validate: (v, _min, _max, typeCheck) => isNegative(v, typeCheck || undefined)
363
- },
364
- powerOfTwo: {
365
- validate: (v, _min, _max, typeCheck) => isPowerOfTwo(v, typeCheck || undefined)
366
- },
367
- ascii: {
368
- validate: (v, _min, _max, typeCheck) => isAscii(v, typeCheck || undefined)
369
- },
370
- array: {
371
- validate: (v, min, max, _typeCheck) => isArrayOfLength(v, min || undefined, max || undefined)
372
- },
373
- email: {
374
- validate: (v, _min, _max, _typeCheck) => isEmail(v)
375
- },
376
- regex: {
377
- validate: (v, _min, _max, typeCheck) => isRegex(v, typeCheck || undefined)
378
- },
379
- json: {
380
- validate: (v, _min, _max, _typeCheck) => isJson(v)
381
- },
382
- jwt: {
383
- validate: (v, _min, _max, _typeCheck) => isJWT(v)
384
- },
385
- symbol: {
386
- validate: (v, _min, _max, _typeCheck) => isSymbol(v)
387
- },
388
- ipAddress: {
389
- validate: (v, _min, _max, _typeCheck) => isIpAddress(v)
390
- },
391
- slug: {
392
- validate: (v, _min, _max, _typeCheck) => isSlug(v)
393
- },
394
- hexadecimal: {
395
- validate: (v, _min, _max, _typeCheck) => isHexadecimal(v)
396
- },
397
- date: {
398
- validate: (v, min, max, _typeCheck) => isValidDate(v, min || undefined, max || undefined)
399
- },
400
- timestamp: {
401
- validate: (v, min, max, typeCheck) => isValidTimestamp(v, min || undefined, max || undefined, typeCheck || undefined)
402
- },
403
- function: {
404
- validate: (v, _min, _max, _typeCheck) => isFunction(v)
405
- },
406
- htmlElement: {
407
- validate: (v, _min, _max, _typeCheck) => isHtmlElement(v)
408
- },
409
- htmlEventAttribute: {
410
- validate: (v, _min, _max, _typeCheck) => isHtmlEventAttribute(v)
411
- },
412
- node: {
413
- validate: (v, _min, _max, _typeCheck) => isNode(v)
414
- },
415
- object: {
416
- validate: (v, _min, _max, _typeCheck) => isObject(v)
417
- }
418
- };
419
- const Required = {
420
- validate: (v) => !isNil(v)
421
- };
422
-
423
- class Property {
424
- constructor(key, type, min, max, required, safe, typeCheck, operations, sanitize, normalize, control, sanitizer, normalizer, controller) {
425
- if (!isString(key, true))
426
- throw new Error(`Property"key" must be a string. Received ${key}`);
427
- if (!isProperty(type, Types))
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
- }
434
- }
435
- this.key = key;
436
- this.type = type;
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
- this.required = isBoolean(required) ? required : false;
440
- this.safe = isBoolean(safe) ? safe : true;
441
- this.typeCheck = isBoolean(typeCheck) ? typeCheck : false;
442
- this.operations = operations || Operations;
443
- this.sanitize = isBoolean(sanitize) ? sanitize : true;
444
- this.normalize = isBoolean(normalize) ? normalize : false;
445
- this.control = isBoolean(control) ? control : true;
446
- this.sanitizer = isFunction(sanitizer) ? sanitizer : null;
447
- this.normalizer = isFunction(normalizer) ? normalizer : null;
448
- this.controller = isFunction(controller) ? controller : null;
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
- }
455
- }
456
-
457
- const Messages = {
458
- missing: (key) => `Missing ${key}`,
459
- invalid: (key, type) => `Invalid ${key}, must be of type ${type}`,
460
- };
461
-
462
- const Methods = ["GET", "PATCH", "PUT", "POST", "DELETE"];
463
-
464
- class Entity {
465
- constructor(table, properties) {
466
- this.table = table;
467
- this.properties = [];
468
- this.cols = {
469
- select: [],
470
- insert: [],
471
- update: [],
472
- merge: [],
473
- delete: []
474
- };
475
- this.unsafeProps = [];
476
- for (const p of properties) {
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);
487
- }
488
- }
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;
498
- }
499
- normalize(rows) {
500
- for (const r of rows) {
501
- for (const { key, sanitize, normalize, sanitizer, normalizer, } of this.properties) {
502
- let v = r[key];
503
- if (v) {
504
- if (sanitize) {
505
- v = this.sanitize(v, sanitizer);
506
- }
507
- if (normalize && normalizer) {
508
- v = normalizer(v);
509
- }
510
- r[key] = v;
511
- }
512
- }
513
- }
514
- return rows;
515
- }
516
- validate(rows, operation) {
517
- if (isIn(operation, Methods))
518
- operation = this.mapMethods(operation);
519
- for (const r of rows) {
520
- for (const { key, type, min, max, required, typeCheck, operations, control, controller } of this.properties) {
521
- const v = r[key];
522
- if (isIn(operation, operations)) {
523
- if (required) {
524
- const rq = this.require(v, key);
525
- if (rq)
526
- return rq;
527
- }
528
- if (v && control) {
529
- const ct = this.control(v, key, type, min, max, typeCheck, controller);
530
- if (ct)
531
- return ct;
532
- }
533
- }
534
- }
535
- }
536
- return null;
537
- }
538
- require(v, key) {
539
- return Required.validate(v) ? null : Messages.missing(key);
540
- }
541
- control(v, key, type, min, max, typeCheck, cb) {
542
- if (cb)
543
- return cb(v) ? null : Messages.invalid(key, type);
544
- return Types[type].validate(v, min, max, typeCheck) ? null : Messages.invalid(key, type);
545
- }
546
- sanitize(v, cb) {
547
- if (cb)
548
- return cb(v);
549
- if (isArray(v, null, null)) {
550
- for (let d of v) {
551
- d = this.trim(d);
552
- }
553
- return v;
554
- }
555
- return this.trim(v);
556
- }
557
- trim(v) {
558
- if (isString(v, true))
559
- return v.trim();
560
- if (isObject(v, true)) {
561
- if (v.has)
562
- for (const p in v) {
563
- if (v.prototype.hasOwnProperty.call(p)) {
564
- let o = v[p];
565
- if (isString(o, true))
566
- o = o.trim();
567
- }
568
- }
569
- return v;
570
- }
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
- }
586
- }
587
-
588
- exports.Entity = Entity;