@futdevpro/nts-dynamo 1.10.5 → 1.10.7

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.
Files changed (79) hide show
  1. package/.github/workflows/main.yml +1 -2
  2. package/build/_collections/archive.util.d.ts +1 -1
  3. package/build/_collections/archive.util.js +2 -2
  4. package/build/_collections/archive.util.js.map +1 -1
  5. package/build/_collections/archive.util.spec.js +3 -3
  6. package/build/_collections/archive.util.spec.js.map +1 -1
  7. package/build/_models/control-models/api-call-params.control-model.d.ts +3 -30
  8. package/build/_models/control-models/api-call-params.control-model.d.ts.map +1 -1
  9. package/build/_models/control-models/api-call-params.control-model.js +26 -13
  10. package/build/_models/control-models/api-call-params.control-model.js.map +1 -1
  11. package/build/_models/control-models/api-call-params.control-model.spec.js +6 -6
  12. package/build/_models/control-models/app-params.control-model.d.ts +1 -1
  13. package/build/_models/control-models/app-params.control-model.d.ts.map +1 -1
  14. package/build/_models/control-models/app-params.control-model.js.map +1 -1
  15. package/build/_models/control-models/endpoint-params.control-model.d.ts +2 -5
  16. package/build/_models/control-models/endpoint-params.control-model.d.ts.map +1 -1
  17. package/build/_models/control-models/endpoint-params.control-model.js +13 -12
  18. package/build/_models/control-models/endpoint-params.control-model.js.map +1 -1
  19. package/build/_modules/socket/_models/socket-presence.control-model.d.ts.map +1 -1
  20. package/build/_modules/socket/_models/socket-presence.control-model.js +3 -1
  21. package/build/_modules/socket/_models/socket-presence.control-model.js.map +1 -1
  22. package/build/_modules/socket/_services/socket-server.service.d.ts.map +1 -1
  23. package/build/_modules/socket/_services/socket-server.service.js +3 -1
  24. package/build/_modules/socket/_services/socket-server.service.js.map +1 -1
  25. package/build/_modules/socket/app-extended.server.d.ts.map +1 -1
  26. package/build/_modules/socket/app-extended.server.js +3 -1
  27. package/build/_modules/socket/app-extended.server.js.map +1 -1
  28. package/build/_services/base/data.service.d.ts +4 -3
  29. package/build/_services/base/data.service.d.ts.map +1 -1
  30. package/build/_services/base/data.service.js +374 -76
  31. package/build/_services/base/data.service.js.map +1 -1
  32. package/build/_services/base/db.service.d.ts.map +1 -1
  33. package/build/_services/base/db.service.js +3 -1
  34. package/build/_services/base/db.service.js.map +1 -1
  35. package/build/_services/base/singleton.service.d.ts.map +1 -1
  36. package/build/_services/base/singleton.service.js +1 -0
  37. package/build/_services/base/singleton.service.js.map +1 -1
  38. package/build/_services/core/api.service.d.ts +1 -1
  39. package/build/_services/core/api.service.d.ts.map +1 -1
  40. package/build/_services/core/api.service.js +19 -7
  41. package/build/_services/core/api.service.js.map +1 -1
  42. package/build/_services/core/api.service.spec.js +4 -3
  43. package/build/_services/core/api.service.spec.js.map +1 -1
  44. package/build/_services/core/auth.service.d.ts +1 -0
  45. package/build/_services/core/auth.service.d.ts.map +1 -1
  46. package/build/_services/core/auth.service.js.map +1 -1
  47. package/build/_services/core/email.service.d.ts.map +1 -1
  48. package/build/_services/core/email.service.js +4 -1
  49. package/build/_services/core/email.service.js.map +1 -1
  50. package/build/_services/core/global.service.d.ts.map +1 -1
  51. package/build/_services/core/global.service.js +1 -0
  52. package/build/_services/core/global.service.js.map +1 -1
  53. package/build/_services/route/routing-module.service.d.ts.map +1 -1
  54. package/build/_services/route/routing-module.service.js +3 -1
  55. package/build/_services/route/routing-module.service.js.map +1 -1
  56. package/build/_services/server/app.server.d.ts.map +1 -1
  57. package/build/_services/server/app.server.js +3 -1
  58. package/build/_services/server/app.server.js.map +1 -1
  59. package/nodemon.json +1 -1
  60. package/package.json +5 -4
  61. package/src/_collections/archive.util.spec.ts +3 -4
  62. package/src/_collections/archive.util.ts +2 -2
  63. package/src/_models/control-models/api-call-params.control-model.spec.ts +6 -6
  64. package/src/_models/control-models/api-call-params.control-model.ts +30 -43
  65. package/src/_models/control-models/app-params.control-model.ts +1 -1
  66. package/src/_models/control-models/endpoint-params.control-model.ts +19 -13
  67. package/src/_modules/socket/_models/socket-presence.control-model.ts +5 -3
  68. package/src/_modules/socket/_services/socket-server.service.ts +3 -1
  69. package/src/_modules/socket/app-extended.server.ts +3 -1
  70. package/src/_services/base/data.service.ts +512 -119
  71. package/src/_services/base/db.service.ts +3 -1
  72. package/src/_services/base/singleton.service.ts +1 -0
  73. package/src/_services/core/api.service.spec.ts +3 -3
  74. package/src/_services/core/api.service.ts +24 -8
  75. package/src/_services/core/auth.service.ts +1 -0
  76. package/src/_services/core/email.service.ts +4 -1
  77. package/src/_services/core/global.service.ts +1 -0
  78. package/src/_services/route/routing-module.service.ts +3 -1
  79. package/src/_services/server/app.server.ts +3 -1
