@dwtechs/antity-pgsql 0.3.3 → 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 +38 -1
- package/dist/antity-pgsql.d.ts +2 -1
- package/dist/antity-pgsql.js +279 -200
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -52,7 +52,9 @@ const entity = new Entity("consumers", [
|
|
|
52
52
|
min: 0,
|
|
53
53
|
max: 120,
|
|
54
54
|
typeCheck: true,
|
|
55
|
+
filter: true,
|
|
55
56
|
methods: ["GET", "PUT", "DELETE"],
|
|
57
|
+
operations: ["SELECT", "UPDATE", "DELETE"],
|
|
56
58
|
required: true,
|
|
57
59
|
safe: true,
|
|
58
60
|
sanitize: true,
|
|
@@ -68,7 +70,9 @@ const entity = new Entity("consumers", [
|
|
|
68
70
|
min: 0,
|
|
69
71
|
max: 255,
|
|
70
72
|
typeCheck: true,
|
|
73
|
+
filter: false,
|
|
71
74
|
methods: ["GET", "POST", "PUT", "DELETE"],
|
|
75
|
+
operations: ["SELECT", "UPDATE", "DELETE"],
|
|
72
76
|
required: true,
|
|
73
77
|
safe: true,
|
|
74
78
|
sanitize: true,
|
|
@@ -84,7 +88,9 @@ const entity = new Entity("consumers", [
|
|
|
84
88
|
min: 0,
|
|
85
89
|
max: 255,
|
|
86
90
|
typeCheck: true,
|
|
91
|
+
filter: false,
|
|
87
92
|
methods: ["GET", "POST", "PUT", "DELETE"],
|
|
93
|
+
operations: ["SELECT", "UPDATE", "DELETE"],
|
|
88
94
|
required: true,
|
|
89
95
|
safe: true,
|
|
90
96
|
sanitize: true,
|
|
@@ -100,7 +106,9 @@ const entity = new Entity("consumers", [
|
|
|
100
106
|
min: 0,
|
|
101
107
|
max: 255,
|
|
102
108
|
typeCheck: true,
|
|
109
|
+
filter: true,
|
|
103
110
|
methods: ["GET", "POST", "PUT", "DELETE"],
|
|
111
|
+
operations: ["SELECT", "UPDATE", "DELETE"],
|
|
104
112
|
required: true,
|
|
105
113
|
safe: true,
|
|
106
114
|
sanitize: true,
|
|
@@ -124,7 +132,7 @@ router.put("/", ..., entity.archive);
|
|
|
124
132
|
|
|
125
133
|
```javascript
|
|
126
134
|
|
|
127
|
-
type Operation = "
|
|
135
|
+
type Operation = "SELECT" | "INSERT" | "UPDATE" | "DELETE";
|
|
128
136
|
|
|
129
137
|
type MatchMode =
|
|
130
138
|
"startsWith" |
|
|
@@ -273,6 +281,35 @@ List of secondary types :
|
|
|
273
281
|
| json | object |
|
|
274
282
|
| object | object |
|
|
275
283
|
|
|
284
|
+
|
|
285
|
+
## Available options for a property
|
|
286
|
+
|
|
287
|
+
Any of these can be passed into the options object for each function.
|
|
288
|
+
|
|
289
|
+
| Name | Type | Description | Default value |
|
|
290
|
+
| :-------------- | :------------------------ | :------------------------------------------------ | :-------------- |
|
|
291
|
+
| key | string | Name of the property |
|
|
292
|
+
| type | Type | Type of the property |
|
|
293
|
+
| min | number \| Date | Minimum value | 0 \| 1900-01-01
|
|
294
|
+
| max | number \| Date | Maximum value | 999999999 \| 2200-12-31
|
|
295
|
+
| required | boolean | Property is required during validation | false
|
|
296
|
+
| safe | boolean | Property is sent in the response | true
|
|
297
|
+
| typeCheck | boolean | Type is checked during validation | false
|
|
298
|
+
| filter | boolean | property is filterable in a SELECT operation | true
|
|
299
|
+
| methods | Method[] | property is validated for the listed methods only | [ "GET", "POST", "PUT", "DELETE" ]
|
|
300
|
+
| operations | Operation[] | SQL DML operations for the property | [ "SELECT", "INSERT", "UPDATE", "DELETE" ]
|
|
301
|
+
| sanitize | boolean | Sanitize the property if true | true
|
|
302
|
+
| normalize | boolean | Normalize the property if true | false
|
|
303
|
+
| validate | boolean | validate the property if true | true
|
|
304
|
+
| sanitizer | ((v:any) => any) \| null | Custom sanitizer function if sanitize is true | null
|
|
305
|
+
| normalizer | ((v:any) => any) \| null | Custop Normalizer function if normalize is true | null
|
|
306
|
+
| validator | ((v:any, min:number, max:number, typeCheck:boolean) => any) \| null | validator function if validate is true | null
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
* *Min and max parameters are not used for boolean type*
|
|
310
|
+
* *TypeCheck Parameter is not used for boolean, string and array types*
|
|
311
|
+
|
|
312
|
+
|
|
276
313
|
## Contributors
|
|
277
314
|
|
|
278
315
|
Antity.js is still in development and we would be glad to get all the help you can provide.
|
package/dist/antity-pgsql.d.ts
CHANGED
|
@@ -24,8 +24,9 @@ SOFTWARE.
|
|
|
24
24
|
https://github.com/DWTechs/Antity-pgsql.js
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
import { Entity
|
|
27
|
+
import { Entity } from "@dwtechs/antity";
|
|
28
28
|
import { Type } from "@dwtechs/antity";
|
|
29
|
+
import { Property } from './property';
|
|
29
30
|
import type { Request, Response, NextFunction } from 'express';
|
|
30
31
|
|
|
31
32
|
export type Operation = "SELECT" | "INSERT" | "UPDATE" | "DELETE";
|
package/dist/antity-pgsql.js
CHANGED
|
@@ -24,79 +24,12 @@ SOFTWARE.
|
|
|
24
24
|
https://github.com/DWTechs/Antity-pgsql.js
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
import {
|
|
27
|
+
import { isArray, isIn, isString } from '@dwtechs/checkard';
|
|
28
28
|
import { deleteProps, add as add$1, chunk, flatten } from '@dwtechs/sparray';
|
|
29
29
|
import { log } from '@dwtechs/winstan';
|
|
30
30
|
import { Entity } from '@dwtechs/antity';
|
|
31
31
|
import Pool from 'pg-pool';
|
|
32
32
|
|
|
33
|
-
function type(type) {
|
|
34
|
-
const s = "string";
|
|
35
|
-
const n = "number";
|
|
36
|
-
const d = "date";
|
|
37
|
-
switch (type) {
|
|
38
|
-
case "integer":
|
|
39
|
-
return n;
|
|
40
|
-
case "float":
|
|
41
|
-
return n;
|
|
42
|
-
case "even":
|
|
43
|
-
return n;
|
|
44
|
-
case "odd":
|
|
45
|
-
return n;
|
|
46
|
-
case "positive":
|
|
47
|
-
return n;
|
|
48
|
-
case "negative":
|
|
49
|
-
return n;
|
|
50
|
-
case "powerOfTwo":
|
|
51
|
-
return n;
|
|
52
|
-
case "ascii":
|
|
53
|
-
return n;
|
|
54
|
-
case "jwt":
|
|
55
|
-
return s;
|
|
56
|
-
case "symbol":
|
|
57
|
-
return s;
|
|
58
|
-
case "password":
|
|
59
|
-
return s;
|
|
60
|
-
case "email":
|
|
61
|
-
return s;
|
|
62
|
-
case "regex":
|
|
63
|
-
return s;
|
|
64
|
-
case "ipAddress":
|
|
65
|
-
return s;
|
|
66
|
-
case "slug":
|
|
67
|
-
return s;
|
|
68
|
-
case "hexadecimal":
|
|
69
|
-
return s;
|
|
70
|
-
case "date":
|
|
71
|
-
return d;
|
|
72
|
-
case "timestamp":
|
|
73
|
-
return d;
|
|
74
|
-
case "function":
|
|
75
|
-
return s;
|
|
76
|
-
case "htmlElement":
|
|
77
|
-
return s;
|
|
78
|
-
case "htmlEventAttribute":
|
|
79
|
-
return s;
|
|
80
|
-
case "node":
|
|
81
|
-
return s;
|
|
82
|
-
case "json":
|
|
83
|
-
return s;
|
|
84
|
-
case "object":
|
|
85
|
-
return s;
|
|
86
|
-
default:
|
|
87
|
-
return s;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const matchModes = {
|
|
92
|
-
string: ["startsWith", "contains", "endsWith", "notContains", "equals", "notEquals", "lt", "lte", "gt", "gte"],
|
|
93
|
-
number: ["equals", "notEquals", "lt", "lte", "gt", "gte"],
|
|
94
|
-
date: ["is", "isNot", "dateAfter"],
|
|
95
|
-
};
|
|
96
|
-
function matchMode(type, matchMode) {
|
|
97
|
-
return isIn(matchModes[type], matchMode);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
33
|
const { DB_HOST, DB_USER, DB_PWD, DB_NAME, DB_PORT, DB_MAX } = process.env;
|
|
101
34
|
var pool = new Pool({
|
|
102
35
|
host: DB_HOST,
|
|
@@ -107,10 +40,12 @@ var pool = new Pool({
|
|
|
107
40
|
max: DB_MAX ? +DB_MAX : 10,
|
|
108
41
|
});
|
|
109
42
|
|
|
43
|
+
const LOGS_PREFIX = '[Antity-PGSQL] ';
|
|
44
|
+
|
|
110
45
|
function start(query, args) {
|
|
111
46
|
const a = JSON.stringify(args);
|
|
112
47
|
const q = query.replace(/[\n\r]+/g, "").replace(/\s{2,}/g, " ");
|
|
113
|
-
log.debug(
|
|
48
|
+
log.debug(`${LOGS_PREFIX}Pgsql: { Query : '${q}', Args : '${a}' }`);
|
|
114
49
|
return Date.now();
|
|
115
50
|
}
|
|
116
51
|
function end(res, time) {
|
|
@@ -169,6 +104,111 @@ function quoteIfUppercase(word) {
|
|
|
169
104
|
return word;
|
|
170
105
|
}
|
|
171
106
|
|
|
107
|
+
function index(index, matchMode) {
|
|
108
|
+
const i = index.map((i) => `$${i}`);
|
|
109
|
+
switch (matchMode) {
|
|
110
|
+
case "startsWith":
|
|
111
|
+
return `${i}%`;
|
|
112
|
+
case "endsWith":
|
|
113
|
+
return `%${i}`;
|
|
114
|
+
case "contains":
|
|
115
|
+
return `%${i}%`;
|
|
116
|
+
case "notContains":
|
|
117
|
+
return `%${i}%`;
|
|
118
|
+
case "in":
|
|
119
|
+
return `(${i})`;
|
|
120
|
+
default:
|
|
121
|
+
return `${i}`;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function comparator(matchMode) {
|
|
126
|
+
switch (matchMode) {
|
|
127
|
+
case "startsWith":
|
|
128
|
+
return "LIKE";
|
|
129
|
+
case "endsWith":
|
|
130
|
+
return "LIKE";
|
|
131
|
+
case "contains":
|
|
132
|
+
return "LIKE";
|
|
133
|
+
case "notContains":
|
|
134
|
+
return "NOT LIKE";
|
|
135
|
+
case "equals":
|
|
136
|
+
return "=";
|
|
137
|
+
case "notEquals":
|
|
138
|
+
return "<>";
|
|
139
|
+
case "in":
|
|
140
|
+
return "IN";
|
|
141
|
+
case "lt":
|
|
142
|
+
return "<";
|
|
143
|
+
case "lte":
|
|
144
|
+
return "<=";
|
|
145
|
+
case "gt":
|
|
146
|
+
return ">";
|
|
147
|
+
case "gte":
|
|
148
|
+
return ">=";
|
|
149
|
+
case "is":
|
|
150
|
+
return "IS";
|
|
151
|
+
case "isNot":
|
|
152
|
+
return "IS NOT";
|
|
153
|
+
case "before":
|
|
154
|
+
return "<";
|
|
155
|
+
case "after":
|
|
156
|
+
return ">";
|
|
157
|
+
default:
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function add(filters) {
|
|
163
|
+
const conditions = [];
|
|
164
|
+
const args = [];
|
|
165
|
+
if (filters) {
|
|
166
|
+
let i = 1;
|
|
167
|
+
for (const k in filters) {
|
|
168
|
+
const { value, matchMode } = filters[k];
|
|
169
|
+
const indexes = isArray(value) ? value.map(() => i++) : [i++];
|
|
170
|
+
const cond = addOne(k, indexes, matchMode);
|
|
171
|
+
if (cond) {
|
|
172
|
+
conditions.push(cond);
|
|
173
|
+
if (isArray(value))
|
|
174
|
+
args.push(...value);
|
|
175
|
+
else
|
|
176
|
+
args.push(value);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return { conditions, args };
|
|
181
|
+
}
|
|
182
|
+
function addOne(key, indexes, matchMode) {
|
|
183
|
+
const sqlKey = `${quoteIfUppercase(key)}`;
|
|
184
|
+
const comparator$1 = comparator(matchMode);
|
|
185
|
+
const index$1 = index(indexes, matchMode);
|
|
186
|
+
return comparator$1 ? `${sqlKey} ${comparator$1} ${index$1}` : "";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function filter(first, rows, sortField, sortOrder, filters) {
|
|
190
|
+
const { conditions, args } = add(filters);
|
|
191
|
+
const filterClause = where(conditions)
|
|
192
|
+
+ orderBy(sortField, sortOrder)
|
|
193
|
+
+ limit(rows, first);
|
|
194
|
+
return { filterClause, args };
|
|
195
|
+
}
|
|
196
|
+
function where(conditions, operator = "AND") {
|
|
197
|
+
if (!conditions.length)
|
|
198
|
+
return "";
|
|
199
|
+
const c = conditions.join(` ${operator} `).trim();
|
|
200
|
+
return ` WHERE ${c}`;
|
|
201
|
+
}
|
|
202
|
+
function orderBy(sortField, sortOrder) {
|
|
203
|
+
if (!sortField)
|
|
204
|
+
return "";
|
|
205
|
+
const o = sortOrder || "ASC";
|
|
206
|
+
return ` ORDER BY ${quoteIfUppercase(sortField)} ${o}`;
|
|
207
|
+
}
|
|
208
|
+
function limit(rows, first) {
|
|
209
|
+
return rows ? ` LIMIT ${rows} OFFSET ${first}` : "";
|
|
210
|
+
}
|
|
211
|
+
|
|
172
212
|
class Select {
|
|
173
213
|
constructor() {
|
|
174
214
|
this._props = [];
|
|
@@ -182,10 +222,15 @@ class Select {
|
|
|
182
222
|
get props() {
|
|
183
223
|
return this._cols;
|
|
184
224
|
}
|
|
185
|
-
query(table, paginate) {
|
|
225
|
+
query(table, paginate, first = 0, rows = null, sortField = null, sortOrder = null, filters = null) {
|
|
186
226
|
const p = paginate ? this._count : '';
|
|
187
227
|
const c = this._cols ? this._cols : '*';
|
|
188
|
-
|
|
228
|
+
const baseQuery = `SELECT ${c}${p} FROM ${quoteIfUppercase(table)}`;
|
|
229
|
+
const { filterClause, args } = filter(first, rows, sortField, sortOrder, filters);
|
|
230
|
+
return {
|
|
231
|
+
query: baseQuery + filterClause,
|
|
232
|
+
args: args
|
|
233
|
+
};
|
|
189
234
|
}
|
|
190
235
|
execute(query, args, client) {
|
|
191
236
|
return execute$1(query, args, client)
|
|
@@ -315,109 +360,165 @@ function execute(date, query, client) {
|
|
|
315
360
|
});
|
|
316
361
|
}
|
|
317
362
|
|
|
318
|
-
function
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
case "
|
|
324
|
-
return
|
|
325
|
-
case "
|
|
326
|
-
return
|
|
327
|
-
case "
|
|
328
|
-
return
|
|
329
|
-
case "
|
|
330
|
-
return
|
|
363
|
+
function type(type) {
|
|
364
|
+
const s = "string";
|
|
365
|
+
const n = "number";
|
|
366
|
+
const d = "date";
|
|
367
|
+
switch (type) {
|
|
368
|
+
case "integer":
|
|
369
|
+
return n;
|
|
370
|
+
case "float":
|
|
371
|
+
return n;
|
|
372
|
+
case "even":
|
|
373
|
+
return n;
|
|
374
|
+
case "odd":
|
|
375
|
+
return n;
|
|
376
|
+
case "positive":
|
|
377
|
+
return n;
|
|
378
|
+
case "negative":
|
|
379
|
+
return n;
|
|
380
|
+
case "powerOfTwo":
|
|
381
|
+
return n;
|
|
382
|
+
case "ascii":
|
|
383
|
+
return n;
|
|
384
|
+
case "jwt":
|
|
385
|
+
return s;
|
|
386
|
+
case "symbol":
|
|
387
|
+
return s;
|
|
388
|
+
case "password":
|
|
389
|
+
return s;
|
|
390
|
+
case "email":
|
|
391
|
+
return s;
|
|
392
|
+
case "regex":
|
|
393
|
+
return s;
|
|
394
|
+
case "ipAddress":
|
|
395
|
+
return s;
|
|
396
|
+
case "slug":
|
|
397
|
+
return s;
|
|
398
|
+
case "hexadecimal":
|
|
399
|
+
return s;
|
|
400
|
+
case "date":
|
|
401
|
+
return d;
|
|
402
|
+
case "timestamp":
|
|
403
|
+
return d;
|
|
404
|
+
case "function":
|
|
405
|
+
return s;
|
|
406
|
+
case "htmlElement":
|
|
407
|
+
return s;
|
|
408
|
+
case "htmlEventAttribute":
|
|
409
|
+
return s;
|
|
410
|
+
case "node":
|
|
411
|
+
return s;
|
|
412
|
+
case "json":
|
|
413
|
+
return s;
|
|
414
|
+
case "object":
|
|
415
|
+
return s;
|
|
331
416
|
default:
|
|
332
|
-
return
|
|
417
|
+
return s;
|
|
333
418
|
}
|
|
334
419
|
}
|
|
335
420
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
return "LIKE";
|
|
344
|
-
case "notContains":
|
|
345
|
-
return "NOT LIKE";
|
|
346
|
-
case "equals":
|
|
347
|
-
return "=";
|
|
348
|
-
case "notEquals":
|
|
349
|
-
return "<>";
|
|
350
|
-
case "in":
|
|
351
|
-
return "IN";
|
|
352
|
-
case "lt":
|
|
353
|
-
return "<";
|
|
354
|
-
case "lte":
|
|
355
|
-
return "<=";
|
|
356
|
-
case "gt":
|
|
357
|
-
return ">";
|
|
358
|
-
case "gte":
|
|
359
|
-
return ">=";
|
|
360
|
-
case "is":
|
|
361
|
-
return "IS";
|
|
362
|
-
case "isNot":
|
|
363
|
-
return "IS NOT";
|
|
364
|
-
case "before":
|
|
365
|
-
return "<";
|
|
366
|
-
case "after":
|
|
367
|
-
return ">";
|
|
368
|
-
default:
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
421
|
+
const matchModes = {
|
|
422
|
+
string: ["startsWith", "contains", "endsWith", "notContains", "equals", "notEquals", "lt", "lte", "gt", "gte"],
|
|
423
|
+
number: ["equals", "notEquals", "lt", "lte", "gt", "gte"],
|
|
424
|
+
date: ["is", "isNot", "dateAfter"],
|
|
425
|
+
};
|
|
426
|
+
function matchMode(type, matchMode) {
|
|
427
|
+
return isIn(matchModes[type], matchMode);
|
|
371
428
|
}
|
|
372
429
|
|
|
373
|
-
function
|
|
374
|
-
const
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
if (
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
430
|
+
function cleanFilters(filters, properties) {
|
|
431
|
+
for (const k in filters) {
|
|
432
|
+
if (filters.hasOwnProperty(k)) {
|
|
433
|
+
const prop = properties.find(p => p.key === k);
|
|
434
|
+
if (!prop) {
|
|
435
|
+
log.warn(`${LOGS_PREFIX}Filters: skipping unknown property: ${k}`);
|
|
436
|
+
delete filters[k];
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
if (!prop.filter) {
|
|
440
|
+
log.warn(`${LOGS_PREFIX}Filters: skipping unfilterable property: ${k}`);
|
|
441
|
+
delete filters[k];
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
const type$1 = type(prop.type);
|
|
445
|
+
const { matchMode: matchMode$1 } = filters[k];
|
|
446
|
+
if (!matchMode$1 || !matchMode(type$1, matchMode$1)) {
|
|
447
|
+
log.warn(`${LOGS_PREFIX}Filters: skipping invalid match mode: "${matchMode$1}" for type: "${type$1}" at property: "${k}"`);
|
|
448
|
+
delete filters[k];
|
|
449
|
+
continue;
|
|
388
450
|
}
|
|
389
451
|
}
|
|
390
452
|
}
|
|
391
|
-
return
|
|
392
|
-
}
|
|
393
|
-
function addOne(key, indexes, matchMode) {
|
|
394
|
-
const sqlKey = `${quoteIfUppercase(key)}`;
|
|
395
|
-
const comparator$1 = comparator(matchMode);
|
|
396
|
-
const index$1 = index(indexes, matchMode);
|
|
397
|
-
return comparator$1 ? `${sqlKey} ${comparator$1} ${index$1}` : "";
|
|
453
|
+
return filters;
|
|
398
454
|
}
|
|
399
455
|
|
|
400
|
-
function
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
+ limit(rows, first);
|
|
405
|
-
return { filterClause, args };
|
|
456
|
+
function logSummary(name, table, properties) {
|
|
457
|
+
const summary = generateSummary(name, table, properties);
|
|
458
|
+
log.info(`${LOGS_PREFIX}Entity "${name}" created successfully`);
|
|
459
|
+
log.info(`${LOGS_PREFIX}Entity Summary:\n${summary}`);
|
|
406
460
|
}
|
|
407
|
-
function
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
461
|
+
function generateSummary(name, table, properties) {
|
|
462
|
+
const lines = [];
|
|
463
|
+
const propLen = properties.length;
|
|
464
|
+
lines.push(`┌─ SQLEntity: "${name}" (Table: ${table})`);
|
|
465
|
+
lines.push(`├─ Total Properties: ${propLen}`);
|
|
466
|
+
const operationStats = getOperationStatistics(properties);
|
|
467
|
+
lines.push(`├─ Operation Distribution:`);
|
|
468
|
+
Object.entries(operationStats).forEach(([op, count]) => {
|
|
469
|
+
lines.push(`│ └─ ${op}: ${count} properties`);
|
|
470
|
+
});
|
|
471
|
+
lines.push(`├─ Property Details:`);
|
|
472
|
+
properties.forEach((p, index) => {
|
|
473
|
+
const isLast = index === propLen - 1;
|
|
474
|
+
const prefix = isLast ? '└─' : '├─';
|
|
475
|
+
lines.push(`│ ${prefix} ${p.key}:`);
|
|
476
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Type: ${p.type}`);
|
|
477
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Min: ${p.min}`);
|
|
478
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Max: ${p.max}`);
|
|
479
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Required: ${p.required}`);
|
|
480
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Safe: ${p.safe}`);
|
|
481
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ TypeCheck: ${p.typeCheck}`);
|
|
482
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Filter: ${p.filter}`);
|
|
483
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Methods: [${p.methods.join(', ')}]`);
|
|
484
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Operations: [${p.operations.join(', ')}]`);
|
|
485
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Sanitize: ${p.sanitize}`);
|
|
486
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Normalize: ${p.normalize}`);
|
|
487
|
+
lines.push(`│ ${isLast ? ' ' : '│'} ├─ Validate: ${p.validate}`);
|
|
488
|
+
});
|
|
489
|
+
const crudMappings = getCrudMappings(properties);
|
|
490
|
+
lines.push(`├─ CRUD Mappings:`);
|
|
491
|
+
Object.entries(crudMappings).forEach(([operation, props]) => {
|
|
492
|
+
lines.push(`│ ├─ ${operation}: [${props.join(', ')}]`);
|
|
493
|
+
});
|
|
494
|
+
lines.push(`└─ Entity initialization completed`);
|
|
495
|
+
return lines.join('\n');
|
|
412
496
|
}
|
|
413
|
-
function
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
497
|
+
function getOperationStatistics(properties) {
|
|
498
|
+
const stats = {};
|
|
499
|
+
properties.forEach(prop => {
|
|
500
|
+
prop.operations.forEach(op => {
|
|
501
|
+
stats[op] = (stats[op] || 0) + 1;
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
return stats;
|
|
418
505
|
}
|
|
419
|
-
function
|
|
420
|
-
|
|
506
|
+
function getCrudMappings(properties) {
|
|
507
|
+
const mappings = {
|
|
508
|
+
'SELECT': [],
|
|
509
|
+
'INSERT': [],
|
|
510
|
+
'UPDATE': [],
|
|
511
|
+
'DELETE': []
|
|
512
|
+
};
|
|
513
|
+
properties.forEach(prop => {
|
|
514
|
+
const p = prop;
|
|
515
|
+
prop.operations.forEach(op => {
|
|
516
|
+
if (mappings[op]) {
|
|
517
|
+
mappings[op].push(p.key);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
return mappings;
|
|
421
522
|
}
|
|
422
523
|
|
|
423
524
|
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
@@ -436,8 +537,8 @@ class SQLEntity extends Entity {
|
|
|
436
537
|
this.ins = new Insert();
|
|
437
538
|
this.upd = new Update();
|
|
438
539
|
this.query = {
|
|
439
|
-
select: (paginate) => {
|
|
440
|
-
return this.sel.query(this.table, paginate);
|
|
540
|
+
select: (paginate, first = 0, rows = null, sortField = null, sortOrder = null, filters = null) => {
|
|
541
|
+
return this.sel.query(this.table, paginate, first, rows, sortField, sortOrder, filters);
|
|
441
542
|
},
|
|
442
543
|
update: (rows, consumerId, consumerName) => {
|
|
443
544
|
return this.upd.query(this.table, rows, consumerId, consumerName);
|
|
@@ -460,14 +561,13 @@ class SQLEntity extends Entity {
|
|
|
460
561
|
const rows = b.rows || null;
|
|
461
562
|
const sortField = b.sortField || null;
|
|
462
563
|
const sortOrder = b.sortOrder === -1 || b.sortOrder === "DESC" ? "DESC" : "ASC";
|
|
463
|
-
const filters =
|
|
564
|
+
const filters = cleanFilters(b.filters, this.properties || []) || null;
|
|
464
565
|
const pagination = b.pagination || false;
|
|
465
566
|
const dbClient = l.dbClient || null;
|
|
466
567
|
log.debug(`get(first='${first}', rows='${rows}',
|
|
467
568
|
sortOrder='${sortOrder}', sortField='${sortField}',
|
|
468
569
|
pagination=${pagination}, filters=${JSON.stringify(filters)}`);
|
|
469
|
-
const {
|
|
470
|
-
const q = this.sel.query(this._table, pagination) + filterClause;
|
|
570
|
+
const { query: q, args } = this.sel.query(this._table, pagination, first, rows, sortField, sortOrder, filters);
|
|
471
571
|
this.sel.execute(q, args, dbClient)
|
|
472
572
|
.then((r) => {
|
|
473
573
|
l.rows = r.rows;
|
|
@@ -482,7 +582,7 @@ class SQLEntity extends Entity {
|
|
|
482
582
|
const dbClient = l.dbClient || null;
|
|
483
583
|
const cId = l.consumerId;
|
|
484
584
|
const cName = l.consumerName;
|
|
485
|
-
log.debug(
|
|
585
|
+
log.debug(`${LOGS_PREFIX}addMany(rows=${rows.length}, consumerId=${cId})`);
|
|
486
586
|
const rtn = this.ins.rtn("id");
|
|
487
587
|
const chunks = chunk(rows);
|
|
488
588
|
for (const c of chunks) {
|
|
@@ -508,7 +608,7 @@ class SQLEntity extends Entity {
|
|
|
508
608
|
const dbClient = l.dbClient || null;
|
|
509
609
|
const cId = l.consumerId;
|
|
510
610
|
const cName = l.consumerName;
|
|
511
|
-
log.debug(
|
|
611
|
+
log.debug(`${LOGS_PREFIX}update(rows=${rows.length}, consumerId=${cId})`);
|
|
512
612
|
const chunks = chunk(rows);
|
|
513
613
|
for (const c of chunks) {
|
|
514
614
|
const { query, args } = this.upd.query(this._table, c, cId, cName);
|
|
@@ -527,7 +627,7 @@ class SQLEntity extends Entity {
|
|
|
527
627
|
const dbClient = l.dbClient || null;
|
|
528
628
|
const cId = l.consumerId;
|
|
529
629
|
const cName = l.consumerName;
|
|
530
|
-
log.debug(
|
|
630
|
+
log.debug(`${LOGS_PREFIX}archive(rows=${rows.length}, consumerId=${cId})`);
|
|
531
631
|
rows = rows.map((id) => (Object.assign(Object.assign({}, id), { archived: true })));
|
|
532
632
|
const chunks = chunk(rows);
|
|
533
633
|
for (const c of chunks) {
|
|
@@ -544,58 +644,37 @@ class SQLEntity extends Entity {
|
|
|
544
644
|
this.delete = (req, res, next) => {
|
|
545
645
|
const date = req.body.date;
|
|
546
646
|
const dbClient = res.locals.dbClient || null;
|
|
547
|
-
log.debug(
|
|
647
|
+
log.debug(`${LOGS_PREFIX}delete archived`);
|
|
548
648
|
const q = query(this._table);
|
|
549
649
|
execute(date, q, dbClient)
|
|
550
650
|
.then(() => next())
|
|
551
651
|
.catch((err) => next(err));
|
|
552
652
|
};
|
|
553
653
|
this._table = name;
|
|
654
|
+
log.info(`${LOGS_PREFIX}Creating SQLEntity: "${name}"`);
|
|
554
655
|
for (const p of properties) {
|
|
555
|
-
this.mapProps(p.
|
|
656
|
+
this.mapProps(p.operations, p.key);
|
|
556
657
|
}
|
|
658
|
+
logSummary(name, this._table, properties);
|
|
557
659
|
}
|
|
558
660
|
get table() {
|
|
559
661
|
return this._table;
|
|
560
662
|
}
|
|
561
663
|
set table(table) {
|
|
562
664
|
if (!isString(table, "!0"))
|
|
563
|
-
throw new Error(
|
|
665
|
+
throw new Error(`${LOGS_PREFIX}table must be a string of length > 0`);
|
|
564
666
|
this._table = table;
|
|
565
667
|
}
|
|
566
|
-
|
|
567
|
-
for (const
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
if (!prop) {
|
|
571
|
-
log.warn(`Filters: skipping unknown property: ${k}`);
|
|
572
|
-
delete filters[k];
|
|
573
|
-
continue;
|
|
574
|
-
}
|
|
575
|
-
const type$1 = type(prop.type);
|
|
576
|
-
const { matchMode: matchMode$1 } = filters[k];
|
|
577
|
-
if (!matchMode$1 || !matchMode(type$1, matchMode$1)) {
|
|
578
|
-
log.warn(`Filters: skipping invalid match mode: "${matchMode$1}" for type: "${type$1}" at property: "${k}"`);
|
|
579
|
-
delete filters[k];
|
|
580
|
-
continue;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
return filters;
|
|
585
|
-
}
|
|
586
|
-
mapProps(methods, key) {
|
|
587
|
-
for (const m of methods) {
|
|
588
|
-
switch (m) {
|
|
589
|
-
case "GET":
|
|
668
|
+
mapProps(operations, key) {
|
|
669
|
+
for (const o of operations) {
|
|
670
|
+
switch (o) {
|
|
671
|
+
case "SELECT":
|
|
590
672
|
this.sel.addProp(key);
|
|
591
673
|
break;
|
|
592
|
-
case "
|
|
593
|
-
this.upd.addProp(key);
|
|
594
|
-
break;
|
|
595
|
-
case "PUT":
|
|
674
|
+
case "UPDATE":
|
|
596
675
|
this.upd.addProp(key);
|
|
597
676
|
break;
|
|
598
|
-
case "
|
|
677
|
+
case "INSERT":
|
|
599
678
|
this.ins.addProp(key);
|
|
600
679
|
break;
|
|
601
680
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dwtechs/antity-pgsql",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Open source library
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Open source library to add PostgreSQL support to @dwtechs/Antity entities.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"entities"
|
|
7
7
|
],
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"dist/"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@dwtechs/checkard": "3.
|
|
40
|
-
"@dwtechs/winstan": "0.
|
|
41
|
-
"@dwtechs/antity": "0.
|
|
42
|
-
"@dwtechs/sparray": "0.2.
|
|
39
|
+
"@dwtechs/checkard": "3.6.0",
|
|
40
|
+
"@dwtechs/winstan": "0.5.0",
|
|
41
|
+
"@dwtechs/antity": "0.13.0",
|
|
42
|
+
"@dwtechs/sparray": "0.2.1",
|
|
43
43
|
"pg": "8.13.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|