@carbonorm/carbonnode 3.7.16 → 3.7.17
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/index.cjs.js +150 -164
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +151 -165
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/httpExecutorSingular.e2e.test.ts +72 -0
- package/src/__tests__/normalizeSingularRequest.test.ts +8 -8
- package/src/__tests__/sakila-db/C6.js +1 -1
- package/src/__tests__/sakila-db/C6.ts +1 -1
- package/src/api/executors/HttpExecutor.ts +4 -35
- package/src/api/handlers/ExpressHandler.ts +10 -23
- package/src/api/utils/normalizeSingularRequest.ts +15 -4
|
@@ -19,7 +19,6 @@ import {apiRequestCache, checkCache, userCustomClearCache} from "../utils/cacheM
|
|
|
19
19
|
import {sortAndSerializeQueryObject} from "../utils/sortAndSerializeQueryObject";
|
|
20
20
|
import {Executor} from "./Executor";
|
|
21
21
|
import {toastOptions, toastOptionsDevs} from "variables/toastOptions";
|
|
22
|
-
import {normalizeSingularRequest} from "../utils/normalizeSingularRequest";
|
|
23
22
|
|
|
24
23
|
export class HttpExecutor<
|
|
25
24
|
G extends OrmGenerics
|
|
@@ -334,9 +333,6 @@ export class HttpExecutor<
|
|
|
334
333
|
|
|
335
334
|
}
|
|
336
335
|
|
|
337
|
-
let addBackPK: (() => void) | undefined;
|
|
338
|
-
let removedPrimaryKV: { key: string; value: any } | undefined;
|
|
339
|
-
|
|
340
336
|
let apiResponse: G['RestTableInterface'][G['PrimaryKey']] | string | boolean | number | undefined;
|
|
341
337
|
|
|
342
338
|
let returnGetNextPageFunction = false;
|
|
@@ -410,22 +406,7 @@ export class HttpExecutor<
|
|
|
410
406
|
|
|
411
407
|
restRequestUri += query[primaryKey] + '/'
|
|
412
408
|
|
|
413
|
-
|
|
414
|
-
removedPrimaryKV = { key: primaryKey, value: removedPkValue };
|
|
415
|
-
|
|
416
|
-
addBackPK = () => {
|
|
417
|
-
query ??= {} as RequestQueryBody<
|
|
418
|
-
G['RequestMethod'],
|
|
419
|
-
G['RestTableInterface'],
|
|
420
|
-
G['CustomAndRequiredFields'],
|
|
421
|
-
G['RequestTableOverrides']
|
|
422
|
-
>;
|
|
423
|
-
query[primaryKey] = removedPkValue;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
delete query[primaryKey]
|
|
427
|
-
|
|
428
|
-
console.log('query', query, 'primaryKey', primaryKey, 'removedPkValue', removedPkValue)
|
|
409
|
+
console.log('query', query, 'primaryKey', primaryKey)
|
|
429
410
|
|
|
430
411
|
} else {
|
|
431
412
|
|
|
@@ -473,19 +454,11 @@ export class HttpExecutor<
|
|
|
473
454
|
withCredentials: withCredentials,
|
|
474
455
|
};
|
|
475
456
|
|
|
476
|
-
// Normalize singular request (GET/PUT/DELETE) into complex ORM shape
|
|
477
|
-
const normalizedQuery = normalizeSingularRequest(
|
|
478
|
-
requestMethod as any,
|
|
479
|
-
query as any,
|
|
480
|
-
restModel as any,
|
|
481
|
-
removedPrimaryKV
|
|
482
|
-
) as typeof query;
|
|
483
|
-
|
|
484
457
|
switch (requestMethod) {
|
|
485
458
|
case GET:
|
|
486
459
|
return [{
|
|
487
460
|
...baseConfig,
|
|
488
|
-
params:
|
|
461
|
+
params: query
|
|
489
462
|
}];
|
|
490
463
|
|
|
491
464
|
case POST:
|
|
@@ -498,12 +471,12 @@ export class HttpExecutor<
|
|
|
498
471
|
return [convert(query), baseConfig];
|
|
499
472
|
|
|
500
473
|
case PUT:
|
|
501
|
-
return [convert(
|
|
474
|
+
return [convert(query), baseConfig];
|
|
502
475
|
|
|
503
476
|
case DELETE:
|
|
504
477
|
return [{
|
|
505
478
|
...baseConfig,
|
|
506
|
-
data: convert(
|
|
479
|
+
data: convert(query)
|
|
507
480
|
}];
|
|
508
481
|
|
|
509
482
|
default:
|
|
@@ -523,10 +496,6 @@ export class HttpExecutor<
|
|
|
523
496
|
|
|
524
497
|
}
|
|
525
498
|
|
|
526
|
-
// todo - wip verify this works
|
|
527
|
-
// we had removed the value from the request to add to the URI.
|
|
528
|
-
addBackPK?.(); // adding back so post-processing methods work
|
|
529
|
-
|
|
530
499
|
// returning the promise with this then is important for tests. todo - we could make that optional.
|
|
531
500
|
// https://rapidapi.com/guides/axios-async-await
|
|
532
501
|
return axiosActiveRequest.then(async (response: AxiosResponse<ResponseDataType, any>): Promise<AxiosResponse<ResponseDataType, any>> => {
|
|
@@ -35,30 +35,17 @@ export function ExpressHandler({C6, mysqlPool}: { C6: iC6Object, mysqlPool: Pool
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const primaryKeyName = primaryKeys[0];
|
|
38
|
-
const primaryKeyShort = primaryKeyName.split('.')[1];
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
case 'DELETE':
|
|
51
|
-
if (primary) {
|
|
52
|
-
payload[C6C.WHERE][primaryKeyName] = primary;
|
|
53
|
-
} else {
|
|
54
|
-
res.status(400).json({error: `Invalid request: ${method} requires a primary key (${primaryKeyName}).`});
|
|
55
|
-
}
|
|
56
|
-
break;
|
|
57
|
-
case 'POST':
|
|
58
|
-
break;
|
|
59
|
-
default:
|
|
60
|
-
res.status(405).json({error: `Method ${method} not allowed`});
|
|
61
|
-
return;
|
|
39
|
+
// If a primary key was provided in the URL, merge it into the payload.
|
|
40
|
+
// Support both complex requests using WHERE and singular requests
|
|
41
|
+
// where the primary key lives at the root of the payload.
|
|
42
|
+
if (primary) {
|
|
43
|
+
if (payload[C6C.WHERE]) {
|
|
44
|
+
payload[C6C.WHERE][primaryKeyName] =
|
|
45
|
+
payload[C6C.WHERE][primaryKeyName] ?? primary;
|
|
46
|
+
} else {
|
|
47
|
+
(payload as any)[primaryKeyName] =
|
|
48
|
+
(payload as any)[primaryKeyName] ?? primary;
|
|
62
49
|
}
|
|
63
50
|
}
|
|
64
51
|
|
|
@@ -60,7 +60,9 @@ export function normalizeSingularRequest<
|
|
|
60
60
|
if (value === undefined) {
|
|
61
61
|
// 2) fully-qualified key matching this short key (from PRIMARY list or by concatenation)
|
|
62
62
|
const fqCandidate = `${restModel.TABLE_NAME}.${pkShort}`;
|
|
63
|
-
const fqKey = pkFulls.find(
|
|
63
|
+
const fqKey = pkFulls.find(
|
|
64
|
+
fq => fq === fqCandidate || fq.endsWith(`.${pkShort}`)
|
|
65
|
+
) ?? fqCandidate;
|
|
64
66
|
value = requestObj[fqKey];
|
|
65
67
|
}
|
|
66
68
|
if (value === undefined && removedPrimary) {
|
|
@@ -93,9 +95,18 @@ export function normalizeSingularRequest<
|
|
|
93
95
|
...rest
|
|
94
96
|
} = request as any;
|
|
95
97
|
|
|
98
|
+
// Map short primary keys to fully-qualified column names
|
|
99
|
+
const shortToFull: Record<string, string> = {};
|
|
100
|
+
for (const [full, short] of Object.entries(restModel.COLUMNS || {})) {
|
|
101
|
+
shortToFull[short as string] = full;
|
|
102
|
+
}
|
|
103
|
+
const pkFullValues = Object.fromEntries(
|
|
104
|
+
Object.entries(pkValues).map(([k, v]) => [shortToFull[k] ?? k, v])
|
|
105
|
+
);
|
|
106
|
+
|
|
96
107
|
if (requestMethod === C6C.GET) {
|
|
97
108
|
const normalized: any = {
|
|
98
|
-
WHERE: { ...
|
|
109
|
+
WHERE: { ...pkFullValues },
|
|
99
110
|
};
|
|
100
111
|
// Preserve pagination if any was added previously
|
|
101
112
|
if ((request as any)[C6C.PAGINATION]) {
|
|
@@ -115,7 +126,7 @@ export function normalizeSingularRequest<
|
|
|
115
126
|
if (requestMethod === C6C.DELETE) {
|
|
116
127
|
const normalized: any = {
|
|
117
128
|
[C6C.DELETE]: true,
|
|
118
|
-
WHERE: { ...
|
|
129
|
+
WHERE: { ...pkFullValues },
|
|
119
130
|
};
|
|
120
131
|
return {
|
|
121
132
|
...normalized,
|
|
@@ -143,7 +154,7 @@ export function normalizeSingularRequest<
|
|
|
143
154
|
|
|
144
155
|
const normalized: any = {
|
|
145
156
|
[C6C.UPDATE]: updateBody,
|
|
146
|
-
WHERE: { ...
|
|
157
|
+
WHERE: { ...pkFullValues },
|
|
147
158
|
};
|
|
148
159
|
|
|
149
160
|
return {
|