@@ -2,19 +2,24 @@
2
2
  import {
3
3
  DyFM_AnyError,
4
4
  DyFM_Array,
5
+ DyFM_BasicProperty_Type,
5
6
  DyFM_Data_Params,
6
7
  DyFM_DataModel_Params,
7
8
  DyFM_DataProperty_Params,
8
9
  DyFM_DBFilter,
10
+ DyFM_DBĐNestedPropertySort,
11
+ DyFM_DBĐPropertySort,
9
12
  DyFM_DBĐSort,
10
13
  DyFM_Error,
11
14
  DyFM_Error_Settings,
12
15
  DyFM_ErrorLevel,
13
16
  DyFM_Log,
14
17
  DyFM_Metadata,
18
+ DyFM_NestPropertySearch,
15
19
  DyFM_RangeValue,
16
20
  DyFM_SearchQuery,
17
- DyFM_SearchResult
21
+ DyFM_SearchResult,
22
+ DyFM_SpecialSearch
18
23
  } from '@futdevpro/fsm-dynamo';
19
24
 
20
25
  import { DyNTS_getArchivedDBName } from '../../_collections/archive.util';
@@ -201,7 +206,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
201
206
 
202
207
  let dataExists: T = await this.dataDBService.getDataById(id);
203
208
 
204
- if (this.haveArchiveDataService && !skipArchiveLoad) {
209
+ if (!dataExists && this.haveArchiveDataService && !skipArchiveLoad) {
205
210
  const archiveDataService: DyNTS_ArchiveDataService<T> = this.getArchiveDataService();
206
211
 
207
212
  dataExists = await archiveDataService.getDataByOriginalId(id, true);
@@ -723,7 +728,24 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
723
728
 
724
729
  await this.validateForSave(data);
725
730
 
726
- if (!data._id && (!this.depKey || !data[this.depKey])) {
731
+ if (!data._id) {
732
+ if (this.depKey && !data[this.depKey]) {
733
+ throw new DyFM_Error({
734
+ ...this._getDefaultErrorSettings(
735
+ 'saveData',
736
+ new Error(
737
+ `saveData was unsuccessful: dependency data id missing from data ` +
738
+ `(key: ${this.depKey}, ${this.dataParams.dataName})`
739
+ )
740
+ ),
741
+
742
+ errorCode: 'NTS-DS0-SD1',
743
+ additionalContent: {
744
+ data: data,
745
+ },
746
+ });
747
+ }
748
+
727
749
  // if ID of dependencyID is not present, data not exists, create new data
728
750
  data = await this.dataDBService.createData(data, this.issuer);
729
751
 
@@ -750,7 +772,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
750
772
  )
751
773
  ),
752
774
 
753
- errorCode: 'NTS-DS0-SD1',
775
+ errorCode: 'NTS-DS0-SD2',
754
776
  additionalContent: {
755
777
  data: data,
756
778
  },
@@ -778,7 +800,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
778
800
  )
779
801
  ),
780
802
 
781
- errorCode: 'NTS-DS0-SD2',
803
+ errorCode: 'NTS-DS0-SD3',
782
804
  additionalContent: {
783
805
  data: data,
784
806
  },
@@ -815,7 +837,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
815
837
  )
816
838
  ),
817
839
 
818
- errorCode: 'NTS-DS0-SD3',
840
+ errorCode: 'NTS-DS0-SD4',
819
841
  });
820
842
  }
821
843
  }
@@ -835,7 +857,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
835
857
  )
836
858
  ),
837
859
 
838
- errorCode: 'NTS-DS0-SD4',
860
+ errorCode: 'NTS-DS0-SD5',
839
861
  additionalContent: {
840
862
  data: data,
841
863
  },
@@ -854,6 +876,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
854
876
  'NTS-DS0-SD2',
855
877
  'NTS-DS0-SD3',
856
878
  'NTS-DS0-SD4',
879
+ 'NTS-DS0-SD5',
857
880
  ].includes(error?.errorCode)) {
858
881
  throw error;
859
882
 
@@ -1101,7 +1124,10 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
1101
1124
  }
1102
1125
  );
