@questwork/q-utilities 0.1.12 → 0.1.14

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.
@@ -1,51 +1,38 @@
1
- /******/ // The require scope
2
- /******/ var __webpack_require__ = {};
3
- /******/
4
- /************************************************************************/
5
- /******/ /* webpack/runtime/define property getters */
6
- /******/ (() => {
7
- /******/ // define getter functions for harmony exports
8
- /******/ __webpack_require__.d = (exports, definition) => {
9
- /******/ for(var key in definition) {
10
- /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
11
- /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
12
- /******/ }
13
- /******/ }
14
- /******/ };
15
- /******/ })();
16
- /******/
17
- /******/ /* webpack/runtime/hasOwnProperty shorthand */
18
- /******/ (() => {
19
- /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
20
- /******/ })();
21
- /******/
22
- /************************************************************************/
23
- var __webpack_exports__ = {};
24
-
25
- // EXPORTS
26
- __webpack_require__.d(__webpack_exports__, {
27
- sh: () => (/* reexport */ ApiResponse),
28
- Yc: () => (/* reexport */ KeyValueObject),
29
- OS: () => (/* reexport */ Metadata),
30
- Z8: () => (/* reexport */ QMeta),
31
- lc: () => (/* reexport */ Repo),
32
- kl: () => (/* reexport */ Service),
33
- Mg: () => (/* reexport */ TemplateCompiler),
34
- _x: () => (/* reexport */ UniqueKeyGenerator),
35
- yl: () => (/* reexport */ concatStringByArray),
36
- l0: () => (/* reexport */ convertString),
37
- Yq: () => (/* reexport */ formatDate),
38
- zn: () => (/* reexport */ generalPost),
39
- G8: () => (/* reexport */ getValidation),
40
- pY: () => (/* reexport */ getValueByKeys_getValueByKeys),
41
- su: () => (/* reexport */ makeApiResponse),
42
- Q6: () => (/* reexport */ makeService),
43
- UI: () => (/* reexport */ objectHelper),
44
- d: () => (/* reexport */ pReduce),
45
- Lv: () => (/* reexport */ padZeros),
46
- Qy: () => (/* reexport */ stringFormatter),
47
- yO: () => (/* reexport */ stringHelper)
48
- });
1
+
2
+ ;// ./lib/helpers/authorize/authorize.js
3
+ function authorize({ allowOwner, query = {}, required, user }) {
4
+ if (!user) {
5
+ throw new Error('Require login.')
6
+ }
7
+ if (!user.permission) {
8
+ throw new Error('You do not have any permission.')
9
+ }
10
+ const scopes = user.permission.getScopes(required || {})
11
+ if (!scopes || scopes.length === 0) {
12
+ throw new Error('You are not allowed in this scope.')
13
+ }
14
+ if (!scopes.includes('*')) {
15
+ query.tenantCode = user.tenantCode
16
+ }
17
+ if (!scopes.includes('TENANT')) {
18
+ query.eventShortCode = user.eventShortCode
19
+ }
20
+ if (!scopes.includes('EVENT')) {
21
+ query.eventRegistrationCode = user.eventRegistrationCode
22
+ }
23
+ if (allowOwner) {
24
+ query.__ALLOW_OWNER = true
25
+ }
26
+ // not good, just use it as example
27
+ if (user.hasExcludedFields) {
28
+ query.__EXCLUDED_FIELDS = user.getExcludedFields(required)
29
+ }
30
+ query.__LOGIN_SUBJECT_CODE = user.loginSubjectCode
31
+ return query
32
+ }
33
+
34
+ ;// ./lib/helpers/authorize/index.js
35
+
49
36
 
50
37
  ;// ./lib/helpers/getValidation/getValidation.js
51
38
  function getValidation(rule, data, getDataByKey, KeyValueObject) {
@@ -264,7 +251,6 @@ function getValueByKeys_getValueByKeys(keys, data) {
264
251
  });
265
252
 
266
253
 
267
-
268
254
  ;// ./lib/helpers/getValueByKeys/index.js
269
255
 
270
256
 
