@carbonorm/carbonnode 6.0.3 → 6.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/dist/executors/SqlExecutor.d.ts +2 -15
- package/dist/handlers/ExpressHandler.d.ts +3 -2
- package/dist/index.cjs.js +111 -18
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +111 -18
- package/dist/index.esm.js.map +1 -1
- package/dist/types/ormInterfaces.d.ts +14 -3
- package/package.json +2 -2
- package/src/__tests__/sakila-db/C6.js +1 -1
- package/src/__tests__/sakila-db/C6.mysqldump.json +1 -1
- package/src/__tests__/sakila-db/C6.mysqldump.sql +1 -1
- package/src/__tests__/sakila-db/C6.ts +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.actor.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.actor.post.json +4 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.actor.post.latest.json +3 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.lookup.json +3 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.address.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.address.post.json +6 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.address.post.latest.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.address.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.address.put.lookup.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.category.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.category.post.json +3 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.category.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.category.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.category.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.city.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.city.post.json +3 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.city.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.city.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.city.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.country.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.country.post.json +3 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.country.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.country.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.country.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.customer.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.json +6 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.latest.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.lookup.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.film.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.film.post.json +3 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.film.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.film.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.film.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.inventory.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.latest.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.lookup.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.language.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.language.post.json +3 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.language.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.language.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.language.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.payment.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.json +3 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.payment.put.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.payment.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.rental.delete.json +1 -0
- package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.json +4 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.latest.json +3 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.json +2 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.lookup.json +3 -3
- package/src/executors/HttpExecutor.ts +2 -1
- package/src/executors/SqlExecutor.ts +132 -22
- package/src/handlers/ExpressHandler.ts +4 -1
- package/src/types/ormInterfaces.ts +13 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"affected": 1,
|
|
3
|
+
"insertId": 16050,
|
|
3
4
|
"rest": [],
|
|
4
5
|
"sql": {
|
|
5
6
|
"sql": "INSERT INTO `payment` (\n `customer_id`, `staff_id`, `rental_id`, `amount`, `payment_date`, `last_update`\n ) VALUES (\n ?, ?, ?, ?, ?, ?\n )",
|
|
@@ -8,8 +9,8 @@
|
|
|
8
9
|
1,
|
|
9
10
|
1,
|
|
10
11
|
1,
|
|
11
|
-
"2026-01
|
|
12
|
-
"2026-01
|
|
12
|
+
"2026-02-01 19:13:51",
|
|
13
|
+
"2026-02-01 19:13:51"
|
|
13
14
|
]
|
|
14
15
|
}
|
|
15
16
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"affected": 1,
|
|
3
|
+
"insertId": 16050,
|
|
3
4
|
"rest": [],
|
|
4
5
|
"sql": {
|
|
5
6
|
"sql": "INSERT INTO `rental` (\n `rental_date`, `inventory_id`, `customer_id`, `return_date`, `staff_id`, `last_update`\n ) VALUES (\n ?, ?, ?, ?, ?, ?\n )",
|
|
6
7
|
"values": [
|
|
7
|
-
"2026-01
|
|
8
|
+
"2026-02-01 19:13:51",
|
|
8
9
|
1,
|
|
9
10
|
1,
|
|
10
|
-
"2026-01
|
|
11
|
+
"2026-02-01 19:13:51",
|
|
11
12
|
1,
|
|
12
|
-
"2026-01
|
|
13
|
+
"2026-02-01 19:13:51"
|
|
13
14
|
]
|
|
14
15
|
}
|
|
15
16
|
}
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"rest": [
|
|
3
3
|
{
|
|
4
4
|
"rental_id": 16050,
|
|
5
|
-
"rental_date": "2026-
|
|
5
|
+
"rental_date": "2026-02-01T19:13:51.000Z",
|
|
6
6
|
"inventory_id": 1,
|
|
7
7
|
"customer_id": 1,
|
|
8
|
-
"return_date": "2026-
|
|
8
|
+
"return_date": "2026-02-01T19:13:51.000Z",
|
|
9
9
|
"staff_id": 1,
|
|
10
|
-
"last_update": "2026-
|
|
10
|
+
"last_update": "2026-02-01T19:13:51.000Z"
|
|
11
11
|
}
|
|
12
12
|
],
|
|
13
13
|
"sql": {
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"rest": [
|
|
3
3
|
{
|
|
4
4
|
"rental_id": 16050,
|
|
5
|
-
"rental_date": "2026-
|
|
5
|
+
"rental_date": "2026-02-01T19:13:51.000Z",
|
|
6
6
|
"inventory_id": 1,
|
|
7
7
|
"customer_id": 1,
|
|
8
|
-
"return_date": "2026-
|
|
8
|
+
"return_date": "2026-02-01T19:13:51.000Z",
|
|
9
9
|
"staff_id": 1,
|
|
10
|
-
"last_update": "2026-
|
|
10
|
+
"last_update": "2026-02-01T19:13:51.000Z"
|
|
11
11
|
}
|
|
12
12
|
],
|
|
13
13
|
"sql": {
|
|
@@ -529,7 +529,8 @@ export class HttpExecutor<
|
|
|
529
529
|
|
|
530
530
|
if (C6.GET === requestMethod && this.isRestResponse(response)) {
|
|
531
531
|
|
|
532
|
-
const responseData =
|
|
532
|
+
const responseData =
|
|
533
|
+
response.data as DetermineResponseDataType<'GET', G['RestTableInterface']>;
|
|
533
534
|
|
|
534
535
|
const pageLimit = query?.[C6.PAGINATION]?.[C6.LIMIT];
|
|
535
536
|
|
|
@@ -47,19 +47,19 @@ export class SqlExecutor<
|
|
|
47
47
|
|
|
48
48
|
case 'POST': {
|
|
49
49
|
const result = await this.runQuery();
|
|
50
|
-
await this.broadcastWebsocketIfConfigured();
|
|
50
|
+
await this.broadcastWebsocketIfConfigured(result);
|
|
51
51
|
return result as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
case 'PUT': {
|
|
55
55
|
const result = await this.runQuery();
|
|
56
|
-
await this.broadcastWebsocketIfConfigured();
|
|
56
|
+
await this.broadcastWebsocketIfConfigured(result);
|
|
57
57
|
return result as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
case 'DELETE': {
|
|
61
61
|
const result = await this.runQuery();
|
|
62
|
-
await this.broadcastWebsocketIfConfigured();
|
|
62
|
+
await this.broadcastWebsocketIfConfigured(result);
|
|
63
63
|
return result as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -110,7 +110,7 @@ export class SqlExecutor<
|
|
|
110
110
|
return `'${JSON.stringify(val)}'`;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
private stripRequestMetadata(source: Record<string,
|
|
113
|
+
private stripRequestMetadata(source: Record<string, unknown>): Record<string, unknown> {
|
|
114
114
|
const ignoredKeys = new Set<string>([
|
|
115
115
|
C6C.SELECT,
|
|
116
116
|
C6C.UPDATE,
|
|
@@ -128,7 +128,7 @@ export class SqlExecutor<
|
|
|
128
128
|
"error",
|
|
129
129
|
]);
|
|
130
130
|
|
|
131
|
-
const filtered: Record<string,
|
|
131
|
+
const filtered: Record<string, unknown> = {};
|
|
132
132
|
for (const [key, value] of Object.entries(source)) {
|
|
133
133
|
if (!ignoredKeys.has(key)) {
|
|
134
134
|
filtered[key] = value;
|
|
@@ -137,10 +137,10 @@ export class SqlExecutor<
|
|
|
137
137
|
return filtered;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
private normalizeRequestPayload(source: Record<string,
|
|
140
|
+
private normalizeRequestPayload(source: Record<string, unknown>): Record<string, unknown> {
|
|
141
141
|
const columns = this.config.restModel.COLUMNS as Record<string, string>;
|
|
142
142
|
const validColumns = new Set(Object.values(columns));
|
|
143
|
-
const normalized: Record<string,
|
|
143
|
+
const normalized: Record<string, unknown> = {};
|
|
144
144
|
|
|
145
145
|
for (const [key, value] of Object.entries(source)) {
|
|
146
146
|
const shortKey = columns[key] ?? (key.includes(".") ? key.split(".").pop()! : key);
|
|
@@ -152,25 +152,27 @@ export class SqlExecutor<
|
|
|
152
152
|
return normalized;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
|
|
156
|
+
private extractRequestBody() {
|
|
157
|
+
const request = this.request;
|
|
157
158
|
|
|
158
159
|
if (this.config.requestMethod === C6C.POST) {
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
const insertRows = request.dataInsertMultipleRows;
|
|
161
|
+
if (Array.isArray(insertRows) && insertRows.length > 0) {
|
|
162
|
+
return insertRows[0] as Record<string, unknown>;
|
|
161
163
|
}
|
|
162
164
|
if (C6C.INSERT in request) {
|
|
163
|
-
return
|
|
165
|
+
return request[C6C.INSERT] ?? {};
|
|
164
166
|
}
|
|
165
167
|
if (C6C.REPLACE in request) {
|
|
166
|
-
return
|
|
168
|
+
return request[C6C.REPLACE] ?? {};
|
|
167
169
|
}
|
|
168
170
|
return this.stripRequestMetadata(request);
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
if (this.config.requestMethod === C6C.PUT) {
|
|
172
174
|
if (request[C6C.UPDATE] && typeof request[C6C.UPDATE] === "object") {
|
|
173
|
-
return request[C6C.UPDATE] as Record<string,
|
|
175
|
+
return request[C6C.UPDATE] as Record<string, unknown>;
|
|
174
176
|
}
|
|
175
177
|
return this.stripRequestMetadata(request);
|
|
176
178
|
}
|
|
@@ -223,29 +225,136 @@ export class SqlExecutor<
|
|
|
223
225
|
return Object.keys(pkValues).length > 0 ? pkValues : null;
|
|
224
226
|
}
|
|
225
227
|
|
|
226
|
-
private
|
|
228
|
+
private extractPrimaryKeyValuesFromData(data: any): Record<string, any> | null {
|
|
229
|
+
if (!data) return null;
|
|
230
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
231
|
+
if (!row || typeof row !== "object") return null;
|
|
232
|
+
|
|
233
|
+
const pkShorts = this.config.restModel.PRIMARY_SHORT;
|
|
234
|
+
const columns = this.config.restModel.COLUMNS as Record<string, string>;
|
|
235
|
+
const pkValues: Record<string, any> = {};
|
|
236
|
+
|
|
237
|
+
for (const pk of pkShorts) {
|
|
238
|
+
if (pk in row) {
|
|
239
|
+
pkValues[pk] = (row as any)[pk];
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const fullKey = Object.keys(columns).find(
|
|
244
|
+
(key) => columns[key] === pk,
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
if (fullKey && fullKey in row) {
|
|
248
|
+
pkValues[pk] = (row as any)[fullKey];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (pkShorts.length > 0 && Object.keys(pkValues).length < pkShorts.length) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return Object.keys(pkValues).length > 0 ? pkValues : null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private async broadcastWebsocketIfConfigured(
|
|
260
|
+
response?: DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>
|
|
261
|
+
): Promise<void> {
|
|
227
262
|
const broadcast = this.config.websocketBroadcast;
|
|
228
|
-
|
|
263
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 broadcastWebsocketIfConfigured start", {
|
|
264
|
+
method: this.config.requestMethod,
|
|
265
|
+
hasBroadcast: Boolean(broadcast),
|
|
266
|
+
});
|
|
267
|
+
if (!broadcast || this.config.requestMethod === C6C.GET) {
|
|
268
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket broadcast skipped", {
|
|
269
|
+
reason: !broadcast ? "no broadcast configured" : "GET request",
|
|
270
|
+
});
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const normalizedRequest = this.normalizeRequestPayload(this.extractRequestBody());
|
|
275
|
+
const pkShorts = this.config.restModel.PRIMARY_SHORT ?? [];
|
|
276
|
+
const columns = this.config.restModel.COLUMNS as Record<string, string>;
|
|
277
|
+
const validColumns = new Set(Object.values(columns));
|
|
278
|
+
let responseRest = response?.rest;
|
|
279
|
+
let responsePrimaryKey = this.extractPrimaryKeyValuesFromData(responseRest);
|
|
280
|
+
|
|
281
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket request payload", {
|
|
282
|
+
normalizedRequest,
|
|
283
|
+
requestPrimaryKey: this.extractPrimaryKeyValues(),
|
|
284
|
+
pkShorts,
|
|
285
|
+
});
|
|
286
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket response payload", {
|
|
287
|
+
responseRest,
|
|
288
|
+
responsePrimaryKey,
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
if (
|
|
292
|
+
(responseRest === null || (Array.isArray(responseRest) && responseRest.length === 0))
|
|
293
|
+
&& this.config.requestMethod === C6C.POST
|
|
294
|
+
) {
|
|
295
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 response rest empty, attempting synthesize", {
|
|
296
|
+
responseRest,
|
|
297
|
+
});
|
|
298
|
+
const insertId = (response as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']> & { insertId?: number | string | null })?.insertId;
|
|
299
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 POST insertId lookup", {
|
|
300
|
+
insertId,
|
|
301
|
+
});
|
|
302
|
+
if (insertId !== undefined && pkShorts.length === 1) {
|
|
303
|
+
const synthesizedRequest = {
|
|
304
|
+
...normalizedRequest,
|
|
305
|
+
};
|
|
306
|
+
const now = new Date().toISOString();
|
|
307
|
+
if (validColumns.has("changed_at") && (synthesizedRequest as Record<string, unknown>).changed_at === undefined) {
|
|
308
|
+
synthesizedRequest.changed_at = now;
|
|
309
|
+
}
|
|
310
|
+
if (validColumns.has("created_at") && (synthesizedRequest as Record<string, unknown>).created_at === undefined) {
|
|
311
|
+
synthesizedRequest.created_at = now;
|
|
312
|
+
}
|
|
313
|
+
if (validColumns.has("updated_at") && (synthesizedRequest as Record<string, unknown>).updated_at === undefined) {
|
|
314
|
+
synthesizedRequest.updated_at = now;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const synthesized = {
|
|
318
|
+
...synthesizedRequest,
|
|
319
|
+
[pkShorts[0]]: insertId,
|
|
320
|
+
};
|
|
321
|
+
// @ts-ignore - todo
|
|
322
|
+
responseRest = [synthesized];
|
|
323
|
+
responsePrimaryKey = {
|
|
324
|
+
[pkShorts[0]]: insertId,
|
|
325
|
+
};
|
|
326
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 synthesized response payload", {
|
|
327
|
+
synthesized,
|
|
328
|
+
responsePrimaryKey,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
229
332
|
|
|
230
333
|
const payload: iRestWebsocketPayload = {
|
|
231
334
|
REST: {
|
|
232
335
|
TABLE_NAME: this.config.restModel.TABLE_NAME as string,
|
|
233
336
|
TABLE_PREFIX: this.config.C6?.PREFIX ?? "",
|
|
234
337
|
METHOD: this.config.requestMethod,
|
|
235
|
-
REQUEST:
|
|
338
|
+
REQUEST: normalizedRequest,
|
|
236
339
|
REQUEST_PRIMARY_KEY: this.extractPrimaryKeyValues(),
|
|
340
|
+
RESPONSE: responseRest,
|
|
341
|
+
RESPONSE_PRIMARY_KEY: responsePrimaryKey,
|
|
237
342
|
},
|
|
238
343
|
};
|
|
239
344
|
|
|
345
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket payload ready", payload);
|
|
346
|
+
|
|
240
347
|
try {
|
|
348
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket broadcast dispatch start");
|
|
241
349
|
await broadcast(payload);
|
|
350
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket broadcast dispatch complete");
|
|
242
351
|
} catch (error) {
|
|
243
352
|
if (this.config.verbose) {
|
|
244
353
|
console.error("[SQL EXECUTOR] websocketBroadcast failed", error);
|
|
245
354
|
}
|
|
246
355
|
}
|
|
247
356
|
}
|
|
248
|
-
async runQuery() {
|
|
357
|
+
async runQuery(): Promise<DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>> {
|
|
249
358
|
const {TABLE_NAME} = this.config.restModel;
|
|
250
359
|
const method = this.config.requestMethod;
|
|
251
360
|
let builder: SelectQueryBuilder<G> | UpdateQueryBuilder<G> | DeleteQueryBuilder<G> | PostQueryBuilder<G>;
|
|
@@ -286,14 +395,15 @@ export class SqlExecutor<
|
|
|
286
395
|
return {
|
|
287
396
|
rest: result.map(this.serialize),
|
|
288
397
|
sql: {sql, values}
|
|
289
|
-
}
|
|
398
|
+
} as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>;
|
|
290
399
|
} else {
|
|
291
400
|
this.config.verbose && console.log(`[SQL EXECUTOR] ✏️ Rows affected:`, result.affectedRows);
|
|
292
401
|
return {
|
|
293
|
-
affected: result.affectedRows,
|
|
294
|
-
|
|
402
|
+
affected: result.affectedRows as number,
|
|
403
|
+
insertId: result.insertId as number,
|
|
404
|
+
rest: [], // TODO - remove rest empty array from non-GET responses?
|
|
295
405
|
sql: {sql, values}
|
|
296
|
-
}
|
|
406
|
+
} as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>;
|
|
297
407
|
}
|
|
298
408
|
});
|
|
299
409
|
}
|
|
@@ -2,7 +2,7 @@ import type {Request, Response, NextFunction} from "express";
|
|
|
2
2
|
import type {Pool} from "mysql2/promise";
|
|
3
3
|
import {C6C} from "../constants/C6Constants";
|
|
4
4
|
import restRequest from "../api/restRequest";
|
|
5
|
-
import type {iC6Object, iRestMethods} from "../types/ormInterfaces";
|
|
5
|
+
import type {iC6Object, iRestMethods, tWebsocketBroadcast} from "../types/ormInterfaces";
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
// TODO - WE MUST make this a generic - optional, but helpful
|
|
@@ -11,10 +11,12 @@ export function ExpressHandler({
|
|
|
11
11
|
C6,
|
|
12
12
|
mysqlPool,
|
|
13
13
|
sqlAllowListPath,
|
|
14
|
+
websocketBroadcast,
|
|
14
15
|
}: {
|
|
15
16
|
C6: iC6Object;
|
|
16
17
|
mysqlPool: Pool;
|
|
17
18
|
sqlAllowListPath?: string;
|
|
19
|
+
websocketBroadcast?: tWebsocketBroadcast;
|
|
18
20
|
}) {
|
|
19
21
|
|
|
20
22
|
return async (req: Request, res: Response, next: NextFunction) => {
|
|
@@ -101,6 +103,7 @@ export function ExpressHandler({
|
|
|
101
103
|
C6,
|
|
102
104
|
mysqlPool,
|
|
103
105
|
sqlAllowListPath,
|
|
106
|
+
websocketBroadcast,
|
|
104
107
|
requestMethod: method,
|
|
105
108
|
restModel: C6.TABLES[table]
|
|
106
109
|
})(payload);
|
|
@@ -77,6 +77,11 @@ export type RequestGetPutDeleteBody<T extends { [key: string]: any } = any> = T
|
|
|
77
77
|
PAGINATION?: Pagination<T>;
|
|
78
78
|
};
|
|
79
79
|
|
|
80
|
+
export type RequestPostBody<T extends { [key: string]: any } = any> = T | {
|
|
81
|
+
INSERT?: Partial<T>;
|
|
82
|
+
REPLACE?: Partial<T>;
|
|
83
|
+
};
|
|
84
|
+
|
|
80
85
|
export type iAPI<T extends { [key: string]: any }> = T & {
|
|
81
86
|
dataInsertMultipleRows?: T[];
|
|
82
87
|
cacheResults?: boolean;
|
|
@@ -94,7 +99,7 @@ export type RequestQueryBody<
|
|
|
94
99
|
Overrides extends { [key: string]: any } = {}
|
|
95
100
|
> = Method extends 'GET' | 'PUT' | 'DELETE'
|
|
96
101
|
? iAPI<RequestGetPutDeleteBody<Modify<T, Overrides> & Custom>>
|
|
97
|
-
: iAPI<Modify<T, Overrides> & Custom
|
|
102
|
+
: iAPI<RequestPostBody<Modify<T, Overrides> & Custom>>;
|
|
98
103
|
|
|
99
104
|
export interface iCacheAPI<ResponseDataType = any> {
|
|
100
105
|
requestArgumentsSerialized: string;
|
|
@@ -119,12 +124,15 @@ export type C6RestResponse<
|
|
|
119
124
|
RestData extends { [key: string]: any },
|
|
120
125
|
Overrides = {}
|
|
121
126
|
> = {
|
|
122
|
-
rest: Method extends 'GET' ? Modify<RestData, Overrides>[] :
|
|
127
|
+
rest: Method extends 'GET' ? Modify<RestData, Overrides>[] : never;
|
|
123
128
|
session?: any;
|
|
124
129
|
sql?: any;
|
|
125
130
|
} & (Method extends 'GET'
|
|
126
131
|
? { next?: () => Promise<DetermineResponseDataType<'GET', RestData, Overrides>> }
|
|
127
|
-
: {
|
|
132
|
+
: {
|
|
133
|
+
affected: number,
|
|
134
|
+
insertId?: number | string,
|
|
135
|
+
});
|
|
128
136
|
|
|
129
137
|
export interface iC6RestResponse<RestData> {
|
|
130
138
|
// Backwards compatibility: base interface for rest/sql/session (singular)
|
|
@@ -172,6 +180,8 @@ export type iRestWebsocketPayload = {
|
|
|
172
180
|
METHOD: iRestMethods;
|
|
173
181
|
REQUEST: Record<string, any>;
|
|
174
182
|
REQUEST_PRIMARY_KEY: Record<string, any> | null;
|
|
183
|
+
RESPONSE?: Record<string, any> | Record<string, any>[];
|
|
184
|
+
RESPONSE_PRIMARY_KEY?: Record<string, any> | null;
|
|
175
185
|
};
|
|
176
186
|
};
|
|
177
187
|
|