1103
1126
  } catch (error) {
1104
- if ([ 'NTS-DS0-VD1', 'NTS-DS0-VD2' ].includes(error?.errorCode)) {
1127
+ if ([
1128
+ 'NTS-DS0-VD1',
1129
+ 'NTS-DS0-VD2'
1130
+ ].includes(error?.errorCode)) {
1105
1131
  throw error;
1106
1132
  } else {
1107
1133
  throw new DyFM_Error({
@@ -1165,24 +1191,92 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
1165
1191
  dataList = await this.getAll();
1166
1192
  }
1167
1193
 
1168
- const filterKeys = Object.keys(query.filterBy);
1194
+ const filterKeys: string[] = Object.keys(query.filterBy);
1169
1195
  const filterFunctionsByKey: { [key: string]: (dataProperty) => boolean } = {};
1170
1196
 
1197
+ const addFilterKeys: string[] = [];
1198
+ const removeFilterKeys: string[] = [];
1199
+
1171
1200
  filterKeys.forEach((key: string): void => {
1172
- filterFunctionsByKey[key] = this.getFilterFunctionForKey(
1173
- key, query.filterBy[key]
1174
- );
1201
+ const filterBy = query.filterBy[key];
1202
+
1203
+ if (filterBy.isSpecialNestSearch) {
1204
+ filterBy.nestedPropertySearches.forEach((nestSearch: DyFM_NestPropertySearch<any>): void => {
1205
+ const nestKey = nestSearch.nestKeys.join('.');
1206
+ filterFunctionsByKey[nestKey] = this.getFilterFunctionForKey(
1207
+ nestKey,
1208
+ nestSearch.search,
1209
+ nestSearch.valueType
1210
+ );
1211
+ query.filterBy[nestKey] = nestSearch;
1212
+ addFilterKeys.push(nestKey);
1213
+ });
1214
+ removeFilterKeys.push(key);
1215
+ } else {
1216
+ filterFunctionsByKey[key] = this.getFilterFunctionForKey(key, filterBy);
1217
+ }
1218
+ });
1219
+
1220
+ addFilterKeys.forEach((key: string): void => {
1221
+ filterKeys.push(key);
1222
+ });
1223
+ removeFilterKeys.forEach((key: string): void => {
1224
+ filterKeys.splice(filterKeys.indexOf(key), 1);
1175
1225
  });
1176
1226
 
1177
1227
  query.sortBy.forEach((sort: DyFM_DBĐSort): void => {
1178
- dataList.sort(this.getSortFunctionForKey(sort.key, sort.order));
1228
+ dataList.sort(this.getSortFunctionForKey(sort));
1179
1229
  });
1180
1230
 
1181
- dataList = dataList.filter(
1182
- (data: T): boolean => filterKeys.every(
1183
- (key: string): boolean => filterFunctionsByKey[key](data[key])
1184
- )
1185
- );
1231
+ if (filterKeys.some((key: string): boolean => key.includes('.'))) {
1232
+ const keyResolvers: { [key: string]: (data: T) => any } = {};
1233
+
1234
+ filterKeys.forEach((key: string): void => {
1235
+ if (key.includes('.')) {
1236
+ if (!query.filterBy[key].nestKeys) {
1237
+ throw new DyFM_Error({
1238
+ ...this._getDefaultErrorSettings(
1239
+ 'searchData',
1240
+ new Error(
1241
+ `searchData failed, nestKeys missing from nestedPropertySearch! ` +
1242
+ `(${this.dataParams.dataName})`
1243
+ )
1244
+ ),
1245
+
1246
+ errorCode: 'NTS-DS0-SD1',
1247
+ });
1248
+ }
1249
+
1250
+ keyResolvers[key] = this.getKeyResolver(query.filterBy[key].nestKeys);
1251
+ } else {
1252
+ keyResolvers[key] = (data: T): any => data[key];
1253
+ }
1254
+ });
1255
+
1256
+ if (filterKeys.some((key: string): boolean => query.filterBy[key].isSpecialNestSearch)) {
1257
+ dataList = dataList.filter(
1258
+ (data: T): boolean => filterKeys.every(
1259
+ (key: string): boolean => query.filterBy[key].isSpecialNestSearch ?
1260
+ keyResolvers[key](data).some(
1261
+ (dataProperty: any): boolean => filterFunctionsByKey[key](dataProperty)
1262
+ ) :
1263
+ filterFunctionsByKey[key](keyResolvers[key](data))
1264
+ )
1265
+ );
1266
+ } else {
1267
+ dataList = dataList.filter(
1268
+ (data: T): boolean => filterKeys.every(
1269
+ (key: string): boolean => filterFunctionsByKey[key](keyResolvers[key](data))
1270
+ )
1271
+ );
1272
+ }
1273
+ } else {
1274
+ dataList = dataList.filter(
1275
+ (data: T): boolean => filterKeys.every(
1276
+ (key: string): boolean => filterFunctionsByKey[key](data[key])
1277
+ )
1278
+ );
1279
+ }
1186
1280
 
1187
1281
  return {
1188
1282
  results: dataList,
@@ -1197,47 +1291,49 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
1197
1291
  }
1198
1292
  }
1199
1293
 
1200
- protected getFilterFunctionForKey<T>(
1294
+ protected getFilterFunctionForKey<T, N>(
1201
1295
  key: string,
1202
- searchValue: T | T[] | DyFM_RangeValue<T>,
1296
+ searchValue: T | T[] | DyFM_RangeValue<T> | DyFM_SpecialSearch<N>,
1297
+ propertyType?: DyFM_BasicProperty_Type
1203
1298
  ): (dataProperty) => boolean {
1204
- if (!this.dataParams.properties[key]) {
1205
- throw new DyFM_Error({
1206
- ...this._getDefaultErrorSettings(
1207
- 'getFilterFunctionForKey',
1208
- new Error(
1209
- `getFilterFunctionForKey failed, key not found in dataParams ` +
1210
- `(${this.dataParams.dataName})`
1211
- )
1212
- ),
1299
+ try {
1300
+ if (searchValue === undefined) {
1301
+ throw new DyFM_Error({
1302
+ ...this._getDefaultErrorSettings(
1303
+ 'getFilterFunctionForKey',
1304
+ new Error(
1305
+ `getFilterFunctionForKey failed, searchValue is missing for key: "${key}" ` +
1306
+ `(${this.dataParams.dataName})`
1307
+ )
1308
+ ),
1213
1309
 
1214
- errorCode: 'NTS-DS0-GFF1',
1215
- });
1216
- }
1310
+ errorCode: 'NTS-DS0-GFF1',
1311
+ });
1312
+ }
1217
1313
 
1218
- if (searchValue === undefined) {
1219
- throw new DyFM_Error({
1220
- ...this._getDefaultErrorSettings(
1221
- 'getFilterFunctionForKey',
1222
- new Error(
1223
- `getFilterFunctionForKey failed, searchValue is missing! ` +
1224
- `(${this.dataParams.dataName})`
1225
- )
1226
- ),
1314
+ if (!key.includes('.')) {
1315
+ if (!this.dataParams.properties[key]) {
1316
+ throw new DyFM_Error({
1317
+ ...this._getDefaultErrorSettings(
1318
+ 'getFilterFunctionForKey',
1319
+ new Error(
1320
+ `getFilterFunctionForKey failed, key not found in dataParams: "${key}" ` +
1321
+ `(${this.dataParams.dataName})`
1322
+ )
1323
+ ),
1227
1324
 
1228
- errorCode: 'NTS-DS0-GFF2',
1229
- });
1230
- }
1325
+ errorCode: 'NTS-DS0-GFF2',
1326
+ });
1327
+ }
1231
1328
 
1232
-
1233
- switch (this.dataParams.properties[key].type) {
1234
- case 'String':
1235
- if (typeof searchValue !== 'string') {
1329
+ propertyType = this.dataParams.properties[key].type;
1330
+ } else {
1331
+ if (!propertyType) {
1236
1332
  throw new DyFM_Error({
1237
1333
  ...this._getDefaultErrorSettings(
1238
1334
  'getFilterFunctionForKey',
1239
1335
  new Error(
1240
- `getFilterFunctionForKey failed, searchValue is not a string! ` +
1336
+ `getFilterFunctionForKey failed, propertyType is missing for key: "${key}" ` +
1241
1337
  `(${this.dataParams.dataName})`
1242
1338
  )
1243
1339
  ),
@@ -1246,79 +1342,256 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
1246
1342
  });
1247
1343
  }
1248
1344
 
1249
- const lowerCaseSearchValue: string = (searchValue as string).toLowerCase();
1250
1345
 
1251
- return (dataProperty): boolean =>
1252
- (dataProperty as string).toLowerCase().includes(lowerCaseSearchValue);
1346
+ }
1347
+
1348
+ switch (propertyType) {
1349
+ case DyFM_BasicProperty_Type.string:
1350
+ if (typeof searchValue !== 'string') {
1351
+ throw new DyFM_Error({
1352
+ ...this._getDefaultErrorSettings(
1353
+ 'getFilterFunctionForKey',
1354
+ new Error(
1355
+ `getFilterFunctionForKey failed, searchValue is not a string! ` +
1356
+ `(${this.dataParams.dataName})`
1357
+ )
1358
+ ),
1253
1359
 
1254
- case 'Date':
1255
- if ((searchValue as DyFM_RangeValue).isRange) {
1256
- const rangeAsNumber = new DyFM_RangeValue<number>(
1257
- +new Date((searchValue as DyFM_RangeValue).from),
1258
- +new Date((searchValue as DyFM_RangeValue).to)
1259
- );
1360
+ errorCode: 'NTS-DS0-GFF4',
1361
+ });
1362
+ }
1260
1363
 
1261
- return (dataProperty): boolean => DyFM_RangeValue.isInRange(
1262
- +new Date(dataProperty), rangeAsNumber
1263
- );
1264
- }
1364
+ if (Array.isArray(searchValue)) {
1365
+ const lowerCaseSearchValueArray: string[] = (searchValue as string[]).filter(
1366
+ (searchString: string): boolean => Boolean(searchString)
1367
+ ).map(
1368
+ (searchString: string): string => searchString.toLowerCase()
1369
+ );
1265
1370
 
1266
- if (Array.isArray(searchValue)) {
1267
- const searchValueAsDateArray = (searchValue as Date[]).map(
1268
- (date: Date): Date => new Date(date)
1269
- );
1371
+ return (dataProperty: string): boolean => lowerCaseSearchValueArray.some(
1372
+ (searchString: string): boolean => dataProperty?.toLowerCase().includes(searchString)
1373
+ );
1374
+ } else {
1375
+ const lowerCaseSearchValue: string = (searchValue as string)?.toLowerCase();
1376
+
1377
+ if (!lowerCaseSearchValue) {
1378
+ return (dataProperty: string): boolean => !dataProperty;
1379
+ }
1380
+
1381
+ return (dataProperty: string): boolean =>
1382
+ dataProperty?.toLowerCase().includes(lowerCaseSearchValue);
1383
+ }
1384
+
1385
+ case DyFM_BasicProperty_Type.date:
1386
+ if ((searchValue as DyFM_RangeValue).isRange) {
1387
+ if (
1388
+ (searchValue as DyFM_RangeValue).from === undefined ||
1389
+ (searchValue as DyFM_RangeValue).from === null
1390
+ ) {
1391
+ const toAsNumber = +new Date((searchValue as DyFM_RangeValue).to);
1392
+
1393
+ return (dataProperty): boolean => +new Date(dataProperty) <= toAsNumber;
1394
+ } else if (
1395
+ (searchValue as DyFM_RangeValue).to === undefined ||
1396
+ (searchValue as DyFM_RangeValue).to === null
1397
+ ) {
1398
+ const fromAsNumber = +new Date((searchValue as DyFM_RangeValue).from);
1399
+
1400
+ return (dataProperty): boolean => +new Date(dataProperty) >= fromAsNumber;
1401
+ }
1402
+
1403
+ const rangeAsNumber = new DyFM_RangeValue<number>(
1404
+ +new Date((searchValue as DyFM_RangeValue).from),
1405
+ +new Date((searchValue as DyFM_RangeValue).to)
1406
+ );
1407
+
1408
+ return (dataProperty): boolean => DyFM_RangeValue.isInRange(
1409
+ +new Date(dataProperty), rangeAsNumber
1410
+ );
1411
+ }
1270
1412
 
1271
- return (dataProperty): boolean => searchValueAsDateArray.includes(new Date(dataProperty));
1272
- }
1413
+ if (Array.isArray(searchValue)) {
1414
+ const searchValueAsNumberArray: number[] = (searchValue as Date[]).map(
1415
+ (date: Date): number => +new Date(date)
1416
+ );
1417
+
1418
+ return (dataProperty): boolean => searchValueAsNumberArray.includes(+new Date(dataProperty));
1419
+ }
1420
+
1421
+ const searchValueAsNumber: number = +new Date(searchValue as Date);
1422
+
1423
+ return (dataProperty): boolean => +new Date(dataProperty) === searchValueAsNumber;
1424
+
1425
+ case DyFM_BasicProperty_Type.number:
1426
+ if ((searchValue as DyFM_RangeValue).isRange) {
1427
+ if (
1428
+ (searchValue as DyFM_RangeValue).from === undefined ||
1429
+ (searchValue as DyFM_RangeValue).from === null
1430
+ ) {
1431
+ return (dataProperty): boolean => dataProperty <= (searchValue as DyFM_RangeValue).to;
1432
+ } else if (
1433
+ (searchValue as DyFM_RangeValue).to === undefined ||
1434
+ (searchValue as DyFM_RangeValue).to === null
1435
+ ) {
1436
+ return (dataProperty): boolean => dataProperty >= (searchValue as DyFM_RangeValue).from;
1437
+ }
1438
+
1439
+ return (dataProperty): boolean => DyFM_RangeValue.isInRange(
1440
+ dataProperty, searchValue as DyFM_RangeValue<number>
1441
+ );
1442
+ }
1443
+
1444
+ if (Array.isArray(searchValue)) {
1445
+ return (dataProperty): boolean => (searchValue as number[]).includes(dataProperty);
1446
+ }
1273
1447
 
1274
- const searchValueAsDate: Date = new Date(searchValue as Date);
1448
+ return (dataProperty): boolean => dataProperty === searchValue;
1275
1449
 
1276
- return (dataProperty): boolean => new Date(dataProperty) === searchValueAsDate;
1450
+ case DyFM_BasicProperty_Type.boolean:
1451
+ return (dataProperty): boolean => dataProperty === searchValue;
1277
1452
 
1278
- case 'Number':
1279
- if ((searchValue as DyFM_RangeValue).isRange) {
1280
- return (dataProperty): boolean => DyFM_RangeValue.isInRange(
1281
- dataProperty, searchValue as DyFM_RangeValue<number>
1282
- );
1283
- }
1453
+ case DyFM_BasicProperty_Type.object:
1454
+ if (Array.isArray(searchValue)) {
1455
+ throw new DyFM_Error({
1456
+ ...this._getDefaultErrorSettings(
1457
+ 'getFilterFunctionForKey',
1458
+ new Error(
1459
+ `getFilterFunctionForKey failed, array search not implemented for this type ` +
1460
+ `(${this.dataParams.dataName})`
1461
+ )
1462
+ ),
1284
1463
 
1285
- if (Array.isArray(searchValue)) {
1286
- return (dataProperty): boolean => (searchValue as number[]).includes(dataProperty);
1287
- }
1288
-
1289
- return (dataProperty): boolean => dataProperty === searchValue;
1464
+ errorCode: 'NTS-DS0-GFF5',
1465
+ });
1466
+ }
1290
1467
 
1291
- case 'Boolean':
1292
- return (dataProperty): boolean => dataProperty === searchValue;
1468
+ return (dataProperty): boolean => {
1469
+ const searchValueKeys: string[] = Object.keys(searchValue as object);
1470
+ const stringifiedSearchValue = {};
1293
1471
 
1294
- default:
1295
- if ((searchValue as DyFM_RangeValue).isRange) {
1296
- throw new DyFM_Error({
1297
- ...this._getDefaultErrorSettings(
1298
- 'getFilterFunctionForKey',
1299
- new Error(
1300
- `getFilterFunctionForKey failed, range search not implemented for this type ` +
1301
- `(${this.dataParams.dataName})`
1302
- )
1303
- ),
1472
+ try {
1473
+ searchValueKeys.forEach(
1474
+ (key: string): void => {
1475
+ stringifiedSearchValue[key] = JSON.stringify(searchValue[key]);
1476
+ }
1477
+ );
1478
+ } catch (error) {
1479
+ throw new DyFM_Error({
1480
+ ...this._getDefaultErrorSettings(
1481
+ 'getFilterFunctionForKey',
1482
+ new Error(
1483
+ `getFilterFunctionForKey failed, object search failed! ` +
1484
+ `(${this.dataParams.dataName})`
1485
+ )
1486
+ ),
1304
1487
 
1305
- errorCode: 'NTS-DS0-GFF3',
1306
- });
1307
- }
1488
+ errorCode: 'NTS-DS0-GFF6',
1489
+ additionalContent: {
1490
+ searchValue: searchValue,
1491
+ },
1492
+ });
1493
+ }
1308
1494
 
1309
- if (Array.isArray(searchValue)) {
1310
- return (dataProperty): boolean => (searchValue as number[]).includes(dataProperty);
1495
+ return searchValueKeys.every(
1496
+ (key: string): boolean => {
1497
+ try {
1498
+ return stringifiedSearchValue[key] === JSON.stringify(dataProperty[key]);
1499
+ } catch (error) {
1500
+ console.error(
1501
+ 'object filter returning false, bc of an error',
1502
+ 'searchValue:', searchValue,
1503
+ 'dataProperty:', dataProperty,
1504
+ 'key:', key,
1505
+ 'error:', error
1506
+ );
1507
+ return false;
1508
+ }
1509
+ }
1510
+ );
1511
+ }
1512
+
1513
+ default:
1514
+ if ((searchValue as DyFM_RangeValue).isRange) {
1515
+ throw new DyFM_Error({
1516
+ ...this._getDefaultErrorSettings(
1517
+ 'getFilterFunctionForKey',
1518
+ new Error(
1519
+ `getFilterFunctionForKey failed, range search not implemented for this type ` +
1520
+ `(${this.dataParams.dataName})`
1521
+ )
1522
+ ),
1523
+
1524
+ errorCode: 'NTS-DS0-GFF7',
1525
+ });
1526
+ }
1527
+
1528
+ if (Array.isArray(searchValue)) {
1529
+ return (dataProperty): boolean => (searchValue as number[]).includes(dataProperty);
1530
+ }
1531
+
1532
+ return (dataProperty): boolean => dataProperty === searchValue;
1533
+ }
1534
+ } catch (error) {
1535
+ throw new DyFM_Error({
1536
+ ...this._getDefaultErrorSettings(
1537
+ 'getFilterFunctionForKey',
1538
+ error
1539
+ ),
1540
+
1541
+ errorCode: 'NTS-DS0-GFF0',
1542
+ additionalContent: {
1543
+ key: key,
1544
+ searchValue: searchValue,
1545
+ propertyType: propertyType,
1546
+ },
1547
+ });
1548
+ }
1549
+ }
1550
+
1551
+ private getKeyResolver(nestKeys: string[]): (data: T) => any {
1552
+ return (data: T): any => {
1553
+ let value: any = data;
1554
+
1555
+ nestKeys.forEach((nestKey: string): void => {
1556
+ if (!value) {
1557
+ return;
1311
1558
  }
1312
1559
 
1313
- return (dataProperty): boolean => dataProperty === searchValue;
1314
- }
1560
+ if (nestKey === '*') {
1561
+ if (Array.isArray(value[nestKey])) {
1562
+ if (Array.isArray(value)) {
1563
+ value = value[nestKey].map((element: any): any => element[nestKey]).flat();
1564
+ } else {
1565
+ value = value[nestKey].map((element: any): any => element[nestKey]);
1566
+ }
1567
+ } else if (value[nestKey] && typeof value[nestKey] === 'object') {
1568
+ value = Object.values(value[nestKey]);
1569
+ } else {
1570
+ value = value[nestKey];
1571
+ }
1572
+ } else if (Array.isArray(value)) {
1573
+ if (!isNaN(+nestKey)) {
1574
+ value = value[+nestKey];
1575
+ } else {
1576
+ value = value.map((element: any): any => element ? element[nestKey] : element);
1577
+ }
1578
+ } else {
1579
+ value = value[nestKey];
1580
+ }
1581
+ });
1582
+
1583
+ return value;
1584
+ };
1315
1585
  }
1316
1586
 
1317
- protected getSortFunctionForKey<T>(
1318
- key: string,
1319
- sortDirection: 1 | -1 | 'asc' | 'desc' | 'ascending' | 'descending'
1320
- ): (a: T, b: T) => number {
1321
- if (!this.dataParams.properties[key]) {
1587
+ protected getSortFunctionForKey<T>(sortSettings: DyFM_DBĐSort): (a: T, b: T) => number {
1588
+ let keyResolver: (data: any) => any;
1589
+ let valueType: DyFM_BasicProperty_Type;
1590
+
1591
+ if (
1592
+ !this.dataParams.properties[(sortSettings as DyFM_DBĐPropertySort).key] &&
1593
+ !(sortSettings as DyFM_DBĐNestedPropertySort).isNestedPropertySort
1594
+ ) {
1322
1595
  throw new DyFM_Error({
1323
1596
  ...this._getDefaultErrorSettings(
1324
1597
  'getSortFunctionForKey',
@@ -1331,44 +1604,82 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
1331
1604
  errorCode: 'NTS-DS0-GSF1',
1332
1605
  });
1333
1606
  }
1607
+
1608
+ if ((sortSettings as DyFM_DBĐNestedPropertySort).isNestedPropertySort) {
1609
+ keyResolver = this.getKeyResolver((sortSettings as DyFM_DBĐNestedPropertySort).nestKeys);
1610
+ valueType = (sortSettings as DyFM_DBĐNestedPropertySort).valueType;
1611
+ } else {
1612
+ keyResolver = (data: T): any => data[(sortSettings as DyFM_DBĐPropertySort).key];
1613
+ valueType = this.dataParams.properties[(sortSettings as DyFM_DBĐPropertySort).key].type;
1614
+ }
1615
+
1616
+ if (!valueType) {
1617
+ throw new DyFM_Error({
1618
+ ...this._getDefaultErrorSettings(
1619
+ 'getSortFunctionForKey',
1620
+ new Error(
1621
+ `getSortFunctionForKey failed, valueType is missing! ` +
1622
+ `(${this.dataParams.dataName})`
1623
+ )
1624
+ ),
1625
+
1626
+ errorCode: 'NTS-DS0-GSF1',
1627
+ });
1628
+ }
1334
1629
 
1335
1630
  const sortValue: 1 | -1 = (
1336
- sortDirection === 1 || sortDirection === 'asc' || sortDirection === 'ascending'
1631
+ sortSettings.order === 1 ||
1632
+ sortSettings.order === 'asc' ||
1633
+ sortSettings.order === 'ascending'
1337
1634
  ) ? 1 : -1;
1338
1635
 
1339
- switch (this.dataParams.properties[key].type) {
1340
- case 'String':
1341
- return (a: T, b: T): number => (a as string).localeCompare(b as string) * sortValue;
1636
+ switch (valueType) {
1637
+ case DyFM_BasicProperty_Type.string:
1638
+ return (a: T, b: T): number => {
1639
+ a = keyResolver(a);
1640
+ b = keyResolver(b);
1641
+
1642
+ return (a as string).localeCompare(b as string) * sortValue;
1643
+ }
1342
1644
 
1343
- case 'Date':
1645
+ case DyFM_BasicProperty_Type.date:
1344
1646
  return (a: T, b: T): number => {
1345
- if (+new Date(a[key]) < +new Date(b[key])) {
1647
+ const aNum = +new Date(keyResolver(a));
1648
+ const bNum = +new Date(keyResolver(b));
1649
+
1650
+ if (aNum < bNum) {
1346
1651
  return -sortValue;
1347
- } else if (+new Date(a[key]) > +new Date(b[key])) {
1652
+ } else if (aNum > bNum) {
1348
1653
  return sortValue;
1349
1654
  } else {
1350
1655
  return 0;
1351
1656
  }
1352
1657
  };
1353
1658
 
1354
- case 'Number':
1659
+ case DyFM_BasicProperty_Type.number:
1355
1660
  return (a: T, b: T): number => {
1356
- if (a[key] < b[key]) {
1661
+ a = keyResolver(a);
1662
+ b = keyResolver(b);
1663
+
1664
+ if (a < b) {
1357
1665
  return -sortValue;
1358
- } else if (a[key] > b[key]) {
1666
+ } else if (a > b) {
1359
1667
  return sortValue;
1360
1668
  } else {
1361
1669
  return 0;
1362
1670
  }
1363
1671
  };
1364
1672
 
1365
- case 'Boolean':
1673
+ case DyFM_BasicProperty_Type.boolean:
1366
1674
  return (a: T, b: T): number => {
1367
- if (a[key] === b[key]) {
1675
+ a = keyResolver(a);
1676
+ b = keyResolver(b);
1677
+
1678
+ if (a === b) {
1368
1679
  return 0;
1369
1680
  }
1370
1681
 
1371
- if (a[key]) {
1682
+ if (a) {
1372
1683
  return sortValue;
1373
1684
  }
1374
1685
 
@@ -1381,7 +1692,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
1381
1692
  'getSortFunctionForKey',
1382
1693
  new Error(
1383
1694
  `getSortFunctionForKey failed, sorting not implemented for this type ` +
1384
- `(${this.dataParams.dataName}, ${this.dataParams.properties[key].type})`
1695
+ `(${this.dataParams.dataName}, ${valueType})`
1385
1696
  )
1386
1697
  ),
1387
1698
 
@@ -1390,6 +1701,86 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
1390
1701
  }
1391
1702
  }
1392
1703
 
1704
+ /* private getSortFunctionForNestedKeys<T>(
1705
+ sortSettings: DyFM_DBĐNestedPropertySort
1706
+ ): (a: T, b: T) => number {
1707
+ const nestedPropertyResolver: (data) => any = this.getKeyResolver(sortSettings.nestKeys);
1708
+
1709
+ const sortValue: 1 | -1 = (
1710
+ sortSettings.order === 1 ||
1711
+ sortSettings.order === 'asc' ||
1712
+ sortSettings.order === 'ascending'
1713
+ ) ? 1 : -1;
1714
+
1715
+ switch (sortSettings.valueType) {
1716
+ case DyFM_BasicProperty_Type.string:
1717
+ return (a: T, b: T): number => {
1718
+ a = nestedPropertyResolver(a);
1719
+ b = nestedPropertyResolver(b);
1720
+
1721
+ return (a as string).localeCompare(b as string) * sortValue
1722
+ };
1723
+
1724
+ case DyFM_BasicProperty_Type.date:
1725
+ return (a: T, b: T): number => {
1726
+ a = nestedPropertyResolver(a);
1727
+ b = nestedPropertyResolver(b);
1728
+
1729
+ if (+new Date(a) < +new Date(b)) {
1730
+ return -sortValue;
1731
+ } else if (+new Date(a) > +new Date(b)) {
1732
+ return sortValue;
1733
+ } else {
1734
+ return 0;
1735
+ }
1736
+ };
1737
+
1738
+ case DyFM_BasicProperty_Type.number:
1739
+ return (a: T, b: T): number => {
1740
+ a = nestedPropertyResolver(a);
1741
+ b = nestedPropertyResolver(b);
1742
+
1743
+ if (a < b) {
1744
+ return -sortValue;
1745
+ } else if (a > b) {
1746
+ return sortValue;
1747
+ } else {
1748
+ return 0;
1749
+ }
1750
+ };
1751
+
1752
+ case DyFM_BasicProperty_Type.boolean:
1753
+ return (a: T, b: T): number => {
1754
+ a = nestedPropertyResolver(a);
1755
+ b = nestedPropertyResolver(b);
1756
+
1757
+ if (a === b) {
1758
+ return 0;
1759
+ }
1760
+
1761
+ if (a) {
1762
+ return sortValue;
1763
+ }
1764
+
1765
+ return -sortValue;
1766
+ };
1767
+
1768
+ default:
1769
+ throw new DyFM_Error({
1770
+ ...this._getDefaultErrorSettings(
1771
+ 'getSortFunctionForKey',
1772
+ new Error(
1773
+ `getSortFunctionForKey failed, sorting not implemented for this type ` +
1774
+ `(${this.dataParams.dataName}, ${this.dataParams.properties[key].type})`
1775
+ )
1776
+ ),
1777
+
1778
+ errorCode: 'NTS-DS0-GSF2',
1779
+ });
1780
+ }
1781
+ } */
1782
+
1783
+
1393
1784
  /**
1394
1785
  * setting up dependency dataHook by DynamoBEDataModelParams
1395
1786
  */
@@ -1452,6 +1843,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
1452
1843
  return {
1453
1844
  status: (error as DyFM_Error)?.___status ?? 500,
1454
1845
  message: (error as Error)?.message ??
1846
+ (error as DyFM_Error)?._message ??
1455
1847
  `${fnName} was UNSUCCESSFUL (NTS; ${this.dataParams.dataName})`,
1456
1848
  addECToUserMsg: !(error as DyFM_Error)?.__userMessage,
1457
1849
  userMessage: (error as DyFM_Error)?.__userMessage ?? this.defaultErrorUserMsg,
@@ -1468,6 +1860,7 @@ export class DyNTS_DataService<T extends DyFM_Metadata> {
1468
1860
  return {
1469
1861
  status: (error as DyFM_Error)?.___status ?? 500,
1470
1862
  message: (error as Error)?.message ??
1863
+ (error as DyFM_Error)?._message ??
1471
1864
  `${fnName} was UNSUCCESSFUL (${DyNTS_global_settings.systemShortCodeName})`,
1472
1865
  addECToUserMsg: !(error as DyFM_Error)?.__userMessage,
1473
1866
  userMessage: (error as DyFM_Error)?.__userMessage ?? this.defaultErrorUserMsg,