fastify-auto-sqlapi 0.0.5 → 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/AGENTS.md +15 -2
- package/AGENTS_BACKEND.md +144 -20
- package/AGENTS_FRONTEND.md +161 -67
- package/README.md +47 -26
- package/dist/bin/generate-schema.js +9 -26
- package/dist/bin/generate-tables.js +7 -30
- package/dist/bin/utils.d.ts +28 -0
- package/dist/bin/utils.d.ts.map +1 -1
- package/dist/bin/utils.js +69 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/cli/load-dependency.d.ts +8 -0
- package/dist/lib/cli/load-dependency.d.ts.map +1 -0
- package/dist/lib/cli/load-dependency.js +21 -0
- package/dist/lib/cli/mysql-introspect.d.ts.map +1 -1
- package/dist/lib/cli/mysql-introspect.js +2 -18
- package/dist/lib/cli/pg-introspect.d.ts.map +1 -1
- package/dist/lib/cli/pg-introspect.js +2 -17
- package/dist/lib/db.d.ts +1 -0
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +33 -55
- package/dist/lib/dialect.d.ts +17 -0
- package/dist/lib/dialect.d.ts.map +1 -1
- package/dist/lib/dialect.js +32 -0
- 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/bulk/bulk-upsert.d.ts.map +1 -1
- package/dist/lib/engine/bulk/bulk-upsert.js +15 -43
- package/dist/lib/engine/rest/delete.d.ts.map +1 -1
- package/dist/lib/engine/rest/delete.js +14 -12
- package/dist/lib/engine/rest/get.d.ts.map +1 -1
- package/dist/lib/engine/rest/get.js +3 -5
- package/dist/lib/engine/rest/insert.d.ts.map +1 -1
- package/dist/lib/engine/rest/insert.js +11 -31
- package/dist/lib/engine/rest/update.d.ts.map +1 -1
- package/dist/lib/engine/rest/update.js +13 -46
- package/dist/lib/engine/search/search.d.ts.map +1 -1
- package/dist/lib/engine/search/search.js +553 -229
- package/dist/lib/engine/write-helpers.d.ts +39 -2
- package/dist/lib/engine/write-helpers.d.ts.map +1 -1
- package/dist/lib/engine/write-helpers.js +55 -12
- package/dist/lib/errors.d.ts +11 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +12 -0
- package/dist/lib/schema/bulk-upsert.d.ts.map +1 -1
- package/dist/lib/schema/bulk-upsert.js +9 -25
- package/dist/lib/schema/helpers.d.ts +28 -1
- package/dist/lib/schema/helpers.d.ts.map +1 -1
- package/dist/lib/schema/helpers.js +38 -0
- package/dist/lib/schema/insert.d.ts.map +1 -1
- package/dist/lib/schema/insert.js +9 -19
- package/dist/lib/schema/search.d.ts.map +1 -1
- package/dist/lib/schema/search.js +138 -50
- package/dist/lib/schema/update.d.ts.map +1 -1
- package/dist/lib/schema/update.js +9 -25
- package/dist/lib/sql-api.d.ts +6 -6
- package/dist/lib/sql-api.d.ts.map +1 -1
- package/dist/lib/sql-api.js +10 -10
- package/dist/lib/table-helpers.d.ts +6 -1
- package/dist/lib/table-helpers.d.ts.map +1 -1
- package/dist/lib/table-helpers.js +42 -2
- package/dist/lib/tenant.d.ts +30 -0
- package/dist/lib/tenant.d.ts.map +1 -1
- package/dist/lib/tenant.js +78 -9
- package/dist/routes/auto/bulk-delete.routes.d.ts.map +1 -1
- package/dist/routes/auto/bulk-delete.routes.js +17 -23
- package/dist/routes/auto/bulk-upsert.routes.d.ts.map +1 -1
- package/dist/routes/auto/bulk-upsert.routes.js +16 -22
- package/dist/routes/auto/delete.routes.d.ts.map +1 -1
- package/dist/routes/auto/delete.routes.js +18 -24
- package/dist/routes/auto/get.routes.d.ts.map +1 -1
- package/dist/routes/auto/get.routes.js +16 -23
- package/dist/routes/auto/insert.routes.d.ts.map +1 -1
- package/dist/routes/auto/insert.routes.js +19 -26
- package/dist/routes/auto/plugin.d.ts.map +1 -1
- package/dist/routes/auto/plugin.js +40 -5
- package/dist/routes/auto/route-helpers.d.ts +27 -2
- package/dist/routes/auto/route-helpers.d.ts.map +1 -1
- package/dist/routes/auto/route-helpers.js +39 -1
- package/dist/routes/auto/search.routes.d.ts.map +1 -1
- package/dist/routes/auto/search.routes.js +47 -47
- package/dist/routes/auto/update.routes.d.ts.map +1 -1
- package/dist/routes/auto/update.routes.js +20 -27
- package/dist/types/cli.d.ts +22 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/cli.js +1 -0
- package/dist/types/computed.d.ts +29 -0
- package/dist/types/computed.d.ts.map +1 -0
- package/dist/types/computed.js +1 -0
- package/dist/types/conditions.d.ts +16 -0
- package/dist/types/conditions.d.ts.map +1 -0
- package/dist/types/conditions.js +1 -0
- package/dist/types/db.d.ts +22 -0
- package/dist/types/db.d.ts.map +1 -0
- package/dist/types/db.js +1 -0
- package/dist/types/dml.d.ts +66 -0
- package/dist/types/dml.d.ts.map +1 -0
- package/dist/types/dml.js +1 -0
- package/dist/types/join.d.ts +44 -0
- package/dist/types/join.d.ts.map +1 -0
- package/dist/types/join.js +1 -0
- package/dist/types/plugin.d.ts +20 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +1 -0
- package/dist/types/schema.d.ts +10 -0
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/types/schema.js +1 -0
- package/dist/types/search.d.ts +45 -0
- package/dist/types/search.d.ts.map +1 -0
- package/dist/types/search.js +1 -0
- package/dist/types/table.d.ts +76 -0
- package/dist/types/table.d.ts.map +1 -0
- package/dist/types/table.js +7 -0
- package/dist/types/tenant.d.ts +19 -0
- package/dist/types/tenant.d.ts.map +1 -0
- package/dist/types/tenant.js +1 -0
- package/dist/types/validation.d.ts +21 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +1 -0
- package/dist/types.d.ts +12 -277
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +12 -7
- package/package.json +3 -3
|
@@ -1,8 +1,45 @@
|
|
|
1
|
+
import type { FastifyRequest } from 'fastify';
|
|
1
2
|
import type { QueryClient } from '../db.js';
|
|
2
3
|
import type { ITable, DbTables, JoinDefinition } from '../../types.js';
|
|
3
|
-
export declare function findWriteJoin(tableConf: ITable,
|
|
4
|
+
export declare function findWriteJoin(tableConf: ITable, alias: string): JoinDefinition | undefined;
|
|
4
5
|
export declare function removeExcludedFields(record: Record<string, unknown>, tableConf: ITable): Record<string, unknown>;
|
|
5
6
|
export declare function findSecondaryTableConf(dbTables: DbTables, joinTableName: string): ITable | undefined;
|
|
7
|
+
interface PrepareCtx {
|
|
8
|
+
db: QueryClient;
|
|
9
|
+
tableConf: ITable;
|
|
10
|
+
request: FastifyRequest;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Prepare a single record for INSERT/UPSERT:
|
|
14
|
+
* 1. shallow camelCase copy of `input`
|
|
15
|
+
* 2. runValidation (camelCase)
|
|
16
|
+
* 3. beforeInsert hook (caller can mutate the camelCase copy)
|
|
17
|
+
* 4. snakecaseRecord → DB format
|
|
18
|
+
* 5. removeExcludedFields
|
|
19
|
+
*
|
|
20
|
+
* Returns both `camel` (input + hook mutations, used for FK auto-fill / afterInsert) and
|
|
21
|
+
* `snake` (DB-ready record). The original `input` is left intact.
|
|
22
|
+
*
|
|
23
|
+
* Pass `secondaries` so the validate hook receives them; pass undefined to skip
|
|
24
|
+
* secondaries-aware validation (e.g. when a bulk-level validator already ran).
|
|
25
|
+
*/
|
|
26
|
+
export declare function prepareInsertRecord(ctx: PrepareCtx, input: Record<string, unknown>, secondaries?: Record<string, Record<string, unknown>[]>, options?: {
|
|
27
|
+
skipValidate?: boolean;
|
|
28
|
+
}): Promise<{
|
|
29
|
+
camel: Record<string, unknown>;
|
|
30
|
+
snake: Record<string, unknown>;
|
|
31
|
+
}>;
|
|
6
32
|
export declare function processSecondaries(db: QueryClient, tableConf: ITable, dbTables: DbTables, mainRecord: Record<string, unknown>, secondaries: Record<string, Record<string, unknown>[]>): Promise<Record<string, Record<string, unknown>[]>>;
|
|
7
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Process per-alias deletion requests for a write join.
|
|
35
|
+
*
|
|
36
|
+
* The FK from `mainRecord` (matching `joinDef.mainField` → `joinDef.joinField`) is
|
|
37
|
+
* auto-injected into every deletion record. This means the consumer can provide just
|
|
38
|
+
* the PK (e.g. `{ id: 5 }`) and the engine will run
|
|
39
|
+
* `DELETE FROM child WHERE id = 5 AND fk_to_main = <main.id>` — both ergonomic
|
|
40
|
+
* (no need to repeat the FK) and safer (cannot accidentally delete a row that
|
|
41
|
+
* doesn't belong to this main).
|
|
42
|
+
*/
|
|
43
|
+
export declare function processDeletions(db: QueryClient, tableConf: ITable, mainRecord: Record<string, unknown>, deletions: Record<string, Record<string, unknown>[]>): Promise<Record<string, Record<string, unknown>[]>>;
|
|
44
|
+
export {};
|
|
8
45
|
//# sourceMappingURL=write-helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/engine/write-helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"write-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/engine/write-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,KAAK,EACV,MAAM,EACN,QAAQ,EACR,cAAc,EAEf,MAAM,gBAAgB,CAAC;AAExB,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,cAAc,GAAG,SAAS,CAE5B;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,SAAS,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,GACpB,MAAM,GAAG,SAAS,CAKpB;AAED,UAAU,UAAU;IAClB,EAAE,EAAE,WAAW,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,cAAc,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,EACvD,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GACnC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAe7E;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,GACrD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CA2DpD;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,GACnD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CA+BpD"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { camelcaseObject, snakecaseRecord } from '../naming.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { runValidation } from './validate.js';
|
|
3
|
+
export function findWriteJoin(tableConf, alias) {
|
|
4
|
+
return tableConf.allowedWriteJoins?.find((j) => j.alias === alias);
|
|
4
5
|
}
|
|
5
6
|
export function removeExcludedFields(record, tableConf) {
|
|
6
7
|
if (!tableConf.excludeFromCreation?.length)
|
|
@@ -19,17 +20,43 @@ export function findSecondaryTableConf(dbTables, joinTableName) {
|
|
|
19
20
|
}
|
|
20
21
|
return undefined;
|
|
21
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Prepare a single record for INSERT/UPSERT:
|
|
25
|
+
* 1. shallow camelCase copy of `input`
|
|
26
|
+
* 2. runValidation (camelCase)
|
|
27
|
+
* 3. beforeInsert hook (caller can mutate the camelCase copy)
|
|
28
|
+
* 4. snakecaseRecord → DB format
|
|
29
|
+
* 5. removeExcludedFields
|
|
30
|
+
*
|
|
31
|
+
* Returns both `camel` (input + hook mutations, used for FK auto-fill / afterInsert) and
|
|
32
|
+
* `snake` (DB-ready record). The original `input` is left intact.
|
|
33
|
+
*
|
|
34
|
+
* Pass `secondaries` so the validate hook receives them; pass undefined to skip
|
|
35
|
+
* secondaries-aware validation (e.g. when a bulk-level validator already ran).
|
|
36
|
+
*/
|
|
37
|
+
export async function prepareInsertRecord(ctx, input, secondaries, options) {
|
|
38
|
+
const camel = { ...input };
|
|
39
|
+
if (!options?.skipValidate) {
|
|
40
|
+
await runValidation(ctx.db, ctx.request, ctx.tableConf, camel, secondaries);
|
|
41
|
+
}
|
|
42
|
+
if (ctx.tableConf.beforeInsert) {
|
|
43
|
+
await ctx.tableConf.beforeInsert(ctx.db, ctx.request, camel);
|
|
44
|
+
}
|
|
45
|
+
let snake = snakecaseRecord(camel, ctx.tableConf.Schema);
|
|
46
|
+
snake = removeExcludedFields(snake, ctx.tableConf);
|
|
47
|
+
return { camel, snake };
|
|
48
|
+
}
|
|
22
49
|
export async function processSecondaries(db, tableConf, dbTables, mainRecord, secondaries) {
|
|
23
50
|
const results = {};
|
|
24
|
-
for (const [
|
|
51
|
+
for (const [alias, records] of Object.entries(secondaries)) {
|
|
25
52
|
if (!records?.length)
|
|
26
53
|
continue;
|
|
27
|
-
const joinDef = findWriteJoin(tableConf,
|
|
54
|
+
const joinDef = findWriteJoin(tableConf, alias);
|
|
28
55
|
if (!joinDef)
|
|
29
56
|
continue;
|
|
30
|
-
const
|
|
57
|
+
const { joinSchema, joinField, mainField } = joinDef;
|
|
31
58
|
const joinCol = joinSchema.col(joinField);
|
|
32
|
-
const secondaryTableConf = findSecondaryTableConf(dbTables,
|
|
59
|
+
const secondaryTableConf = findSecondaryTableConf(dbTables, joinSchema.tableName);
|
|
33
60
|
const secondaryPk = secondaryTableConf?.primary || joinField;
|
|
34
61
|
const secondaryPkCol = Array.isArray(secondaryPk)
|
|
35
62
|
? secondaryPk.map((f) => joinSchema.col(f))
|
|
@@ -56,28 +83,44 @@ export async function processSecondaries(db, tableConf, dbTables, mainRecord, se
|
|
|
56
83
|
else {
|
|
57
84
|
pkRows = await db.bulkInsert(joinSchema.tableName, preparedRecords, secondaryPkCol);
|
|
58
85
|
}
|
|
59
|
-
results[
|
|
86
|
+
results[alias] = pkRows.map((r) => camelcaseObject(r, joinSchema));
|
|
60
87
|
}
|
|
61
88
|
return results;
|
|
62
89
|
}
|
|
63
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Process per-alias deletion requests for a write join.
|
|
92
|
+
*
|
|
93
|
+
* The FK from `mainRecord` (matching `joinDef.mainField` → `joinDef.joinField`) is
|
|
94
|
+
* auto-injected into every deletion record. This means the consumer can provide just
|
|
95
|
+
* the PK (e.g. `{ id: 5 }`) and the engine will run
|
|
96
|
+
* `DELETE FROM child WHERE id = 5 AND fk_to_main = <main.id>` — both ergonomic
|
|
97
|
+
* (no need to repeat the FK) and safer (cannot accidentally delete a row that
|
|
98
|
+
* doesn't belong to this main).
|
|
99
|
+
*/
|
|
100
|
+
export async function processDeletions(db, tableConf, mainRecord, deletions) {
|
|
64
101
|
const results = {};
|
|
65
|
-
for (const [
|
|
102
|
+
for (const [alias, records] of Object.entries(deletions)) {
|
|
66
103
|
if (!records?.length)
|
|
67
104
|
continue;
|
|
68
|
-
const joinDef = findWriteJoin(tableConf,
|
|
105
|
+
const joinDef = findWriteJoin(tableConf, alias);
|
|
69
106
|
if (!joinDef)
|
|
70
107
|
continue;
|
|
71
|
-
const
|
|
108
|
+
const { joinSchema, joinField, mainField } = joinDef;
|
|
109
|
+
const joinCol = joinSchema.col(joinField);
|
|
110
|
+
const mainValue = Array.isArray(mainField)
|
|
111
|
+
? mainRecord[mainField[0]]
|
|
112
|
+
: mainRecord[mainField];
|
|
72
113
|
const deletedRows = [];
|
|
73
114
|
for (const rec of records) {
|
|
74
115
|
const snaked = snakecaseRecord(rec, joinSchema);
|
|
116
|
+
// Auto-inject FK to main: scopes the DELETE to children owned by this main.
|
|
117
|
+
snaked[joinCol] = mainValue;
|
|
75
118
|
const affectedRows = await db.delete(joinSchema.tableName, snaked);
|
|
76
119
|
if (affectedRows > 0) {
|
|
77
120
|
deletedRows.push(camelcaseObject(snaked, joinSchema));
|
|
78
121
|
}
|
|
79
122
|
}
|
|
80
|
-
results[
|
|
123
|
+
results[alias] = deletedRows;
|
|
81
124
|
}
|
|
82
125
|
return results;
|
|
83
126
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a plain Error decorated with `statusCode` (and optionally `validationErrors`),
|
|
3
|
+
* which Fastify reads to emit the corresponding HTTP response.
|
|
4
|
+
*
|
|
5
|
+
* Using a function instead of a custom class keeps the throw sites lightweight
|
|
6
|
+
* and matches the existing convention across the codebase.
|
|
7
|
+
*/
|
|
8
|
+
export declare function httpError(statusCode: number, message: string): Error & {
|
|
9
|
+
statusCode: number;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAI7F"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a plain Error decorated with `statusCode` (and optionally `validationErrors`),
|
|
3
|
+
* which Fastify reads to emit the corresponding HTTP response.
|
|
4
|
+
*
|
|
5
|
+
* Using a function instead of a custom class keeps the throw sites lightweight
|
|
6
|
+
* and matches the existing convention across the codebase.
|
|
7
|
+
*/
|
|
8
|
+
export function httpError(statusCode, message) {
|
|
9
|
+
const err = new Error(message);
|
|
10
|
+
err.statusCode = statusCode;
|
|
11
|
+
return err;
|
|
12
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-upsert.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/bulk-upsert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"bulk-upsert.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/bulk-upsert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAS/C,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oGAgBxE;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,oGAa5E"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
2
|
import { primaryAsString } from '../../types.js';
|
|
3
|
-
import {
|
|
4
|
-
import { pkSchema, buildSecondaryFields, applySchemaOverrides } from './helpers.js';
|
|
3
|
+
import { pkSchema, applySchemaOverrides, attachWriteJoinSections, writeJoinBodyFields, writeJoinResponseFields, } from './helpers.js';
|
|
5
4
|
export function BulkUpsertTableBody(dbTables, tableName) {
|
|
6
5
|
const tableConf = dbTables[tableName];
|
|
7
6
|
const schema = tableConf.Schema;
|
|
@@ -9,18 +8,10 @@ export function BulkUpsertTableBody(dbTables, tableName) {
|
|
|
9
8
|
const itemProperties = {
|
|
10
9
|
main: mainSchema,
|
|
11
10
|
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const secondaryTableConf = findSecondaryTableConf(dbTables, joinSchema.tableName);
|
|
17
|
-
const joinFields = buildSecondaryFields(joinSchema, joinField, secondaryTableConf);
|
|
18
|
-
secondaryProperties[joinSchema.tableName] = Type.Array(Type.Object(joinFields));
|
|
19
|
-
deletionProperties[joinSchema.tableName] = Type.Array(Type.Partial(Type.Object(joinSchema.fields)));
|
|
20
|
-
}
|
|
21
|
-
itemProperties.secondaries = Type.Optional(Type.Partial(Type.Object(secondaryProperties)));
|
|
22
|
-
itemProperties.deletions = Type.Optional(Type.Partial(Type.Object(deletionProperties)));
|
|
23
|
-
}
|
|
11
|
+
attachWriteJoinSections(itemProperties, tableConf, dbTables, {
|
|
12
|
+
withDeletions: true,
|
|
13
|
+
secondaryFields: writeJoinBodyFields,
|
|
14
|
+
});
|
|
24
15
|
return Type.Array(Type.Object(itemProperties));
|
|
25
16
|
}
|
|
26
17
|
export function BulkUpsertTableResponse(dbTables, tableName) {
|
|
@@ -28,16 +19,9 @@ export function BulkUpsertTableResponse(dbTables, tableName) {
|
|
|
28
19
|
const responseProperties = {
|
|
29
20
|
main: Type.Object(pkSchema(tableConf, tableConf.Schema, primaryAsString(tableConf.primary))),
|
|
30
21
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const secondaryTableConf = findSecondaryTableConf(dbTables, joinSchema.tableName);
|
|
36
|
-
secondaryProperties[joinSchema.tableName] = Type.Array(Type.Object(pkSchema(secondaryTableConf, joinSchema, joinField)));
|
|
37
|
-
deletionProperties[joinSchema.tableName] = Type.Array(Type.Partial(Type.Object(joinSchema.fields)));
|
|
38
|
-
}
|
|
39
|
-
responseProperties.secondaries = Type.Optional(Type.Partial(Type.Object(secondaryProperties)));
|
|
40
|
-
responseProperties.deletions = Type.Optional(Type.Partial(Type.Object(deletionProperties)));
|
|
41
|
-
}
|
|
22
|
+
attachWriteJoinSections(responseProperties, tableConf, dbTables, {
|
|
23
|
+
withDeletions: true,
|
|
24
|
+
secondaryFields: writeJoinResponseFields,
|
|
25
|
+
});
|
|
42
26
|
return Type.Array(Type.Object(responseProperties));
|
|
43
27
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type TSchema } from '@sinclair/typebox';
|
|
2
|
-
import type { ITable, SchemaDefinition } from '../../types.js';
|
|
2
|
+
import type { ITable, SchemaDefinition, DbTables, JoinDefinition } from '../../types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Build a PK-only schema for response shapes (single or composite PK).
|
|
5
5
|
* Falls back to `fallback` field if tableConf is undefined.
|
|
@@ -16,4 +16,31 @@ export declare function buildSecondaryFields(joinSchema: SchemaDefinition, joinF
|
|
|
16
16
|
* Replaces matching field schemas with the override.
|
|
17
17
|
*/
|
|
18
18
|
export declare function applySchemaOverrides(fields: Record<string, TSchema>, tableConf: ITable): Record<string, TSchema>;
|
|
19
|
+
type JoinFieldsBuilder = (join: JoinDefinition, secondaryConf: ITable | undefined) => Record<string, TSchema>;
|
|
20
|
+
/**
|
|
21
|
+
* Maps each writeJoin alias to a Type.Array(Type.Object(...)) using the provided fields builder.
|
|
22
|
+
* When `itemsPartial` is true, wraps each item with Type.Partial — used for deletion sub-schemas
|
|
23
|
+
* where every field is a matcher (the engine auto-injects the FK to main).
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildJoinAliasMap(tableConf: ITable, dbTables: DbTables, build: JoinFieldsBuilder, options?: {
|
|
26
|
+
itemsPartial?: boolean;
|
|
27
|
+
}): Record<string, TSchema>;
|
|
28
|
+
/**
|
|
29
|
+
* Attach `secondaries` (and optionally `deletions`) sections to the given target object,
|
|
30
|
+
* iterating once over `tableConf.allowedWriteJoins`. Mutates `target` in-place.
|
|
31
|
+
* Used by body and response schema builders for insert/update/bulk-upsert.
|
|
32
|
+
*
|
|
33
|
+
* Deletions are emitted with every field Optional (Type.Partial) because the engine
|
|
34
|
+
* auto-injects the FK to main and the consumer typically just provides the PK (or a small
|
|
35
|
+
* subset of fields) to identify which child rows to delete.
|
|
36
|
+
*/
|
|
37
|
+
export declare function attachWriteJoinSections(target: Record<string, TSchema>, tableConf: ITable, dbTables: DbTables, options: {
|
|
38
|
+
withDeletions: boolean;
|
|
39
|
+
secondaryFields: JoinFieldsBuilder;
|
|
40
|
+
}): void;
|
|
41
|
+
/** JoinFieldsBuilder for body schemas: includes all join fields with FK + excluded made Optional. */
|
|
42
|
+
export declare const writeJoinBodyFields: JoinFieldsBuilder;
|
|
43
|
+
/** JoinFieldsBuilder for response schemas: PK only. */
|
|
44
|
+
export declare const writeJoinResponseFields: JoinFieldsBuilder;
|
|
45
|
+
export {};
|
|
19
46
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGzF;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQ3H;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,gBAAgB,EAC5B,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,GAAG,SAAS,GACrC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgBzB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,SAAS,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED,KAAK,iBAAiB,GAAG,CACvB,IAAI,EAAE,cAAc,EACpB,aAAa,EAAE,MAAM,GAAG,SAAS,KAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE7B;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE;IAAE,aAAa,EAAE,OAAO,CAAC;IAAC,eAAe,EAAE,iBAAiB,CAAA;CAAE,GACtE,IAAI,CAmBN;AAED,qGAAqG;AACrG,eAAO,MAAM,mBAAmB,EAAE,iBACmB,CAAC;AAEtD,uDAAuD;AACvD,eAAO,MAAM,uBAAuB,EAAE,iBACG,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
|
+
import { findSecondaryTableConf } from '../engine/write-helpers.js';
|
|
2
3
|
/**
|
|
3
4
|
* Build a PK-only schema for response shapes (single or composite PK).
|
|
4
5
|
* Falls back to `fallback` field if tableConf is undefined.
|
|
@@ -46,3 +47,40 @@ export function applySchemaOverrides(fields, tableConf) {
|
|
|
46
47
|
}
|
|
47
48
|
return result;
|
|
48
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Maps each writeJoin alias to a Type.Array(Type.Object(...)) using the provided fields builder.
|
|
52
|
+
* When `itemsPartial` is true, wraps each item with Type.Partial — used for deletion sub-schemas
|
|
53
|
+
* where every field is a matcher (the engine auto-injects the FK to main).
|
|
54
|
+
*/
|
|
55
|
+
export function buildJoinAliasMap(tableConf, dbTables, build, options = {}) {
|
|
56
|
+
const out = {};
|
|
57
|
+
if (!tableConf.allowedWriteJoins?.length)
|
|
58
|
+
return out;
|
|
59
|
+
for (const j of tableConf.allowedWriteJoins) {
|
|
60
|
+
const sc = findSecondaryTableConf(dbTables, j.joinSchema.tableName);
|
|
61
|
+
const item = Type.Object(build(j, sc));
|
|
62
|
+
out[j.alias] = Type.Array(options.itemsPartial ? Type.Partial(item) : item);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Attach `secondaries` (and optionally `deletions`) sections to the given target object,
|
|
68
|
+
* iterating once over `tableConf.allowedWriteJoins`. Mutates `target` in-place.
|
|
69
|
+
* Used by body and response schema builders for insert/update/bulk-upsert.
|
|
70
|
+
*
|
|
71
|
+
* Deletions are emitted with every field Optional (Type.Partial) because the engine
|
|
72
|
+
* auto-injects the FK to main and the consumer typically just provides the PK (or a small
|
|
73
|
+
* subset of fields) to identify which child rows to delete.
|
|
74
|
+
*/
|
|
75
|
+
export function attachWriteJoinSections(target, tableConf, dbTables, options) {
|
|
76
|
+
if (!tableConf.allowedWriteJoins?.length)
|
|
77
|
+
return;
|
|
78
|
+
target.secondaries = Type.Optional(Type.Partial(Type.Object(buildJoinAliasMap(tableConf, dbTables, options.secondaryFields))));
|
|
79
|
+
if (options.withDeletions) {
|
|
80
|
+
target.deletions = Type.Optional(Type.Partial(Type.Object(buildJoinAliasMap(tableConf, dbTables, ({ joinSchema }) => joinSchema.fields, { itemsPartial: true }))));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** JoinFieldsBuilder for body schemas: includes all join fields with FK + excluded made Optional. */
|
|
84
|
+
export const writeJoinBodyFields = (j, sc) => buildSecondaryFields(j.joinSchema, j.joinField, sc);
|
|
85
|
+
/** JoinFieldsBuilder for response schemas: PK only. */
|
|
86
|
+
export const writeJoinResponseFields = (j, sc) => pkSchema(sc, j.joinSchema, j.joinField);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insert.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/insert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAErE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"insert.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/insert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAErE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAS/C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAsB9E;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAalF"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
2
|
import { primaryAsString } from '../../types.js';
|
|
3
|
-
import {
|
|
4
|
-
import { pkSchema, buildSecondaryFields, applySchemaOverrides } from './helpers.js';
|
|
3
|
+
import { pkSchema, applySchemaOverrides, attachWriteJoinSections, writeJoinBodyFields, writeJoinResponseFields, } from './helpers.js';
|
|
5
4
|
export function InsertTableBody(dbTables, tableName) {
|
|
6
5
|
const tableConf = dbTables[tableName];
|
|
7
6
|
const schema = tableConf.Schema;
|
|
@@ -15,15 +14,10 @@ export function InsertTableBody(dbTables, tableName) {
|
|
|
15
14
|
const bodyProperties = {
|
|
16
15
|
main: Type.Object(mainFields),
|
|
17
16
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const joinFields = buildSecondaryFields(joinSchema, joinField, secondaryTableConf);
|
|
23
|
-
secondaryProperties[joinSchema.tableName] = Type.Array(Type.Object(joinFields));
|
|
24
|
-
}
|
|
25
|
-
bodyProperties.secondaries = Type.Optional(Type.Partial(Type.Object(secondaryProperties)));
|
|
26
|
-
}
|
|
17
|
+
attachWriteJoinSections(bodyProperties, tableConf, dbTables, {
|
|
18
|
+
withDeletions: false,
|
|
19
|
+
secondaryFields: writeJoinBodyFields,
|
|
20
|
+
});
|
|
27
21
|
return Type.Object(bodyProperties);
|
|
28
22
|
}
|
|
29
23
|
export function InsertTableResponse(dbTables, tableName) {
|
|
@@ -31,13 +25,9 @@ export function InsertTableResponse(dbTables, tableName) {
|
|
|
31
25
|
const responseProperties = {
|
|
32
26
|
main: Type.Object(pkSchema(tableConf, tableConf.Schema, primaryAsString(tableConf.primary))),
|
|
33
27
|
};
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
secondaryProperties[joinSchema.tableName] = Type.Array(Type.Object(pkSchema(secondaryTableConf, joinSchema, joinField)));
|
|
39
|
-
}
|
|
40
|
-
responseProperties.secondaries = Type.Optional(Type.Partial(Type.Object(secondaryProperties)));
|
|
41
|
-
}
|
|
28
|
+
attachWriteJoinSections(responseProperties, tableConf, dbTables, {
|
|
29
|
+
withDeletions: false,
|
|
30
|
+
secondaryFields: writeJoinResponseFields,
|
|
31
|
+
});
|
|
42
32
|
return Type.Object(responseProperties);
|
|
43
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAErE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAErE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAY/C,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAuHlF;AAED,eAAO,MAAM,sBAAsB;;;;;;;;EASjC,CAAC;AAEH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAmElF"}
|