@dwtechs/antity-pgsql 0.15.1 → 0.16.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 +45 -37
- package/dist/antity-pgsql.d.ts +21 -15
- package/dist/antity-pgsql.js +63 -58
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -22,24 +22,14 @@
|
|
|
22
22
|
- 🚚 Shipped as EcmaScrypt module
|
|
23
23
|
- 📝 Written in Typescript
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
## Support
|
|
27
|
-
|
|
28
|
-
- node: 22
|
|
29
|
-
|
|
30
|
-
This is the oldest targeted versions. The library should work properly on older versions of Node.js but we do not support it officially.
|
|
31
|
-
|
|
32
|
-
|
|
33
25
|
## Installation
|
|
34
26
|
|
|
35
27
|
```bash
|
|
36
28
|
$ npm i @dwtechs/antity-pgsql
|
|
37
29
|
```
|
|
38
30
|
|
|
39
|
-
|
|
40
31
|
## Usage
|
|
41
32
|
|
|
42
|
-
|
|
43
33
|
```javascript
|
|
44
34
|
|
|
45
35
|
import { SQLEntity } from "@dwtechs/antity-pgsql";
|
|
@@ -140,6 +130,8 @@ router.get("/:id/history", ..., entity.getHistory);
|
|
|
140
130
|
|
|
141
131
|
type Operation = "SELECT" | "INSERT" | "UPDATE";
|
|
142
132
|
|
|
133
|
+
type Row = Record<string, string | number | boolean | Date | number[]>;
|
|
134
|
+
|
|
143
135
|
type MatchMode =
|
|
144
136
|
"startsWith" |
|
|
145
137
|
"endsWith" |
|
|
@@ -149,6 +141,7 @@ type MatchMode =
|
|
|
149
141
|
"notEquals" |
|
|
150
142
|
"between" |
|
|
151
143
|
"in" |
|
|
144
|
+
"notIn" |
|
|
152
145
|
"lt" |
|
|
153
146
|
"lte" |
|
|
154
147
|
"gt" |
|
|
@@ -171,6 +164,21 @@ type Filter = {
|
|
|
171
164
|
operator?: string; // 'and' | 'or' - Used when multiple filters apply to the same property
|
|
172
165
|
}
|
|
173
166
|
|
|
167
|
+
type PGClient = {
|
|
168
|
+
query(text: string, values?: unknown[]): Promise<PGResponse>;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
type PGResponse = {
|
|
172
|
+
rows: Record<string, unknown>[];
|
|
173
|
+
rowCount: number | null;
|
|
174
|
+
total?: number;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
type SelectResponse = {
|
|
178
|
+
rows: Record<string, unknown>[];
|
|
179
|
+
total?: number;
|
|
180
|
+
};
|
|
181
|
+
|
|
174
182
|
type ExpressMiddleware = (req: Request, res: Response, next: NextFunction) => void;
|
|
175
183
|
type ExpressMiddlewareAsync = (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
176
184
|
type SubstackTuple = [ExpressMiddleware, ExpressMiddleware, ExpressMiddlewareAsync];
|
|
@@ -206,32 +214,28 @@ class SQLEntity {
|
|
|
206
214
|
args: (Filter["value"])[];
|
|
207
215
|
};
|
|
208
216
|
update: (
|
|
209
|
-
rows:
|
|
210
|
-
|
|
211
|
-
consumerName?: string) => {
|
|
217
|
+
rows: Row[],
|
|
218
|
+
consumer?: { id?: number | string, nickname?: string }) => {
|
|
212
219
|
query: string;
|
|
213
220
|
args: unknown[];
|
|
214
221
|
};
|
|
215
222
|
archive: (
|
|
216
|
-
rows:
|
|
217
|
-
|
|
218
|
-
consumerName?: string) => {
|
|
223
|
+
rows: Row[],
|
|
224
|
+
consumer?: { id?: number | string, nickname?: string }) => {
|
|
219
225
|
query: string;
|
|
220
226
|
args: unknown[];
|
|
221
227
|
};
|
|
222
228
|
insert: (
|
|
223
|
-
rows:
|
|
224
|
-
|
|
225
|
-
consumerName?: string,
|
|
229
|
+
rows: Row[],
|
|
230
|
+
consumer?: { id?: number | string, nickname?: string },
|
|
226
231
|
rtn?: string) => {
|
|
227
232
|
query: string;
|
|
228
233
|
args: unknown[];
|
|
229
234
|
};
|
|
230
235
|
upsert: (
|
|
231
|
-
rows:
|
|
236
|
+
rows: Row[],
|
|
232
237
|
conflictTarget: string | string[],
|
|
233
|
-
|
|
234
|
-
consumerName?: string,
|
|
238
|
+
consumer?: { id?: number | string, nickname?: string },
|
|
235
239
|
rtn?: string) => {
|
|
236
240
|
query: string;
|
|
237
241
|
args: unknown[];
|
|
@@ -266,7 +270,7 @@ function filter(
|
|
|
266
270
|
function execute(
|
|
267
271
|
query: string,
|
|
268
272
|
args: (string | number | boolean | Date | number[])[],
|
|
269
|
-
client:
|
|
273
|
+
client: PGClient | null,
|
|
270
274
|
): Promise<PGResponse>;
|
|
271
275
|
|
|
272
276
|
|
|
@@ -307,10 +311,10 @@ Using substacks simplifies your route definitions and ensures consistent data pr
|
|
|
307
311
|
### Query Methods
|
|
308
312
|
|
|
309
313
|
- **query.select()**: Generates a SELECT query. When the `rows` parameter is provided (not null), pagination is automatically enabled and the query includes `COUNT(*) OVER () AS total` to return the total number of rows. The total count is extracted from results and returned separately from the row data.
|
|
310
|
-
- **query.insert()**: Generates an INSERT query. Accepts an array of objects with properties matching the entity definition. Optionally appends `
|
|
311
|
-
- **query.update()**: Generates an UPDATE query using CASE statements. Accepts an array of objects with `id` property. Optionally appends `
|
|
312
|
-
- **query.upsert()**: Generates an INSERT ... ON CONFLICT ... DO UPDATE query. (See [Upsert](#upsert-insert-or-update) section below.) Accepts an array of objects and a `conflictTarget` (single column name or array of column names) that defines uniqueness. If a conflict occurs on the specified column(s), the row is updated; otherwise, it is inserted. Properties are automatically included if they have both INSERT and UPDATE operations. Optionally appends `
|
|
313
|
-
- **query.archive()**: Generates a simplified `UPDATE ... SET archived = true WHERE id IN (...)` query. Accepts an array of objects with `id` property. Optionally appends `
|
|
314
|
+
- **query.insert()**: Generates an INSERT query. Accepts an array of `Row` objects with properties matching the entity definition. Consumer fields are appended directly to the query arguments — row objects are **not mutated**. Optionally appends `consumer.id` and `consumer.nickname` for history tracking. Supports `RETURNING` clause via the `rtn` parameter.
|
|
315
|
+
- **query.update()**: Generates an UPDATE query using CASE statements. Accepts an array of `Row` objects with `id` property. Optionally appends `consumer.id` and `consumer.nickname` for history tracking.
|
|
316
|
+
- **query.upsert()**: Generates an INSERT ... ON CONFLICT ... DO UPDATE query. (See [Upsert](#upsert-insert-or-update) section below.) Accepts an array of `Row` objects and a `conflictTarget` (single column name or array of column names) that defines uniqueness. If a conflict occurs on the specified column(s), the row is updated; otherwise, it is inserted. Properties are automatically included if they have both INSERT and UPDATE operations. Consumer fields are appended directly to the query arguments — row objects are **not mutated**. Optionally appends `consumer.id` and `consumer.nickname` for history tracking. Supports `RETURNING` clause via the `rtn` parameter.
|
|
317
|
+
- **query.archive()**: Generates a simplified `UPDATE ... SET archived = true WHERE id IN (...)` query. Accepts an array of `Row` objects with `id` property. Optionally appends `consumer.id` and `consumer.nickname` for history tracking. Does not require an `archived` field in the rows — it is set directly in the SQL.
|
|
314
318
|
- **sync()**: Atomically synchronises the table with the provided rows inside a single PostgreSQL transaction. Missing rows are inserted, existing rows are updated, and rows absent from the list are deleted. Accepts optional `idField` (default `'id'`) and `filters` to restrict the scope of managed rows. Stores the result in `res.locals.rows` and a summary `{ inserted, updated, deleted }` in `res.locals.sync`.
|
|
315
319
|
- **delete()**: Deletes rows by their IDs. Expects `req.body.rows` to be an array of objects with `id` property: `[{id: 1}, {id: 2}]`
|
|
316
320
|
- **deleteArchive()**: Deletes archived rows that were archived before a specific date using a PostgreSQL SECURITY DEFINER function. Expects `req.body.date` to be a Date object.
|
|
@@ -372,7 +376,7 @@ res.locals.sync // { inserted: 1, updated: 1, deleted: 1 }
|
|
|
372
376
|
- **Atomic**: All insert / update / delete operations are wrapped in a single transaction.
|
|
373
377
|
- **Filter scope**: When `filters` are provided, only rows matching the filter are considered "managed". Rows outside the filter are never touched.
|
|
374
378
|
- **Property selection**: Insert uses `INSERT` properties; update uses `UPDATE` properties — same as the standalone `add` and `update` middlewares.
|
|
375
|
-
- **Consumer tracking**: `
|
|
379
|
+
- **Consumer tracking**: `consumer.id` and `consumer.nickname` from `res.locals.consumer` are forwarded to inserts and updates for history tracking.
|
|
376
380
|
|
|
377
381
|
### Upsert (Insert or Update)
|
|
378
382
|
|
|
@@ -432,8 +436,7 @@ router.post('/users/upsert', ...entity.upsertArraySubstack);
|
|
|
432
436
|
const { query, args } = entity.query.upsert(
|
|
433
437
|
[{ id: 1, name: 'John', email: 'john@example.com' }],
|
|
434
438
|
'id',
|
|
435
|
-
1, //
|
|
436
|
-
'admin', // consumerName (optional)
|
|
439
|
+
{ id: 1, nickname: 'admin' }, // consumer (optional)
|
|
437
440
|
'RETURNING id' // return clause (optional)
|
|
438
441
|
);
|
|
439
442
|
// Generates:
|
|
@@ -538,7 +541,8 @@ List of possible match modes :
|
|
|
538
541
|
| notContains | | string | Whether the value does not contain filter value |
|
|
539
542
|
| equals | | string \| number | Whether the value equals the filter value |
|
|
540
543
|
| notEquals | | string \| number | Whether the value does not equal the filter value |
|
|
541
|
-
| in | | string[] \| number[] | Whether the value
|
|
544
|
+
| in | | string[] \| number[] | Whether the value is included in the list |
|
|
545
|
+
| notIn | | string[] \| number[] | Whether the value is not included in the list |
|
|
542
546
|
| lt | | string \| number | Whether the value is less than the filter value |
|
|
543
547
|
| lte | | string \| number | Whether the value is less than or equals to the filter value |
|
|
544
548
|
| gt | | string \| number | Whether the value is greater than the filter value |
|
|
@@ -557,8 +561,8 @@ List of compatible match modes for each property types
|
|
|
557
561
|
|
|
558
562
|
| Name | Match modes |
|
|
559
563
|
| :---------- | :---------------------- |
|
|
560
|
-
| string | startsWith,<br>contains,<br>endsWith,<br>notContains,<br>equals,<br>notEquals,<br>lt,<br>lte,<br>gt,<br>gte |
|
|
561
|
-
| number | equals,<br>notEquals,<br>lt,<br>lte,<br>gt,<br>gte |
|
|
564
|
+
| string | startsWith,<br>contains,<br>endsWith,<br>notContains,<br>equals,<br>notEquals,<br>in,<br>notIn,<br>lt,<br>lte,<br>gt,<br>gte |
|
|
565
|
+
| number | equals,<br>notEquals,<br>in,<br>notIn,<br>lt,<br>lte,<br>gt,<br>gte |
|
|
562
566
|
| date | is,<br>isNot,<br>before,<br>after |
|
|
563
567
|
| boolean | is,<br>isNot |
|
|
564
568
|
| string[] | in |
|
|
@@ -612,21 +616,25 @@ Any of these can be passed into the options object for each function.
|
|
|
612
616
|
| isTypeChecked | boolean | Type is checked during validation | false
|
|
613
617
|
| isFilterable | boolean | property is filterable in a SELECT operation | true
|
|
614
618
|
| operations | Operation[] | Property is used for the DML operations only | ["SELECT", "INSERT", "UPDATE"]
|
|
615
|
-
| sanitizer | ((v:
|
|
616
|
-
| normalizer | ((v:
|
|
617
|
-
| validator | ((v:
|
|
619
|
+
| sanitizer | ((v: unknown) => unknown) \| null | Custom sanitizer function if sanitize is true | null
|
|
620
|
+
| normalizer | ((v: unknown) => unknown) \| null | Custom Normalizer function if normalize is true | null
|
|
621
|
+
| validator | ((v: unknown) => unknown) \| null | validator function if validate is true | null
|
|
618
622
|
|
|
619
623
|
|
|
620
624
|
* *Min and max parameters are not used for boolean type*
|
|
621
625
|
* *TypeCheck Parameter is not used for boolean, string and array types*
|
|
622
626
|
|
|
627
|
+
## Support
|
|
628
|
+
|
|
629
|
+
| Environment | Version |
|
|
630
|
+
| :---------- | :-----: |
|
|
631
|
+
| Node.js | >= 22 |
|
|
623
632
|
|
|
624
633
|
## Contributors
|
|
625
634
|
|
|
626
635
|
Antity.js is still in development and we would be glad to get all the help you can provide.
|
|
627
636
|
To contribute please read **[contributor.md](https://github.com/DWTechs/Antity.js/blob/main/contributor.md)** for detailed installation guide.
|
|
628
637
|
|
|
629
|
-
|
|
630
638
|
## Stack
|
|
631
639
|
|
|
632
640
|
| Purpose | Choice | Motivation |
|
package/dist/antity-pgsql.d.ts
CHANGED
|
@@ -27,7 +27,6 @@ https://github.com/DWTechs/Antity-pgsql.js
|
|
|
27
27
|
import { Entity, Property as BaseProperty } from "@dwtechs/antity";
|
|
28
28
|
import type { Type, Method } from "@dwtechs/antity";
|
|
29
29
|
import type { Request, Response, NextFunction } from 'express';
|
|
30
|
-
import type { Pool, PoolClient } from 'pg';
|
|
31
30
|
|
|
32
31
|
export type Operation = "SELECT" | "INSERT" | "UPDATE";
|
|
33
32
|
export type Sort = "ASC" | "DESC";
|
|
@@ -75,9 +74,20 @@ export type Geometry = {
|
|
|
75
74
|
maxLat: number;
|
|
76
75
|
};
|
|
77
76
|
};
|
|
77
|
+
export type Row = Record<string, Filter["value"]>;
|
|
78
|
+
|
|
79
|
+
export type PGClient = {
|
|
80
|
+
query(text: string, values?: unknown[]): Promise<PGResponse>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type SelectResponse = {
|
|
84
|
+
rows: Record<string, unknown>[];
|
|
85
|
+
total?: number;
|
|
86
|
+
};
|
|
87
|
+
|
|
78
88
|
export type PGResponse = {
|
|
79
89
|
rows: Record<string, unknown>[];
|
|
80
|
-
rowCount: number;
|
|
90
|
+
rowCount: number | null;
|
|
81
91
|
total?: number;
|
|
82
92
|
command?: string;
|
|
83
93
|
oid?: number;
|
|
@@ -132,27 +142,24 @@ export declare class SQLEntity extends Entity {
|
|
|
132
142
|
};
|
|
133
143
|
|
|
134
144
|
update: (
|
|
135
|
-
rows:
|
|
136
|
-
|
|
137
|
-
consumerName?: string
|
|
145
|
+
rows: Row[],
|
|
146
|
+
consumer?: { id?: number | string, nickname?: string }
|
|
138
147
|
) => {
|
|
139
148
|
query: string;
|
|
140
149
|
args: unknown[];
|
|
141
150
|
};
|
|
142
151
|
|
|
143
152
|
archive: (
|
|
144
|
-
rows:
|
|
145
|
-
|
|
146
|
-
consumerName?: string
|
|
153
|
+
rows: Row[],
|
|
154
|
+
consumer?: { id?: number | string, nickname?: string }
|
|
147
155
|
) => {
|
|
148
156
|
query: string;
|
|
149
157
|
args: unknown[];
|
|
150
158
|
};
|
|
151
159
|
|
|
152
160
|
insert: (
|
|
153
|
-
rows:
|
|
154
|
-
|
|
155
|
-
consumerName?: string,
|
|
161
|
+
rows: Row[],
|
|
162
|
+
consumer?: { id?: number | string, nickname?: string },
|
|
156
163
|
rtn?: string
|
|
157
164
|
) => {
|
|
158
165
|
query: string;
|
|
@@ -160,10 +167,9 @@ export declare class SQLEntity extends Entity {
|
|
|
160
167
|
};
|
|
161
168
|
|
|
162
169
|
upsert: (
|
|
163
|
-
rows:
|
|
170
|
+
rows: Row[],
|
|
164
171
|
conflictTarget: string | string[],
|
|
165
|
-
|
|
166
|
-
consumerName?: string,
|
|
172
|
+
consumer?: { id?: number | string, nickname?: string },
|
|
167
173
|
rtn?: string
|
|
168
174
|
) => {
|
|
169
175
|
query: string;
|
|
@@ -202,6 +208,6 @@ export declare function filter(
|
|
|
202
208
|
export declare function execute(
|
|
203
209
|
query: string,
|
|
204
210
|
args: (string | number | boolean | Date | number[])[],
|
|
205
|
-
client:
|
|
211
|
+
client: PGClient | null
|
|
206
212
|
): Promise<PGResponse>;
|
|
207
213
|
|
package/dist/antity-pgsql.js
CHANGED
|
@@ -43,15 +43,15 @@ var pool = new Pool({
|
|
|
43
43
|
const LOGS_PREFIX = '[Antity-PGSQL] ';
|
|
44
44
|
|
|
45
45
|
function start(query, args) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
log.debug(() => {
|
|
47
|
+
const a = JSON.stringify(args);
|
|
48
|
+
const q = query.replace(/[\n\r]+/g, "").replace(/\s{2,}/g, " ");
|
|
49
|
+
return `${LOGS_PREFIX}Pgsql: { Query : '${q}', Args : '${a}' }`;
|
|
50
|
+
});
|
|
49
51
|
return Date.now();
|
|
50
52
|
}
|
|
51
53
|
function end(res, time) {
|
|
52
|
-
|
|
53
|
-
const t = Date.now() - time;
|
|
54
|
-
log.debug(`Pgsql response in ${t}ms : ${r}`);
|
|
54
|
+
log.debug(() => `Pgsql response in ${Date.now() - time}ms : ${JSON.stringify(res)}`);
|
|
55
55
|
}
|
|
56
56
|
var perf = {
|
|
57
57
|
start,
|
|
@@ -108,6 +108,7 @@ function index(index, matchMode) {
|
|
|
108
108
|
const i = index.map((i) => `$${i}`);
|
|
109
109
|
switch (matchMode) {
|
|
110
110
|
case "in":
|
|
111
|
+
case "notIn":
|
|
111
112
|
return `(${i})`;
|
|
112
113
|
default:
|
|
113
114
|
return `${i}`;
|
|
@@ -130,6 +131,8 @@ function comparator(matchMode) {
|
|
|
130
131
|
return "<>";
|
|
131
132
|
case "in":
|
|
132
133
|
return "IN";
|
|
134
|
+
case "notIn":
|
|
135
|
+
return "NOT IN";
|
|
133
136
|
case "lt":
|
|
134
137
|
return "<";
|
|
135
138
|
case "lte":
|
|
@@ -308,13 +311,14 @@ class Insert {
|
|
|
308
311
|
const args = [];
|
|
309
312
|
let i = 0;
|
|
310
313
|
for (const row of rows) {
|
|
311
|
-
if (consumerId !== undefined && consumerName !== undefined) {
|
|
312
|
-
row.consumerId = consumerId;
|
|
313
|
-
row.consumerName = consumerName;
|
|
314
|
-
}
|
|
315
314
|
query += `${$i(nbProps, i)}, `;
|
|
316
315
|
for (const prop of propsToUse) {
|
|
317
|
-
|
|
316
|
+
if (prop === "consumerId")
|
|
317
|
+
args.push(consumerId);
|
|
318
|
+
else if (prop === "consumerName")
|
|
319
|
+
args.push(consumerName);
|
|
320
|
+
else
|
|
321
|
+
args.push(row[prop]);
|
|
318
322
|
}
|
|
319
323
|
i += nbProps;
|
|
320
324
|
}
|
|
@@ -353,7 +357,7 @@ class Update {
|
|
|
353
357
|
const propsToUse = [...this._props];
|
|
354
358
|
if (consumerId !== undefined && consumerName !== undefined)
|
|
355
359
|
propsToUse.push("consumerId", "consumerName");
|
|
356
|
-
log.debug(`${LOGS_PREFIX}Update query input rows: ${JSON.stringify(rows, null, 2)}`);
|
|
360
|
+
log.debug(() => `${LOGS_PREFIX}Update query input rows: ${JSON.stringify(rows, null, 2)}`);
|
|
357
361
|
const l = rows.length;
|
|
358
362
|
const args = rows.map(row => row.id);
|
|
359
363
|
let query = `UPDATE ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} SET `;
|
|
@@ -419,14 +423,13 @@ class Upsert {
|
|
|
419
423
|
const args = [];
|
|
420
424
|
let i = 0;
|
|
421
425
|
for (const row of rows) {
|
|
422
|
-
if (consumerId !== undefined && consumerName !== undefined) {
|
|
423
|
-
row.consumerId = consumerId;
|
|
424
|
-
row.consumerName = consumerName;
|
|
425
|
-
}
|
|
426
426
|
query += `${$i(nbProps, i)}, `;
|
|
427
|
-
for (const prop of
|
|
427
|
+
for (const prop of this._props) {
|
|
428
428
|
args.push(row[prop]);
|
|
429
429
|
}
|
|
430
|
+
if (consumerId !== undefined && consumerName !== undefined) {
|
|
431
|
+
args.push(consumerId, consumerName);
|
|
432
|
+
}
|
|
430
433
|
i += nbProps;
|
|
431
434
|
}
|
|
432
435
|
query = query.slice(0, -2);
|
|
@@ -463,7 +466,7 @@ var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
|
|
463
466
|
};
|
|
464
467
|
class Archive {
|
|
465
468
|
query(schema, table, rows, consumerId, consumerName) {
|
|
466
|
-
log.debug(`${LOGS_PREFIX}Archive query input rows: ${JSON.stringify(rows, null, 2)}`);
|
|
469
|
+
log.debug(() => `${LOGS_PREFIX}Archive query input rows: ${JSON.stringify(rows, null, 2)}`);
|
|
467
470
|
const l = rows.length;
|
|
468
471
|
const args = rows.map(row => row.id);
|
|
469
472
|
let query = `UPDATE ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} SET archived = true`;
|
|
@@ -571,8 +574,8 @@ function type(type) {
|
|
|
571
574
|
}
|
|
572
575
|
|
|
573
576
|
const matchModes = {
|
|
574
|
-
string: ["startsWith", "contains", "endsWith", "notContains", "equals", "notEquals", "lt", "lte", "gt", "gte"],
|
|
575
|
-
number: ["equals", "notEquals", "lt", "lte", "gt", "gte"],
|
|
577
|
+
string: ["startsWith", "contains", "endsWith", "notContains", "equals", "notEquals", "lt", "lte", "gt", "gte", "in", "notIn"],
|
|
578
|
+
number: ["equals", "notEquals", "lt", "lte", "gt", "gte", "in", "notIn"],
|
|
576
579
|
date: ["is", "isNot", "dateAfter"],
|
|
577
580
|
};
|
|
578
581
|
function matchMode(type, matchMode) {
|
|
@@ -584,12 +587,12 @@ function cleanFilters(filters, properties) {
|
|
|
584
587
|
if (filters.hasOwnProperty(k)) {
|
|
585
588
|
const prop = properties.find(p => p.key === k);
|
|
586
589
|
if (!prop) {
|
|
587
|
-
log.warn(`${LOGS_PREFIX}Filters: skipping unknown property: ${k}`);
|
|
590
|
+
log.warn(() => `${LOGS_PREFIX}Filters: skipping unknown property: ${k}`);
|
|
588
591
|
delete filters[k];
|
|
589
592
|
continue;
|
|
590
593
|
}
|
|
591
594
|
if (!prop.isFilterable) {
|
|
592
|
-
log.warn(`${LOGS_PREFIX}Filters: skipping unfilterable property: ${k}`);
|
|
595
|
+
log.warn(() => `${LOGS_PREFIX}Filters: skipping unfilterable property: ${k}`);
|
|
593
596
|
delete filters[k];
|
|
594
597
|
continue;
|
|
595
598
|
}
|
|
@@ -599,7 +602,7 @@ function cleanFilters(filters, properties) {
|
|
|
599
602
|
const validFilters = filterArray.filter((f) => {
|
|
600
603
|
const { matchMode: matchMode$1 } = f;
|
|
601
604
|
if (!matchMode$1 || !matchMode(type$1, matchMode$1)) {
|
|
602
|
-
log.warn(`${LOGS_PREFIX}Filters: skipping invalid match mode: "${matchMode$1}" for type: "${type$1}" at property: "${k}"`);
|
|
605
|
+
log.warn(() => `${LOGS_PREFIX}Filters: skipping invalid match mode: "${matchMode$1}" for type: "${type$1}" at property: "${k}"`);
|
|
603
606
|
return false;
|
|
604
607
|
}
|
|
605
608
|
return true;
|
|
@@ -614,9 +617,8 @@ function cleanFilters(filters, properties) {
|
|
|
614
617
|
}
|
|
615
618
|
|
|
616
619
|
function logSummary(name, table, properties) {
|
|
617
|
-
const summary = generateSummary(name, table, properties);
|
|
618
620
|
log.info(`${LOGS_PREFIX}Entity "${name}" created successfully`);
|
|
619
|
-
log.info(`${LOGS_PREFIX}Entity Summary:\n${
|
|
621
|
+
log.info(() => `${LOGS_PREFIX}Entity Summary:\n${generateSummary(name, table, properties)}`);
|
|
620
622
|
}
|
|
621
623
|
function generateSummary(name, table, properties) {
|
|
622
624
|
const lines = [];
|
|
@@ -699,20 +701,20 @@ class SQLEntity extends Entity {
|
|
|
699
701
|
select: (first = 0, rows = null, sortField = null, sortOrder = null, filters = null) => {
|
|
700
702
|
return this.sel.query(this.schema, this.table, first, rows, sortField, sortOrder, filters);
|
|
701
703
|
},
|
|
702
|
-
update: (rows,
|
|
703
|
-
return this.upd.query(this.schema, this.table, rows,
|
|
704
|
+
update: (rows, consumer) => {
|
|
705
|
+
return this.upd.query(this.schema, this.table, rows, consumer === null || consumer === void 0 ? void 0 : consumer.id, consumer === null || consumer === void 0 ? void 0 : consumer.nickname);
|
|
704
706
|
},
|
|
705
|
-
insert: (rows,
|
|
706
|
-
return this.ins.query(this.schema, this.table, rows,
|
|
707
|
+
insert: (rows, consumer, rtn = "") => {
|
|
708
|
+
return this.ins.query(this.schema, this.table, rows, consumer === null || consumer === void 0 ? void 0 : consumer.id, consumer === null || consumer === void 0 ? void 0 : consumer.nickname, rtn);
|
|
707
709
|
},
|
|
708
|
-
upsert: (rows, conflictTarget,
|
|
709
|
-
return this.ups.query(this.schema, this.table, rows, conflictTarget,
|
|
710
|
+
upsert: (rows, conflictTarget, consumer, rtn = "") => {
|
|
711
|
+
return this.ups.query(this.schema, this.table, rows, conflictTarget, consumer === null || consumer === void 0 ? void 0 : consumer.id, consumer === null || consumer === void 0 ? void 0 : consumer.nickname, rtn);
|
|
710
712
|
},
|
|
711
713
|
delete: (ids) => {
|
|
712
714
|
return queryById(this.schema, this.table, ids);
|
|
713
715
|
},
|
|
714
|
-
archive: (rows,
|
|
715
|
-
return this.arc.query(this.schema, this.table, rows,
|
|
716
|
+
archive: (rows, consumer) => {
|
|
717
|
+
return this.arc.query(this.schema, this.table, rows, consumer === null || consumer === void 0 ? void 0 : consumer.id, consumer === null || consumer === void 0 ? void 0 : consumer.nickname);
|
|
716
718
|
},
|
|
717
719
|
deleteArchive: () => {
|
|
718
720
|
return queryByDate();
|
|
@@ -732,9 +734,7 @@ class SQLEntity extends Entity {
|
|
|
732
734
|
const filters = cleanFilters(b.filters, this.properties) || null;
|
|
733
735
|
const pagination = b.pagination || false;
|
|
734
736
|
const dbClient = l.dbClient || null;
|
|
735
|
-
log.debug(`get(first='${first}', rows='${rows}',
|
|
736
|
-
sortOrder='${sortOrder}', sortField='${sortField}',
|
|
737
|
-
pagination=${pagination}, filters=${JSON.stringify(filters)}`);
|
|
737
|
+
log.debug(() => `get(first='${first}', rows='${rows}', sortOrder='${sortOrder}', sortField='${sortField}', pagination=${pagination}, filters=${JSON.stringify(filters)}`);
|
|
738
738
|
const { query, args } = this.sel.query(this._schema, this._table, first, rows, sortField, sortOrder, filters);
|
|
739
739
|
this.sel.execute(query, args, dbClient)
|
|
740
740
|
.then((r) => {
|
|
@@ -745,12 +745,13 @@ class SQLEntity extends Entity {
|
|
|
745
745
|
.catch((err) => next(err));
|
|
746
746
|
};
|
|
747
747
|
this.add = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
748
|
+
var _a, _b;
|
|
748
749
|
const l = res.locals;
|
|
749
750
|
const rows = req.body.rows;
|
|
750
751
|
const dbClient = l.dbClient || null;
|
|
751
|
-
const cId = l.
|
|
752
|
-
const cName = l.
|
|
753
|
-
log.debug(`${LOGS_PREFIX}addMany(rows=${rows.length}, consumerId=${cId})`);
|
|
752
|
+
const cId = (_a = l.consumer) === null || _a === void 0 ? void 0 : _a.id;
|
|
753
|
+
const cName = (_b = l.consumer) === null || _b === void 0 ? void 0 : _b.nickname;
|
|
754
|
+
log.debug(() => `${LOGS_PREFIX}addMany(rows=${rows.length}, consumerId=${cId})`);
|
|
754
755
|
const rtn = this.ins.rtn("id");
|
|
755
756
|
const chunks = chunk(rows);
|
|
756
757
|
for (const c of chunks) {
|
|
@@ -771,12 +772,13 @@ class SQLEntity extends Entity {
|
|
|
771
772
|
next();
|
|
772
773
|
});
|
|
773
774
|
this.update = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
775
|
+
var _a, _b;
|
|
774
776
|
const l = res.locals;
|
|
775
777
|
const r = req.body.rows;
|
|
776
778
|
const dbClient = l.dbClient || null;
|
|
777
|
-
const cId = l.
|
|
778
|
-
const cName = l.
|
|
779
|
-
log.debug(`${LOGS_PREFIX}update(rows=${r.length}, consumerId=${cId})`);
|
|
779
|
+
const cId = (_a = l.consumer) === null || _a === void 0 ? void 0 : _a.id;
|
|
780
|
+
const cName = (_b = l.consumer) === null || _b === void 0 ? void 0 : _b.nickname;
|
|
781
|
+
log.debug(() => `${LOGS_PREFIX}update(rows=${r.length}, consumerId=${cId})`);
|
|
780
782
|
const chunks = chunk(r);
|
|
781
783
|
for (const c of chunks) {
|
|
782
784
|
const { query, args } = this.upd.query(this._schema, this._table, c, cId, cName);
|
|
@@ -791,19 +793,20 @@ class SQLEntity extends Entity {
|
|
|
791
793
|
next();
|
|
792
794
|
});
|
|
793
795
|
this.upsert = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
796
|
+
var _a, _b;
|
|
794
797
|
const l = res.locals;
|
|
795
798
|
const rows = req.body.rows;
|
|
796
799
|
const conflictTarget = req.body.conflictTarget;
|
|
797
800
|
const dbClient = l.dbClient || null;
|
|
798
|
-
const cId = l.
|
|
799
|
-
const cName = l.
|
|
801
|
+
const cId = (_a = l.consumer) === null || _a === void 0 ? void 0 : _a.id;
|
|
802
|
+
const cName = (_b = l.consumer) === null || _b === void 0 ? void 0 : _b.nickname;
|
|
800
803
|
if (!conflictTarget) {
|
|
801
804
|
return next({ status: 400, msg: "Missing conflictTarget for upsert operation" });
|
|
802
805
|
}
|
|
803
806
|
if (!rows || !Array.isArray(rows) || rows.length === 0) {
|
|
804
807
|
return next({ status: 400, msg: "Missing or empty rows array for upsert operation" });
|
|
805
808
|
}
|
|
806
|
-
log.debug(`${LOGS_PREFIX}upsert(rows=${rows.length}, conflictTarget=${conflictTarget}, consumerId=${cId})`);
|
|
809
|
+
log.debug(() => `${LOGS_PREFIX}upsert(rows=${rows.length}, conflictTarget=${conflictTarget}, consumerId=${cId})`);
|
|
807
810
|
const rtn = this.ups.rtn("id");
|
|
808
811
|
const chunks = chunk(rows);
|
|
809
812
|
for (const c of chunks) {
|
|
@@ -824,12 +827,13 @@ class SQLEntity extends Entity {
|
|
|
824
827
|
next();
|
|
825
828
|
});
|
|
826
829
|
this.archive = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
830
|
+
var _a, _b;
|
|
827
831
|
const l = res.locals;
|
|
828
|
-
|
|
832
|
+
const r = req.body.rows;
|
|
829
833
|
const dbClient = l.dbClient || null;
|
|
830
|
-
const cId = l.
|
|
831
|
-
const cName = l.
|
|
832
|
-
log.debug(`${LOGS_PREFIX}archive(rows=${r.length}, consumerId=${cId})`);
|
|
834
|
+
const cId = (_a = l.consumer) === null || _a === void 0 ? void 0 : _a.id;
|
|
835
|
+
const cName = (_b = l.consumer) === null || _b === void 0 ? void 0 : _b.nickname;
|
|
836
|
+
log.debug(() => `${LOGS_PREFIX}archive(rows=${r.length}, consumerId=${cId})`);
|
|
833
837
|
const chunks = chunk(r);
|
|
834
838
|
for (const c of chunks) {
|
|
835
839
|
const { query, args } = this.arc.query(this._schema, this._table, c, cId, cName);
|
|
@@ -846,7 +850,7 @@ class SQLEntity extends Entity {
|
|
|
846
850
|
const rows = req.body.rows;
|
|
847
851
|
const dbClient = res.locals.dbClient || null;
|
|
848
852
|
const ids = rows.map((row) => row.id);
|
|
849
|
-
log.debug(`${LOGS_PREFIX}delete ${rows.length} rows : (${ids.join(", ")})`);
|
|
853
|
+
log.debug(() => `${LOGS_PREFIX}delete ${rows.length} rows : (${ids.join(", ")})`);
|
|
850
854
|
const { query, args } = queryById(this._schema, this._table, ids);
|
|
851
855
|
try {
|
|
852
856
|
yield execute(query, args, dbClient);
|
|
@@ -859,7 +863,7 @@ class SQLEntity extends Entity {
|
|
|
859
863
|
this.deleteArchive = (req, res, next) => {
|
|
860
864
|
const date = req.body.date;
|
|
861
865
|
const dbClient = res.locals.dbClient || null;
|
|
862
|
-
log.debug(`${LOGS_PREFIX}deleteArchive(schema=${this._schema}, table=${this._table}, date=${date})`);
|
|
866
|
+
log.debug(() => `${LOGS_PREFIX}deleteArchive(schema=${this._schema}, table=${this._table}, date=${date})`);
|
|
863
867
|
executeArchived(this._schema, this._table, date, queryByDate(), dbClient)
|
|
864
868
|
.then(() => next())
|
|
865
869
|
.catch((err) => next(err));
|
|
@@ -868,9 +872,10 @@ class SQLEntity extends Entity {
|
|
|
868
872
|
const id = req.params.id;
|
|
869
873
|
const dbClient = res.locals.dbClient || null;
|
|
870
874
|
if (!id) {
|
|
871
|
-
|
|
875
|
+
next({ status: 400, msg: "Missing id" });
|
|
876
|
+
return;
|
|
872
877
|
}
|
|
873
|
-
log.debug(`${LOGS_PREFIX}getHistory(schema=${this._schema}, table=${this._table}, id=${id})`);
|
|
878
|
+
log.debug(() => `${LOGS_PREFIX}getHistory(schema=${this._schema}, table=${this._table}, id=${id})`);
|
|
874
879
|
const sql = `
|
|
875
880
|
SELECT id, tstamp, operation, "consumerId", "consumerName"
|
|
876
881
|
FROM log.history
|
|
@@ -892,16 +897,16 @@ class SQLEntity extends Entity {
|
|
|
892
897
|
.catch((err) => next(err));
|
|
893
898
|
};
|
|
894
899
|
this.sync = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
895
|
-
var _a;
|
|
900
|
+
var _a, _b, _c;
|
|
896
901
|
const l = res.locals;
|
|
897
902
|
const rows = req.body.rows;
|
|
898
903
|
const idField = (_a = req.body.idField) !== null && _a !== void 0 ? _a : 'id';
|
|
899
|
-
const cId = l.
|
|
900
|
-
const cName = l.
|
|
904
|
+
const cId = (_b = l.consumer) === null || _b === void 0 ? void 0 : _b.id;
|
|
905
|
+
const cName = (_c = l.consumer) === null || _c === void 0 ? void 0 : _c.nickname;
|
|
901
906
|
if (!rows || !Array.isArray(rows)) {
|
|
902
907
|
return next({ status: 400, msg: "Missing or invalid rows array for sync operation" });
|
|
903
908
|
}
|
|
904
|
-
log.debug(`${LOGS_PREFIX}sync(rows=${rows.length}, idField=${idField}, consumerId=${cId})`);
|
|
909
|
+
log.debug(() => `${LOGS_PREFIX}sync(rows=${rows.length}, idField=${idField}, consumerId=${cId})`);
|
|
905
910
|
const cleanedFilters = cleanFilters(req.body.filters, this.properties) || null;
|
|
906
911
|
const { conditions, args: filterArgs } = add(cleanedFilters);
|
|
907
912
|
const whereClause = conditions.length ? ` WHERE ${conditions.join(' AND ')}` : '';
|
|
@@ -961,7 +966,7 @@ class SQLEntity extends Entity {
|
|
|
961
966
|
});
|
|
962
967
|
this._table = name;
|
|
963
968
|
this._schema = schema;
|
|
964
|
-
log.info(`${LOGS_PREFIX}Creating SQLEntity: "${name}"`);
|
|
969
|
+
log.info(() => `${LOGS_PREFIX}Creating SQLEntity: "${name}"`);
|
|
965
970
|
for (const p of properties) {
|
|
966
971
|
this.mapProps(p.operations, p.key);
|
|
967
972
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dwtechs/antity-pgsql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Open source library to add PostgreSQL support to @dwtechs/Antity entities.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"entities"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@dwtechs/checkard": "3.6.0",
|
|
40
|
-
"@dwtechs/winstan": "0.
|
|
40
|
+
"@dwtechs/winstan": "0.7.0",
|
|
41
41
|
"@dwtechs/antity": "0.16.0",
|
|
42
42
|
"@dwtechs/sparray": "0.2.1",
|
|
43
43
|
"pg": "8.20.0"
|