@dwtechs/antity-pgsql 0.15.2 → 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 +58 -56
- 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,
|
|
@@ -311,13 +311,14 @@ class Insert {
|
|
|
311
311
|
const args = [];
|
|
312
312
|
let i = 0;
|
|
313
313
|
for (const row of rows) {
|
|
314
|
-
if (consumerId !== undefined && consumerName !== undefined) {
|
|
315
|
-
row.consumerId = consumerId;
|
|
316
|
-
row.consumerName = consumerName;
|
|
317
|
-
}
|
|
318
314
|
query += `${$i(nbProps, i)}, `;
|
|
319
315
|
for (const prop of propsToUse) {
|
|
320
|
-
|
|
316
|
+
if (prop === "consumerId")
|
|
317
|
+
args.push(consumerId);
|
|
318
|
+
else if (prop === "consumerName")
|
|
319
|
+
args.push(consumerName);
|
|
320
|
+
else
|
|
321
|
+
args.push(row[prop]);
|
|
321
322
|
}
|
|
322
323
|
i += nbProps;
|
|
323
324
|
}
|
|
@@ -356,7 +357,7 @@ class Update {
|
|
|
356
357
|
const propsToUse = [...this._props];
|
|
357
358
|
if (consumerId !== undefined && consumerName !== undefined)
|
|
358
359
|
propsToUse.push("consumerId", "consumerName");
|
|
359
|
-
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)}`);
|
|
360
361
|
const l = rows.length;
|
|
361
362
|
const args = rows.map(row => row.id);
|
|
362
363
|
let query = `UPDATE ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} SET `;
|
|
@@ -422,14 +423,13 @@ class Upsert {
|
|
|
422
423
|
const args = [];
|
|
423
424
|
let i = 0;
|
|
424
425
|
for (const row of rows) {
|
|
425
|
-
if (consumerId !== undefined && consumerName !== undefined) {
|
|
426
|
-
row.consumerId = consumerId;
|
|
427
|
-
row.consumerName = consumerName;
|
|
428
|
-
}
|
|
429
426
|
query += `${$i(nbProps, i)}, `;
|
|
430
|
-
for (const prop of
|
|
427
|
+
for (const prop of this._props) {
|
|
431
428
|
args.push(row[prop]);
|
|
432
429
|
}
|
|
430
|
+
if (consumerId !== undefined && consumerName !== undefined) {
|
|
431
|
+
args.push(consumerId, consumerName);
|
|
432
|
+
}
|
|
433
433
|
i += nbProps;
|
|
434
434
|
}
|
|
435
435
|
query = query.slice(0, -2);
|
|
@@ -466,7 +466,7 @@ var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
|
|
466
466
|
};
|
|
467
467
|
class Archive {
|
|
468
468
|
query(schema, table, rows, consumerId, consumerName) {
|
|
469
|
-
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)}`);
|
|
470
470
|
const l = rows.length;
|
|
471
471
|
const args = rows.map(row => row.id);
|
|
472
472
|
let query = `UPDATE ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} SET archived = true`;
|
|
@@ -587,12 +587,12 @@ function cleanFilters(filters, properties) {
|
|
|
587
587
|
if (filters.hasOwnProperty(k)) {
|
|
588
588
|
const prop = properties.find(p => p.key === k);
|
|
589
589
|
if (!prop) {
|
|
590
|
-
log.warn(`${LOGS_PREFIX}Filters: skipping unknown property: ${k}`);
|
|
590
|
+
log.warn(() => `${LOGS_PREFIX}Filters: skipping unknown property: ${k}`);
|
|
591
591
|
delete filters[k];
|
|
592
592
|
continue;
|
|
593
593
|
}
|
|
594
594
|
if (!prop.isFilterable) {
|
|
595
|
-
log.warn(`${LOGS_PREFIX}Filters: skipping unfilterable property: ${k}`);
|
|
595
|
+
log.warn(() => `${LOGS_PREFIX}Filters: skipping unfilterable property: ${k}`);
|
|
596
596
|
delete filters[k];
|
|
597
597
|
continue;
|
|
598
598
|
}
|
|
@@ -602,7 +602,7 @@ function cleanFilters(filters, properties) {
|
|
|
602
602
|
const validFilters = filterArray.filter((f) => {
|
|
603
603
|
const { matchMode: matchMode$1 } = f;
|
|
604
604
|
if (!matchMode$1 || !matchMode(type$1, matchMode$1)) {
|
|
605
|
-
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}"`);
|
|
606
606
|
return false;
|
|
607
607
|
}
|
|
608
608
|
return true;
|
|
@@ -617,9 +617,8 @@ function cleanFilters(filters, properties) {
|
|
|
617
617
|
}
|
|
618
618
|
|
|
619
619
|
function logSummary(name, table, properties) {
|
|
620
|
-
const summary = generateSummary(name, table, properties);
|
|
621
620
|
log.info(`${LOGS_PREFIX}Entity "${name}" created successfully`);
|
|
622
|
-
log.info(`${LOGS_PREFIX}Entity Summary:\n${
|
|
621
|
+
log.info(() => `${LOGS_PREFIX}Entity Summary:\n${generateSummary(name, table, properties)}`);
|
|
623
622
|
}
|
|
624
623
|
function generateSummary(name, table, properties) {
|
|
625
624
|
const lines = [];
|
|
@@ -702,20 +701,20 @@ class SQLEntity extends Entity {
|
|
|
702
701
|
select: (first = 0, rows = null, sortField = null, sortOrder = null, filters = null) => {
|
|
703
702
|
return this.sel.query(this.schema, this.table, first, rows, sortField, sortOrder, filters);
|
|
704
703
|
},
|
|
705
|
-
update: (rows,
|
|
706
|
-
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);
|
|
707
706
|
},
|
|
708
|
-
insert: (rows,
|
|
709
|
-
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);
|
|
710
709
|
},
|
|
711
|
-
upsert: (rows, conflictTarget,
|
|
712
|
-
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);
|
|
713
712
|
},
|
|
714
713
|
delete: (ids) => {
|
|
715
714
|
return queryById(this.schema, this.table, ids);
|
|
716
715
|
},
|
|
717
|
-
archive: (rows,
|
|
718
|
-
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);
|
|
719
718
|
},
|
|
720
719
|
deleteArchive: () => {
|
|
721
720
|
return queryByDate();
|
|
@@ -735,9 +734,7 @@ class SQLEntity extends Entity {
|
|
|
735
734
|
const filters = cleanFilters(b.filters, this.properties) || null;
|
|
736
735
|
const pagination = b.pagination || false;
|
|
737
736
|
const dbClient = l.dbClient || null;
|
|
738
|
-
log.debug(`get(first='${first}', rows='${rows}',
|
|
739
|
-
sortOrder='${sortOrder}', sortField='${sortField}',
|
|
740
|
-
pagination=${pagination}, filters=${JSON.stringify(filters)}`);
|
|
737
|
+
log.debug(() => `get(first='${first}', rows='${rows}', sortOrder='${sortOrder}', sortField='${sortField}', pagination=${pagination}, filters=${JSON.stringify(filters)}`);
|
|
741
738
|
const { query, args } = this.sel.query(this._schema, this._table, first, rows, sortField, sortOrder, filters);
|
|
742
739
|
this.sel.execute(query, args, dbClient)
|
|
743
740
|
.then((r) => {
|
|
@@ -748,12 +745,13 @@ class SQLEntity extends Entity {
|
|
|
748
745
|
.catch((err) => next(err));
|
|
749
746
|
};
|
|
750
747
|
this.add = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
748
|
+
var _a, _b;
|
|
751
749
|
const l = res.locals;
|
|
752
750
|
const rows = req.body.rows;
|
|
753
751
|
const dbClient = l.dbClient || null;
|
|
754
|
-
const cId = l.
|
|
755
|
-
const cName = l.
|
|
756
|
-
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})`);
|
|
757
755
|
const rtn = this.ins.rtn("id");
|
|
758
756
|
const chunks = chunk(rows);
|
|
759
757
|
for (const c of chunks) {
|
|
@@ -774,12 +772,13 @@ class SQLEntity extends Entity {
|
|
|
774
772
|
next();
|
|
775
773
|
});
|
|
776
774
|
this.update = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
775
|
+
var _a, _b;
|
|
777
776
|
const l = res.locals;
|
|
778
777
|
const r = req.body.rows;
|
|
779
778
|
const dbClient = l.dbClient || null;
|
|
780
|
-
const cId = l.
|
|
781
|
-
const cName = l.
|
|
782
|
-
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})`);
|
|
783
782
|
const chunks = chunk(r);
|
|
784
783
|
for (const c of chunks) {
|
|
785
784
|
const { query, args } = this.upd.query(this._schema, this._table, c, cId, cName);
|
|
@@ -794,19 +793,20 @@ class SQLEntity extends Entity {
|
|
|
794
793
|
next();
|
|
795
794
|
});
|
|
796
795
|
this.upsert = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
796
|
+
var _a, _b;
|
|
797
797
|
const l = res.locals;
|
|
798
798
|
const rows = req.body.rows;
|
|
799
799
|
const conflictTarget = req.body.conflictTarget;
|
|
800
800
|
const dbClient = l.dbClient || null;
|
|
801
|
-
const cId = l.
|
|
802
|
-
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;
|
|
803
803
|
if (!conflictTarget) {
|
|
804
804
|
return next({ status: 400, msg: "Missing conflictTarget for upsert operation" });
|
|
805
805
|
}
|
|
806
806
|
if (!rows || !Array.isArray(rows) || rows.length === 0) {
|
|
807
807
|
return next({ status: 400, msg: "Missing or empty rows array for upsert operation" });
|
|
808
808
|
}
|
|
809
|
-
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})`);
|
|
810
810
|
const rtn = this.ups.rtn("id");
|
|
811
811
|
const chunks = chunk(rows);
|
|
812
812
|
for (const c of chunks) {
|
|
@@ -827,12 +827,13 @@ class SQLEntity extends Entity {
|
|
|
827
827
|
next();
|
|
828
828
|
});
|
|
829
829
|
this.archive = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
830
|
+
var _a, _b;
|
|
830
831
|
const l = res.locals;
|
|
831
|
-
|
|
832
|
+
const r = req.body.rows;
|
|
832
833
|
const dbClient = l.dbClient || null;
|
|
833
|
-
const cId = l.
|
|
834
|
-
const cName = l.
|
|
835
|
-
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})`);
|
|
836
837
|
const chunks = chunk(r);
|
|
837
838
|
for (const c of chunks) {
|
|
838
839
|
const { query, args } = this.arc.query(this._schema, this._table, c, cId, cName);
|
|
@@ -849,7 +850,7 @@ class SQLEntity extends Entity {
|
|
|
849
850
|
const rows = req.body.rows;
|
|
850
851
|
const dbClient = res.locals.dbClient || null;
|
|
851
852
|
const ids = rows.map((row) => row.id);
|
|
852
|
-
log.debug(`${LOGS_PREFIX}delete ${rows.length} rows : (${ids.join(", ")})`);
|
|
853
|
+
log.debug(() => `${LOGS_PREFIX}delete ${rows.length} rows : (${ids.join(", ")})`);
|
|
853
854
|
const { query, args } = queryById(this._schema, this._table, ids);
|
|
854
855
|
try {
|
|
855
856
|
yield execute(query, args, dbClient);
|
|
@@ -862,7 +863,7 @@ class SQLEntity extends Entity {
|
|
|
862
863
|
this.deleteArchive = (req, res, next) => {
|
|
863
864
|
const date = req.body.date;
|
|
864
865
|
const dbClient = res.locals.dbClient || null;
|
|
865
|
-
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})`);
|
|
866
867
|
executeArchived(this._schema, this._table, date, queryByDate(), dbClient)
|
|
867
868
|
.then(() => next())
|
|
868
869
|
.catch((err) => next(err));
|
|
@@ -871,9 +872,10 @@ class SQLEntity extends Entity {
|
|
|
871
872
|
const id = req.params.id;
|
|
872
873
|
const dbClient = res.locals.dbClient || null;
|
|
873
874
|
if (!id) {
|
|
874
|
-
|
|
875
|
+
next({ status: 400, msg: "Missing id" });
|
|
876
|
+
return;
|
|
875
877
|
}
|
|
876
|
-
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})`);
|
|
877
879
|
const sql = `
|
|
878
880
|
SELECT id, tstamp, operation, "consumerId", "consumerName"
|
|
879
881
|
FROM log.history
|
|
@@ -895,16 +897,16 @@ class SQLEntity extends Entity {
|
|
|
895
897
|
.catch((err) => next(err));
|
|
896
898
|
};
|
|
897
899
|
this.sync = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
898
|
-
var _a;
|
|
900
|
+
var _a, _b, _c;
|
|
899
901
|
const l = res.locals;
|
|
900
902
|
const rows = req.body.rows;
|
|
901
903
|
const idField = (_a = req.body.idField) !== null && _a !== void 0 ? _a : 'id';
|
|
902
|
-
const cId = l.
|
|
903
|
-
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;
|
|
904
906
|
if (!rows || !Array.isArray(rows)) {
|
|
905
907
|
return next({ status: 400, msg: "Missing or invalid rows array for sync operation" });
|
|
906
908
|
}
|
|
907
|
-
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})`);
|
|
908
910
|
const cleanedFilters = cleanFilters(req.body.filters, this.properties) || null;
|
|
909
911
|
const { conditions, args: filterArgs } = add(cleanedFilters);
|
|
910
912
|
const whereClause = conditions.length ? ` WHERE ${conditions.join(' AND ')}` : '';
|
|
@@ -964,7 +966,7 @@ class SQLEntity extends Entity {
|
|
|
964
966
|
});
|
|
965
967
|
this._table = name;
|
|
966
968
|
this._schema = schema;
|
|
967
|
-
log.info(`${LOGS_PREFIX}Creating SQLEntity: "${name}"`);
|
|
969
|
+
log.info(() => `${LOGS_PREFIX}Creating SQLEntity: "${name}"`);
|
|
968
970
|
for (const p of properties) {
|
|
969
971
|
this.mapProps(p.operations, p.key);
|
|
970
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"
|