@dwtechs/antity-pgsql 0.16.0 → 0.17.1
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 +9 -9
- package/dist/antity-pgsql.js +7 -6
- package/package.json +1 -1
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)
|
|
@@ -311,10 +311,10 @@ Using substacks simplifies your route definitions and ensures consistent data pr
|
|
|
311
311
|
### Query Methods
|
|
312
312
|
|
|
313
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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` as `creatorId` and `consumer.nickname` as `name` for audit 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` as `updaterId` and `consumer.nickname` as `name` for audit 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` as `creatorId` and `consumer.nickname` as `name` for audit 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` as `updaterId` and `consumer.nickname` as `name` for audit tracking. Does not require an `archived` field in the rows — it is set directly in the SQL.
|
|
318
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`.
|
|
319
319
|
- **delete()**: Deletes rows by their IDs. Expects `req.body.rows` to be an array of objects with `id` property: `[{id: 1}, {id: 2}]`
|
|
320
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.
|
|
@@ -376,7 +376,7 @@ res.locals.sync // { inserted: 1, updated: 1, deleted: 1 }
|
|
|
376
376
|
- **Atomic**: All insert / update / delete operations are wrapped in a single transaction.
|
|
377
377
|
- **Filter scope**: When `filters` are provided, only rows matching the filter are considered "managed". Rows outside the filter are never touched.
|
|
378
378
|
- **Property selection**: Insert uses `INSERT` properties; update uses `UPDATE` properties — same as the standalone `add` and `update` middlewares.
|
|
379
|
-
- **Consumer tracking**: `consumer.id` and `consumer.nickname` from `res.locals.consumer` are forwarded to inserts and updates for
|
|
379
|
+
- **Consumer tracking**: `consumer.id` and `consumer.nickname` from `res.locals.consumer` are forwarded to inserts as `creatorId`/`name` and to updates as `updaterId`/`name` for audit tracking.
|
|
380
380
|
|
|
381
381
|
### Upsert (Insert or Update)
|
|
382
382
|
|
|
@@ -440,13 +440,13 @@ const { query, args } = entity.query.upsert(
|
|
|
440
440
|
'RETURNING id' // return clause (optional)
|
|
441
441
|
);
|
|
442
442
|
// Generates:
|
|
443
|
-
// INSERT INTO public.users (name, email,
|
|
443
|
+
// INSERT INTO public.users (name, email, creatorId, name)
|
|
444
444
|
// VALUES ($1, $2, $3, $4)
|
|
445
445
|
// ON CONFLICT (id) DO UPDATE SET
|
|
446
446
|
// name = EXCLUDED.name,
|
|
447
447
|
// email = EXCLUDED.email,
|
|
448
|
-
//
|
|
449
|
-
//
|
|
448
|
+
// creatorId = EXCLUDED.creatorId,
|
|
449
|
+
// name = EXCLUDED.name
|
|
450
450
|
// RETURNING id
|
|
451
451
|
```
|
|
452
452
|
|
package/dist/antity-pgsql.js
CHANGED
|
@@ -305,7 +305,7 @@ class Insert {
|
|
|
305
305
|
if (consumerId !== undefined && consumerName !== undefined) {
|
|
306
306
|
propsToUse.push("consumerId", "consumerName");
|
|
307
307
|
nbProps += 2;
|
|
308
|
-
cols += `,
|
|
308
|
+
cols += `, creatorId, name`;
|
|
309
309
|
}
|
|
310
310
|
let query = `INSERT INTO ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} (${cols}) VALUES `;
|
|
311
311
|
const args = [];
|
|
@@ -365,13 +365,14 @@ class Update {
|
|
|
365
365
|
for (const p of propsToUse) {
|
|
366
366
|
if (rows[0][p] === undefined)
|
|
367
367
|
continue;
|
|
368
|
-
|
|
368
|
+
const colName = p === "consumerId" ? "updaterId" : p === "consumerName" ? "name" : quoteIfUppercase(p);
|
|
369
|
+
query += `${colName} = CASE `;
|
|
369
370
|
for (let j = 0; j < l; j++) {
|
|
370
371
|
const row = rows[j];
|
|
371
372
|
query += `WHEN id = $${j + 1} THEN $${i++} `;
|
|
372
373
|
args.push(row[p]);
|
|
373
374
|
}
|
|
374
|
-
query += `ELSE ${
|
|
375
|
+
query += `ELSE ${colName} END, `;
|
|
375
376
|
}
|
|
376
377
|
query = `${query.slice(0, -2)} WHERE id IN ${$i(l, 0)}`;
|
|
377
378
|
return { query, args };
|
|
@@ -412,9 +413,9 @@ class Upsert {
|
|
|
412
413
|
let cols = this._cols;
|
|
413
414
|
if (consumerId !== undefined && consumerName !== undefined) {
|
|
414
415
|
propsToUse.push("consumerId", "consumerName");
|
|
415
|
-
quotedPropsToUse.push(`
|
|
416
|
+
quotedPropsToUse.push(`creatorId`, `name`);
|
|
416
417
|
nbProps += 2;
|
|
417
|
-
cols += `,
|
|
418
|
+
cols += `, creatorId, name`;
|
|
418
419
|
}
|
|
419
420
|
const conflictColumns = Array.isArray(conflictTarget)
|
|
420
421
|
? conflictTarget.map(col => quoteIfUppercase(col)).join(", ")
|
|
@@ -471,7 +472,7 @@ class Archive {
|
|
|
471
472
|
const args = rows.map(row => row.id);
|
|
472
473
|
let query = `UPDATE ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} SET archived = true`;
|
|
473
474
|
if (consumerId !== undefined && consumerName !== undefined) {
|
|
474
|
-
query += `,
|
|
475
|
+
query += `, updaterId = $${l + 1}, name = $${l + 2}`;
|
|
475
476
|
args.push(consumerId, consumerName);
|
|
476
477
|
}
|
|
477
478
|
query += ` WHERE id IN ${$i(l, 0)}`;
|