@@ -292,7 +278,26 @@ class TemplateCompilerException extends Error {
292
278
  ;// ./lib/models/templateCompiler/constants.js
293
279
  const _EMPTY = '_EMPTY'
294
280
  const _FN_NAMES = [
295
- 'get', 'map', 'join', 'concatIf', 'exec', 'filterOne', 'filterAll', 'formatDate', 'eq', 'neq', 'gt', 'lt', 'gte', 'lte', 'isEmpty', 'isNotEmpty', 'toLowerCase', 'toUpperCase'
281
+ 'concatIf',
282
+ 'divide',
283
+ 'eq',
284
+ 'exec',
285
+ 'filterAll',
286
+ 'filterOne',
287
+ 'formatDate',
288
+ 'get',
289
+ 'gt',
290
+ 'gte',
291
+ 'isEmpty',
292
+ 'isNotEmpty',
293
+ 'join',
294
+ 'lt',
295
+ 'lte',
296
+ 'map',
297
+ 'neq',
298
+ 'removeHtml',
299
+ 'toLowerCase',
300
+ 'toUpperCase',
296
301
  ]
297
302
  const _HIDE = '_HIDE'
298
303
  const _NOT_EMPTY = '_NOT_EMPTY'
@@ -333,6 +338,20 @@ function _concatIf(data, args) {
333
338
 
334
339
 
335
340
 
341
+ ;// ./lib/models/templateCompiler/helpers/_divide.js
342
+ function _divide(value, divisor) {
343
+ try {
344
+ if (Number.isNaN(value)) {
345
+ return value
346
+ }
347
+ return (value / divisor)
348
+ } catch (e) {
349
+ throw e
350
+ }
351
+ }
352
+
353
+
354
+
336
355
  ;// ./lib/models/templateCompiler/helpers/_eq.js
337
356
 
338
357
 
@@ -865,6 +884,66 @@ function _neq(data, args) {
865
884
 
866
885
 
867
886
 
887
+ ;// ./lib/models/templateCompiler/helpers/_removeHtml.js
888
+
889
+
890
+ function _removeHtml(html, args) {
891
+ if (html === null || html === undefined) {
892
+ return null
893
+ }
894
+ if (!Array.isArray(args)) {
895
+ throw new TemplateCompilerException(`_removeHtml: ${TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException}: args parts must be array`)
896
+ }
897
+
898
+ return _htmlToPlainText(html, args[0])
899
+ }
900
+
901
+ function _htmlToPlainText(html, delimiter = '\n') {
902
+ if (typeof delimiter !== 'string') {
903
+ delimiter = '\n'; // Fallback to default if not a string
904
+ }
905
+
906
+ // First decode HTML entities and normalize whitespace
907
+ const decodedHtml = html
908
+ .replace(/ /g, ' ')
909
+ .replace(/\s+/g, ' '); // Collapse all whitespace to single spaces
910
+
911
+ // Process HTML tags
912
+ let text = decodedHtml
913
+ // Replace block tags with temporary marker (~~~)
914
+ .replace(/<\/?(p|div|h[1-6]|ul|ol|li|pre|section|article|table|tr|td|th)(\s[^>]*)?>/gi, '~~~')
915
+ // Replace <br> tags with temporary marker (~~~)
916
+ .replace(/<br\s*\/?>/gi, '~~~')
917
+ // Remove all other tags
918
+ .replace(/<[^>]+>/g, '')
919
+ // Convert markers to specified delimiter
920
+ .replace(/~~~+/g, delimiter)
921
+ // Trim and clean whitespace
922
+ .trim();
923
+
924
+ // Special handling for empty delimiter
925
+ if (delimiter === '') {
926
+ // Collapse all whitespace to single space
927
+ text = text.replace(/\s+/g, ' ');
928
+ } else {
929
+
930
+
931
+ // Collapse multiple delimiters to single
932
+ text = text.replace(new RegExp(`${escapeRegExp(delimiter)}+`, 'g'), delimiter);
933
+ // Remove leading/trailing delimiters
934
+ text = text.replace(new RegExp(`^${escapeRegExp(delimiter)}|${escapeRegExp(delimiter)}$`, 'g'), '');
935
+ }
936
+
937
+ return text;
938
+ }
939
+
940
+
941
+ function escapeRegExp(string) {
942
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
943
+ }
944
+
945
+
946
+
868
947
  ;// ./lib/models/templateCompiler/helpers/_toLowerCase.js
869
948
 
870
949
 
@@ -917,6 +996,8 @@ function _toUpperCase(data, args) {
917
996
 
918
997
 
919
998
 
999
+
1000
+
920
1001
 
921
1002
 
922
1003
 
@@ -944,6 +1025,9 @@ class TemplateCompiler {
944
1025
  static concatIf(data, args) {
945
1026
  return _concatIf(data, args)
946
1027
  }
1028
+ static divide(data, args) {
1029
+ return _divide(data, args)
1030
+ }
947
1031
  static eq(data, args) {
948
1032
  return _eq(data, args)
949
1033
  }
@@ -955,7 +1039,6 @@ class TemplateCompiler {
955
1039
  static formatDate(data, args) {
956
1040
  return _formatDate(data, args)
957
1041
  }
958
-
959
1042
  static get(data, key, failover = null) {
960
1043
  return _get(data, key, failover)
961
1044
  }
@@ -986,6 +1069,9 @@ class TemplateCompiler {
986
1069
  static neq(data, args) {
987
1070
  return _neq(data, args)
988
1071
  }
1072
+ static removeHtml(data, args) {
1073
+ return _removeHtml(data, args)
1074
+ }
989
1075
  static toLowerCase(data, args) {
990
1076
  return _toLowerCase(data, args)
991
1077
  }
@@ -995,6 +1081,9 @@ class TemplateCompiler {
995
1081
  static parseFunction(expression) {
996
1082
  return _parseFunction(expression, _FN_NAMES)
997
1083
  }
1084
+ static parseParams(parameters) {
1085
+ return _parseParams(parameters)
1086
+ }
998
1087
 
999
1088
  pipe(expression = '') {
1000
1089
  this.delimiters = expression.substring(0, 2) === '{{' ? TAGS_HANDLEBAR : TAGS_EJS
@@ -1077,6 +1166,10 @@ function _parseSinglePart(input) {
1077
1166
  // 去掉双引号,返回
1078
1167
  return input.substring(1, input.length - 1)
1079
1168
  }
1169
+ if (input.startsWith("'") && input.endsWith("'")) {
1170
+ // 去掉双引号,返回
1171
+ return input.substring(1, input.length - 1)
1172
+ }
1080
1173
 
1081
1174
  const _input = _toBasicType(input)
1082
1175
 
@@ -1104,6 +1197,10 @@ function _toBasicType(input) {
1104
1197
  // 去掉双引号,返回
1105
1198
  return input.substring(1, input.length - 1)
1106
1199
  }
1200
+ if (input.startsWith("'") && input.endsWith("'")) {
1201
+ // 去掉双引号,返回
1202
+ return input.substring(1, input.length - 1)
1203
+ }
1107
1204
  if (input === 'true') {
1108
1205
  return true
1109
1206
  }
@@ -1126,8 +1223,20 @@ function _callFunction(data, functionName, parameters) {
1126
1223
  try {
1127
1224
  let failover
1128
1225
  switch (functionName) {
1226
+ case 'concatIf':
1227
+ return _concatIf(data, parameters)
1228
+ case 'divide':
1229
+ return _divide(data, parameters)
1230
+ case 'eq':
1231
+ return _eq(data, parameters)
1129
1232
  case 'exec':
1130
1233
  return _exec(data, parameters)
1234
+ case 'filterAll':
1235
+ return _filterAll(data, parameters)
1236
+ case 'filterOne':
1237
+ return _filterOne(data, parameters)
1238
+ case 'formatDate':
1239
+ return _formatDate(data, parameters)
1131
1240
  case 'get':
1132
1241
  if (parameters.length > 2) {
1133
1242
  throw new TemplateCompilerException(TEMPLATE_COMPILER_EXCEPTION_TYPE.argumentFormatException)
@@ -1136,34 +1245,26 @@ function _callFunction(data, functionName, parameters) {
1136
1245
  failover = parameters[parameters.length - 1]
1137
1246
  }
1138
1247
  return _get(data, parameters[0], failover)
1139
- case 'join':
1140
- return _join(data, parameters[0])
1141
- case 'map':
1142
- return _map(data, parameters)
1143
- case 'concatIf':
1144
- return _concatIf(data, parameters)
1145
- case 'filterOne':
1146
- return _filterOne(data, parameters)
1147
- case 'filterAll':
1148
- return _filterAll(data, parameters)
1149
- case 'formatDate':
1150
- return _formatDate(data, parameters)
1151
- case 'eq':
1152
- return _eq(data, parameters)
1153
- case 'neq':
1154
- return _neq(data, parameters)
1155
1248
  case 'gt':
1156
1249
  return _gt(data, parameters)
1157
1250
  case 'gte':
1158
1251
  return _gte(data, parameters)
1159
- case 'lt':
1160
- return _lt(data, parameters)
1161
- case 'lte':
1162
- return _lte(data, parameters)
1163
1252
  case 'isEmpty':
1164
1253
  return _isEmpty(data, parameters)
1165
1254
  case 'isNotEmpty':
1166
1255
  return _isNotEmpty(data, parameters)
1256
+ case 'join':
1257
+ return _join(data, parameters[0])
1258
+ case 'lt':
1259
+ return _lt(data, parameters)
1260
+ case 'lte':
1261
+ return _lte(data, parameters)
1262
+ case 'map':
1263
+ return _map(data, parameters)
1264
+ case 'neq':
1265
+ return _neq(data, parameters)
1266
+ case 'removeHtml':
1267
+ return _removeHtml(data, parameters)
1167
1268
  case 'toLowerCase':
1168
1269
  return _toLowerCase(data)
1169
1270
  case 'toUpperCase':
@@ -1312,42 +1413,59 @@ const objectHelper = {
1312
1413
  },
1313
1414
  merge,
1314
1415
  set(obj, path, value) {
1315
- const parts = path.split('.')
1316
- let current = obj
1416
+ const parts = path.split('.');
1417
+ let current = obj;
1418
+
1419
+ // 处理所有中间部分
1317
1420
  for (let i = 0; i < parts.length - 1; i++) {
1318
- const part = parts[i]
1319
- if (part.endsWith('[]')) {
1320
- // 处理数组遍历
1321
- const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
1322
- if (Array.isArray(current[key])) {
1323
- current[key].forEach((item) => set(item, parts.slice(i + 1).join('.'), value))
1421
+ const part = parts[i];
1422
+ let key, index;
1423
+
1424
+ // 检查是否是数组索引格式,如key[0]
1425
+ const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
1426
+ if (arrayMatch) {
1427
+ key = arrayMatch[1];
1428
+ index = parseInt(arrayMatch[2], 10);
1429
+ // 确保当前层级的数组存在
1430
+ if (!current[key] || !Array.isArray(current[key])) {
1431
+ current[key] = [];
1324
1432
  }
1325
- return // 处理完数组后直接返回
1326
- }
1327
- if (part.includes('[') && part.includes(']')) {
1328
- // 处理数组索引
1329
- const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
1330
- if (arrayMatch) {
1331
- const key = arrayMatch[1]
1332
- const index = arrayMatch[2]
1333
- if (Array.isArray(current[key]) && current[key][index]) {
1334
- current = current[key][index]
1335
- } else {
1336
- return // 如果数组或索引不存在,直接返回
1337
- }
1433
+ // 扩展数组到足够大
1434
+ while (current[key].length <= index) {
1435
+ current[key].push(undefined);
1338
1436
  }
1437
+ // 如果当前位置未定义或为null,初始化为对象
1438
+ if (current[key][index] == null) {
1439
+ current[key][index] = {};
1440
+ }
1441
+ current = current[key][index];
1339
1442
  } else {
1340
1443
  // 处理普通属性
1341
1444
  if (!current[part]) {
1342
- current[part] = {} // 如果属性不存在,创建一个空对象
1445
+ current[part] = {};
1343
1446
  }
1344
- current = current[part]
1447
+ current = current[part];
1448
+ }
1449
+ }
1450
+
1451
+ // 处理最后一部分
1452
+ const lastPart = parts[parts.length - 1];
1453
+ const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/);
1454
+ if (arrayMatch) {
1455
+ const key = arrayMatch[1];
1456
+ const index = parseInt(arrayMatch[2], 10);
1457
+ // 确保数组存在
1458
+ if (!current[key] || !Array.isArray(current[key])) {
1459
+ current[key] = [];
1345
1460
  }
1461
+ // 扩展数组到所需索引
1462
+ while (current[key].length <= index) {
1463
+ current[key].push(undefined);
1464
+ }
1465
+ current[key][index] = value;
1466
+ } else {
1467
+ current[lastPart] = value;
1346
1468
  }
1347
-
1348
- // 设置最终属性值
1349
- const lastPart = parts[parts.length - 1]
1350
- current[lastPart] = value
1351
1469
  }
1352
1470
  }
1353
1471
 
@@ -1415,112 +1533,727 @@ async function pReduce(iterable, reducer, initialValue) {
1415
1533
 
1416
1534
 
1417
1535
 
1418
- ;// ./lib/models/apiResponse/apiResponse.js
1419
- class ApiResponse {
1420
- constructor(options = {}) {
1536
+ ;// ./lib/models/repo/repo.js
1537
+
1538
+
1539
+ class Repo {
1540
+ constructor(options) {
1421
1541
  options = options || {}
1422
- this._data = options.data || options._data || []
1423
- this.err = options.err
1424
- this.isNew = options.isNew || false
1425
- this.message = options.message
1426
- this.total = options.total || 0
1427
- this._instanceBuilder = options._instanceBuilder
1542
+ this.model = options.model
1543
+ this._sharedOptions = options._sharedOptions // { session: this.dbTransaction }
1544
+ this._queryOptions = options._queryOptions
1545
+ this._saveOptions = options._saveOptions
1546
+ this._Class = options._constructor && options._constructor._Class
1547
+ ? options._constructor._Class
1548
+ : null
1428
1549
  }
1429
-
1430
1550
  static init(options = {}) {
1431
- if (options instanceof this) {
1432
- return options
1433
- }
1434
- const instance = new this(options)
1435
- return instance
1551
+ return init(this, options)
1436
1552
  }
1437
1553
  static get _classname() {
1438
- return 'ApiResponse'
1554
+ return 'Repo'
1439
1555
  }
1440
1556
  static get _superclass() {
1441
- return 'ApiResponse'
1557
+ return 'Repo'
1442
1558
  }
1443
1559
 
1444
- // getters
1445
- get data() {
1446
- if (this._instanceBuilder && (typeof this._instanceBuilder === 'function')) {
1447
- return this._data.map(this._instanceBuilder)
1448
- }
1449
- return this._data
1560
+ get _classname() {
1561
+ return 'Repo'
1450
1562
  }
1451
- }
1452
-
1453
-
1454
1563
 
1455
- ;// ./lib/models/apiResponse/makeApiResponse.js
1564
+ get _superclass() {
1565
+ return 'Repo'
1566
+ }
1456
1567
 
1568
+ get isValid() {
1569
+ return this.model
1570
+ && (typeof this.model.deleteOne === 'function')
1571
+ && (typeof this.model.findAll === 'function')
1572
+ && (typeof this.model.saveOne === 'function')
1573
+ }
1457
1574
 
1458
- function makeApiResponse({ repo, result }) {
1459
- return ApiResponse.init({
1460
- ...result,
1461
- _instanceBuilder: (i) => {
1462
- return repo.init(i)
1575
+ get queryOptions() {
1576
+ return {
1577
+ ...this._sharedOptions,
1578
+ ...this._queryOptions,
1463
1579
  }
1464
- })
1465
- }
1466
-
1467
-
1468
-
1469
- ;// ./lib/models/apiResponse/index.js
1470
-
1471
-
1472
-
1473
-
1474
-
1475
- ;// ./lib/models/keyValueObject/keyValueObject.js
1476
- class KeyValueObject {
1477
- constructor(options = {}) {
1478
- options = options || {}
1479
- this.key = options.key || null
1480
- this.value = (typeof options.value !== 'undefined') ? options.value : ''
1481
1580
  }
1482
1581
 
1483
- // Class methods
1484
- static init(options = {}) {
1485
- if (options instanceof this) {
1486
- return options
1582
+ get saveOptions() {
1583
+ return {
1584
+ ...this._sharedOptions,
1585
+ ...this._saveOptions,
1487
1586
  }
1488
- const instance = new this(options)
1489
- return instance.isValid ? instance : null
1490
1587
  }
1491
- static initFromArray(arr = []) {
1492
- if (Array.isArray(arr)) {
1493
- return arr.map((a) => this.init(a))
1588
+
1589
+ init(options) {
1590
+ if (this._Class && typeof this._Class.init === 'function') {
1591
+ return this._Class.init(options)
1494
1592
  }
1495
- return []
1496
- }
1497
- static initOnlyValidFromArray(arr = []) {
1498
- return this.initFromArray(arr).filter((i) => i)
1499
- }
1500
- static get _classname() {
1501
- return 'KeyValueObject'
1502
- }
1503
- static get _superclass() {
1504
- return 'KeyValueObject'
1593
+ return options
1505
1594
  }
1506
1595
 
1507
- static addItem(arr, key, value) {
1508
- arr.push(this.init({ key, value }))
1509
- }
1510
- static addRecord(arr = [], key, value) {
1511
- if (!this.hasKeyValue(arr, key, value)) {
1512
- arr.push(this.init({ key, value }))
1596
+ async deleteOne({ id }) {
1597
+ try {
1598
+ const result = await this.model.deleteOne({ _id: id })
1599
+ return {
1600
+ ...result, // { message: 'ok', total }
1601
+ isNew: false,
1602
+ data: []
1603
+ }
1604
+ } catch (err) {
1605
+ throw err
1513
1606
  }
1514
- return arr
1515
1607
  }
1516
- static appendRecord(arr = [], key, value) {
1517
- return arr.map((item) => {
1518
- if (this.sameKey(item, key)) {
1519
- item.value = [...item.value, ...value]
1520
- }
1521
- return item
1608
+
1609
+ // systemLog is optional
1610
+ findAll({ query, systemLog }) {
1611
+ const log = _makeLog({
1612
+ systemLog,
1613
+ label: 'REPO_READ',
1614
+ message: `fn ${this._classname}.prototype.findAll`,
1615
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1522
1616
  })
1523
- }
1617
+ return new Promise((resolve, reject) => {
1618
+ this.model.findAll(query, this.queryOptions, (err, data, total) => {
1619
+ if (err) {
1620
+ log({ level: 'warn', output: err.toString() })
1621
+ reject(err)
1622
+ } else {
1623
+ const result = {
1624
+ isNew: false,
1625
+ data,
1626
+ total: total || data.length
1627
+ }
1628
+ log({ level: 'info', output: { ...result } })
1629
+ resolve(result)
1630
+ }
1631
+ })
1632
+ })
1633
+ }
1634
+
1635
+ findOne({ query, systemLog }) {
1636
+ const log = _makeLog({
1637
+ systemLog,
1638
+ label: 'REPO_READ',
1639
+ message: `fn ${this._classname}.prototype.findOne`,
1640
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1641
+ })
1642
+ return new Promise((resolve, reject) => {
1643
+ this.model.findAll(query, this.queryOptions, (err, data) => {
1644
+ if (err) {
1645
+ reject(err)
1646
+ } else if (data.length === 1) {
1647
+ const result = {
1648
+ isNew: false,
1649
+ data,
1650
+ total: 1
1651
+ }
1652
+ log({ level: 'info', output: { ...result } })
1653
+ resolve(result)
1654
+ } else if (data.length === 0) {
1655
+ reject(new Error('record not found'))
1656
+ } else {
1657
+ reject(new Error('more than one is found'))
1658
+ }
1659
+ })
1660
+ })
1661
+ .catch((err) => {
1662
+ log({ level: 'warn', output: err.toString() })
1663
+ throw err
1664
+ })
1665
+ }
1666
+
1667
+ saveAll({ docs, systemLog }) {
1668
+ let isNew
1669
+ const log = _makeLog({
1670
+ systemLog,
1671
+ label: 'REPO_WRITE',
1672
+ message: `fn ${this._classname}.prototype.saveAll`,
1673
+ input: [{ docs: [...docs], systemLog: { ...systemLog } }]
1674
+ })
1675
+ const promise = typeof this.model.saveAll === 'function'
1676
+ ? this.model.saveAll({ docs })
1677
+ : Promise.all(docs.map(async (doc) => {
1678
+ if (doc) {
1679
+ const result = await this.saveOne({ doc })
1680
+ isNew = result.isNew
1681
+ const _data = result._data || result.data
1682
+ return _data[0]
1683
+ }
1684
+ return null
1685
+ }))
1686
+ return promise.then((savedData) => {
1687
+ if (savedData.length !== 1) isNew = null
1688
+ const result = {
1689
+ data: savedData,
1690
+ isNew,
1691
+ total: savedData.length
1692
+ }
1693
+ log({ level: 'info', output: { ...result } })
1694
+ return result
1695
+ }).catch((err) => {
1696
+ log({ level: 'warn', output: err.toString() })
1697
+ throw err
1698
+ })
1699
+ }
1700
+
1701
+ saveOne({ doc, systemLog }) {
1702
+ const log = _makeLog({
1703
+ systemLog,
1704
+ label: 'REPO_WRITE',
1705
+ message: `fn ${this._classname}.prototype.saveOne`,
1706
+ input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
1707
+ })
1708
+ return new Promise((resolve, reject) => {
1709
+ this.model.saveOne(doc, this.saveOptions, (err, result) => {
1710
+ if (err) {
1711
+ log({ level: 'warn', output: err.toString() })
1712
+ reject(err)
1713
+ } else {
1714
+ log({ level: 'info', output: { ...result } })
1715
+ resolve(result)
1716
+ }
1717
+ })
1718
+ })
1719
+ }
1720
+ }
1721
+
1722
+ function _makeLog({ systemLog, label, message: message1, input } = {}) {
1723
+ return ({ level, messgae: massage2, output } = {}) => {
1724
+ if (systemLog && systemLog.systemLogHelper) {
1725
+ systemLog.systemLogHelper.log({
1726
+ batchId: systemLog.batchId,
1727
+ label,
1728
+ level,
1729
+ message: massage2 || message1,
1730
+ data: {
1731
+ payload: {
1732
+ input,
1733
+ output
1734
+ }
1735
+ }
1736
+ })
1737
+ }
1738
+ }
1739
+ }
1740
+
1741
+
1742
+
1743
+ ;// ./lib/models/repo/index.js
1744
+
1745
+
1746
+
1747
+
1748
+ ;// ./lib/models/apiResponse/apiResponse.js
1749
+ class ApiResponse {
1750
+ constructor(options = {}) {
1751
+ options = options || {}
1752
+ this._data = options.data || options._data || []
1753
+ this.err = options.err
1754
+ this.isNew = options.isNew || false
1755
+ this.message = options.message
1756
+ this.total = options.total || 0
1757
+ this._instanceBuilder = options._instanceBuilder
1758
+ }
1759
+
1760
+ static init(options = {}) {
1761
+ if (options instanceof this) {
1762
+ return options
1763
+ }
1764
+ const instance = new this(options)
1765
+ return instance
1766
+ }
1767
+ static get _classname() {
1768
+ return 'ApiResponse'
1769
+ }
1770
+ static get _superclass() {
1771
+ return 'ApiResponse'
1772
+ }
1773
+
1774
+ // getters
1775
+ get data() {
1776
+ if (this._instanceBuilder && (typeof this._instanceBuilder === 'function')) {
1777
+ return this._data.map(this._instanceBuilder)
1778
+ }
1779
+ return this._data
1780
+ }
1781
+ }
1782
+
1783
+
1784
+
1785
+ ;// ./lib/models/apiResponse/makeApiResponse.js
1786
+
1787
+
1788
+ function makeApiResponse({ repo, result }) {
1789
+ return ApiResponse.init({
1790
+ ...result,
1791
+ _instanceBuilder: (i) => {
1792
+ return repo.init(i)
1793
+ }
1794
+ })
1795
+ }
1796
+
1797
+
1798
+
1799
+ ;// ./lib/models/service/service.js
1800
+
1801
+
1802
+
1803
+ class Service {
1804
+ constructor({ repo }) {
1805
+ this.repo = repo
1806
+ }
1807
+
1808
+ static get _classname() {
1809
+ return 'Service'
1810
+ }
1811
+ static get _superclass() {
1812
+ return 'Service'
1813
+ }
1814
+
1815
+ deleteOne({ id }) {
1816
+ return this.repo.deleteOne({ id })
1817
+ .catch(() => {
1818
+ throw new Error(`Not found for query: ${id}`)
1819
+ })
1820
+ }
1821
+
1822
+ async findAll({ query = {}, systemLog } = {}) {
1823
+ const result = await this.repo.findAll({ query, systemLog })
1824
+ return makeApiResponse({
1825
+ repo: this.repo,
1826
+ result
1827
+ })
1828
+ }
1829
+
1830
+ async findOne({ query = {}, systemLog } = {}) {
1831
+ const result = await this.repo.findOne({ query, systemLog })
1832
+ return makeApiResponse({
1833
+ repo: this.repo,
1834
+ result
1835
+ })
1836
+ }
1837
+
1838
+ init(options) {
1839
+ return this.repo.init(options)
1840
+ }
1841
+ initFromArray(arr = []) {
1842
+ if (Array.isArray(arr)) {
1843
+ return arr.map((a) => this.init(a))
1844
+ }
1845
+ return []
1846
+ }
1847
+ initOnlyValidFromArray(arr = []) {
1848
+ return this.initFromArray(arr).filter((i) => i)
1849
+ }
1850
+
1851
+ async saveAll({ docs = [], config = {}, systemLog } = {}) {
1852
+ const copies = docs.map((doc) => {
1853
+ return config.skipInit ? doc : this.init(doc)
1854
+ })
1855
+ const result = await this.repo.saveAll({ docs: copies, systemLog })
1856
+ return makeApiResponse({
1857
+ repo: this.repo,
1858
+ result
1859
+ })
1860
+ }
1861
+
1862
+ // set skipInit to true if we want to use POST for query
1863
+ async saveOne({ doc = {}, config = {}, systemLog } = {}) {
1864
+ const copy = config.skipInit ? doc : this.init(doc)
1865
+ if (copy) {
1866
+ const result = await this.repo.saveOne({ doc: copy, systemLog })
1867
+ return makeApiResponse({
1868
+ repo: this.repo,
1869
+ result
1870
+ })
1871
+ }
1872
+ return {
1873
+ isNew: null,
1874
+ data: [],
1875
+ err: new Error('doc is not a valid instance')
1876
+ }
1877
+ }
1878
+ }
1879
+
1880
+ function makeService({ repo }) {
1881
+ if (repo === undefined) {
1882
+ throw new Error('repo is required.')
1883
+ }
1884
+ if (repo._superclass !== Repo._superclass) {
1885
+ throw new Error('repo is not an instance of Repo.')
1886
+ }
1887
+ return new Service({ repo })
1888
+ }
1889
+
1890
+
1891
+
1892
+ ;// ./lib/models/service/index.js
1893
+
1894
+
1895
+
1896
+
1897
+ ;// ./lib/helpers/generalPost/generalPost.js
1898
+
1899
+
1900
+
1901
+
1902
+
1903
+ async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator, resourceInfo }) {
1904
+ const { resources, data, globalShared = {}, shared = {}, relationship = {} } = body
1905
+ const _resourceInfo = resourceInfo || body.resourceInfo
1906
+ _attachShared(data, globalShared, shared)
1907
+ const obj = await pReduce(resources, async (acc, resource) => {
1908
+ const service = _makeService(resource, _resourceInfo, UniqueKeyGenerator, GeneralModel)
1909
+ _createRelationship(data, relationship[resource], acc)
1910
+ const _data = data[resource]
1911
+ const result = await service.saveAll({ docs: [].concat(_data) })
1912
+ acc[resource] = Array.isArray(_data) ? result._data : result._data[0]
1913
+ return acc
1914
+ }, {})
1915
+ return obj
1916
+ }
1917
+
1918
+ function _attachShared(data, globalShared = {}, shared = {}) {
1919
+ Object.keys(shared).forEach((key) => {
1920
+ const _data = data[key]
1921
+ if (Array.isArray(_data)) {
1922
+ data[key] = _data.map((_dataItem) => {
1923
+ return objectHelper.merge({}, _dataItem, globalShared, shared[key] || {})
1924
+ })
1925
+ } else {
1926
+ data[key] = objectHelper.merge({}, _data, globalShared, shared[key] || {})
1927
+ }
1928
+ })
1929
+ }
1930
+
1931
+ function _createRelationship(data, relationship = {}, object) {
1932
+ Object.keys(relationship).forEach((key) => {
1933
+ const path = relationship[key]
1934
+ const val = objectHelper.get(object, path)
1935
+ objectHelper.set(data, key, val)
1936
+ })
1937
+ }
1938
+
1939
+ function _makeService(resource, resourceInfo, UniqueKeyGenerator, GeneralModel) {
1940
+ const { collectionName, fields } = resourceInfo[resource]
1941
+ const uniqueKeyGenerator = UniqueKeyGenerator.makeGenerator(fields)
1942
+ const model = new GeneralModel({ collectionName, uniqueKeyGenerator })
1943
+ return makeService({
1944
+ repo: new Repo({ model })
1945
+ })
1946
+ }
1947
+
1948
+
1949
+
1950
+ ;// ./lib/helpers/generalPost/index.js
1951
+
1952
+
1953
+
1954
+
1955
+ ;// ./lib/helpers/init/init.js
1956
+ function init(_class, options) {
1957
+ if (options instanceof _class) {
1958
+ return options
1959
+ }
1960
+ try {
1961
+ const instance = new _class(options)
1962
+ return instance.isValid !== false ? instance : null
1963
+ } catch (e) {
1964
+ console.log(`init failed for class: ${_class._classname || 'no _classname'}`, e)
1965
+ return null
1966
+ }
1967
+ }
1968
+
1969
+ ;// ./lib/helpers/init/index.js
1970
+
1971
+
1972
+ ;// ./lib/helpers/initFromArray/initFromArray.js
1973
+
1974
+
1975
+ function initFromArray(_class, arr) {
1976
+ if (Array.isArray(arr)) {
1977
+ return arr.map((a) => init(_class, a))
1978
+ }
1979
+ return []
1980
+ }
1981
+
1982
+ ;// ./lib/helpers/initFromArray/index.js
1983
+
1984
+
1985
+ ;// ./lib/helpers/initOnlyValidFromArray/initOnlyValidFromArray.js
1986
+
1987
+
1988
+ function initOnlyValidFromArray(_class, arr) {
1989
+ return initFromArray(_class, arr).filter((i) => i)
1990
+ }
1991
+
1992
+ ;// ./lib/helpers/initOnlyValidFromArray/index.js
1993
+
1994
+
1995
+ ;// ./lib/helpers/padZeros/padZeros.js
1996
+ function padZeros(num, minLength = 6) {
1997
+ num = num.toString()
1998
+ if (num.length < minLength) {
1999
+ return padZeros('0' + num, minLength)
2000
+ }
2001
+ return num
2002
+ }
2003
+
2004
+
2005
+
2006
+ ;// ./lib/helpers/padZeros/index.js
2007
+
2008
+
2009
+
2010
+
2011
+ ;// ./lib/helpers/pReduce/index.js
2012
+
2013
+
2014
+
2015
+
2016
+ ;// ./lib/helpers/stringFormatter/stringFormatter.js
2017
+ function stringFormatter(str, delimiter = '_') {
2018
+ if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
2019
+ return null
2020
+ }
2021
+ return str.toString()
2022
+ .trim()
2023
+ .toUpperCase()
2024
+ .replace('-', delimiter)
2025
+ .replace(' ', delimiter)
2026
+ }
2027
+
2028
+
2029
+
2030
+ ;// ./lib/helpers/stringFormatter/index.js
2031
+
2032
+
2033
+
2034
+
2035
+ ;// ./lib/helpers/stringHelper/stringHelper.js
2036
+ function baseXEncode(num, base = 34) {
2037
+ const charset = getBaseCharset(base)
2038
+ return encode(num, charset)
2039
+ }
2040
+
2041
+ function encode(int, charset) {
2042
+ const { byCode } = charset
2043
+ if (int === 0) {
2044
+ return byCode[0]
2045
+ }
2046
+
2047
+ let res = ''
2048
+ const max = charset.length
2049
+ while (int > 0) {
2050
+ res = byCode[int % max] + res
2051
+ int = Math.floor(int / max)
2052
+ }
2053
+ return res
2054
+ }
2055
+
2056
+ function getBaseCharset(base) {
2057
+ let charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZ'
2058
+ if (base === 58) {
2059
+ charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz'
2060
+ }
2061
+ return indexCharset(charset)
2062
+ }
2063
+
2064
+ function indexCharset(str) {
2065
+ const byCode = {}
2066
+ const byChar = {}
2067
+ const { length } = str
2068
+ let char
2069
+ for (let i = 0; i < length; i++) {
2070
+ char = str[i]
2071
+ byCode[i] = char
2072
+ byChar[char] = i;
2073
+ }
2074
+ return { byCode, byChar, length }
2075
+ }
2076
+
2077
+ function isSame(str1, str2) {
2078
+ if (typeof str1 !== 'string' || typeof str2 !== 'string') {
2079
+ return false
2080
+ }
2081
+ return str1.trim().toUpperCase() === str2.trim().toUpperCase()
2082
+ }
2083
+
2084
+ function randomString({ len = 16, pattern = 'a1' } = {}) {
2085
+ const A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
2086
+ const a = 'abcdefghijklmnopqrstuvwxyz'
2087
+ const num = '1234567890'
2088
+ const mark = '~!@#$%^&*_+-='
2089
+ let str = ''
2090
+ if (pattern.includes('A')) {
2091
+ str += A
2092
+ }
2093
+ if (pattern.includes('a')) {
2094
+ str += a
2095
+ }
2096
+ if (pattern.includes('1')) {
2097
+ str += num
2098
+ }
2099
+ if (pattern.includes('#')) {
2100
+ str += mark
2101
+ }
2102
+ const chars = [...str]
2103
+ return [...Array(len)].map(i => {
2104
+ return chars[(Math.random() * chars.length) | 0]
2105
+ }).join``
2106
+ }
2107
+
2108
+ function reverse(str) {
2109
+ const _str = (typeof str !== 'string') ? str.toString() : str
2110
+ const splitString = _str.split('')
2111
+ const reverseArray = splitString.reverse()
2112
+ return reverseArray.join('')
2113
+ }
2114
+
2115
+ function setCode(base = 34) {
2116
+ const now = (new Date()).valueOf()
2117
+ const random = randomString({
2118
+ len: 8,
2119
+ pattern: '1'
2120
+ })
2121
+ const str = reverse(`${now}${random}`)
2122
+ // const str = `${now}${random}`
2123
+ return baseXEncode(str, base)
2124
+ }
2125
+
2126
+ function toCamelCase(str) {
2127
+ if (!str) return ''
2128
+ return str
2129
+ .trim()
2130
+ .split(/\s+/)
2131
+ .map((word, index) => {
2132
+ if (!word) return ''
2133
+ if (index === 0) {
2134
+ return word.toLowerCase()
2135
+ }
2136
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
2137
+ })
2138
+ .join('')
2139
+ }
2140
+
2141
+ const stringHelper = {
2142
+ isSame,
2143
+ setCode,
2144
+ toCamelCase,
2145
+ }
2146
+
2147
+
2148
+
2149
+ ;// ./lib/helpers/stringHelper/index.js
2150
+
2151
+
2152
+
2153
+
2154
+ ;// ./lib/helpers/trackingPlugin/trackingPlugin.js
2155
+ function trackingPlugin(schema, options) {
2156
+ // Add meta fields
2157
+ schema.add({
2158
+ meta: {
2159
+ active: { type: Boolean, default: true },
2160
+ created: { type: Number },
2161
+ creator: { type: String },
2162
+ deleted: { type: Boolean, default: false },
2163
+ modified: { type: Number },
2164
+ owner: { type: String },
2165
+ }
2166
+ })
2167
+
2168
+ // Auto-update hook
2169
+ schema.pre('save', function(next) {
2170
+ this.meta.modified = Date.now()
2171
+ next()
2172
+ })
2173
+
2174
+ // Optional: Add helper methods
2175
+ // schema.methods.touch = function(userId) {
2176
+ // this.meta.updatedAt = new Date()
2177
+ // this.meta.updatedBy = userId
2178
+ // }
2179
+ }
2180
+
2181
+ ;// ./lib/helpers/trackingPlugin/index.js
2182
+
2183
+
2184
+ ;// ./lib/helpers/index.js
2185
+
2186
+
2187
+
2188
+
2189
+
2190
+
2191
+
2192
+
2193
+
2194
+
2195
+
2196
+
2197
+
2198
+
2199
+
2200
+
2201
+
2202
+ ;// ./lib/models/apiResponse/index.js
2203
+
2204
+
2205
+
2206
+
2207
+
2208
+ ;// ./lib/models/keyValueObject/keyValueObject.js
2209
+ class KeyValueObject {
2210
+ constructor(options = {}) {
2211
+ options = options || {}
2212
+ this.key = options.key || null
2213
+ this.value = (typeof options.value !== 'undefined') ? options.value : ''
2214
+ }
2215
+
2216
+ // Class methods
2217
+ static init(options = {}) {
2218
+ if (options instanceof this) {
2219
+ return options
2220
+ }
2221
+ const instance = new this(options)
2222
+ return instance.isValid ? instance : null
2223
+ }
2224
+ static initFromArray(arr = []) {
2225
+ if (Array.isArray(arr)) {
2226
+ return arr.map((a) => this.init(a))
2227
+ }
2228
+ return []
2229
+ }
2230
+ static initOnlyValidFromArray(arr = []) {
2231
+ return this.initFromArray(arr).filter((i) => i)
2232
+ }
2233
+ static get _classname() {
2234
+ return 'KeyValueObject'
2235
+ }
2236
+ static get _superclass() {
2237
+ return 'KeyValueObject'
2238
+ }
2239
+
2240
+ static addItem(arr, key, value) {
2241
+ arr.push(this.init({ key, value }))
2242
+ }
2243
+ static addRecord(arr = [], key, value) {
2244
+ if (!this.hasKeyValue(arr, key, value)) {
2245
+ arr.push(this.init({ key, value }))
2246
+ }
2247
+ return arr
2248
+ }
2249
+ static appendRecord(arr = [], key, value) {
2250
+ return arr.map((item) => {
2251
+ if (this.sameKey(item, key)) {
2252
+ item.value = [...item.value, ...value]
2253
+ }
2254
+ return item
2255
+ })
2256
+ }
1524
2257
  static appendValueArray(arr = [], key, value) {
1525
2258
  return arr.map((item) => {
1526
2259
  if (this.sameKey(item, key)) {
@@ -1695,20 +2428,6 @@ function _isSame(key1, key2) {
1695
2428
 
1696
2429
 
1697
2430
 
1698
- ;// ./lib/helpers/stringFormatter/stringFormatter.js
1699
- function stringFormatter(str, delimiter = '_') {
1700
- if (str === null || typeof str === 'undefined' || typeof str.toString === 'undefined') {
1701
- return null
1702
- }
1703
- return str.toString()
1704
- .trim()
1705
- .toUpperCase()
1706
- .replace('-', delimiter)
1707
- .replace(' ', delimiter)
1708
- }
1709
-
1710
-
1711
-
1712
2431
  ;// ./lib/models/metadata/metadata.js
1713
2432
 
1714
2433
 
@@ -1820,314 +2539,218 @@ class QMeta {
1820
2539
 
1821
2540
 
1822
2541
 
1823
- ;// ./lib/models/repo/repo.js
1824
- class Repo {
1825
- constructor(options) {
2542
+ ;// ./lib/models/trackedEntity/trackedEntity.js
2543
+
2544
+
2545
+ class TrackedEntity {
2546
+ constructor(options = {}) {
1826
2547
  options = options || {}
1827
- this.model = options.model
1828
- this._sharedOptions = options._sharedOptions // { session: this.dbTransaction }
1829
- this._queryOptions = options._queryOptions
1830
- this._saveOptions = options._saveOptions
1831
- this._Class = options._constructor && options._constructor._Class
1832
- ? options._constructor._Class
1833
- : null
1834
- }
1835
- static init(options = {}) {
1836
- if (options instanceof this) {
1837
- return options
2548
+ const timestamp = Date.now()
2549
+ const _tracking = {
2550
+ active: options.active ?? true,
2551
+ created: options.created ?? timestamp,
2552
+ creator: options.creator ?? '',
2553
+ deleted: options.deleted ?? false,
2554
+ modified: options.modified ?? timestamp,
2555
+ owner: options.owner ?? '',
1838
2556
  }
1839
- const instance = new this(options)
1840
- return instance.isValid ? instance : null
2557
+
2558
+ this.meta = { ..._tracking, ...options.meta }
2559
+
2560
+ // if (trackFlat) {
2561
+ // Object.assign(this, _tracking)
2562
+ // } else {
2563
+ // this.meta = { ..._tracking, ...options.meta }
2564
+ // }
1841
2565
  }
2566
+
2567
+ // Class methods
1842
2568
  static get _classname() {
1843
- return 'Repo'
2569
+ return 'TrackedEntity'
1844
2570
  }
1845
2571
  static get _superclass() {
1846
- return 'Repo'
2572
+ return 'TrackedEntity'
1847
2573
  }
1848
2574
 
1849
- get _classname() {
1850
- return 'Repo'
2575
+ static init(options = {}) {
2576
+ return init(this, options)
1851
2577
  }
1852
-
1853
- get _superclass() {
1854
- return 'Repo'
2578
+ static initFromArray(arr = []) {
2579
+ return initFromArray(this, arr)
2580
+ }
2581
+ static initOnlyValidFromArray(arr = []) {
2582
+ return initOnlyValidFromArray(this, arr)
1855
2583
  }
2584
+ // static nest(entity) {
2585
+ // const { active, created, creator, deleted, modified, owner, ...rest } = entity
2586
+ // return { ...rest, meta: { active, created, creator, deleted, modified, owner } }
2587
+ // }
1856
2588
 
2589
+ // getters
1857
2590
  get isValid() {
1858
- return this.model
1859
- && (typeof this.model.deleteOne === 'function')
1860
- && (typeof this.model.findAll === 'function')
1861
- && (typeof this.model.saveOne === 'function')
2591
+ return !!this
1862
2592
  }
1863
-
1864
- get queryOptions() {
1865
- return {
1866
- ...this._sharedOptions,
1867
- ...this._queryOptions,
1868
- }
2593
+ get active() {
2594
+ return this.meta?.active ?? this.active
1869
2595
  }
1870
-
1871
- get saveOptions() {
1872
- return {
1873
- ...this._sharedOptions,
1874
- ...this._saveOptions,
1875
- }
2596
+ get created() {
2597
+ return this.meta?.created ?? this.created
1876
2598
  }
1877
-
1878
- init(options) {
1879
- if (this._Class && typeof this._Class.init === 'function') {
1880
- return this._Class.init(options)
2599
+ get creator() {
2600
+ return this.meta?.creator ?? this.creator
2601
+ }
2602
+ get deleted() {
2603
+ return this.meta?.deleted ?? this.deleted
2604
+ }
2605
+ get modified() {
2606
+ return this.meta?.modified ?? this.modified
2607
+ }
2608
+ get owner() {
2609
+ return this.meta?.owner ?? this.owner
2610
+ }
2611
+ delete() {
2612
+ return this.setDeleted()
2613
+ }
2614
+ setActive() {
2615
+ if (this.meta) {
2616
+ this.meta.active = true
2617
+ } else {
2618
+ this.active = true
1881
2619
  }
1882
- return options
2620
+ return this
1883
2621
  }
1884
-
1885
- async deleteOne({ id }) {
1886
- try {
1887
- const result = await this.model.deleteOne({ _id: id })
1888
- return {
1889
- ...result, // { message: 'ok', total }
1890
- isNew: false,
1891
- data: []
1892
- }
1893
- } catch (err) {
1894
- throw err
2622
+ setDeleted() {
2623
+ if (this.meta) {
2624
+ this.meta.deleted = true
2625
+ } else {
2626
+ this.deleted = true
1895
2627
  }
2628
+ return this
1896
2629
  }
1897
-
1898
- // systemLog is optional
1899
- findAll({ query, systemLog }) {
1900
- const log = _makeLog({
1901
- systemLog,
1902
- label: 'REPO_READ',
1903
- message: `fn ${this._classname}.prototype.findAll`,
1904
- input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1905
- })
1906
- return new Promise((resolve, reject) => {
1907
- this.model.findAll(query, this.queryOptions, (err, data, total) => {
1908
- if (err) {
1909
- log({ level: 'warn', output: err.toString() })
1910
- reject(err)
1911
- } else {
1912
- const result = {
1913
- isNew: false,
1914
- data,
1915
- total: total || data.length
1916
- }
1917
- log({ level: 'info', output: { ...result } })
1918
- resolve(result)
1919
- }
1920
- })
1921
- })
2630
+ setModified() {
2631
+ const timestamp = Date.now()
2632
+ if (this.meta) {
2633
+ this.meta.modified = timestamp
2634
+ } else {
2635
+ this.modified = timestamp
2636
+ }
2637
+ return this
1922
2638
  }
1923
-
1924
- findOne({ query, systemLog }) {
1925
- const log = _makeLog({
1926
- systemLog,
1927
- label: 'REPO_READ',
1928
- message: `fn ${this._classname}.prototype.findOne`,
1929
- input: [{ query: { ...query }, systemLog: { ...systemLog } }]
1930
- })
1931
- return new Promise((resolve, reject) => {
1932
- this.model.findAll(query, this.queryOptions, (err, data) => {
1933
- if (err) {
1934
- reject(err)
1935
- } else if (data.length === 1) {
1936
- const result = {
1937
- isNew: false,
1938
- data,
1939
- total: 1
1940
- }
1941
- log({ level: 'info', output: { ...result } })
1942
- resolve(result)
1943
- } else if (data.length === 0) {
1944
- reject(new Error('record not found'))
1945
- } else {
1946
- reject(new Error('more than one is found'))
1947
- }
1948
- })
1949
- })
1950
- .catch((err) => {
1951
- log({ level: 'warn', output: err.toString() })
1952
- throw err
1953
- })
2639
+ setOwner(owner) {
2640
+ if (!owner) {
2641
+ return this
2642
+ }
2643
+ if (this.meta) {
2644
+ this.meta.owner = owner
2645
+ } else {
2646
+ this.owner = owner
2647
+ }
2648
+ return this
1954
2649
  }
1955
-
1956
- saveAll({ docs, systemLog }) {
1957
- let isNew
1958
- const log = _makeLog({
1959
- systemLog,
1960
- label: 'REPO_WRITE',
1961
- message: `fn ${this._classname}.prototype.saveAll`,
1962
- input: [{ docs: [...docs], systemLog: { ...systemLog } }]
1963
- })
1964
- const promise = typeof this.model.saveAll === 'function'
1965
- ? this.model.saveAll({ docs })
1966
- : Promise.all(docs.map(async (doc) => {
1967
- if (doc) {
1968
- const result = await this.saveOne({ doc })
1969
- isNew = result.isNew
1970
- const _data = result._data || result.data
1971
- return _data[0]
1972
- }
1973
- return null
1974
- }))
1975
- return promise.then((savedData) => {
1976
- if (savedData.length !== 1) isNew = null
1977
- const result = {
1978
- data: savedData,
1979
- isNew,
1980
- total: savedData.length
1981
- }
1982
- log({ level: 'info', output: { ...result } })
1983
- return result
1984
- }).catch((err) => {
1985
- log({ level: 'warn', output: err.toString() })
1986
- throw err
1987
- })
2650
+ unsetActive() {
2651
+ if (this.meta) {
2652
+ this.meta.active = false
2653
+ } else {
2654
+ this.active = false
2655
+ }
2656
+ return this
1988
2657
  }
1989
-
1990
- saveOne({ doc, systemLog }) {
1991
- const log = _makeLog({
1992
- systemLog,
1993
- label: 'REPO_WRITE',
1994
- message: `fn ${this._classname}.prototype.saveOne`,
1995
- input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
1996
- })
1997
- return new Promise((resolve, reject) => {
1998
- this.model.saveOne(doc, this.saveOptions, (err, result) => {
1999
- if (err) {
2000
- log({ level: 'warn', output: err.toString() })
2001
- reject(err)
2002
- } else {
2003
- log({ level: 'info', output: { ...result } })
2004
- resolve(result)
2005
- }
2006
- })
2007
- })
2658
+ unsetDeleted() {
2659
+ if (this.meta) {
2660
+ this.meta.deleted = false
2661
+ } else {
2662
+ this.deleted = false
2663
+ }
2664
+ return this
2008
2665
  }
2009
- }
2010
2666
 
2011
- function _makeLog({ systemLog, label, message: message1, input } = {}) {
2012
- return ({ level, messgae: massage2, output } = {}) => {
2013
- if (systemLog && systemLog.systemLogHelper) {
2014
- systemLog.systemLogHelper.log({
2015
- batchId: systemLog.batchId,
2016
- label,
2017
- level,
2018
- message: massage2 || message1,
2019
- data: {
2020
- payload: {
2021
- input,
2022
- output
2023
- }
2024
- }
2025
- })
2667
+ update(update) {
2668
+ if (update.meta) {
2669
+ this.meta = { ...this.meta, ...update.meta }
2026
2670
  }
2671
+ return this.setModified()
2027
2672
  }
2028
2673
  }
2029
2674
 
2675
+ ;// ./lib/models/trackedEntity/index.js
2030
2676
 
2677
+ // Explicit named export (optional)
2031
2678
 
2032
- ;// ./lib/models/repo/index.js
2679
+ ;// ./lib/models/tenantAwareEntity/tenantAwareEntity.js
2033
2680
 
2034
2681
 
2035
2682
 
2036
2683
 
2037
- ;// ./lib/models/service/service.js
2684
+ class TenantAwareEntity extends TrackedEntity {
2685
+ constructor(options = {}) {
2686
+ options = options || {}
2038
2687
 
2688
+ /**
2689
+ * instead of throw error, we choose to implement the isValid checking
2690
+ */
2691
+ // if (!options.tenantCode) {
2692
+ // throw new Error('tenantCode required')
2693
+ // }
2039
2694
 
2695
+ super(options)
2040
2696
 
2041
- class Service {
2042
- constructor({ repo }) {
2043
- this.repo = repo
2697
+ this._tenant = options._tenant
2698
+
2699
+ this.metadata = Metadata.initOnlyValidFromArray(options.metadata)
2700
+ this.remarks = KeyValueObject.initOnlyValidFromArray(options.remarks)
2701
+ this.tenantCode = options.tenantCode // Required for multi-tenancy
2044
2702
  }
2045
2703
 
2704
+ // Class methods
2046
2705
  static get _classname() {
2047
- return 'Service'
2706
+ return 'TenantAwareEntity'
2048
2707
  }
2049
2708
  static get _superclass() {
2050
- return 'Service'
2709
+ return 'TenantAwareEntity'
2051
2710
  }
2052
2711
 
2053
- deleteOne({ id }) {
2054
- return this.repo.deleteOne({ id })
2055
- .catch(() => {
2056
- throw new Error(`Not found for query: ${id}`)
2057
- })
2712
+ // getters
2713
+ get isValid() {
2714
+ return super.isValid && !!this.tenantCode // Required for multi-tenancy
2058
2715
  }
2059
2716
 
2060
- async findAll({ query = {}, systemLog } = {}) {
2061
- const result = await this.repo.findAll({ query, systemLog })
2062
- return makeApiResponse({
2063
- repo: this.repo,
2064
- result
2065
- })
2717
+ // instance methods
2718
+ getMetadata() {
2719
+ return this.metadata
2066
2720
  }
2067
-
2068
- async findOne({ query = {}, systemLog } = {}) {
2069
- const result = await this.repo.findOne({ query, systemLog })
2070
- return makeApiResponse({
2071
- repo: this.repo,
2072
- result
2073
- })
2721
+ getMetadataByKey(key) {
2722
+ return Metadata.foundByKey(this.metadata, key)
2074
2723
  }
2075
-
2076
- init(options) {
2077
- return this.repo.init(options)
2724
+ getMetadataValueByKey(key) {
2725
+ const found = this.getMetadataByKey(key)
2726
+ return found ? found.value : null
2078
2727
  }
2079
- initFromArray(arr = []) {
2080
- if (Array.isArray(arr)) {
2081
- return arr.map((a) => this.init(a))
2082
- }
2083
- return []
2728
+ getRemarks() {
2729
+ return this.remarks
2084
2730
  }
2085
- initOnlyValidFromArray(arr = []) {
2086
- return this.initFromArray(arr).filter((i) => i)
2731
+ getRemarkByKey(key) {
2732
+ return KeyValueObject.foundByKey(this.remarks, key)
2087
2733
  }
2088
-
2089
- async saveAll({ docs = [], systemLog } = {}) {
2090
- const copies = docs.map((doc) => {
2091
- return this.init(doc)
2092
- })
2093
- const result = await this.repo.saveAll({ docs: copies, systemLog })
2094
- return makeApiResponse({
2095
- repo: this.repo,
2096
- result
2097
- })
2734
+ getRemarksValueByKey(key) {
2735
+ const found = this.getRemarkByKey(key)
2736
+ return found ? found.value : null
2737
+ }
2738
+ getTenantCode() {
2739
+ return this.tenantCode
2098
2740
  }
2099
2741
 
2100
- async saveOne({ doc = {}, systemLog } = {}) {
2101
- const copy = this.init(doc)
2102
- if (copy) {
2103
- const result = await this.repo.saveOne({ doc: copy, systemLog })
2104
- return makeApiResponse({
2105
- repo: this.repo,
2106
- result
2107
- })
2742
+ update(update) {
2743
+ if (update.metadata && Array.isArray(update.metadata)) {
2744
+ this.metadata = Metadata.initOnlyValidFromArray(update.metadata)
2108
2745
  }
2109
- return {
2110
- isNew: null,
2111
- data: [],
2112
- err: new Error('doc is not a valid instance')
2746
+ if (update.remarks && Array.isArray(update.remarks)) {
2747
+ this.remarks = KeyValueObject.initOnlyValidFromArray(update.remarks)
2113
2748
  }
2749
+ return super.update(update)
2114
2750
  }
2115
2751
  }
2116
2752
 
2117
- function makeService({ repo }) {
2118
- if (repo === undefined) {
2119
- throw new Error('repo is required.')
2120
- }
2121
- if (repo._superclass !== Repo._superclass) {
2122
- throw new Error('repo is not an instance of Repo.')
2123
- }
2124
- return new Service({ repo })
2125
- }
2126
-
2127
-
2128
-
2129
- ;// ./lib/models/service/index.js
2130
-
2753
+ ;// ./lib/models/tenantAwareEntity/index.js
2131
2754
 
2132
2755
 
2133
2756
 
@@ -2189,191 +2812,6 @@ function _makeSetCode(fieldName, options) {
2189
2812
 
2190
2813
 
2191
2814
 
2192
- ;// ./lib/helpers/generalPost/generalPost.js
2193
-
2194
-
2195
-
2196
-
2197
- async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator, resourceInfo }) {
2198
- const { resources, data, globalShared = {}, shared = {}, relationship = {} } = body
2199
- const _resourceInfo = resourceInfo || body.resourceInfo
2200
- _attachShared(data, globalShared, shared)
2201
- const obj = await pReduce(resources, async (acc, resource) => {
2202
- const service = _makeService(resource, _resourceInfo, UniqueKeyGenerator, GeneralModel)
2203
- _createRelationship(data, relationship[resource], acc)
2204
- const _data = data[resource]
2205
- const result = await service.saveAll({ docs: [].concat(_data) })
2206
- acc[resource] = Array.isArray(_data) ? result._data : result._data[0]
2207
- return acc
2208
- }, {})
2209
- return obj
2210
- }
2211
-
2212
- function _attachShared(data, globalShared = {}, shared = {}) {
2213
- Object.keys(shared).forEach((key) => {
2214
- const _data = data[key]
2215
- data[key] = objectHelper.merge({}, _data, globalShared, shared[key] || {})
2216
- })
2217
- }
2218
-
2219
- function _createRelationship(data, relationship = {}, object) {
2220
- Object.keys(relationship).forEach((key) => {
2221
- const path = relationship[key]
2222
- const val = objectHelper.get(object, path)
2223
- objectHelper.set(data, key, val)
2224
- })
2225
- }
2226
-
2227
- function _makeService(resource, resourceInfo, UniqueKeyGenerator, GeneralModel) {
2228
- const { collectionName, fields } = resourceInfo[resource]
2229
- const uniqueKeyGenerator = UniqueKeyGenerator.makeGenerator(fields)
2230
- const model = new GeneralModel({ collectionName, uniqueKeyGenerator })
2231
- return makeService({
2232
- repo: new Repo({ model })
2233
- })
2234
- }
2235
-
2236
-
2237
-
2238
- ;// ./lib/helpers/generalPost/index.js
2239
-
2240
-
2241
-
2242
-
2243
- ;// ./lib/helpers/padZeros/padZeros.js
2244
- function padZeros(num, minLength = 6) {
2245
- num = num.toString()
2246
- if (num.length < minLength) {
2247
- return padZeros('0' + num, minLength)
2248
- }
2249
- return num
2250
- }
2251
-
2252
-
2253
-
2254
- ;// ./lib/helpers/padZeros/index.js
2255
-
2256
-
2257
-
2258
-
2259
- ;// ./lib/helpers/pReduce/index.js
2260
-
2261
-
2262
-
2263
-
2264
- ;// ./lib/helpers/stringFormatter/index.js
2265
-
2266
-
2267
-
2268
-
2269
- ;// ./lib/helpers/stringHelper/stringHelper.js
2270
- function baseXEncode(num, base = 34) {
2271
- const charset = getBaseCharset(base)
2272
- return encode(num, charset)
2273
- }
2274
-
2275
- function encode(int, charset) {
2276
- let byCode = charset.byCode;
2277
- if (int === 0) {
2278
- return byCode[0];
2279
- }
2280
-
2281
- var res = "",
2282
- max = charset.length;
2283
- while (int > 0) {
2284
- res = byCode[int % max] + res;
2285
- int = Math.floor(int / max);
2286
- }
2287
- return res;
2288
- }
2289
-
2290
- function getBaseCharset(base) {
2291
- let charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZ'
2292
- if (base === 58) {
2293
- charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz'
2294
- }
2295
- return indexCharset(charset)
2296
- }
2297
-
2298
- function indexCharset(str) {
2299
- var byCode = {},
2300
- byChar = {},
2301
- length = str.length,
2302
- i, char;
2303
- for (i = 0; i < length; i++) {
2304
- char = str[i];
2305
- byCode[i] = char;
2306
- byChar[char] = i;
2307
- }
2308
- return { byCode: byCode, byChar: byChar, length: length };
2309
- }
2310
-
2311
- function randomString({ len = 16, pattern = 'a1' } = {}) {
2312
- const A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
2313
- const a = 'abcdefghijklmnopqrstuvwxyz'
2314
- const num = '1234567890'
2315
- const mark = '~!@#$%^&*_+-='
2316
- let str = ''
2317
- if (pattern.includes('A')) {
2318
- str += A
2319
- }
2320
- if (pattern.includes('a')) {
2321
- str += a
2322
- }
2323
- if (pattern.includes('1')) {
2324
- str += num
2325
- }
2326
- if (pattern.includes('#')) {
2327
- str += mark
2328
- }
2329
- const chars = [...str]
2330
- return [...Array(len)].map(i => {
2331
- return chars[(Math.random() * chars.length) | 0]
2332
- }).join``
2333
- }
2334
-
2335
- function reverse(str) {
2336
- if (typeof str !== 'string') {
2337
- str = str.toString()
2338
- }
2339
- const splitString = str.split('')
2340
- const reverseArray = splitString.reverse()
2341
- return reverseArray.join('')
2342
- }
2343
-
2344
- function setCode(base = 34) {
2345
- const now = (new Date()).valueOf()
2346
- const random = randomString({
2347
- len: 8,
2348
- pattern: '1'
2349
- })
2350
- const str = reverse(`${now}${random}`)
2351
- // const str = `${now}${random}`
2352
- return baseXEncode(str, base)
2353
- }
2354
-
2355
- const stringHelper = {
2356
- setCode
2357
- }
2358
-
2359
-
2360
- ;// ./lib/helpers/stringHelper/index.js
2361
-
2362
-
2363
-
2364
-
2365
-
2366
- ;// ./lib/helpers/index.js
2367
-
2368
-
2369
-
2370
-
2371
-
2372
-
2373
-
2374
-
2375
-
2376
-
2377
2815
 
2378
2816
 
2379
2817
  ;// ./lib/index.js
@@ -2383,25 +2821,4 @@ const stringHelper = {
2383
2821
  ;// ./index.js
2384
2822
 
2385
2823
 
2386
- var __webpack_exports__ApiResponse = __webpack_exports__.sh;
2387
- var __webpack_exports__KeyValueObject = __webpack_exports__.Yc;
2388
- var __webpack_exports__Metadata = __webpack_exports__.OS;
2389
- var __webpack_exports__QMeta = __webpack_exports__.Z8;
2390
- var __webpack_exports__Repo = __webpack_exports__.lc;
2391
- var __webpack_exports__Service = __webpack_exports__.kl;
2392
- var __webpack_exports__TemplateCompiler = __webpack_exports__.Mg;
2393
- var __webpack_exports__UniqueKeyGenerator = __webpack_exports__._x;
2394
- var __webpack_exports__concatStringByArray = __webpack_exports__.yl;
2395
- var __webpack_exports__convertString = __webpack_exports__.l0;
2396
- var __webpack_exports__formatDate = __webpack_exports__.Yq;
2397
- var __webpack_exports__generalPost = __webpack_exports__.zn;
2398
- var __webpack_exports__getValidation = __webpack_exports__.G8;
2399
- var __webpack_exports__getValueByKeys = __webpack_exports__.pY;
2400
- var __webpack_exports__makeApiResponse = __webpack_exports__.su;
2401
- var __webpack_exports__makeService = __webpack_exports__.Q6;
2402
- var __webpack_exports__objectHelper = __webpack_exports__.UI;
2403
- var __webpack_exports__pReduce = __webpack_exports__.d;
2404
- var __webpack_exports__padZeros = __webpack_exports__.Lv;
2405
- var __webpack_exports__stringFormatter = __webpack_exports__.Qy;
2406
- var __webpack_exports__stringHelper = __webpack_exports__.yO;
2407
- export { __webpack_exports__ApiResponse as ApiResponse, __webpack_exports__KeyValueObject as KeyValueObject, __webpack_exports__Metadata as Metadata, __webpack_exports__QMeta as QMeta, __webpack_exports__Repo as Repo, __webpack_exports__Service as Service, __webpack_exports__TemplateCompiler as TemplateCompiler, __webpack_exports__UniqueKeyGenerator as UniqueKeyGenerator, __webpack_exports__concatStringByArray as concatStringByArray, __webpack_exports__convertString as convertString, __webpack_exports__formatDate as formatDate, __webpack_exports__generalPost as generalPost, __webpack_exports__getValidation as getValidation, __webpack_exports__getValueByKeys as getValueByKeys, __webpack_exports__makeApiResponse as makeApiResponse, __webpack_exports__makeService as makeService, __webpack_exports__objectHelper as objectHelper, __webpack_exports__pReduce as pReduce, __webpack_exports__padZeros as padZeros, __webpack_exports__stringFormatter as stringFormatter, __webpack_exports__stringHelper as stringHelper };
2824
+ export { ApiResponse, KeyValueObject, Metadata, QMeta, Repo, Service, TemplateCompiler, TenantAwareEntity, TrackedEntity, UniqueKeyGenerator, authorize, concatStringByArray, convertString, formatDate, generalPost, getValidation, getValueByKeys_getValueByKeys as getValueByKeys, init, initFromArray, initOnlyValidFromArray, makeApiResponse, makeService, objectHelper, pReduce, padZeros, stringFormatter, stringHelper, trackingPlugin };