fastify-auto-sqlapi 0.1.1 → 0.1.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/dist/lib/engine/bulk/bulk-delete.d.ts.map +1 -1
- package/dist/lib/engine/bulk/bulk-delete.js +8 -2
- package/dist/lib/engine/rest/delete.d.ts.map +1 -1
- package/dist/lib/engine/rest/delete.js +9 -2
- package/dist/lib/sql-api.js +2 -2
- package/dist/lib/tenant.d.ts +7 -0
- package/dist/lib/tenant.d.ts.map +1 -1
- package/dist/lib/tenant.js +21 -0
- package/dist/routes/auto/plugin.d.ts.map +1 -1
- package/dist/routes/auto/plugin.js +40 -5
- package/dist/types/dml.d.ts +2 -0
- package/dist/types/dml.d.ts.map +1 -1
- package/dist/types/table.d.ts +24 -0
- package/dist/types/table.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-delete.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/bulk/bulk-delete.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bulk-delete.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/bulk/bulk-delete.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE5E,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAwC5F"}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { ConditionBuilder } from 'node-condition-builder';
|
|
2
|
-
import { buildTenantDeleteWhere } from '../../tenant.js';
|
|
2
|
+
import { buildTenantDeleteWhere, assertTenantOwnsAll } from '../../tenant.js';
|
|
3
3
|
import { primaryAsString } from '../../../types.js';
|
|
4
4
|
export async function bulkDeleteEngine(params) {
|
|
5
|
-
const { db, tableConf, ids, tenant } = params;
|
|
5
|
+
const { db, tableConf, ids, tenant, request } = params;
|
|
6
6
|
if (!ids.length)
|
|
7
7
|
return [];
|
|
8
8
|
const pk = primaryAsString(tableConf.primary);
|
|
9
9
|
const pkCol = tableConf.Schema.col(pk);
|
|
10
10
|
const tableName = tableConf.Schema.tableName;
|
|
11
|
+
if (tableConf.beforeBulkDelete) {
|
|
12
|
+
// Enforce tenant ownership of every id before the hook (single batched SELECT), so it
|
|
13
|
+
// never runs for rows the tenant cannot access. Called once with all ids — no loop.
|
|
14
|
+
await assertTenantOwnsAll(db, tenant, tableName, pkCol, ids);
|
|
15
|
+
await tableConf.beforeBulkDelete(db, request, ids);
|
|
16
|
+
}
|
|
11
17
|
let where;
|
|
12
18
|
let values;
|
|
13
19
|
if (tenant) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/rest/delete.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/rest/delete.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAY,MAAM,mBAAmB,CAAC;AAE9E,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA8B9E"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import { buildTenantDeleteWhere } from '../../tenant.js';
|
|
1
|
+
import { buildTenantDeleteWhere, assertTenantOwnsAll } from '../../tenant.js';
|
|
2
2
|
import { httpError } from '../../errors.js';
|
|
3
3
|
import { primaryAsString } from '../../../types.js';
|
|
4
4
|
export async function deleteEngine(params) {
|
|
5
|
-
const { db, tableConf, id, tenant } = params;
|
|
5
|
+
const { db, tableConf, id, tenant, request } = params;
|
|
6
6
|
const pk = primaryAsString(tableConf.primary);
|
|
7
7
|
const pkCol = tableConf.Schema.col(pk);
|
|
8
8
|
const tableName = tableConf.Schema.tableName;
|
|
9
|
+
if (tableConf.beforeDelete) {
|
|
10
|
+
// Enforce tenant ownership before the hook so it never runs for rows the tenant
|
|
11
|
+
// cannot access. (When no hook is defined, the tenant-scoped DELETE below already
|
|
12
|
+
// prevents deleting non-owned rows, so the extra SELECT is skipped.)
|
|
13
|
+
await assertTenantOwnsAll(db, tenant, tableName, pkCol, [id]);
|
|
14
|
+
await tableConf.beforeDelete(db, request, id);
|
|
15
|
+
}
|
|
9
16
|
if (!tenant) {
|
|
10
17
|
const affectedRows = await db.delete(tableName, { [pkCol]: id });
|
|
11
18
|
if (affectedRows === 0)
|
package/dist/lib/sql-api.js
CHANGED
|
@@ -99,7 +99,7 @@ export class SqlApi {
|
|
|
99
99
|
async delete(tableName, id, request) {
|
|
100
100
|
const tableConf = this.getTableConf(tableName);
|
|
101
101
|
const tenant = await this.getTenant(tableName, request);
|
|
102
|
-
return deleteEngine({ db: this.db, tableConf, id, tenant });
|
|
102
|
+
return deleteEngine({ db: this.db, tableConf, id, tenant, request });
|
|
103
103
|
}
|
|
104
104
|
async bulkUpsert(tableName, items, request) {
|
|
105
105
|
const tableConf = this.getTableConf(tableName);
|
|
@@ -116,7 +116,7 @@ export class SqlApi {
|
|
|
116
116
|
async bulkDelete(tableName, ids, request) {
|
|
117
117
|
const tableConf = this.getTableConf(tableName);
|
|
118
118
|
const tenant = await this.getTenant(tableName, request);
|
|
119
|
-
return bulkDeleteEngine({ db: this.db, tableConf, ids, tenant });
|
|
119
|
+
return bulkDeleteEngine({ db: this.db, tableConf, ids, tenant, request });
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
export function createSqlApi(dbOrPool, dbTables, options) {
|
package/dist/lib/tenant.d.ts
CHANGED
|
@@ -39,4 +39,11 @@ export declare function buildTenantUpdateExtra(tenant: TenantContext | undefined
|
|
|
39
39
|
* No-op for direct or no-tenant — those are enforced via `extraCondition` in the UPDATE itself.
|
|
40
40
|
*/
|
|
41
41
|
export declare function assertTenantOwnership(db: QueryClient, tenant: TenantContext | undefined, tableName: string, pkCol: string, pkValue: ConditionValue): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Assert that EVERY pk in `ids` exists and belongs to the tenant, for both direct and indirect
|
|
44
|
+
* scopes. Throws 404 if any id is missing or not owned. No-op when `tenant` is undefined or `ids`
|
|
45
|
+
* is empty. Used by the delete engines to enforce tenant ownership BEFORE running a `beforeDelete`/
|
|
46
|
+
* `beforeBulkDelete` hook, so user code never runs against rows the caller cannot access.
|
|
47
|
+
*/
|
|
48
|
+
export declare function assertTenantOwnsAll(db: QueryClient, tenant: TenantContext | undefined, tableName: string, pkCol: string, ids: ConditionValue[]): Promise<void>;
|
|
42
49
|
//# sourceMappingURL=tenant.d.ts.map
|
package/dist/lib/tenant.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/lib/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAE/G,OAAO,KAAK,EACV,MAAM,EACN,mBAAmB,EACnB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,aAAa,EACd,MAAM,aAAa,CAAC;AAMrB,wBAAsB,aAAa,CACjC,OAAO,EAAE,mBAAmB,EAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CASpC;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,QAAQ,EAAE,GACpB,gBAAgB,CAclB;AAED,wBAAgB,eAAe,CAC7B,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,mBAAmB,EAC1B,aAAa,EAAE,MAAM,GACpB,MAAM,CAMR;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,QAAQ,EAAE,GACpB,IAAI,CAiBN;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,mBAAmB,EAC1B,SAAS,EAAE,QAAQ,EAAE,EACrB,QAAQ,EAAE,OAAO,EAAE,GAClB,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,GAAG,cAAc,EAAE,EACrD,MAAM,EAAE,aAAa,GACpB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAsBtC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,WAAW,GACjB,IAAI,CAGN;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GACjC,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,aAAa,GAAG,SAAS,GAChC,gBAAgB,GAAG,SAAS,CAM9B;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAUf"}
|
|
1
|
+
{"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/lib/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAE/G,OAAO,KAAK,EACV,MAAM,EACN,mBAAmB,EACnB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,aAAa,EACd,MAAM,aAAa,CAAC;AAMrB,wBAAsB,aAAa,CACjC,OAAO,EAAE,mBAAmB,EAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CASpC;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,QAAQ,EAAE,GACpB,gBAAgB,CAclB;AAED,wBAAgB,eAAe,CAC7B,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,mBAAmB,EAC1B,aAAa,EAAE,MAAM,GACpB,MAAM,CAMR;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,QAAQ,EAAE,GACpB,IAAI,CAiBN;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,mBAAmB,EAC1B,SAAS,EAAE,QAAQ,EAAE,EACrB,QAAQ,EAAE,OAAO,EAAE,GAClB,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,GAAG,cAAc,EAAE,EACrD,MAAM,EAAE,aAAa,GACpB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAsBtC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,WAAW,GACjB,IAAI,CAGN;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GACjC,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,aAAa,GAAG,SAAS,GAChC,gBAAgB,GAAG,SAAS,CAM9B;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,cAAc,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|
package/dist/lib/tenant.js
CHANGED
|
@@ -156,3 +156,24 @@ export async function assertTenantOwnership(db, tenant, tableName, pkCol, pkValu
|
|
|
156
156
|
throw httpError(404, 'Record not found');
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Assert that EVERY pk in `ids` exists and belongs to the tenant, for both direct and indirect
|
|
161
|
+
* scopes. Throws 404 if any id is missing or not owned. No-op when `tenant` is undefined or `ids`
|
|
162
|
+
* is empty. Used by the delete engines to enforce tenant ownership BEFORE running a `beforeDelete`/
|
|
163
|
+
* `beforeBulkDelete` hook, so user code never runs against rows the caller cannot access.
|
|
164
|
+
*/
|
|
165
|
+
export async function assertTenantOwnsAll(db, tenant, tableName, pkCol, ids) {
|
|
166
|
+
if (!tenant || !ids.length)
|
|
167
|
+
return;
|
|
168
|
+
const qualifiedPk = `${db.qi(tableName)}.${db.qi(pkCol)}`;
|
|
169
|
+
const cb = new ConditionBuilder('AND');
|
|
170
|
+
cb.isIn(qualifiedPk, ids);
|
|
171
|
+
cb.append(buildTenantCondition(db, tenant.scope, tenant.ids));
|
|
172
|
+
const join = isIndirect(tenant.scope) ? ` ${buildTenantJoin(db, tenant.scope, tableName)}` : '';
|
|
173
|
+
const sql = `SELECT DISTINCT ${qualifiedPk} AS pk FROM ${db.qi(tableName)}${join} WHERE ${cb.build(1, db.ph)}`;
|
|
174
|
+
const r = await db.query(sql, cb.getValues());
|
|
175
|
+
const uniqueRequested = new Set(ids.map((v) => String(v))).size;
|
|
176
|
+
if (r.rows.length < uniqueRequested) {
|
|
177
|
+
throw httpError(404, 'Record not found');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,SAAS,CAAC;AAO7D,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AASjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,eAAe;QACvB,MAAM,EAAE,MAAM,CAAC;KAChB;CACF;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,SAAS,CAAC;AAO7D,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AASjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,eAAe;QACvB,MAAM,EAAE,MAAM,CAAC;KAChB;CACF;kCAuDU,eAAe,WACf,mBAAmB,KAC3B,OAAO,CAAC,IAAI,CAAC;AAHhB,wBAiFoC"}
|
|
@@ -13,6 +13,45 @@ import updateRoutes from './update.routes.js';
|
|
|
13
13
|
import deleteRoutes from './delete.routes.js';
|
|
14
14
|
import bulkUpsertRoutes from './bulk-upsert.routes.js';
|
|
15
15
|
import bulkDeleteRoutes from './bulk-delete.routes.js';
|
|
16
|
+
// Schema combinators for which Ajv reports one error per failed branch plus a
|
|
17
|
+
// single combinator-level summary error, all targeting the same path.
|
|
18
|
+
const COMBINATOR_KEYWORDS = new Set(['anyOf', 'oneOf']);
|
|
19
|
+
/**
|
|
20
|
+
* Converts Ajv validation errors into response fields, stripping the noise Ajv
|
|
21
|
+
* emits for schema combinators.
|
|
22
|
+
*
|
|
23
|
+
* An enum modelled as `anyOf` of `const`s fails every branch when invalid, so Ajv
|
|
24
|
+
* produces one `const` error per branch plus an `anyOf` error — all on the same
|
|
25
|
+
* path. We keep only the combinator error for those paths and drop the per-branch
|
|
26
|
+
* errors, then deduplicate any remaining identical entries. `required` errors are
|
|
27
|
+
* re-pointed from the parent object to the actually missing property.
|
|
28
|
+
*/
|
|
29
|
+
function normalizeAjvErrors(errors) {
|
|
30
|
+
const toPath = (v) => {
|
|
31
|
+
const path = (v.instancePath || '').replace(/\//g, '.').replace(/^\./, '');
|
|
32
|
+
const missing = v.params?.missingProperty;
|
|
33
|
+
if (v.keyword === 'required' && missing) {
|
|
34
|
+
return path ? `${path}.${missing}` : missing;
|
|
35
|
+
}
|
|
36
|
+
return path;
|
|
37
|
+
};
|
|
38
|
+
const mapped = errors.map((v) => ({
|
|
39
|
+
path: toPath(v),
|
|
40
|
+
message: v.message || 'invalid',
|
|
41
|
+
code: v.keyword || 'unknown',
|
|
42
|
+
}));
|
|
43
|
+
const combinatorPaths = new Set(mapped.filter((f) => COMBINATOR_KEYWORDS.has(f.code)).map((f) => f.path));
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
return mapped.filter((f) => {
|
|
46
|
+
if (combinatorPaths.has(f.path) && !COMBINATOR_KEYWORDS.has(f.code))
|
|
47
|
+
return false;
|
|
48
|
+
const key = `${f.path}|${f.code}|${f.message}`;
|
|
49
|
+
if (seen.has(key))
|
|
50
|
+
return false;
|
|
51
|
+
seen.add(key);
|
|
52
|
+
return true;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
16
55
|
export default fp(async function fastifyAutoSqlApi(fastify, options) {
|
|
17
56
|
// Set ConditionBuilder dialect globally
|
|
18
57
|
const dialect = getDialect(options.dialect || 'postgres');
|
|
@@ -49,11 +88,7 @@ export default fp(async function fastifyAutoSqlApi(fastify, options) {
|
|
|
49
88
|
instance.setErrorHandler((error, request, reply) => {
|
|
50
89
|
// Schema validation errors (Ajv)
|
|
51
90
|
if (error.validation) {
|
|
52
|
-
const fields = error.validation
|
|
53
|
-
path: (v.instancePath || '').replace(/\//g, '.').replace(/^\./, ''),
|
|
54
|
-
message: v.message || 'invalid',
|
|
55
|
-
code: v.keyword || 'unknown',
|
|
56
|
-
}));
|
|
91
|
+
const fields = normalizeAjvErrors(error.validation);
|
|
57
92
|
return reply.status(400).send({
|
|
58
93
|
statusCode: 400,
|
|
59
94
|
error: 'Bad Request',
|
package/dist/types/dml.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export interface GetResult {
|
|
|
37
37
|
}
|
|
38
38
|
export interface DeleteParams extends DmlBaseParams {
|
|
39
39
|
id: string | number;
|
|
40
|
+
request?: FastifyRequest;
|
|
40
41
|
}
|
|
41
42
|
export interface DeleteResult {
|
|
42
43
|
main: Record<string, unknown>;
|
|
@@ -56,6 +57,7 @@ export interface BulkUpsertResult {
|
|
|
56
57
|
}
|
|
57
58
|
export interface BulkDeleteParams extends DmlBaseParams {
|
|
58
59
|
ids: (string | number)[];
|
|
60
|
+
request?: FastifyRequest;
|
|
59
61
|
}
|
|
60
62
|
export interface BulkDeleteResult {
|
|
61
63
|
main: Record<string, unknown>;
|
package/dist/types/dml.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dml.d.ts","sourceRoot":"","sources":["../../src/types/dml.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,UAAU,aAAa;IACrB,EAAE,EAAE,WAAW,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,UAAU,kBAAmB,SAAQ,aAAa;IAChD,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;CACzB;AAID,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;CACzD;AAID,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;CACvD;AAID,MAAM,WAAW,SAAU,SAAQ,aAAa;IAC9C,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAID,MAAM,WAAW,YAAa,SAAQ,aAAa;IACjD,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"dml.d.ts","sourceRoot":"","sources":["../../src/types/dml.ts"],"names":[],"mappings":"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"}
|
package/dist/types/table.d.ts
CHANGED
|
@@ -40,6 +40,30 @@ export interface ITable<F extends Record<string, TSchema> = Record<string, TSche
|
|
|
40
40
|
afterInsert?: (db: QueryClient, req: FastifyRequest, record: {
|
|
41
41
|
[K in keyof F]?: Static<F[K]>;
|
|
42
42
|
}, secondaryRecords?: unknown) => Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Runs before a single record is deleted (DELETE /rest/:id). Throw to abort the
|
|
45
|
+
* deletion (the thrown error's `statusCode`/`message` are surfaced to the client).
|
|
46
|
+
* Use it to enforce referential or business rules the DB cascade would otherwise hide.
|
|
47
|
+
*
|
|
48
|
+
* For tenant-scoped tables the hook only runs once ownership has been verified, so it
|
|
49
|
+
* never fires for rows the caller cannot access.
|
|
50
|
+
*
|
|
51
|
+
* `req` is the Fastify request that triggered the operation. It is always present when
|
|
52
|
+
* the delete comes through the auto-generated HTTP route. It is `undefined` only if you
|
|
53
|
+
* call `sqlApi.delete(table, id)` programmatically without passing a request — in that
|
|
54
|
+
* case any hook that reads request context (e.g. `req.user`) must guard for it.
|
|
55
|
+
*/
|
|
56
|
+
beforeDelete?: (db: QueryClient, req: FastifyRequest, id: string | number) => void | Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Bulk counterpart of `beforeDelete`, invoked ONCE with all ids before a bulk delete
|
|
59
|
+
* (POST /bulk/:table/delete). Called once — not per id — to preserve the single-query
|
|
60
|
+
* optimization. Throw to abort the whole batch. `beforeDelete` is NOT called for bulk
|
|
61
|
+
* deletes; configure this hook if you need a guard there.
|
|
62
|
+
*
|
|
63
|
+
* Same `req` caveat as `beforeDelete`: present via the HTTP route, `undefined` only when
|
|
64
|
+
* `sqlApi.bulkDelete(table, ids)` is called programmatically without a request.
|
|
65
|
+
*/
|
|
66
|
+
beforeBulkDelete?: (db: QueryClient, req: FastifyRequest, ids: (string | number)[]) => void | Promise<void>;
|
|
43
67
|
defaultOrder?: string;
|
|
44
68
|
excludeFromCreation?: (string & keyof F)[];
|
|
45
69
|
distinctResults?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/types/table.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/types/table.ts"],"names":[],"mappings":"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"}
|