@carbonorm/carbonnode 6.0.4 → 6.0.6
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/handlers/ExpressHandler.d.ts +3 -2
- package/dist/index.cjs.js +51 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +51 -3
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- 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.post.json +3 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.actor.post.latest.json +3 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.actor.put.lookup.json +3 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.address.post.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.address.post.latest.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.address.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.address.put.lookup.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.category.post.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.category.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.category.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.category.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.city.post.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.city.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.city.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.city.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.country.post.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.country.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.country.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.country.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.customer.post.latest.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.customer.put.lookup.json +5 -5
- package/src/__tests__/sakila-db/sqlResponses/C6.film.post.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.film.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.film.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.film.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.inventory.post.latest.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.inventory.put.lookup.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.language.post.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.language.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.language.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.language.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.payment.post.latest.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.payment.put.lookup.json +2 -2
- package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.json +3 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.rental.post.latest.json +3 -3
- package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.json +1 -1
- package/src/__tests__/sakila-db/sqlResponses/C6.rental.put.lookup.json +3 -3
- package/src/api/restRequest.ts +10 -0
- package/src/executors/HttpExecutor.ts +2 -1
- package/src/executors/SqlExecutor.ts +56 -16
- package/src/handlers/ExpressHandler.ts +4 -1
|
@@ -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
|
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import {DeleteQueryBuilder} from "../orm/queries/DeleteQueryBuilder";
|
|
2
|
-
import {PostQueryBuilder} from "../orm/queries/PostQueryBuilder";
|
|
3
|
-
import {SelectQueryBuilder} from "../orm/queries/SelectQueryBuilder";
|
|
4
|
-
import {UpdateQueryBuilder} from "../orm/queries/UpdateQueryBuilder";
|
|
5
|
-
import {OrmGenerics} from "../types/ormGenerics";
|
|
6
|
-
import {C6Constants as C6C} from "../constants/C6Constants";
|
|
1
|
+
import { DeleteQueryBuilder } from "../orm/queries/DeleteQueryBuilder";
|
|
2
|
+
import { PostQueryBuilder } from "../orm/queries/PostQueryBuilder";
|
|
3
|
+
import { SelectQueryBuilder } from "../orm/queries/SelectQueryBuilder";
|
|
4
|
+
import { UpdateQueryBuilder } from "../orm/queries/UpdateQueryBuilder";
|
|
5
|
+
import { OrmGenerics } from "../types/ormGenerics";
|
|
6
|
+
import { C6Constants as C6C } from "../constants/C6Constants";
|
|
7
7
|
import {
|
|
8
8
|
DetermineResponseDataType,
|
|
9
9
|
iRestWebsocketPayload,
|
|
10
10
|
} from "../types/ormInterfaces";
|
|
11
11
|
import namedPlaceholders from 'named-placeholders';
|
|
12
|
-
import type {PoolConnection} from 'mysql2/promise';
|
|
13
|
-
import {Buffer} from 'buffer';
|
|
14
|
-
import {Executor} from "./Executor";
|
|
12
|
+
import type { PoolConnection } from 'mysql2/promise';
|
|
13
|
+
import { Buffer } from 'buffer';
|
|
14
|
+
import { Executor } from "./Executor";
|
|
15
15
|
import { normalizeSingularRequest } from "../utils/normalizeSingularRequest";
|
|
16
|
-
import {loadSqlAllowList, normalizeSql} from "../utils/sqlAllowList";
|
|
16
|
+
import { loadSqlAllowList, normalizeSql } from "../utils/sqlAllowList";
|
|
17
17
|
|
|
18
18
|
export class SqlExecutor<
|
|
19
19
|
G extends OrmGenerics
|
|
20
20
|
> extends Executor<G> {
|
|
21
21
|
|
|
22
22
|
async execute(): Promise<DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>> {
|
|
23
|
-
const {TABLE_NAME} = this.config.restModel;
|
|
23
|
+
const { TABLE_NAME } = this.config.restModel;
|
|
24
24
|
const method = this.config.requestMethod;
|
|
25
25
|
|
|
26
26
|
// Normalize singular T-shaped requests into complex ORM shape (GET/PUT/DELETE)
|
|
@@ -42,6 +42,13 @@ export class SqlExecutor<
|
|
|
42
42
|
switch (method) {
|
|
43
43
|
case 'GET': {
|
|
44
44
|
const rest = await this.runQuery();
|
|
45
|
+
if (this.config.reactBootstrap) {
|
|
46
|
+
this.config.reactBootstrap.updateRestfulObjectArrays({
|
|
47
|
+
dataOrCallback: (rest as any).rest,
|
|
48
|
+
stateKey: this.config.restModel.TABLE_NAME,
|
|
49
|
+
uniqueObjectId: this.config.restModel.PRIMARY_SHORT as any,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
45
52
|
return rest as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>;
|
|
46
53
|
}
|
|
47
54
|
|
|
@@ -260,7 +267,16 @@ export class SqlExecutor<
|
|
|
260
267
|
response?: DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>
|
|
261
268
|
): Promise<void> {
|
|
262
269
|
const broadcast = this.config.websocketBroadcast;
|
|
263
|
-
|
|
270
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 broadcastWebsocketIfConfigured start", {
|
|
271
|
+
method: this.config.requestMethod,
|
|
272
|
+
hasBroadcast: Boolean(broadcast),
|
|
273
|
+
});
|
|
274
|
+
if (!broadcast || this.config.requestMethod === C6C.GET) {
|
|
275
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket broadcast skipped", {
|
|
276
|
+
reason: !broadcast ? "no broadcast configured" : "GET request",
|
|
277
|
+
});
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
264
280
|
|
|
265
281
|
const normalizedRequest = this.normalizeRequestPayload(this.extractRequestBody());
|
|
266
282
|
const pkShorts = this.config.restModel.PRIMARY_SHORT ?? [];
|
|
@@ -269,11 +285,27 @@ export class SqlExecutor<
|
|
|
269
285
|
let responseRest = response?.rest;
|
|
270
286
|
let responsePrimaryKey = this.extractPrimaryKeyValuesFromData(responseRest);
|
|
271
287
|
|
|
288
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket request payload", {
|
|
289
|
+
normalizedRequest,
|
|
290
|
+
requestPrimaryKey: this.extractPrimaryKeyValues(),
|
|
291
|
+
pkShorts,
|
|
292
|
+
});
|
|
293
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket response payload", {
|
|
294
|
+
responseRest,
|
|
295
|
+
responsePrimaryKey,
|
|
296
|
+
});
|
|
297
|
+
|
|
272
298
|
if (
|
|
273
299
|
(responseRest === null || (Array.isArray(responseRest) && responseRest.length === 0))
|
|
274
300
|
&& this.config.requestMethod === C6C.POST
|
|
275
301
|
) {
|
|
302
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 response rest empty, attempting synthesize", {
|
|
303
|
+
responseRest,
|
|
304
|
+
});
|
|
276
305
|
const insertId = (response as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']> & { insertId?: number | string | null })?.insertId;
|
|
306
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 POST insertId lookup", {
|
|
307
|
+
insertId,
|
|
308
|
+
});
|
|
277
309
|
if (insertId !== undefined && pkShorts.length === 1) {
|
|
278
310
|
const synthesizedRequest = {
|
|
279
311
|
...normalizedRequest,
|
|
@@ -298,6 +330,10 @@ export class SqlExecutor<
|
|
|
298
330
|
responsePrimaryKey = {
|
|
299
331
|
[pkShorts[0]]: insertId,
|
|
300
332
|
};
|
|
333
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 synthesized response payload", {
|
|
334
|
+
synthesized,
|
|
335
|
+
responsePrimaryKey,
|
|
336
|
+
});
|
|
301
337
|
}
|
|
302
338
|
}
|
|
303
339
|
|
|
@@ -313,8 +349,12 @@ export class SqlExecutor<
|
|
|
313
349
|
},
|
|
314
350
|
};
|
|
315
351
|
|
|
352
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket payload ready", payload);
|
|
353
|
+
|
|
316
354
|
try {
|
|
355
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket broadcast dispatch start");
|
|
317
356
|
await broadcast(payload);
|
|
357
|
+
this.config.verbose && console.log("[SQL EXECUTOR] 📣 websocket broadcast dispatch complete");
|
|
318
358
|
} catch (error) {
|
|
319
359
|
if (this.config.verbose) {
|
|
320
360
|
console.error("[SQL EXECUTOR] websocketBroadcast failed", error);
|
|
@@ -322,7 +362,7 @@ export class SqlExecutor<
|
|
|
322
362
|
}
|
|
323
363
|
}
|
|
324
364
|
async runQuery(): Promise<DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>> {
|
|
325
|
-
const {TABLE_NAME} = this.config.restModel;
|
|
365
|
+
const { TABLE_NAME } = this.config.restModel;
|
|
326
366
|
const method = this.config.requestMethod;
|
|
327
367
|
let builder: SelectQueryBuilder<G> | UpdateQueryBuilder<G> | DeleteQueryBuilder<G> | PostQueryBuilder<G>;
|
|
328
368
|
|
|
@@ -361,15 +401,15 @@ export class SqlExecutor<
|
|
|
361
401
|
if (method === 'GET') {
|
|
362
402
|
return {
|
|
363
403
|
rest: result.map(this.serialize),
|
|
364
|
-
sql: {sql, values}
|
|
404
|
+
sql: { sql, values }
|
|
365
405
|
} as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>;
|
|
366
406
|
} else {
|
|
367
|
-
this.config.verbose &&
|
|
407
|
+
this.config.verbose && console.log(`[SQL EXECUTOR] ✏️ Rows affected:`, result.affectedRows);
|
|
368
408
|
return {
|
|
369
409
|
affected: result.affectedRows as number,
|
|
370
410
|
insertId: result.insertId as number,
|
|
371
411
|
rest: [], // TODO - remove rest empty array from non-GET responses?
|
|
372
|
-
sql: {sql, values}
|
|
412
|
+
sql: { sql, values }
|
|
373
413
|
} as DetermineResponseDataType<G['RequestMethod'], G['RestTableInterface']>;
|
|
374
414
|
}
|
|
375
415
|
});
|
|
@@ -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);
|