@dwtechs/antity-pgsql 0.17.1 → 0.17.2
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 +23 -5
- package/dist/antity-pgsql.js +5 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -123,6 +123,24 @@ router.get("/:id/history", ..., entity.getHistory);
|
|
|
123
123
|
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
+
### Expected table structure
|
|
127
|
+
|
|
128
|
+
```sql
|
|
129
|
+
CREATE TABLE IF NOT EXISTS "service" (
|
|
130
|
+
id SERIAL PRIMARY KEY,
|
|
131
|
+
name varchar(20) NOT NULL,
|
|
132
|
+
pattern TEXT,
|
|
133
|
+
archived BOOLEAN DEFAULT FALSE,
|
|
134
|
+
"archivedAt" TIMESTAMP,
|
|
135
|
+
"creatorId" INT,
|
|
136
|
+
"creatorName" TEXT,
|
|
137
|
+
"updaterId" INT,
|
|
138
|
+
"updaterName" TEXT,
|
|
139
|
+
"createdAt" TIMESTAMP DEFAULT NOW(),
|
|
140
|
+
"updatedAt" TIMESTAMP NULL
|
|
141
|
+
);
|
|
142
|
+
```
|
|
143
|
+
|
|
126
144
|
## API Reference
|
|
127
145
|
|
|
128
146
|
|
|
@@ -311,10 +329,10 @@ Using substacks simplifies your route definitions and ensures consistent data pr
|
|
|
311
329
|
### Query Methods
|
|
312
330
|
|
|
313
331
|
- **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` as `creatorId` and `consumer.nickname` as `
|
|
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 `
|
|
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 `
|
|
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 `
|
|
332
|
+
- **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.
|
|
333
|
+
- **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.
|
|
334
|
+
- **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.
|
|
335
|
+
- **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 `updaterName` for audit tracking. Does not require an `archived` field in the rows — it is set directly in the SQL.
|
|
318
336
|
- **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
337
|
- **delete()**: Deletes rows by their IDs. Expects `req.body.rows` to be an array of objects with `id` property: `[{id: 1}, {id: 2}]`
|
|
320
338
|
- **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 +394,7 @@ res.locals.sync // { inserted: 1, updated: 1, deleted: 1 }
|
|
|
376
394
|
- **Atomic**: All insert / update / delete operations are wrapped in a single transaction.
|
|
377
395
|
- **Filter scope**: When `filters` are provided, only rows matching the filter are considered "managed". Rows outside the filter are never touched.
|
|
378
396
|
- **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 as `creatorId`/`
|
|
397
|
+
- **Consumer tracking**: `consumer.id` and `consumer.nickname` from `res.locals.consumer` are forwarded to inserts as `creatorId`/`creatorName` and to updates as `updaterId`/`updaterName` for audit tracking.
|
|
380
398
|
|
|
381
399
|
### Upsert (Insert or Update)
|
|
382
400
|
|
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 += `, creatorId,
|
|
308
|
+
cols += `, "creatorId", "creatorName"`;
|
|
309
309
|
}
|
|
310
310
|
let query = `INSERT INTO ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} (${cols}) VALUES `;
|
|
311
311
|
const args = [];
|
|
@@ -365,7 +365,7 @@ class Update {
|
|
|
365
365
|
for (const p of propsToUse) {
|
|
366
366
|
if (rows[0][p] === undefined)
|
|
367
367
|
continue;
|
|
368
|
-
const colName = p === "consumerId" ? "updaterId" : p === "consumerName" ? "
|
|
368
|
+
const colName = p === "consumerId" ? '"updaterId"' : p === "consumerName" ? '"updaterName"' : quoteIfUppercase(p);
|
|
369
369
|
query += `${colName} = CASE `;
|
|
370
370
|
for (let j = 0; j < l; j++) {
|
|
371
371
|
const row = rows[j];
|
|
@@ -413,9 +413,9 @@ class Upsert {
|
|
|
413
413
|
let cols = this._cols;
|
|
414
414
|
if (consumerId !== undefined && consumerName !== undefined) {
|
|
415
415
|
propsToUse.push("consumerId", "consumerName");
|
|
416
|
-
quotedPropsToUse.push(`creatorId`, `
|
|
416
|
+
quotedPropsToUse.push(`"creatorId"`, `"creatorName"`);
|
|
417
417
|
nbProps += 2;
|
|
418
|
-
cols += `, creatorId,
|
|
418
|
+
cols += `, "creatorId", "creatorName"`;
|
|
419
419
|
}
|
|
420
420
|
const conflictColumns = Array.isArray(conflictTarget)
|
|
421
421
|
? conflictTarget.map(col => quoteIfUppercase(col)).join(", ")
|
|
@@ -472,7 +472,7 @@ class Archive {
|
|
|
472
472
|
const args = rows.map(row => row.id);
|
|
473
473
|
let query = `UPDATE ${quoteIfUppercase(schema)}.${quoteIfUppercase(table)} SET archived = true`;
|
|
474
474
|
if (consumerId !== undefined && consumerName !== undefined) {
|
|
475
|
-
query += `, updaterId = $${l + 1},
|
|
475
|
+
query += `, "updaterId" = $${l + 1}, "updaterName" = $${l + 2}`;
|
|
476
476
|
args.push(consumerId, consumerName);
|
|
477
477
|
}
|
|
478
478
|
query += ` WHERE id IN ${$i(l, 0)}`;
|