@carbonorm/carbonnode 3.6.6 → 3.7.0

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/README.md CHANGED
@@ -562,6 +562,21 @@ export default Users;
562
562
 
563
563
 
564
564
 
565
+ # Git Hooks
566
+
567
+ This project uses Git hooks to automate certain tasks:
568
+
569
+ - **pre-commit**: Builds the project before pushing to ensure only working code is pushed
570
+ - **post-push**: Automatically publishes to npm when the version number changes
571
+
572
+ To set up the Git hooks, run:
573
+
574
+ ```bash
575
+ npm run hooks:setup
576
+ ```
577
+
578
+ This will configure Git to use the hooks in the `.githooks` directory. The hooks are automatically set up when you run `npm install` as well.
579
+
565
580
  # Support and Issues
566
581
 
567
582
  Any issues found should be reported on [GitHub](https://github.com/CarbonORM/CarbonNode/issues).
@@ -2,3 +2,4 @@ export declare const A: (tableName: string, alias: string) => string;
2
2
  export declare const F: (qualifiedCol: string, alias: string) => string;
3
3
  export declare const fieldEq: (leftCol: string, rightCol: string, leftAlias: string, rightAlias: string) => Record<string, string>;
4
4
  export declare const distSphere: (fromCol: string, toCol: string, fromAlias: string, toAlias: string) => any[];
5
+ export declare const stContains: (envelope: string, shape: string) => any[];
@@ -5,6 +5,7 @@ import { Modify } from "./modifyTypes";
5
5
  import { JoinType, OrderDirection, SQLComparisonOperator, SQLFunction } from "./mysqlTypes";
6
6
  import { CarbonReact } from "@carbonorm/carbonreact";
7
7
  import { OrmGenerics } from "./ormGenerics";
8
+ import { restOrm } from "../restOrm";
8
9
  export type iRestMethods = 'GET' | 'POST' | 'PUT' | 'DELETE';
9
10
  export declare const POST = "POST";
10
11
  export declare const PUT = "PUT";
@@ -215,7 +216,9 @@ export interface iC6Object<RestTableInterfaces extends {
215
216
  [K in Extract<keyof RestTableInterfaces, string>]: C6RestfulModel<K, RestTableInterfaces[K], keyof RestTableInterfaces[K] & string>;
216
217
  };
217
218
  PREFIX: string;
218
- IMPORT: (tableName: string) => Promise<iDynamicApiImport>;
219
+ ORM: {
220
+ [K in Extract<keyof RestTableInterfaces, string>]: C6RestfulModel<K, RestTableInterfaces[K], keyof RestTableInterfaces[K] & string> & ReturnType<typeof restOrm<OrmGenerics<any>>>;
221
+ }[];
219
222
  [key: string]: any;
220
223
  }
