@carbonorm/carbonnode 3.7.10 → 3.7.12
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/api/orm/queries/UpdateQueryBuilder.d.ts +1 -0
- package/dist/index.cjs.js +46 -17
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +46 -17
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/normalizeSingularRequest.test.ts +30 -0
- package/src/__tests__/sakila-db/C6.js +1 -1
- package/src/__tests__/sakila-db/C6.ts +1 -1
- package/src/__tests__/sqlBuilders.test.ts +18 -0
- package/src/api/orm/queries/UpdateQueryBuilder.ts +9 -1
- package/src/api/utils/normalizeSingularRequest.ts +25 -11
|
@@ -4,6 +4,14 @@ import { PaginationBuilder } from '../builders/PaginationBuilder';
|
|
|
4
4
|
import {SqlBuilderResult} from "../utils/sqlUtils";
|
|
5
5
|
|
|
6
6
|
export class UpdateQueryBuilder<G extends OrmGenerics> extends PaginationBuilder<G>{
|
|
7
|
+
private trimTablePrefix(table: string, column: string): string {
|
|
8
|
+
if (!column.includes('.')) return column;
|
|
9
|
+
const [prefix, col] = column.split('.', 2);
|
|
10
|
+
if (prefix !== table) {
|
|
11
|
+
throw new Error(`Invalid prefixed column: '${column}'. Expected prefix '${table}.'`);
|
|
12
|
+
}
|
|
13
|
+
return col;
|
|
14
|
+
}
|
|
7
15
|
|
|
8
16
|
build(
|
|
9
17
|
table: string,
|
|
@@ -23,7 +31,7 @@ export class UpdateQueryBuilder<G extends OrmGenerics> extends PaginationBuilder
|
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
const setClauses = Object.entries(this.request[C6C.UPDATE])
|
|
26
|
-
.map(([col, val]) => `\`${col}\` = ${this.addParam(params, col, val)}`);
|
|
34
|
+
.map(([col, val]) => `\`${this.trimTablePrefix(table, col)}\` = ${this.addParam(params, col, val)}`);
|
|
27
35
|
|
|
28
36
|
sql += ` SET ${setClauses.join(', ')}`;
|
|
29
37
|
|
|
@@ -40,23 +40,36 @@ export function normalizeSingularRequest<
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const pkShorts: string[] = Array.isArray(restModel.PRIMARY_SHORT) ? [...restModel.PRIMARY_SHORT] : [];
|
|
43
|
+
const pkFulls: string[] = Array.isArray((restModel as any).PRIMARY) ? [...(restModel as any).PRIMARY] : [];
|
|
44
|
+
const resolveShortKey = (key: string): string => {
|
|
45
|
+
const cols = (restModel as any).COLUMNS || {};
|
|
46
|
+
return (cols as any)[key] ?? key;
|
|
47
|
+
};
|
|
43
48
|
if (!pkShorts.length) {
|
|
44
49
|
// For GET requests, do not enforce primary key presence; treat as a collection query.
|
|
45
50
|
if (requestMethod === C6C.GET) return request;
|
|
46
51
|
throw new Error(`Table (${restModel.TABLE_NAME}) has no primary key; singular request syntax is not allowed.`);
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
// Build pk map from request + possibly removed primary key
|
|
54
|
+
// Build pk map from request + possibly removed primary key (accept short or fully-qualified keys)
|
|
50
55
|
const pkValues: Record<string, any> = {};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
const requestObj = request as any;
|
|
57
|
+
for (const pkShort of pkShorts) {
|
|
58
|
+
// 1) direct short key
|
|
59
|
+
let value = requestObj[pkShort];
|
|
60
|
+
if (value === undefined) {
|
|
61
|
+
// 2) fully-qualified key matching this short key (from PRIMARY list or by concatenation)
|
|
62
|
+
const fqCandidate = `${restModel.TABLE_NAME}.${pkShort}`;
|
|
63
|
+
const fqKey = pkFulls.find(fq => fq === fqCandidate || fq.endsWith(`.${pkShort}`)) ?? fqCandidate;
|
|
64
|
+
value = requestObj[fqKey];
|
|
65
|
+
}
|
|
66
|
+
if (value === undefined && removedPrimary) {
|
|
67
|
+
// 3) removedPrimary may provide either short or fully-qualified key
|
|
68
|
+
const removedKeyShort = resolveShortKey(removedPrimary.key);
|
|
69
|
+
if (removedKeyShort === pkShort) value = removedPrimary.value;
|
|
56
70
|
}
|
|
57
|
-
if (
|
|
58
|
-
pkValues[
|
|
59
|
-
continue;
|
|
71
|
+
if (value !== undefined && value !== null) {
|
|
72
|
+
pkValues[pkShort] = value;
|
|
60
73
|
}
|
|
61
74
|
}
|
|
62
75
|
|
|
@@ -118,10 +131,11 @@ export function normalizeSingularRequest<
|
|
|
118
131
|
// PUT
|
|
119
132
|
const updateBody: Record<string, any> = {};
|
|
120
133
|
for (const k of Object.keys(rest)) {
|
|
121
|
-
if (pkShorts.includes(k)) continue; // don't update PK columns
|
|
122
134
|
// Skip special request keys if any slipped through
|
|
123
135
|
if (specialKeys.has(k)) continue;
|
|
124
|
-
|
|
136
|
+
const shortKey = resolveShortKey(k);
|
|
137
|
+
if (pkShorts.includes(shortKey)) continue; // don't update PK columns (short or fully qualified)
|
|
138
|
+
updateBody[shortKey] = (rest as any)[k];
|
|
125
139
|
}
|
|
126
140
|
if (Object.keys(updateBody).length === 0) {
|
|
127
141
|
throw new Error(`Singular PUT request for table (${restModel.TABLE_NAME}) must include at least one non-primary field to update.`);
|