fastify-auto-sqlapi 0.0.3 → 0.0.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/AGENTS.md +2 -2
- package/AGENTS_BACKEND.md +111 -15
- package/AGENTS_FRONTEND.md +126 -1
- package/README.md +135 -18
- package/dist/bin/generate-schema.js +3 -3
- package/dist/bin/generate-tables.js +1 -1
- package/dist/bin/utils.d.ts +1 -1
- package/dist/bin/utils.d.ts.map +1 -1
- package/dist/bin/utils.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/cli/mysql-introspect.d.ts.map +1 -1
- package/dist/lib/cli/mysql-introspect.js +9 -2
- package/dist/lib/cli/pg-introspect.d.ts.map +1 -1
- package/dist/lib/cli/pg-introspect.js +8 -1
- package/dist/lib/cli/schema-codegen.d.ts +1 -1
- package/dist/lib/cli/schema-codegen.d.ts.map +1 -1
- package/dist/lib/cli/schema-codegen.js +11 -4
- package/dist/lib/cli/tables-codegen.d.ts.map +1 -1
- package/dist/lib/cli/tables-codegen.js +30 -1
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +10 -4
- package/dist/lib/engine/bulk/bulk-upsert.d.ts.map +1 -1
- package/dist/lib/engine/bulk/bulk-upsert.js +41 -27
- package/dist/lib/engine/rest/get.js +1 -1
- package/dist/lib/engine/rest/insert.d.ts.map +1 -1
- package/dist/lib/engine/rest/insert.js +25 -21
- package/dist/lib/engine/rest/update.d.ts.map +1 -1
- package/dist/lib/engine/rest/update.js +42 -38
- package/dist/lib/engine/search/search.d.ts.map +1 -1
- package/dist/lib/engine/search/search.js +235 -39
- package/dist/lib/engine/validate.d.ts +11 -0
- package/dist/lib/engine/validate.d.ts.map +1 -0
- package/dist/lib/engine/validate.js +29 -0
- package/dist/lib/engine/write-helpers.js +4 -4
- package/dist/lib/naming.d.ts +11 -2
- package/dist/lib/naming.d.ts.map +1 -1
- package/dist/lib/naming.js +33 -5
- package/dist/lib/schema/bulk-upsert.js +2 -2
- package/dist/lib/schema/helpers.d.ts +5 -0
- package/dist/lib/schema/helpers.d.ts.map +1 -1
- package/dist/lib/schema/helpers.js +15 -0
- package/dist/lib/schema/insert.js +2 -2
- package/dist/lib/schema/search.d.ts.map +1 -1
- package/dist/lib/schema/search.js +16 -10
- package/dist/lib/schema/update.d.ts.map +1 -1
- package/dist/lib/schema/update.js +4 -3
- package/dist/lib/table-helpers.d.ts.map +1 -1
- package/dist/lib/table-helpers.js +9 -1
- package/dist/routes/auto/plugin.d.ts.map +1 -1
- package/dist/routes/auto/plugin.js +12 -1
- package/dist/types.d.ts +47 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -4,7 +4,6 @@ import * as path from 'node:path';
|
|
|
4
4
|
import { loadConfig } from '../lib/cli/config.js';
|
|
5
5
|
import { parseSchemaFile, generateSingleTableFile, generateDbTablesIndex } from '../lib/cli/tables-codegen.js';
|
|
6
6
|
import { loadEnvFile, CONSOLE_COLORS, display, displayAsTableRow, error } from './utils.js';
|
|
7
|
-
loadEnvFile();
|
|
8
7
|
function printHelp() {
|
|
9
8
|
console.log('');
|
|
10
9
|
display('Usage:', CONSOLE_COLORS.yellow);
|
|
@@ -53,6 +52,7 @@ async function main() {
|
|
|
53
52
|
}
|
|
54
53
|
display('++++++ fastify-auto-sqlapi: generating tables template ++++++', CONSOLE_COLORS.yellow);
|
|
55
54
|
const config = await loadConfig();
|
|
55
|
+
loadEnvFile(config.envFile);
|
|
56
56
|
const outputDir = path.resolve(process.cwd(), cliArgs.output || config.outputDir);
|
|
57
57
|
const schemasDir = path.join(outputDir, 'schemas');
|
|
58
58
|
const tablesDir = path.join(outputDir, 'tables');
|
package/dist/bin/utils.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Load .env file from cwd if it exists.
|
|
3
3
|
* Does not override already-set environment variables.
|
|
4
4
|
*/
|
|
5
|
-
export declare function loadEnvFile(): void;
|
|
5
|
+
export declare function loadEnvFile(envFile?: string): void;
|
|
6
6
|
export declare const CONSOLE_COLORS: {
|
|
7
7
|
readonly black: 30;
|
|
8
8
|
readonly gray: 90;
|
package/dist/bin/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/bin/utils.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,WAAW,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/bin/utils.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAqBlD;AAED,eAAO,MAAM,cAAc;;;;;;;;CAQjB,CAAC;AAEX,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAU,GAChB,IAAI,CAQN;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,IAAI,CAE7D;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAExC"}
|
package/dist/bin/utils.js
CHANGED
|
@@ -4,8 +4,8 @@ import { resolve } from 'node:path';
|
|
|
4
4
|
* Load .env file from cwd if it exists.
|
|
5
5
|
* Does not override already-set environment variables.
|
|
6
6
|
*/
|
|
7
|
-
export function loadEnvFile() {
|
|
8
|
-
const envPath = resolve(process.cwd(), '.env');
|
|
7
|
+
export function loadEnvFile(envFile) {
|
|
8
|
+
const envPath = resolve(process.cwd(), envFile || '.env');
|
|
9
9
|
if (!existsSync(envPath))
|
|
10
10
|
return;
|
|
11
11
|
const content = readFileSync(envPath, 'utf-8');
|
package/dist/index.d.ts
CHANGED
|
@@ -30,5 +30,5 @@ export { BulkDeleteTableBody, BulkDeleteTableResponse } from './lib/schema/bulk-
|
|
|
30
30
|
export { default as bulkDeleteRoutes } from './routes/auto/bulk-delete.routes.js';
|
|
31
31
|
export { Type, type Static } from '@sinclair/typebox';
|
|
32
32
|
export { ConditionBuilder, Expression } from 'node-condition-builder';
|
|
33
|
-
export type { SqlApiConfig, ColumnInfo, TableMap, Queryable, SqlResult, DbRecord, DbRecordValue, SelectOptions, SchemaDefinition, JoinDefinition, ITable, DbTables, SqlApiPluginOptions, SwaggerOptions, SearchParams, SearchResult, Paginator, PaginationResult, TableFilterFn, ExtendedConditionFn, FilterRecord, AggregationRequest, JoinGroupRequest, GetParams, GetResult, DeleteParams, DeleteResult, InsertParams, InsertResult, BulkUpsertItem, BulkUpsertParams, BulkUpsertResult, BulkDeleteParams, BulkDeleteResult, ConditionMethod, SearchCondition, UpdateParams, UpdateResult, TenantId, TenantScope, TenantScopeDirect, TenantScopeIndirect, TenantContext, } from './types.js';
|
|
33
|
+
export type { SqlApiConfig, ColumnInfo, TableMap, Queryable, SqlResult, DbRecord, DbRecordValue, SelectOptions, SchemaDefinition, JoinDefinition, ITable, DbTables, SqlApiPluginOptions, SwaggerOptions, SearchParams, SearchResult, Paginator, PaginationResult, TableFilterFn, ExtendedConditionFn, FilterRecord, AggregationRequest, JoinGroupRequest, GetParams, GetResult, DeleteParams, DeleteResult, InsertParams, InsertResult, BulkUpsertItem, BulkUpsertParams, BulkUpsertResult, BulkDeleteParams, BulkDeleteResult, ConditionMethod, SearchCondition, UpdateParams, UpdateResult, TenantId, TenantScope, TenantScopeDirect, TenantScopeIndirect, TenantContext, ValidationError, ValidatorFn, BulkValidatorItem, BulkValidatorFn, } from './types.js';
|
|
34
34
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mysql-introspect.d.ts","sourceRoot":"","sources":["../../../src/lib/cli/mysql-introspect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,wBAAgB,0BAA0B,IAAI;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAmBA;AAkDD,wBAAsB,qBAAqB,CACzC,gBAAgB,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAClG,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"mysql-introspect.d.ts","sourceRoot":"","sources":["../../../src/lib/cli/mysql-introspect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,wBAAgB,0BAA0B,IAAI;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAmBA;AAkDD,wBAAsB,qBAAqB,CACzC,gBAAgB,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAClG,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,EAAE,CAAC,CAuCvB"}
|
|
@@ -67,7 +67,8 @@ function mapMysqlType(dataType) {
|
|
|
67
67
|
}
|
|
68
68
|
export async function introspectMysqlTables(connectionConfig, schema) {
|
|
69
69
|
// Dynamic import: mysql2 is optional peer dependency.
|
|
70
|
-
//
|
|
70
|
+
// Try the consumer's CWD first (so it works when installed), then fall back to
|
|
71
|
+
// the plugin's own node_modules (so it works in the plugin's own tests).
|
|
71
72
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
73
|
let mysql2;
|
|
73
74
|
try {
|
|
@@ -75,7 +76,13 @@ export async function introspectMysqlTables(connectionConfig, schema) {
|
|
|
75
76
|
mysql2 = require('mysql2/promise');
|
|
76
77
|
}
|
|
77
78
|
catch {
|
|
78
|
-
|
|
79
|
+
try {
|
|
80
|
+
const require = createRequire(import.meta.url);
|
|
81
|
+
mysql2 = require('mysql2/promise');
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
throw new Error('mysql2 is required for MySQL/MariaDB introspection. Install it with: npm install mysql2');
|
|
85
|
+
}
|
|
79
86
|
}
|
|
80
87
|
const connection = await mysql2.createConnection(connectionConfig);
|
|
81
88
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-introspect.d.ts","sourceRoot":"","sources":["../../../src/lib/cli/pg-introspect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,wBAAgB,qBAAqB,IAAI,MAAM,CAY9C;AAED,wBAAsB,gBAAgB,CACpC,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"pg-introspect.d.ts","sourceRoot":"","sources":["../../../src/lib/cli/pg-introspect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,wBAAgB,qBAAqB,IAAI,MAAM,CAY9C;AAED,wBAAsB,gBAAgB,CACpC,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,EAAE,CAAC,CAkCvB"}
|
|
@@ -19,7 +19,14 @@ export async function introspectTables(connectionString, schema) {
|
|
|
19
19
|
pg = require('pg');
|
|
20
20
|
}
|
|
21
21
|
catch {
|
|
22
|
-
|
|
22
|
+
try {
|
|
23
|
+
// Fallback: resolve from the package's own node_modules
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
pg = require('pg');
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw new Error('pg is required for PostgreSQL introspection. Install it with: npm install pg');
|
|
29
|
+
}
|
|
23
30
|
}
|
|
24
31
|
const client = new pg.Client({ connectionString });
|
|
25
32
|
try {
|
|
@@ -4,5 +4,5 @@ export declare function convertColType(udtName: string, columnInfo: {
|
|
|
4
4
|
is_nullable: string;
|
|
5
5
|
}): string;
|
|
6
6
|
export declare function buildTableMap(rows: ColumnInfo[]): TableMap;
|
|
7
|
-
export declare function generateSchemaFile(schemaName: string, tableName: string, fields: Record<string, string>): string;
|
|
7
|
+
export declare function generateSchemaFile(schemaName: string, tableName: string, fields: Record<string, string>, colMap: Record<string, string>): string;
|
|
8
8
|
//# sourceMappingURL=schema-codegen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-codegen.d.ts","sourceRoot":"","sources":["../../../src/lib/cli/schema-codegen.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE3D,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE;IAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACjE,MAAM,CAoDR;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"schema-codegen.d.ts","sourceRoot":"","sources":["../../../src/lib/cli/schema-codegen.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE3D,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE;IAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACjE,MAAM,CAoDR;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,QAAQ,CAqB1D;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,CA2CR"}
|
|
@@ -57,20 +57,26 @@ export function buildTableMap(rows) {
|
|
|
57
57
|
acc[schemaName] = {
|
|
58
58
|
name: row.table_name,
|
|
59
59
|
fields: {},
|
|
60
|
+
colMap: {},
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
|
-
|
|
63
|
+
const fieldName = toCamelCase(row.column_name);
|
|
64
|
+
acc[schemaName].fields[fieldName] = convertColType(row.udt_name, row);
|
|
65
|
+
acc[schemaName].colMap[fieldName] = row.column_name;
|
|
63
66
|
return acc;
|
|
64
67
|
}, {});
|
|
65
68
|
}
|
|
66
|
-
export function generateSchemaFile(schemaName, tableName, fields) {
|
|
69
|
+
export function generateSchemaFile(schemaName, tableName, fields, colMap) {
|
|
67
70
|
const fieldsStr = JSON.stringify(fields, null, 2).replace(/"(.*?)"\s*:\s*"Type(.*?)"/g, '$1: Type$2');
|
|
71
|
+
const colMapStr = JSON.stringify(colMap, null, 2);
|
|
68
72
|
return `// Auto-generated by fastify-auto-sqlapi. Do not edit.
|
|
69
|
-
import { Type
|
|
73
|
+
import { Type } from "fastify-auto-sqlapi";
|
|
70
74
|
import type { Static } from "fastify-auto-sqlapi";
|
|
71
75
|
|
|
72
76
|
const _Schema = ${fieldsStr};
|
|
73
77
|
|
|
78
|
+
const _colMap: Record<string, string> = ${colMapStr};
|
|
79
|
+
|
|
74
80
|
const validation = Type.Object(_Schema, { $id: "${schemaName}" });
|
|
75
81
|
const partialValidation = Type.Object(
|
|
76
82
|
Object.fromEntries(
|
|
@@ -83,7 +89,8 @@ const partialValidation = Type.Object(
|
|
|
83
89
|
);
|
|
84
90
|
|
|
85
91
|
export const Schema = {
|
|
86
|
-
col: (f: keyof typeof _Schema) =>
|
|
92
|
+
col: (f: keyof typeof _Schema) => _colMap[f as string] ?? f,
|
|
93
|
+
colMap: _colMap,
|
|
87
94
|
fields: _Schema,
|
|
88
95
|
validation,
|
|
89
96
|
tableName: "${tableName}",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tables-codegen.d.ts","sourceRoot":"","sources":["../../../src/lib/cli/tables-codegen.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA2BpE;AAgBD,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,gBAAgB,EAAE,CAwB3E;AAID,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"tables-codegen.d.ts","sourceRoot":"","sources":["../../../src/lib/cli/tables-codegen.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA2BpE;AAgBD,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,gBAAgB,EAAE,CAwB3E;AAID,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,MAAM,CAwHhG;AAID,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAqBrE;AAID,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CA6FlE"}
|
|
@@ -98,6 +98,7 @@ export function generateSingleTableFile(schema, allSchemas) {
|
|
|
98
98
|
const lines = [];
|
|
99
99
|
// Imports
|
|
100
100
|
lines.push(`import {defineTable, exportTableInfo, Type} from 'fastify-auto-sqlapi';`);
|
|
101
|
+
lines.push(`import type {ValidationError} from 'fastify-auto-sqlapi';`);
|
|
101
102
|
lines.push(`import {${schema.schemaName} as Schema} from '../schemas/${schema.schemaName}';`);
|
|
102
103
|
// Commented imports for related schemas
|
|
103
104
|
for (const relSchema of relatedSchemas) {
|
|
@@ -140,6 +141,27 @@ export function generateSingleTableFile(schema, allSchemas) {
|
|
|
140
141
|
lines.push(` // allowedReadJoins: [],`);
|
|
141
142
|
}
|
|
142
143
|
lines.push(` // upsertMap: buildUpsertRules(buildUpsertRule(Schema, ['${pk}'])),`);
|
|
144
|
+
// schemaOverrides: suggest email format if email field exists, otherwise minLength on first string field
|
|
145
|
+
const emailField = schema.fields.find(f => f.toLowerCase().includes('email'));
|
|
146
|
+
if (emailField) {
|
|
147
|
+
lines.push(` // schemaOverrides: { ${emailField}: Type.String({ format: 'email' }) },`);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const stringField = schema.fields.find(f => f !== pk && schema.fieldTypes[f]?.includes('String'));
|
|
151
|
+
if (stringField) {
|
|
152
|
+
lines.push(` // schemaOverrides: { ${stringField}: Type.String({ minLength: 1 }) },`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
lines.push(` // schemaOverrides: {},`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// validate: use first non-PK field for example
|
|
159
|
+
const exampleField = schema.fields.find(f => f !== pk) || schema.fields[0];
|
|
160
|
+
lines.push(` validate: async (db, req, main, secondaries) => {`);
|
|
161
|
+
lines.push(` const errors: ValidationError[] = [];`);
|
|
162
|
+
lines.push(` // if (!main.${exampleField}) errors.push(['${exampleField}', 'required']);`);
|
|
163
|
+
lines.push(` return errors;`);
|
|
164
|
+
lines.push(` },`);
|
|
143
165
|
lines.push(` // beforeInsert: async (db, req, record) => {},`);
|
|
144
166
|
lines.push(` // beforeUpdate: async (db, req, fields) => {},`);
|
|
145
167
|
if (childRels.length > 0) {
|
|
@@ -188,7 +210,7 @@ export function generateTablesFile(schemas) {
|
|
|
188
210
|
const lines = [];
|
|
189
211
|
// Imports
|
|
190
212
|
lines.push(`import {defineTable, exportTableInfo, Type} from 'fastify-auto-sqlapi';`);
|
|
191
|
-
lines.push(`import type { DbTables } from 'fastify-auto-sqlapi';`);
|
|
213
|
+
lines.push(`import type { DbTables, ValidationError } from 'fastify-auto-sqlapi';`);
|
|
192
214
|
lines.push(``);
|
|
193
215
|
// Schema imports
|
|
194
216
|
for (const schema of schemas) {
|
|
@@ -223,6 +245,13 @@ export function generateTablesFile(schemas) {
|
|
|
223
245
|
lines.push(` // allowedReadJoins: [],`);
|
|
224
246
|
}
|
|
225
247
|
lines.push(` // upsertMap: buildUpsertRules(buildUpsertRule(${schema.schemaName}, ['${pk}'])),`);
|
|
248
|
+
lines.push(` // schemaOverrides: {},`);
|
|
249
|
+
const exampleFieldLegacy = schema.fields.find(f => f !== pk) || schema.fields[0];
|
|
250
|
+
lines.push(` validate: async (db, req, main, secondaries) => {`);
|
|
251
|
+
lines.push(` const errors: ValidationError[] = [];`);
|
|
252
|
+
lines.push(` // if (!main.${exampleFieldLegacy}) errors.push(['${exampleFieldLegacy}', 'required']);`);
|
|
253
|
+
lines.push(` return errors;`);
|
|
254
|
+
lines.push(` },`);
|
|
226
255
|
lines.push(` // beforeInsert: async (db, req, record) => {},`);
|
|
227
256
|
lines.push(` // beforeUpdate: async (db, req, fields) => {},`);
|
|
228
257
|
const childRels = relsByChild.get(schema.schemaName) || [];
|
package/dist/lib/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK/C,sCAAsC;AACtC,eAAO,MAAM,WAAW,GAAI,GAAG,MAAM,WAA0B,CAAC;AAEhE,qBAAa,WAAW;;IACtB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,UAAU;IAKnD,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAE/B;IAED,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAE9B;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAI7B,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU;IAIrC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IA6FlB,MAAM,CACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,QAAQ,EAChB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAoB7B,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,QAAQ,EAChB,YAAY,EAAE,MAAM,EAAE,EACtB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAuB7B,UAAU,CACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,QAAQ,EAAE,EACnB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EACxB,SAAS,SAAqB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK/C,sCAAsC;AACtC,eAAO,MAAM,WAAW,GAAI,GAAG,MAAM,WAA0B,CAAC;AAEhE,qBAAa,WAAW;;IACtB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,UAAU;IAKnD,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAE/B;IAED,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAE9B;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAI7B,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU;IAIrC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IA6FlB,MAAM,CACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,QAAQ,EAChB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAoB7B,cAAc,CAClB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,QAAQ,EAChB,YAAY,EAAE,MAAM,EAAE,EACtB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAuB7B,UAAU,CACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,QAAQ,EAAE,EACnB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EACxB,SAAS,SAAqB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IA+B/B,kBAAkB,CACtB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,QAAQ,EAAE,EACnB,YAAY,EAAE,MAAM,EAAE,EACtB,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EACxB,SAAS,SAAqB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAiC/B,MAAM,CACV,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,QAAQ,EAChB,KAAK,EAAE,QAAQ,EACf,cAAc,CAAC,EAAE,gBAAgB,GAChC,OAAO,CAAC,MAAM,CAAC;IAuBZ,MAAM,CACV,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,QAAQ,GACd,OAAO,CAAC,MAAM,CAAC;IAYZ,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACxC,SAAS,EACT,OAAa,EACb,KAAK,EACL,MAAM,EACN,KAAY,EACZ,OAAY,EACZ,KAAU,EACV,QAAgB,GACjB,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;CAchC;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,EACf,WAAW,CAAC,EAAE,MAAM,GACnB,WAAW,CAGb"}
|
package/dist/lib/db.js
CHANGED
|
@@ -149,8 +149,12 @@ export class QueryClient {
|
|
|
149
149
|
results.push(...result.rows);
|
|
150
150
|
}
|
|
151
151
|
else {
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
// MySQL: insertId is the FIRST generated ID of the multi-row insert.
|
|
153
|
+
// Subsequent rows follow sequentially assuming auto_increment_increment=1 (default).
|
|
154
|
+
const firstId = result.insertId;
|
|
155
|
+
for (let j = 0; j < chunk.length; j++) {
|
|
156
|
+
const id = typeof firstId === 'number' ? firstId + j : undefined;
|
|
157
|
+
results.push(this.#mysqlPkResult(pkCol, chunk[j], id));
|
|
154
158
|
}
|
|
155
159
|
}
|
|
156
160
|
}
|
|
@@ -174,8 +178,10 @@ export class QueryClient {
|
|
|
174
178
|
results.push(...result.rows);
|
|
175
179
|
}
|
|
176
180
|
else {
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
const firstId = result.insertId;
|
|
182
|
+
for (let j = 0; j < chunk.length; j++) {
|
|
183
|
+
const id = typeof firstId === 'number' ? firstId + j : undefined;
|
|
184
|
+
results.push(this.#mysqlPkResult(pkCol, chunk[j], id));
|
|
179
185
|
}
|
|
180
186
|
}
|
|
181
187
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-upsert.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/bulk/bulk-upsert.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bulk-upsert.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/bulk/bulk-upsert.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAGjB,MAAM,mBAAmB,CAAC;AAE3B,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAoG5F"}
|
|
@@ -1,23 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { snakecaseRecord } from '../../naming.js';
|
|
2
2
|
import { removeExcludedFields, processSecondaries, processDeletions } from '../write-helpers.js';
|
|
3
3
|
import { injectTenantValue, validateTenantFK } from '../../tenant.js';
|
|
4
|
+
import { runValidation, runBulkValidation } from '../validate.js';
|
|
4
5
|
import { primaryAsString } from '../../../types.js';
|
|
5
6
|
export async function bulkUpsertEngine(params) {
|
|
6
7
|
const { db, tableConf, dbTables, request, items, tenant } = params;
|
|
7
8
|
if (!items.length)
|
|
8
9
|
return [];
|
|
10
|
+
const schema = tableConf.Schema;
|
|
9
11
|
const pk = primaryAsString(tableConf.primary);
|
|
10
|
-
const pkCol =
|
|
11
|
-
// 1.
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
const pkCol = schema.col(pk);
|
|
13
|
+
// 1. Mutable camelCase copies of each item.main
|
|
14
|
+
const inputMains = items.map((item) => ({ ...item.main }));
|
|
15
|
+
// 2. Custom validation (camelCase)
|
|
16
|
+
if (tableConf.validateBulk) {
|
|
17
|
+
await runBulkValidation(db, request, tableConf, items);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
for (let i = 0; i < items.length; i++) {
|
|
21
|
+
await runValidation(db, request, tableConf, inputMains[i], items[i].secondaries);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// 3. beforeInsert hook per record (camelCase)
|
|
25
|
+
if (tableConf.beforeInsert) {
|
|
26
|
+
for (const rec of inputMains) {
|
|
27
|
+
await tableConf.beforeInsert(db, request, rec);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// 4. Convert to DB format (after user mutations)
|
|
31
|
+
const preparedMains = inputMains.map((rec) => {
|
|
32
|
+
let converted = snakecaseRecord(rec, schema);
|
|
33
|
+
converted = removeExcludedFields(converted, tableConf);
|
|
34
|
+
return converted;
|
|
16
35
|
});
|
|
17
|
-
//
|
|
36
|
+
// 5. Tenant: inject or validate FK (enforced after user mutations)
|
|
18
37
|
if (tenant) {
|
|
19
38
|
if ('through' in tenant.scope) {
|
|
20
|
-
// Indirect: collect all FK values, validate in batch
|
|
21
39
|
const scope = tenant.scope;
|
|
22
40
|
const fkCol = scope.through.localField;
|
|
23
41
|
const fkValues = preparedMains.map((rec) => rec[fkCol]);
|
|
@@ -29,31 +47,27 @@ export async function bulkUpsertEngine(params) {
|
|
|
29
47
|
}
|
|
30
48
|
}
|
|
31
49
|
}
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
for (const rec of preparedMains) {
|
|
35
|
-
await tableConf.beforeInsert(db, request, rec);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
// 3. Bulk upsert all mains in one query → returns PK-only
|
|
39
|
-
const upsertKeys = tableConf.upsertMap?.get(tableConf.Schema);
|
|
50
|
+
// 6. Bulk upsert all mains in one query → returns PK-only
|
|
51
|
+
const upsertKeys = tableConf.upsertMap?.get(schema);
|
|
40
52
|
let pkRows;
|
|
41
53
|
if (upsertKeys) {
|
|
42
|
-
const conflictCols = upsertKeys.map((k) =>
|
|
43
|
-
pkRows = await db.bulkInsertOrUpdate(
|
|
54
|
+
const conflictCols = upsertKeys.map((k) => schema.col(k));
|
|
55
|
+
pkRows = await db.bulkInsertOrUpdate(schema.tableName, preparedMains, conflictCols, pkCol);
|
|
44
56
|
}
|
|
45
57
|
else {
|
|
46
|
-
pkRows = await db.bulkInsert(
|
|
58
|
+
pkRows = await db.bulkInsert(schema.tableName, preparedMains, pkCol);
|
|
47
59
|
}
|
|
48
|
-
|
|
49
|
-
// 4. Process secondaries and deletions per item
|
|
60
|
+
// 7. Process secondaries, deletions, afterInsert per item (all camelCase)
|
|
50
61
|
const results = [];
|
|
51
62
|
for (let i = 0; i < items.length; i++) {
|
|
52
63
|
const item = items[i];
|
|
53
|
-
const mainPk =
|
|
54
|
-
|
|
55
|
-
// For
|
|
56
|
-
|
|
64
|
+
const mainPk = pkRows[i]; // PK-only (already in camelCase field name since PK uses camelCase field)
|
|
65
|
+
// pkRows entries come from SQL RETURNING or insertId — keys are DB column names.
|
|
66
|
+
// For simple PK named the same in API and DB (like 'id') this is transparent.
|
|
67
|
+
// If PK name differs (rare), the user should not rely on mainPk for FK auto-fill — it's the merged inputMain that drives FK.
|
|
68
|
+
const result = { main: { [pk]: mainPk[pkCol] ?? mainPk[pk] } };
|
|
69
|
+
// FK auto-fill: input camelCase + generated PK
|
|
70
|
+
const mainForFK = { ...inputMains[i], [pk]: mainPk[pkCol] ?? mainPk[pk] };
|
|
57
71
|
if (item.secondaries && Object.keys(item.secondaries).length > 0) {
|
|
58
72
|
const sec = await processSecondaries(db, tableConf, dbTables, mainForFK, item.secondaries);
|
|
59
73
|
if (Object.keys(sec).length > 0)
|
|
@@ -64,7 +78,7 @@ export async function bulkUpsertEngine(params) {
|
|
|
64
78
|
if (Object.keys(del).length > 0)
|
|
65
79
|
result.deletions = del;
|
|
66
80
|
}
|
|
67
|
-
//
|
|
81
|
+
// 8. afterInsert hook per item (camelCase)
|
|
68
82
|
if (tableConf.afterInsert) {
|
|
69
83
|
await tableConf.afterInsert(db, request, mainForFK, result.secondaries);
|
|
70
84
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insert.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/rest/insert.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"insert.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/rest/insert.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EAGb,MAAM,mBAAmB,CAAC;AAE3B,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA2E9E"}
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import { camelcaseObject, snakecaseRecord } from '../../naming.js';
|
|
2
2
|
import { removeExcludedFields, processSecondaries } from '../write-helpers.js';
|
|
3
3
|
import { injectTenantValue, validateTenantFK } from '../../tenant.js';
|
|
4
|
+
import { runValidation } from '../validate.js';
|
|
4
5
|
import { primaryAsString } from '../../../types.js';
|
|
5
6
|
export async function insertEngine(params) {
|
|
6
7
|
const { db, tableConf, dbTables, request, record, secondaries, tenant } = params;
|
|
8
|
+
const schema = tableConf.Schema;
|
|
7
9
|
const pk = primaryAsString(tableConf.primary);
|
|
8
|
-
const pkCol =
|
|
9
|
-
// 1.
|
|
10
|
-
|
|
10
|
+
const pkCol = schema.col(pk);
|
|
11
|
+
// 1. Mutable copy of input in camelCase (user-facing format)
|
|
12
|
+
const inputRecord = { ...record };
|
|
13
|
+
// 2. Custom validation (camelCase)
|
|
14
|
+
await runValidation(db, request, tableConf, inputRecord, secondaries);
|
|
15
|
+
// 3. beforeInsert hook (camelCase — user can mutate with schema field names)
|
|
16
|
+
if (tableConf.beforeInsert) {
|
|
17
|
+
await tableConf.beforeInsert(db, request, inputRecord);
|
|
18
|
+
}
|
|
19
|
+
// 4. Convert to DB format (after all user mutations)
|
|
20
|
+
let mainRecord = snakecaseRecord(inputRecord, schema);
|
|
11
21
|
mainRecord = removeExcludedFields(mainRecord, tableConf);
|
|
12
|
-
//
|
|
22
|
+
// 5. Tenant: inject or validate (enforced after user mutations for security)
|
|
13
23
|
if (tenant) {
|
|
14
24
|
if ('through' in tenant.scope) {
|
|
15
|
-
// Indirect: validate FK belongs to tenant
|
|
16
25
|
const scope = tenant.scope;
|
|
17
26
|
const fkCol = scope.through.localField;
|
|
18
27
|
const fkValue = mainRecord[fkCol];
|
|
@@ -22,34 +31,29 @@ export async function insertEngine(params) {
|
|
|
22
31
|
injectTenantValue(mainRecord, tenant.scope, tenant.ids);
|
|
23
32
|
}
|
|
24
33
|
}
|
|
25
|
-
//
|
|
26
|
-
if (tableConf.beforeInsert) {
|
|
27
|
-
await tableConf.beforeInsert(db, request, mainRecord);
|
|
28
|
-
}
|
|
29
|
-
// 3. Insert main → returns PK-only
|
|
34
|
+
// 6. Insert main → returns PK-only
|
|
30
35
|
let pkResult;
|
|
31
|
-
const upsertKeys = tableConf.upsertMap?.get(
|
|
36
|
+
const upsertKeys = tableConf.upsertMap?.get(schema);
|
|
32
37
|
if (upsertKeys) {
|
|
33
|
-
const conflictCols = upsertKeys.map((k) =>
|
|
34
|
-
pkResult = await db.insertOrUpdate(
|
|
38
|
+
const conflictCols = upsertKeys.map((k) => schema.col(k));
|
|
39
|
+
pkResult = await db.insertOrUpdate(schema.tableName, mainRecord, conflictCols, pkCol);
|
|
35
40
|
}
|
|
36
41
|
else {
|
|
37
|
-
pkResult = await db.insert(
|
|
42
|
+
pkResult = await db.insert(schema.tableName, mainRecord, pkCol);
|
|
38
43
|
}
|
|
39
|
-
const mainPkCamel = camelcaseObject(pkResult);
|
|
40
|
-
//
|
|
44
|
+
const mainPkCamel = camelcaseObject(pkResult, schema);
|
|
45
|
+
// 7. Secondaries: need full record for FK auto-fill (camelCase)
|
|
41
46
|
let secondaryResults;
|
|
42
47
|
if (secondaries && Object.keys(secondaries).length > 0) {
|
|
43
|
-
|
|
44
|
-
const mainForFK = { ...camelcaseObject(mainRecord), ...mainPkCamel };
|
|
48
|
+
const mainForFK = { ...inputRecord, ...mainPkCamel };
|
|
45
49
|
secondaryResults = await processSecondaries(db, tableConf, dbTables, mainForFK, secondaries);
|
|
46
50
|
}
|
|
47
|
-
//
|
|
51
|
+
// 8. afterInsert hook (camelCase — input merged with generated PK)
|
|
48
52
|
if (tableConf.afterInsert) {
|
|
49
|
-
const mainForHook = { ...
|
|
53
|
+
const mainForHook = { ...inputRecord, ...mainPkCamel };
|
|
50
54
|
await tableConf.afterInsert(db, request, mainForHook, secondaryResults);
|
|
51
55
|
}
|
|
52
|
-
//
|
|
56
|
+
// 9. Return PK-only
|
|
53
57
|
const result = { main: mainPkCamel };
|
|
54
58
|
if (secondaryResults && Object.keys(secondaryResults).length > 0) {
|
|
55
59
|
result.secondaries = secondaryResults;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/rest/update.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../../src/lib/engine/rest/update.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EAGb,MAAM,mBAAmB,CAAC;AAE3B,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAkI9E"}
|