221
224
  export interface tC6RestApi {
package/dist/index.cjs.js CHANGED
@@ -842,7 +842,8 @@ var HttpExecutor = /** @class */ (function (_super) {
842
842
  // A part of me exists that wants to remove this, but it's a good feature
843
843
  // this allows developers the ability to cache requests based on primary key
844
844
  // for tables like `photos` this can be a huge performance boost
845
- if (undefined !== query
845
+ if (POST !== requestMethod
846
+ && undefined !== query
846
847
  && null !== query
847
848
  && undefined !== primaryKey
848
849
  && primaryKey in query) {
@@ -908,11 +909,11 @@ var HttpExecutor = /** @class */ (function (_super) {
908
909
  // returning the promise with this then is important for tests. todo - we could make that optional.
909
910
  // https://rapidapi.com/guides/axios-async-await
910
911
  return [2 /*return*/, axiosActiveRequest.then(function (response) { return tslib.__awaiter(_this, void 0, void 0, function () {
911
- var cacheIndex, callback, responseData_1, dependencies_1, fetchReferences_1, apiRequestPromises, _loop_1, _a, _b, _c, _i, tableToFetch;
912
+ var cacheIndex, callback, responseData_1, dependencies_1, fetchReferences_1, apiRequestPromises, _loop_1, tableToFetch;
912
913
  var _this = this;
913
- var _d, _e, _f, _g, _h, _j;
914
- return tslib.__generator(this, function (_k) {
915
- switch (_k.label) {
914
+ var _a, _b, _c, _d, _e, _f;
915
+ return tslib.__generator(this, function (_g) {
916
+ switch (_g.label) {
916
917
  case 0:
917
918
  // noinspection SuspiciousTypeOfGuard
918
919
  if (typeof response.data === 'string') {
@@ -971,12 +972,12 @@ var HttpExecutor = /** @class */ (function (_super) {
971
972
  else {
972
973
  callback();
973
974
  }
974
- if (!(C6.GET === requestMethod)) return [3 /*break*/, 6];
975
+ if (!(C6.GET === requestMethod)) return [3 /*break*/, 2];
975
976
  responseData_1 = response.data;
976
- returnGetNextPageFunction = 1 !== ((_d = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _d === void 0 ? void 0 : _d[C6.LIMIT]) &&
977
- ((_e = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _e === void 0 ? void 0 : _e[C6.LIMIT]) === responseData_1.rest.length;
977
+ returnGetNextPageFunction = 1 !== ((_a = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _a === void 0 ? void 0 : _a[C6.LIMIT]) &&
978
+ ((_b = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _b === void 0 ? void 0 : _b[C6.LIMIT]) === responseData_1.rest.length;
978
979
  if (false === isTest() || this.config.verbose) {
979
- console.groupCollapsed('%c API: Response (' + requestMethod + ' ' + tableName + ') returned length (' + ((_f = responseData_1.rest) === null || _f === void 0 ? void 0 : _f.length) + ') of possible (' + ((_g = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _g === void 0 ? void 0 : _g[C6.LIMIT]) + ') limit!', 'color: #0c0');
980
+ console.groupCollapsed('%c API: Response (' + requestMethod + ' ' + tableName + ') returned length (' + ((_c = responseData_1.rest) === null || _c === void 0 ? void 0 : _c.length) + ') of possible (' + ((_d = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _d === void 0 ? void 0 : _d[C6.LIMIT]) + ') limit!', 'color: #0c0');
980
981
  console.log('%c ' + requestMethod + ' ' + tableName, 'color: #0c0');
981
982
  console.log('%c Request Data (note you may see the success and/or error prompt):', 'color: #0c0', this.request);
982
983
  console.log('%c Response Data:', 'color: #0c0', responseData_1.rest);
@@ -991,12 +992,12 @@ var HttpExecutor = /** @class */ (function (_super) {
991
992
  responseData_1.next = undefined;
992
993
  if (true === debug
993
994
  && isLocal()) {
994
- reactToastify.toast.success("DEVS: Response returned length (" + ((_h = responseData_1.rest) === null || _h === void 0 ? void 0 : _h.length) + ") less than limit (" + ((_j = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _j === void 0 ? void 0 : _j[C6.LIMIT]) + ").", toastOptionsDevs);
995
+ reactToastify.toast.success("DEVS: Response returned length (" + ((_e = responseData_1.rest) === null || _e === void 0 ? void 0 : _e.length) + ") less than limit (" + ((_f = query === null || query === void 0 ? void 0 : query[C6.PAGINATION]) === null || _f === void 0 ? void 0 : _f[C6.LIMIT]) + ").", toastOptionsDevs);
995
996
  }
996
997
  }
997
998
  if (!(fetchDependencies
998
999
  && 'number' === typeof fetchDependencies
999
- && responseData_1.rest.length > 0)) return [3 /*break*/, 6];
1000
+ && responseData_1.rest.length > 0)) return [3 /*break*/, 2];
1000
1001
  console.groupCollapsed('%c API: Fetch Dependencies segment (' + requestMethod + ' ' + tableName + ')'
1001
1002
  + (fetchDependencies & exports.eFetchDependencies.CHILDREN ? ' | (CHILDREN|REFERENCED) ' : '')
1002
1003
  + (fetchDependencies & exports.eFetchDependencies.PARENTS ? ' | (PARENTS|REFERENCED_BY)' : '')
@@ -1067,97 +1068,73 @@ var HttpExecutor = /** @class */ (function (_super) {
1067
1068
  }); });
1068
1069
  console.log('fetchReferences', fetchReferences_1);
1069
1070
  _loop_1 = function (tableToFetch) {
1070
- var referencesTables, shouldContinue, fetchTable, RestApi, nextFetchDependencies;
1071
- var _l;
1072
- return tslib.__generator(this, function (_m) {
1073
- switch (_m.label) {
1074
- case 0:
1075
- if (fetchDependencies & exports.eFetchDependencies.C6ENTITY
1076
- && 'string' === typeof tableName
1077
- && tableName.endsWith("carbon_carbons")) {
1078
- referencesTables = responseData_1.rest.reduce(function (accumulator, row) {
1079
- if ('entity_tag' in row && !accumulator.includes(row['entity_tag'])) {
1080
- accumulator.push(row['entity_tag']);
1081
- }
1082
- return accumulator;
1083
- }, []).map(function (entityTag) { return entityTag.split('\\').pop().toLowerCase(); });
1084
- shouldContinue = referencesTables.find(function (referencesTable) { return tableToFetch.endsWith(referencesTable); });
1085
- if (!shouldContinue) {
1086
- console.log('%c C6ENTITY: The constraintTableName (' + tableToFetch + ') did not end with any value in referencesTables', 'color: #c00', referencesTables);
1087
- return [2 /*return*/, "continue"];
1088
- }
1089
- console.log('%c C6ENTITY: The constraintTableName (' + tableToFetch + ') will be fetched.', 'color: #0c0');
1090
- }
1091
- return [4 /*yield*/, C6.IMPORT(tableToFetch)];
1092
- case 1:
1093
- fetchTable = _m.sent();
1094
- RestApi = fetchTable.default;
1095
- console.log('%c Fetch Dependencies will select (' + tableToFetch + ') using GET request', 'color: #33ccff');
1096
- nextFetchDependencies = exports.eFetchDependencies.NONE;
1097
- if (fetchDependencies & exports.eFetchDependencies.RECURSIVE) {
1098
- if (fetchDependencies & exports.eFetchDependencies.ALL) {
1099
- throw Error('Recursive fetch dependencies with both PARENT and CHILD reference will result in an infin1ite loop. As there is not real ending condition, this is not supported.');
1100
- }
1101
- nextFetchDependencies = fetchDependencies;
1102
- }
1103
- else if (fetchDependencies & exports.eFetchDependencies.C6ENTITY) {
1104
- if (tableToFetch === "carbon_carbons") {
1105
- nextFetchDependencies = fetchDependencies;
1106
- }
1107
- else {
1108
- nextFetchDependencies = fetchDependencies ^ exports.eFetchDependencies.C6ENTITY;
1109
- }
1110
- }
1111
- console.log('fetchReferences', fetchReferences_1[tableToFetch], "Current fetchDependencies for (" + operatingTable + "):", fetchDependencies, "New fetchDependencies for (" + tableToFetch + "): ", nextFetchDependencies);
1112
- // todo - filter out ids that exist in state?!? note - remember that this does not necessarily mean the pk, but only known is its an FK to somewhere
1113
- // it not certain that they are using carbons' entities either
1114
- // this is a dynamic call to the rest api, any generated table may resolve with (RestApi)
1115
- // todo - using value to avoid joins.... but. maybe this should be a parameterizable option -- think race conditions; its safer to join
1116
- apiRequestPromises.push(RestApi.Get((_l = {},
1117
- _l[C6.WHERE] = {
1118
- 0: Object.keys(fetchReferences_1[tableToFetch]).reduce(function (sum, column) {
1119
- fetchReferences_1[tableToFetch][column] = fetchReferences_1[tableToFetch][column].flat(Infinity);
1120
- if (0 === fetchReferences_1[tableToFetch][column].length) {
1121
- console.warn('The column (' + column + ') was not found in the response data. We will not fetch.', responseData_1);
1122
- return false;
1123
- }
1124
- sum[column] = fetchReferences_1[tableToFetch][column].length === 1
1125
- ? fetchReferences_1[tableToFetch][column][0]
1126
- : [
1127
- C6.IN, fetchReferences_1[tableToFetch][column]
1128
- ];
1129
- return sum;
1130
- }, {})
1131
- },
1132
- _l.fetchDependencies = nextFetchDependencies,
1133
- _l)));
1134
- return [2 /*return*/];
1071
+ var _h;
1072
+ if (fetchDependencies & exports.eFetchDependencies.C6ENTITY
1073
+ && 'string' === typeof tableName
1074
+ && tableName.endsWith("carbon_carbons")) {
1075
+ // todo - rethink the table ref entity system - when tables are renamed? no hooks exist in mysql
1076
+ // since were already filtering on column, we can assume the first row constraint is the same as the rest
1077
+ var referencesTables = responseData_1.rest.reduce(function (accumulator, row) {
1078
+ if ('entity_tag' in row && !accumulator.includes(row['entity_tag'])) {
1079
+ accumulator.push(row['entity_tag']);
1080
+ }
1081
+ return accumulator;
1082
+ }, []).map(function (entityTag) { return entityTag.split('\\').pop().toLowerCase(); });
1083
+ var shouldContinue = referencesTables.find(function (referencesTable) { return tableToFetch.endsWith(referencesTable); });
1084
+ if (!shouldContinue) {
1085
+ console.log('%c C6ENTITY: The constraintTableName (' + tableToFetch + ') did not end with any value in referencesTables', 'color: #c00', referencesTables);
1086
+ return "continue";
1135
1087
  }
1136
- });
1088
+ console.log('%c C6ENTITY: The constraintTableName (' + tableToFetch + ') will be fetched.', 'color: #0c0');
1089
+ }
1090
+ var RestApi = C6.ORM[tableToFetch];
1091
+ console.log('%c Fetch Dependencies will select (' + tableToFetch + ') using GET request', 'color: #33ccff');
1092
+ var nextFetchDependencies = exports.eFetchDependencies.NONE;
1093
+ if (fetchDependencies & exports.eFetchDependencies.RECURSIVE) {
1094
+ if (fetchDependencies & exports.eFetchDependencies.ALL) {
1095
+ throw Error('Recursive fetch dependencies with both PARENT and CHILD reference will result in an infin1ite loop. As there is not real ending condition, this is not supported.');
1096
+ }
1097
+ nextFetchDependencies = fetchDependencies;
1098
+ }
1099
+ else if (fetchDependencies & exports.eFetchDependencies.C6ENTITY) {
1100
+ if (tableToFetch === "carbon_carbons") {
1101
+ nextFetchDependencies = fetchDependencies;
1102
+ }
1103
+ else {
1104
+ nextFetchDependencies = fetchDependencies ^ exports.eFetchDependencies.C6ENTITY;
1105
+ }
1106
+ }
1107
+ console.log('fetchReferences', fetchReferences_1[tableToFetch], "Current fetchDependencies for (" + operatingTable + "):", fetchDependencies, "New fetchDependencies for (" + tableToFetch + "): ", nextFetchDependencies);
1108
+ // todo - filter out ids that exist in state?!? note - remember that this does not necessarily mean the pk, but only known is its an FK to somewhere
1109
+ // it not certain that they are using carbons' entities either
1110
+ // this is a dynamic call to the rest api, any generated table may resolve with (RestApi)
1111
+ // todo - using value to avoid joins.... but. maybe this should be a parameterizable option -- think race conditions; its safer to join
1112
+ apiRequestPromises.push(RestApi.Get((_h = {},
1113
+ _h[C6.WHERE] = {
1114
+ 0: Object.keys(fetchReferences_1[tableToFetch]).reduce(function (sum, column) {
1115
+ fetchReferences_1[tableToFetch][column] = fetchReferences_1[tableToFetch][column].flat(Infinity);
1116
+ if (0 === fetchReferences_1[tableToFetch][column].length) {
1117
+ console.warn('The column (' + column + ') was not found in the response data. We will not fetch.', responseData_1);
1118
+ return false;
1119
+ }
1120
+ sum[column] = fetchReferences_1[tableToFetch][column].length === 1
1121
+ ? fetchReferences_1[tableToFetch][column][0]
1122
+ : [
1123
+ C6.IN, fetchReferences_1[tableToFetch][column]
1124
+ ];
1125
+ return sum;
1126
+ }, {})
1127
+ },
1128
+ _h.fetchDependencies = nextFetchDependencies,
1129
+ _h)));
1137
1130
  };
1138
- _a = fetchReferences_1;
1139
- _b = [];
1140
- for (_c in _a)
1141
- _b.push(_c);
1142
- _i = 0;
1143
- _k.label = 1;
1144
- case 1:
1145
- if (!(_i < _b.length)) return [3 /*break*/, 4];
1146
- _c = _b[_i];
1147
- if (!(_c in _a)) return [3 /*break*/, 3];
1148
- tableToFetch = _c;
1149
- return [5 /*yield**/, _loop_1(tableToFetch)];
1150
- case 2:
1151
- _k.sent();
1152
- _k.label = 3;
1153
- case 3:
1154
- _i++;
1155
- return [3 /*break*/, 1];
1156
- case 4:
1131
+ for (tableToFetch in fetchReferences_1) {
1132
+ _loop_1(tableToFetch);
1133
+ }
1157
1134
  console.groupEnd();
1158
1135
  return [4 /*yield*/, Promise.all(apiRequestPromises)];
1159
- case 5:
1160
- _k.sent();
1136
+ case 1:
1137
+ _g.sent();
1161
1138
  apiRequestPromises.map(function (promise) { return tslib.__awaiter(_this, void 0, void 0, function () {
1162
1139
  var _a, _b;
1163
1140
  return tslib.__generator(this, function (_c) {
@@ -1175,8 +1152,8 @@ var HttpExecutor = /** @class */ (function (_super) {
1175
1152
  }
1176
1153
  });
1177
1154
  }); });
1178
- _k.label = 6;
1179
- case 6:
1155
+ _g.label = 2;
1156
+ case 2:
1180
1157
  if (debug && isLocal()) {
1181
1158
  reactToastify.toast.success("DEVS: (" + requestMethod + ") request complete.", toastOptionsDevs);
1182
1159
  }
@@ -1278,7 +1255,16 @@ var ConditionBuilder = /** @class */ (function (_super) {
1278
1255
  C6C.IS, C6C.IS_NOT,
1279
1256
  C6C.BETWEEN, 'NOT BETWEEN',
1280
1257
  C6C.MATCH_AGAINST,
1281
- C6C.ST_DISTANCE_SPHERE
1258
+ C6C.ST_DISTANCE_SPHERE,
1259
+ // spatial predicates
1260
+ C6C.ST_CONTAINS,
1261
+ C6C.ST_INTERSECTS,
1262
+ C6C.ST_WITHIN,
1263
+ C6C.ST_CROSSES,
1264
+ C6C.ST_DISJOINT,
1265
+ C6C.ST_EQUALS,
1266
+ C6C.ST_OVERLAPS,
1267
+ C6C.ST_TOUCHES
1282
1268
  ]);
1283
1269
  return _this;
1284
1270
  }
@@ -1360,6 +1346,19 @@ var ConditionBuilder = /** @class */ (function (_super) {
1360
1346
  var threshold = Array.isArray(value) ? value[0] : value;
1361
1347
  return "ST_Distance_Sphere(".concat(col1, ", ").concat(col2, ") < ").concat(_this.addParam(params, '', threshold));
1362
1348
  }
1349
+ if ([
1350
+ C6C.ST_CONTAINS,
1351
+ C6C.ST_INTERSECTS,
1352
+ C6C.ST_WITHIN,
1353
+ C6C.ST_CROSSES,
1354
+ C6C.ST_DISJOINT,
1355
+ C6C.ST_EQUALS,
1356
+ C6C.ST_OVERLAPS,
1357
+ C6C.ST_TOUCHES
1358
+ ].includes(column)) {
1359
+ var geom1 = op[0], geom2 = op[1];
1360
+ return "".concat(column, "(").concat(geom1, ", ").concat(geom2, ")");
1361
+ }
1363
1362
  }
1364
1363
  var leftIsCol = _this.isColumnRef(column);
1365
1364
  var leftIsRef = _this.isTableReference(column);
@@ -1924,7 +1923,7 @@ function ExpressHandler(_a) {
1924
1923
  payload[C6C.WHERE][primaryKeyName] = primary;
1925
1924
  }
1926
1925
  else {
1927
- res.status(400).json({ error: "Invalid request: ".concat(method, " requires a primary key.") });
1926
+ res.status(400).json({ error: "Invalid request: ".concat(method, " requires a primary key (").concat(primaryKeyName, ").") });
1928
1927
  }
1929
1928
  break;
1930
1929
  case 'POST':
@@ -1973,6 +1972,10 @@ var fieldEq = function (leftCol, rightCol, leftAlias, rightAlias) {
1973
1972
  var distSphere = function (fromCol, toCol, fromAlias, toAlias) {
1974
1973
  return [C6C.ST_DISTANCE_SPHERE, F(fromCol, fromAlias), F(toCol, toAlias)];
1975
1974
  };
1975
+ // ST_Contains for map envelope/shape queries
1976
+ var stContains = function (envelope, shape) {
1977
+ return [C6C.ST_CONTAINS, envelope, shape];
1978
+ };
1976
1979
 
1977
1980
  function determineRuntimeJsType(mysqlType) {
1978
1981
  var base = mysqlType.toLowerCase().split('(')[0];
@@ -2119,6 +2122,7 @@ exports.removePrefixIfExists = removePrefixIfExists;
2119
2122
  exports.restOrm = restOrm;
2120
2123
  exports.restRequest = restRequest;
2121
2124
  exports.sortAndSerializeQueryObject = sortAndSerializeQueryObject;
2125
+ exports.stContains = stContains;
2122
2126
  exports.timeout = timeout;
2123
2127
  exports.toastOptions = toastOptions;
2124
2128
  exports.toastOptionsDevs = toastOptionsDevs;