@dwtechs/antity-pgsql 0.17.3 → 0.17.5
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 +2 -2
- package/dist/antity-pgsql.js +16 -24
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
[](https://opensource.org/licenses/MIT)
|
|
3
3
|
[](https://www.npmjs.com/package/@dwtechs/antity-pgsql)
|
|
4
4
|
[](https://www.npmjs.com/package/@dwtechs/antity-pgsql)
|
|
5
|
-

|
|
6
6
|
|
|
7
7
|
- [Synopsis](#synopsis)
|
|
8
8
|
- [Support](#support)
|
|
@@ -333,7 +333,7 @@ Using substacks simplifies your route definitions and ensures consistent data pr
|
|
|
333
333
|
|
|
334
334
|
### Query Methods
|
|
335
335
|
|
|
336
|
-
- **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.
|
|
336
|
+
- **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. The `sortField` parameter is validated against the entity's known properties; an unrecognised value is silently dropped.
|
|
337
337
|
- **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` as `creatorId` and `consumer.nickname` as `creatorName` for audit tracking. Supports `RETURNING` clause via the `rtn` parameter.
|
|
338
338
|
- **query.update()**: Generates an UPDATE query using CASE statements. Accepts an array of `Row` objects with `id` property. Optionally appends `consumer.id` as `updaterId` and `consumer.nickname` as `updaterName` for audit tracking.
|
|
339
339
|
- **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` as `creatorId` and `consumer.nickname` as `creatorName` for audit tracking. Supports `RETURNING` clause via the `rtn` parameter.
|
package/dist/antity-pgsql.js
CHANGED
|
@@ -100,7 +100,7 @@ const reserved = new Set([
|
|
|
100
100
|
]);
|
|
101
101
|
function quoteIfUppercase(word) {
|
|
102
102
|
if (/[A-Z]/.test(word) || reserved.has(word.toLowerCase()))
|
|
103
|
-
return `"${word}"`;
|
|
103
|
+
return `"${word.replace(/"/g, '""')}"`;
|
|
104
104
|
return word;
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -307,11 +307,11 @@ class Insert {
|
|
|
307
307
|
nbProps += 2;
|
|
308
308
|
cols += `, "creatorId", "creatorName"`;
|
|
309
309
|
}
|
|
310
|
-
let query = `INSERT INTO ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} (${cols}) VALUES `;
|
|
311
310
|
const args = [];
|
|
311
|
+
const valueParts = [];
|
|
312
312
|
let i = 0;
|
|
313
313
|
for (const row of rows) {
|
|
314
|
-
|
|
314
|
+
valueParts.push($i(nbProps, i));
|
|
315
315
|
for (const prop of propsToUse) {
|
|
316
316
|
if (prop === "consumerId")
|
|
317
317
|
args.push(consumerId);
|
|
@@ -322,7 +322,7 @@ class Insert {
|
|
|
322
322
|
}
|
|
323
323
|
i += nbProps;
|
|
324
324
|
}
|
|
325
|
-
query =
|
|
325
|
+
let query = `INSERT INTO ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} (${cols}) VALUES ${valueParts.join(", ")}`;
|
|
326
326
|
if (rtn)
|
|
327
327
|
query += ` ${rtn}`;
|
|
328
328
|
return { query, args };
|
|
@@ -348,8 +348,8 @@ class Update {
|
|
|
348
348
|
log.debug(() => `${LOGS_PREFIX}Update query input rows: ${JSON.stringify(rows, null, 2)}`);
|
|
349
349
|
const l = rows.length;
|
|
350
350
|
const args = rows.map(row => row.id);
|
|
351
|
-
let query = `UPDATE ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} SET `;
|
|
352
351
|
let i = args.length + 1;
|
|
352
|
+
const setClauses = [];
|
|
353
353
|
for (const p of propsToUse) {
|
|
354
354
|
const isConsumerId = p === "consumerId";
|
|
355
355
|
const isConsumerName = p === "consumerName";
|
|
@@ -357,9 +357,9 @@ class Update {
|
|
|
357
357
|
if (!isConsumerProp && rows[0][p] === undefined)
|
|
358
358
|
continue;
|
|
359
359
|
const colName = isConsumerId ? '"updaterId"' : isConsumerName ? '"updaterName"' : quoteIfUppercase(p);
|
|
360
|
-
|
|
360
|
+
const whenParts = [];
|
|
361
361
|
for (let j = 0; j < l; j++) {
|
|
362
|
-
|
|
362
|
+
whenParts.push(`WHEN id = $${j + 1} THEN $${i++}`);
|
|
363
363
|
if (isConsumerId)
|
|
364
364
|
args.push(consumerId);
|
|
365
365
|
else if (isConsumerName)
|
|
@@ -367,9 +367,9 @@ class Update {
|
|
|
367
367
|
else
|
|
368
368
|
args.push(rows[j][p]);
|
|
369
369
|
}
|
|
370
|
-
|
|
370
|
+
setClauses.push(`${colName} = CASE ${whenParts.join(" ")} ELSE ${colName} END`);
|
|
371
371
|
}
|
|
372
|
-
query =
|
|
372
|
+
const query = `UPDATE ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} SET ${setClauses.join(", ")} WHERE id IN ${$i(l, 0)}`;
|
|
373
373
|
return { query, args };
|
|
374
374
|
}
|
|
375
375
|
async execute(query, args, client) {
|
|
@@ -421,16 +421,13 @@ class Upsert {
|
|
|
421
421
|
i += nbProps;
|
|
422
422
|
}
|
|
423
423
|
query = query.slice(0, -2);
|
|
424
|
-
query += ` ON CONFLICT (${conflictColumns}) DO UPDATE SET `;
|
|
425
424
|
const conflictTargetArray = Array.isArray(conflictTarget) ? conflictTarget : [conflictTarget];
|
|
426
425
|
const updateCols = quotedPropsToUse.filter((_, idx) => {
|
|
427
426
|
const propName = propsToUse[idx];
|
|
428
427
|
return !conflictTargetArray.includes(propName);
|
|
429
428
|
});
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
}
|
|
433
|
-
query = query.slice(0, -2);
|
|
429
|
+
const updateSetClause = updateCols.map(col => `${col} = EXCLUDED.${col}`).join(", ");
|
|
430
|
+
query += ` ON CONFLICT (${conflictColumns}) DO UPDATE SET ${updateSetClause}`;
|
|
434
431
|
if (rtn)
|
|
435
432
|
query += ` ${rtn}`;
|
|
436
433
|
return { query, args };
|
|
@@ -471,14 +468,7 @@ function queryByDate() {
|
|
|
471
468
|
return `SELECT hard_delete($1, $2, $3)`;
|
|
472
469
|
}
|
|
473
470
|
async function executeArchived(schema, table, date, query, client) {
|
|
474
|
-
|
|
475
|
-
try {
|
|
476
|
-
db = await execute(query, [schema, table, date], client);
|
|
477
|
-
}
|
|
478
|
-
catch (err) {
|
|
479
|
-
throw err;
|
|
480
|
-
}
|
|
481
|
-
return db;
|
|
471
|
+
return execute(query, [schema, table, date], client);
|
|
482
472
|
}
|
|
483
473
|
|
|
484
474
|
function type(type) {
|
|
@@ -706,7 +696,8 @@ class SQLEntity extends Entity {
|
|
|
706
696
|
}
|
|
707
697
|
query = {
|
|
708
698
|
select: (first = 0, rows = null, sortField = null, sortOrder = null, filters = null) => {
|
|
709
|
-
|
|
699
|
+
const validatedSortField = sortField && this.properties.some(p => p.key === sortField) ? sortField : null;
|
|
700
|
+
return this.sel.query(this.schema, this.table, first, rows, validatedSortField, sortOrder, filters);
|
|
710
701
|
},
|
|
711
702
|
update: (rows, consumer) => {
|
|
712
703
|
return this.upd.query(this.schema, this.table, rows, consumer?.id, consumer?.nickname);
|
|
@@ -735,7 +726,8 @@ class SQLEntity extends Entity {
|
|
|
735
726
|
const b = req.body;
|
|
736
727
|
const first = b?.first ?? 0;
|
|
737
728
|
const rows = b.rows || null;
|
|
738
|
-
const
|
|
729
|
+
const rawSortField = b.sortField || null;
|
|
730
|
+
const sortField = rawSortField && this.properties.some(p => p.key === rawSortField) ? rawSortField : null;
|
|
739
731
|
const sortOrder = b.sortOrder === -1 || b.sortOrder === "DESC" ? "DESC" : "ASC";
|
|
740
732
|
const filters = cleanFilters(b.filters, this.properties) || null;
|
|
741
733
|
const pagination = b.pagination || false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dwtechs/antity-pgsql",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.5",
|
|
4
4
|
"description": "Open source library to add PostgreSQL support to @dwtechs/Antity entities.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"entities"
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@dwtechs/checkard": "3.6.0",
|
|
38
38
|
"@dwtechs/winstan": "0.7.0",
|
|
39
|
-
"@dwtechs/antity": "0.
|
|
39
|
+
"@dwtechs/antity": "0.18.0",
|
|
40
40
|
"@dwtechs/sparray": "0.2.1",
|
|
41
41
|
"pg": "8.20.0"
|
|
42
42
|
},
|