@questwork/q-utilities 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -55,14 +55,19 @@ __webpack_require__.d(__webpack_exports__, {
55
55
  QMeta: () => (/* reexport */ QMeta),
56
56
  Repo: () => (/* reexport */ Repo),
57
57
  Service: () => (/* reexport */ Service),
58
+ UniqueKeyGenerator: () => (/* reexport */ UniqueKeyGenerator),
58
59
  convertString: () => (/* reexport */ convertString),
59
60
  formatDate: () => (/* reexport */ formatDate),
61
+ generalPost: () => (/* reexport */ generalPost),
60
62
  getValidation: () => (/* reexport */ getValidation),
61
63
  getValueByKeys: () => (/* reexport */ getValueByKeys),
62
64
  makeApiResponse: () => (/* reexport */ makeApiResponse),
63
65
  makeService: () => (/* reexport */ makeService),
66
+ objectHelper: () => (/* reexport */ objectHelper),
67
+ pReduce: () => (/* reexport */ pReduce),
64
68
  padZeros: () => (/* reexport */ padZeros),
65
- stringFormatter: () => (/* reexport */ stringFormatter)
69
+ stringFormatter: () => (/* reexport */ stringFormatter),
70
+ stringHelper: () => (/* reexport */ stringHelper)
66
71
  });
67
72
 
68
73
  ;// ./lib/helpers/convertString/convertString.js
@@ -289,39 +294,138 @@ function getValueByKeys(keys, data) {
289
294
  ;// ./lib/helpers/getValueByKeys/index.js
290
295
 
291
296
 
292
- ;// ./lib/helpers/padZeros/padZeros.js
293
- function padZeros(num, minLength = 6) {
294
- num = num.toString()
295
- if (num.length < minLength) {
296
- return padZeros('0' + num, minLength)
297
+ ;// ./lib/helpers/objectHelper/objectHelper.js
298
+ const objectHelper = {
299
+ get(obj, path) {
300
+ const parts = path.split('.')
301
+ return parts.reduce((acc, part) => {
302
+ if (part.endsWith('[]')) {
303
+ // 处理数组遍历
304
+ const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
305
+ if (Array.isArray(acc[key])) {
306
+ return acc[key] // 返回整个数组
307
+ }
308
+ return [] // 如果不是数组,返回空数组
309
+ }
310
+ if (part.includes('[') && part.includes(']')) {
311
+ // 处理数组索引
312
+ const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
313
+ if (arrayMatch) {
314
+ const key = arrayMatch[1]
315
+ const index = arrayMatch[2]
316
+ return acc && acc[key] && acc[key][index]
317
+ }
318
+ } else if (acc && Array.isArray(acc)) {
319
+ // 如果当前值是数组,提取每个对象的指定属性
320
+ return acc.map((item) => item[part])
321
+ } else {
322
+ // 处理普通属性
323
+ return acc && acc[part]
324
+ }
325
+ }, obj)
326
+ },
327
+ merge,
328
+ set(obj, path, value) {
329
+ const parts = path.split('.')
330
+ let current = obj
331
+ for (let i = 0; i < parts.length - 1; i++) {
332
+ const part = parts[i]
333
+ if (part.endsWith('[]')) {
334
+ // 处理数组遍历
335
+ const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
336
+ if (Array.isArray(current[key])) {
337
+ current[key].forEach((item) => set(item, parts.slice(i + 1).join('.'), value))
338
+ }
339
+ return // 处理完数组后直接返回
340
+ }
341
+ if (part.includes('[') && part.includes(']')) {
342
+ // 处理数组索引
343
+ const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
344
+ if (arrayMatch) {
345
+ const key = arrayMatch[1]
346
+ const index = arrayMatch[2]
347
+ if (Array.isArray(current[key]) && current[key][index]) {
348
+ current = current[key][index]
349
+ } else {
350
+ return // 如果数组或索引不存在,直接返回
351
+ }
352
+ }
353
+ } else {
354
+ // 处理普通属性
355
+ if (!current[part]) {
356
+ current[part] = {} // 如果属性不存在,创建一个空对象
357
+ }
358
+ current = current[part]
359
+ }
360
+ }
361
+
362
+ // 设置最终属性值
363
+ const lastPart = parts[parts.length - 1]
364
+ current[lastPart] = value
297
365
  }
298
- return num
299
366
  }
300
367
 
368
+ function merge(target, ...sources) {
369
+ if (!sources.length) return target
301
370
 
371
+ const source = sources.shift() // 取出第一个源对象
302
372
 
303
- ;// ./lib/helpers/padZeros/index.js
304
-
305
-
373
+ if (_isObject(target) && _isObject(source)) {
374
+ for (const key in source) {
375
+ if (_isObject(source[key])) {
376
+ if (!target[key]) {
377
+ // 如果目标对象没有该属性,创建一个空对象
378
+ target[key] = {}
379
+ }
380
+ // 递归合并
381
+ merge(target[key], source[key])
382
+ } else {
383
+ // 直接覆盖
384
+ target[key] = source[key]
385
+ }
386
+ }
387
+ }
306
388
 
389
+ // 继续合并剩余的源对象
390
+ return merge(target, ...sources)
391
+ }
307
392
 
308
- ;// ./lib/helpers/stringFormatter/stringFormatter.js
309
- function stringFormatter(str) {
310
- return (str || '').toUpperCase().replace('-', '_').replace(' ', '_')
393
+ function _isObject(obj) {
394
+ return obj && typeof obj === 'object' && !Array.isArray(obj)
311
395
  }
312
396
 
313
397
 
314
398
 
315
- ;// ./lib/helpers/stringFormatter/index.js
399
+ ;// ./lib/helpers/objectHelper/index.js
316
400
 
317
401
 
318
402
 
319
403
 
320
- ;// ./lib/helpers/index.js
404
+ ;// ./lib/helpers/pReduce/pReduce.js
405
+ async function pReduce(iterable, reducer, initialValue) {
406
+ return new Promise((resolve, reject) => {
407
+ const iterator = iterable[Symbol.iterator]()
408
+ let index = 0
321
409
 
410
+ const next = async total => {
411
+ const element = iterator.next()
322
412
 
413
+ if (element.done) {
414
+ resolve(total)
415
+ return
416
+ }
323
417
 
418
+ try {
419
+ const [resolvedTotal, resolvedValue] = await Promise.all([total, element.value])
420
+ next(reducer(resolvedTotal, resolvedValue, index++))
421
+ } catch (error) {
422
+ reject(error)
423
+ }
424
+ }
324
425
 
426
+ next(initialValue)
427
+ })
428
+ }
325
429
 
326
430
 
327
431
 
@@ -601,6 +705,13 @@ class KeyValueObject {
601
705
 
602
706
 
603
707
 
708
+ ;// ./lib/helpers/stringFormatter/stringFormatter.js
709
+ function stringFormatter(str) {
710
+ return (str || '').toUpperCase().replace('-', '_').replace(' ', '_')
711
+ }
712
+
713
+
714
+
604
715
  ;// ./lib/models/metadata/metadata.js
605
716
 
606
717
 
@@ -781,68 +892,112 @@ class Repo {
781
892
  }
782
893
  }
783
894
 
784
- findAll({ query }) {
895
+ // systemLog is optional
896
+ findAll({ query, systemLog }) {
897
+ const log = _makeLog({
898
+ systemLog,
899
+ label: 'REPO_READ',
900
+ message: `fn ${this._classname}.prototype.findAll`,
901
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
902
+ })
785
903
  return new Promise((resolve, reject) => {
786
904
  this.model.findAll(query, this.queryOptions, (err, data, total) => {
787
905
  if (err) {
906
+ log({ level: 'warn', output: err.toString() })
788
907
  reject(err)
789
908
  } else {
790
- resolve({
909
+ const result = {
791
910
  isNew: false,
792
911
  data,
793
912
  total: total || data.length
794
- })
913
+ }
914
+ log({ level: 'info', output: { ...result } })
915
+ resolve(result)
795
916
  }
796
917
  })
797
918
  })
798
919
  }
799
920
 
800
- findOne({ query }) {
921
+ findOne({ query, systemLog }) {
922
+ const log = _makeLog({
923
+ systemLog,
924
+ label: 'REPO_READ',
925
+ message: `fn ${this._classname}.prototype.findOne`,
926
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
927
+ })
801
928
  return new Promise((resolve, reject) => {
802
929
  this.model.findAll(query, this.queryOptions, (err, data) => {
803
930
  if (err) {
804
931
  reject(err)
805
932
  } else if (data.length === 1) {
806
- resolve({
933
+ const result = {
807
934
  isNew: false,
808
935
  data,
809
936
  total: 1
810
- })
937
+ }
938
+ log({ level: 'info', output: { ...result } })
939
+ resolve(result)
811
940
  } else if (data.length === 0) {
812
941
  reject(new Error('record not found'))
813
942
  } else {
814
943
  reject(new Error('more than one is found'))
815
944
  }
816
945
  })
946
+ .catch((err) => {
947
+ log({ level: 'warn', output: err.toString() })
948
+ throw err
949
+ })
817
950
  })
818
951
  }
819
952
 
820
- saveAll({ docs }) {
953
+ saveAll({ docs, systemLog }) {
821
954
  let isNew
822
- return Promise.all(docs.map(async (doc) => {
823
- if (doc) {
824
- const result = await this.saveOne({ doc })
825
- isNew = result.isNew
826
- const _data = result._data || result.data
827
- return _data[0]
828
- }
829
- return null
830
- })).then((savedData) => {
955
+ const log = _makeLog({
956
+ systemLog,
957
+ label: 'REPO_WRITE',
958
+ message: `fn ${this._classname}.prototype.saveAll`,
959
+ input: [{ docs: [...docs], systemLog: { ...systemLog } }]
960
+ })
961
+ const promise = typeof this.model.saveAll === 'function'
962
+ ? this.model.saveAll({ docs })
963
+ : Promise.all(docs.map(async (doc) => {
964
+ if (doc) {
965
+ const result = await this.saveOne({ doc })
966
+ isNew = result.isNew
967
+ const _data = result._data || result.data
968
+ return _data[0]
969
+ }
970
+ return null
971
+ }))
972
+ return promise.then((savedData) => {
831
973
  if (savedData.length !== 1) isNew = null
832
- return {
974
+ const result = {
833
975
  data: savedData,
834
976
  isNew,
835
977
  total: savedData.length
836
978
  }
979
+ log({ level: 'info', output: { ...result } })
980
+ return result
981
+ }).catch((err) => {
982
+ log({ level: 'warn', output: err.toString() })
983
+ throw err
837
984
  })
838
985
  }
839
986
 
840
- saveOne({ doc }) {
987
+ saveOne({ doc, systemLog }) {
988
+ const log = _makeLog({
989
+ systemLog,
990
+ label: 'REPO_WRITE',
991
+ message: `fn ${this._classname}.prototype.saveOne`,
992
+ input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
993
+ })
841
994
  return new Promise((resolve, reject) => {
842
995
  this.model.saveOne(doc, this.saveOptions, (err, result) => {
843
996
  if (err) {
997
+ log({ level: 'warn', output: err.toString() })
844
998
  reject(err)
845
999
  } else {
1000
+ log({ level: 'info', output: { ...result } })
846
1001
  resolve(result)
847
1002
  }
848
1003
  })
@@ -850,6 +1005,25 @@ class Repo {
850
1005
  }
851
1006
  }
852
1007
 
1008
+ function _makeLog({ systemLog, label, message: message1, input } = {}) {
1009
+ return ({ level, messgae: massage2, output } = {}) => {
1010
+ if (systemLog && systemLog.systemLogHelper) {
1011
+ systemLog.systemLogHelper.log({
1012
+ batchId: systemLog.batchId,
1013
+ label,
1014
+ level,
1015
+ message: massage2 || message1,
1016
+ data: {
1017
+ payload: {
1018
+ input,
1019
+ output
1020
+ }
1021
+ }
1022
+ })
1023
+ }
1024
+ }
1025
+ }
1026
+
853
1027
 
854
1028
 
855
1029
  ;// ./lib/models/repo/index.js
@@ -880,16 +1054,16 @@ class Service {
880
1054
  })
881
1055
  }
882
1056
 
883
- async findAll({ query = {} } = {}) {
884
- const result = await this.repo.findAll({ query })
1057
+ async findAll({ query = {}, systemLog } = {}) {
1058
+ const result = await this.repo.findAll({ query, systemLog })
885
1059
  return makeApiResponse({
886
1060
  repo: this.repo,
887
1061
  result
888
1062
  })
889
1063
  }
890
1064
 
891
- async findOne({ query = {} } = {}) {
892
- const result = await this.repo.findOne({ query })
1065
+ async findOne({ query = {}, systemLog } = {}) {
1066
+ const result = await this.repo.findOne({ query, systemLog })
893
1067
  return makeApiResponse({
894
1068
  repo: this.repo,
895
1069
  result
@@ -903,21 +1077,21 @@ class Service {
903
1077
  return arr.map((i) => this.init(i))
904
1078
  }
905
1079
 
906
- async saveAll({ docs = [] } = {}) {
1080
+ async saveAll({ docs = [], systemLog } = {}) {
907
1081
  const copies = docs.map((doc) => {
908
1082
  return this.init(doc)
909
1083
  })
910
- const result = await this.repo.saveAll({ docs: copies })
1084
+ const result = await this.repo.saveAll({ docs: copies, systemLog })
911
1085
  return makeApiResponse({
912
1086
  repo: this.repo,
913
1087
  result
914
1088
  })
915
1089
  }
916
1090
 
917
- async saveOne({ doc = {} } = {}) {
1091
+ async saveOne({ doc = {}, systemLog } = {}) {
918
1092
  const copy = this.init(doc)
919
1093
  if (copy) {
920
- const result = await this.repo.saveOne({ doc: copy })
1094
+ const result = await this.repo.saveOne({ doc: copy, systemLog })
921
1095
  return makeApiResponse({
922
1096
  repo: this.repo,
923
1097
  result
@@ -948,6 +1122,54 @@ function makeService({ repo }) {
948
1122
 
949
1123
 
950
1124
 
1125
+ ;// ./lib/models/uniqueKeyGenerator/uniqueKeyGenerator.js
1126
+
1127
+
1128
+ class UniqueKeyGenerator {
1129
+ static get _classname() {
1130
+ return 'UniqueKeyGenerator'
1131
+ }
1132
+ static get _superclass() {
1133
+ return 'UniqueKeyGenerator'
1134
+ }
1135
+ static makeFormatter({ fieldName, format, options }) {
1136
+ switch (format) {
1137
+ case 'set_code':
1138
+ return _makeSetCode(fieldName, options)
1139
+ default:
1140
+ return _makeSetCode(fieldName, options)
1141
+ }
1142
+ }
1143
+ static makeGenerator(arr) {
1144
+ const fns = arr.map((item) => this.makeFormatter(item))
1145
+ return async (obj) => {
1146
+ const output = await pReduce(fns, async (acc, fn) => {
1147
+ const _obj = await fn(obj)
1148
+ return Object.assign(acc, _obj)
1149
+ }, obj)
1150
+ return output
1151
+ }
1152
+ }
1153
+ }
1154
+
1155
+ function _makeSetCode(fieldName, options) {
1156
+ return async (obj = {}) => {
1157
+ if (obj[fieldName]) {
1158
+ return {}
1159
+ }
1160
+ return {
1161
+ [fieldName]: stringHelper.setCode()
1162
+ }
1163
+ }
1164
+ }
1165
+
1166
+
1167
+
1168
+ ;// ./lib/models/uniqueKeyGenerator/index.js
1169
+
1170
+
1171
+
1172
+
951
1173
  ;// ./lib/models/index.js
952
1174
 
953
1175
 
@@ -956,6 +1178,193 @@ function makeService({ repo }) {
956
1178
 
957
1179
 
958
1180
 
1181
+
1182
+ ;// ./lib/helpers/generalPost/generalPost.js
1183
+
1184
+
1185
+
1186
+
1187
+ async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator, resourceInfo }) {
1188
+ const { resources, data, globalShared = {}, shared = {}, relationship = {} } = body
1189
+ const _resourceInfo = resourceInfo || body.resourceInfo
1190
+ _attachShared(data, globalShared, shared)
1191
+ const obj = await pReduce(resources, async (acc, resource) => {
1192
+ const service = _makeService(resource, _resourceInfo, UniqueKeyGenerator, GeneralModel)
1193
+ _createRelationship(data, relationship[resource], acc)
1194
+ const _data = data[resource]
1195
+ const result = await service.saveAll({ docs: [].concat(_data) })
1196
+ acc[resource] = Array.isArray(_data) ? result._data : result._data[0]
1197
+ return acc
1198
+ }, {})
1199
+ return obj
1200
+ }
1201
+
1202
+ function _attachShared(data, globalShared = {}, shared = {}) {
1203
+ Object.keys(shared).forEach((key) => {
1204
+ const _data = data[key]
1205
+ data[key] = objectHelper.merge({}, _data, globalShared, shared[key] || {})
1206
+ })
1207
+ }
1208
+
1209
+ function _createRelationship(data, relationship = {}, object) {
1210
+ Object.keys(relationship).forEach((key) => {
1211
+ const path = relationship[key]
1212
+ const val = objectHelper.get(object, path)
1213
+ objectHelper.set(data, key, val)
1214
+ })
1215
+ }
1216
+
1217
+ function _makeService(resource, resourceInfo, UniqueKeyGenerator, GeneralModel) {
1218
+ const { collectionName, fields } = resourceInfo[resource]
1219
+ const uniqueKeyGenerator = UniqueKeyGenerator.makeGenerator(fields)
1220
+ const model = new GeneralModel({ collectionName, uniqueKeyGenerator })
1221
+ return makeService({
1222
+ repo: new Repo({ model })
1223
+ })
1224
+ }
1225
+
1226
+
1227
+
1228
+ ;// ./lib/helpers/generalPost/index.js
1229
+
1230
+
1231
+
1232
+
1233
+ ;// ./lib/helpers/padZeros/padZeros.js
1234
+ function padZeros(num, minLength = 6) {
1235
+ num = num.toString()
1236
+ if (num.length < minLength) {
1237
+ return padZeros('0' + num, minLength)
1238
+ }
1239
+ return num
1240
+ }
1241
+
1242
+
1243
+
1244
+ ;// ./lib/helpers/padZeros/index.js
1245
+
1246
+
1247
+
1248
+
1249
+ ;// ./lib/helpers/pReduce/index.js
1250
+
1251
+
1252
+
1253
+
1254
+ ;// ./lib/helpers/stringFormatter/index.js
1255
+
1256
+
1257
+
1258
+
1259
+ ;// ./lib/helpers/stringHelper/stringHelper.js
1260
+ function baseXEncode(num, base = 34) {
1261
+ const charset = getBaseCharset(base)
1262
+ return encode(num, charset)
1263
+ }
1264
+
1265
+ function encode(int, charset) {
1266
+ let byCode = charset.byCode;
1267
+ if (int === 0) {
1268
+ return byCode[0];
1269
+ }
1270
+
1271
+ var res = "",
1272
+ max = charset.length;
1273
+ while (int > 0) {
1274
+ res = byCode[int % max] + res;
1275
+ int = Math.floor(int / max);
1276
+ }
1277
+ return res;
1278
+ }
1279
+
1280
+ function getBaseCharset(base) {
1281
+ let charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZ'
1282
+ if (base === 58) {
1283
+ charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz'
1284
+ }
1285
+ return indexCharset(charset)
1286
+ }
1287
+
1288
+ function indexCharset(str) {
1289
+ var byCode = {},
1290
+ byChar = {},
1291
+ length = str.length,
1292
+ i, char;
1293
+ for (i = 0; i < length; i++) {
1294
+ char = str[i];
1295
+ byCode[i] = char;
1296
+ byChar[char] = i;
1297
+ }
1298
+ return { byCode: byCode, byChar: byChar, length: length };
1299
+ }
1300
+
1301
+ function randomString({ len = 16, pattern = 'a1' } = {}) {
1302
+ const A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
1303
+ const a = 'abcdefghijklmnopqrstuvwxyz'
1304
+ const num = '1234567890'
1305
+ const mark = '~!@#$%^&*_+-='
1306
+ let str = ''
1307
+ if (pattern.includes('A')) {
1308
+ str += A
1309
+ }
1310
+ if (pattern.includes('a')) {
1311
+ str += a
1312
+ }
1313
+ if (pattern.includes('1')) {
1314
+ str += num
1315
+ }
1316
+ if (pattern.includes('#')) {
1317
+ str += mark
1318
+ }
1319
+ const chars = [...str]
1320
+ return [...Array(len)].map(i => {
1321
+ return chars[(Math.random() * chars.length) | 0]
1322
+ }).join``
1323
+ }
1324
+
1325
+ function reverse(str) {
1326
+ if (typeof str !== 'string') {
1327
+ str = str.toString()
1328
+ }
1329
+ const splitString = str.split('')
1330
+ const reverseArray = splitString.reverse()
1331
+ return reverseArray.join('')
1332
+ }
1333
+
1334
+ function setCode(base = 34) {
1335
+ const now = (new Date()).valueOf()
1336
+ const random = randomString({
1337
+ len: 8,
1338
+ pattern: '1'
1339
+ })
1340
+ const str = reverse(`${now}${random}`)
1341
+ // const str = `${now}${random}`
1342
+ return baseXEncode(str, base)
1343
+ }
1344
+
1345
+ const stringHelper = {
1346
+ setCode
1347
+ }
1348
+
1349
+
1350
+ ;// ./lib/helpers/stringHelper/index.js
1351
+
1352
+
1353
+
1354
+
1355
+
1356
+ ;// ./lib/helpers/index.js
1357
+
1358
+
1359
+
1360
+
1361
+
1362
+
1363
+
1364
+
1365
+
1366
+
1367
+
959
1368
  ;// ./lib/index.js
960
1369
 
961
1370
 
package/dist/index.min.js CHANGED
@@ -30,14 +30,19 @@ __webpack_require__.d(__webpack_exports__, {
30
30
  Z8: () => (/* reexport */ QMeta),
31
31
  lc: () => (/* reexport */ Repo),
32
32
  kl: () => (/* reexport */ Service),
33
+ _x: () => (/* reexport */ UniqueKeyGenerator),
33
34
  l0: () => (/* reexport */ convertString),
34
35
  Yq: () => (/* reexport */ formatDate),
36
+ zn: () => (/* reexport */ generalPost),
35
37
  G8: () => (/* reexport */ getValidation),
36
38
  pY: () => (/* reexport */ getValueByKeys),
37
39
  su: () => (/* reexport */ makeApiResponse),
38
40
  Q6: () => (/* reexport */ makeService),
41
+ UI: () => (/* reexport */ objectHelper),
42
+ d: () => (/* reexport */ pReduce),
39
43
  Lv: () => (/* reexport */ padZeros),
40
- Qy: () => (/* reexport */ stringFormatter)
44
+ Qy: () => (/* reexport */ stringFormatter),
45
+ yO: () => (/* reexport */ stringHelper)
41
46
  });
42
47
 
43
48
  ;// ./lib/helpers/convertString/convertString.js
@@ -264,39 +269,138 @@ function getValueByKeys(keys, data) {
264
269
  ;// ./lib/helpers/getValueByKeys/index.js
265
270
 
266
271
 
267
- ;// ./lib/helpers/padZeros/padZeros.js
268
- function padZeros(num, minLength = 6) {
269
- num = num.toString()
270
- if (num.length < minLength) {
271
- return padZeros('0' + num, minLength)
272
+ ;// ./lib/helpers/objectHelper/objectHelper.js
273
+ const objectHelper = {
274
+ get(obj, path) {
275
+ const parts = path.split('.')
276
+ return parts.reduce((acc, part) => {
277
+ if (part.endsWith('[]')) {
278
+ // 处理数组遍历
279
+ const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
280
+ if (Array.isArray(acc[key])) {
281
+ return acc[key] // 返回整个数组
282
+ }
283
+ return [] // 如果不是数组,返回空数组
284
+ }
285
+ if (part.includes('[') && part.includes(']')) {
286
+ // 处理数组索引
287
+ const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
288
+ if (arrayMatch) {
289
+ const key = arrayMatch[1]
290
+ const index = arrayMatch[2]
291
+ return acc && acc[key] && acc[key][index]
292
+ }
293
+ } else if (acc && Array.isArray(acc)) {
294
+ // 如果当前值是数组,提取每个对象的指定属性
295
+ return acc.map((item) => item[part])
296
+ } else {
297
+ // 处理普通属性
298
+ return acc && acc[part]
299
+ }
300
+ }, obj)
301
+ },
302
+ merge,
303
+ set(obj, path, value) {
304
+ const parts = path.split('.')
305
+ let current = obj
306
+ for (let i = 0; i < parts.length - 1; i++) {
307
+ const part = parts[i]
308
+ if (part.endsWith('[]')) {
309
+ // 处理数组遍历
310
+ const key = part.slice(0, -2) // 去掉 '[]' 得到属性名
311
+ if (Array.isArray(current[key])) {
312
+ current[key].forEach((item) => set(item, parts.slice(i + 1).join('.'), value))
313
+ }
314
+ return // 处理完数组后直接返回
315
+ }
316
+ if (part.includes('[') && part.includes(']')) {
317
+ // 处理数组索引
318
+ const arrayMatch = part.match(/(\w+)\[(\d+)\]/)
319
+ if (arrayMatch) {
320
+ const key = arrayMatch[1]
321
+ const index = arrayMatch[2]
322
+ if (Array.isArray(current[key]) && current[key][index]) {
323
+ current = current[key][index]
324
+ } else {
325
+ return // 如果数组或索引不存在,直接返回
326
+ }
327
+ }
328
+ } else {
329
+ // 处理普通属性
330
+ if (!current[part]) {
331
+ current[part] = {} // 如果属性不存在,创建一个空对象
332
+ }
333
+ current = current[part]
334
+ }
335
+ }
336
+
337
+ // 设置最终属性值
338
+ const lastPart = parts[parts.length - 1]
339
+ current[lastPart] = value
272
340
  }
273
- return num
274
341
  }
275
342
 
343
+ function merge(target, ...sources) {
344
+ if (!sources.length) return target
276
345
 
346
+ const source = sources.shift() // 取出第一个源对象
277
347
 
278
- ;// ./lib/helpers/padZeros/index.js
279
-
280
-
348
+ if (_isObject(target) && _isObject(source)) {
349
+ for (const key in source) {
350
+ if (_isObject(source[key])) {
351
+ if (!target[key]) {
352
+ // 如果目标对象没有该属性,创建一个空对象
353
+ target[key] = {}
354
+ }
355
+ // 递归合并
356
+ merge(target[key], source[key])
357
+ } else {
358
+ // 直接覆盖
359
+ target[key] = source[key]
360
+ }
361
+ }
362
+ }
281
363
 
364
+ // 继续合并剩余的源对象
365
+ return merge(target, ...sources)
366
+ }
282
367
 
283
- ;// ./lib/helpers/stringFormatter/stringFormatter.js
284
- function stringFormatter(str) {
285
- return (str || '').toUpperCase().replace('-', '_').replace(' ', '_')
368
+ function _isObject(obj) {
369
+ return obj && typeof obj === 'object' && !Array.isArray(obj)
286
370
  }
287
371
 
288
372
 
289
373
 
290
- ;// ./lib/helpers/stringFormatter/index.js
374
+ ;// ./lib/helpers/objectHelper/index.js
291
375
 
292
376
 
293
377
 
294
378
 
295
- ;// ./lib/helpers/index.js
379
+ ;// ./lib/helpers/pReduce/pReduce.js
380
+ async function pReduce(iterable, reducer, initialValue) {
381
+ return new Promise((resolve, reject) => {
382
+ const iterator = iterable[Symbol.iterator]()
383
+ let index = 0
296
384
 
385
+ const next = async total => {
386
+ const element = iterator.next()
297
387
 
388
+ if (element.done) {
389
+ resolve(total)
390
+ return
391
+ }
298
392
 
393
+ try {
394
+ const [resolvedTotal, resolvedValue] = await Promise.all([total, element.value])
395
+ next(reducer(resolvedTotal, resolvedValue, index++))
396
+ } catch (error) {
397
+ reject(error)
398
+ }
399
+ }
299
400
 
401
+ next(initialValue)
402
+ })
403
+ }
300
404
 
301
405
 
302
406
 
@@ -576,6 +680,13 @@ class KeyValueObject {
576
680
 
577
681
 
578
682
 
683
+ ;// ./lib/helpers/stringFormatter/stringFormatter.js
684
+ function stringFormatter(str) {
685
+ return (str || '').toUpperCase().replace('-', '_').replace(' ', '_')
686
+ }
687
+
688
+
689
+
579
690
  ;// ./lib/models/metadata/metadata.js
580
691
 
581
692
 
@@ -756,68 +867,112 @@ class Repo {
756
867
  }
757
868
  }
758
869
 
759
- findAll({ query }) {
870
+ // systemLog is optional
871
+ findAll({ query, systemLog }) {
872
+ const log = _makeLog({
873
+ systemLog,
874
+ label: 'REPO_READ',
875
+ message: `fn ${this._classname}.prototype.findAll`,
876
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
877
+ })
760
878
  return new Promise((resolve, reject) => {
761
879
  this.model.findAll(query, this.queryOptions, (err, data, total) => {
762
880
  if (err) {
881
+ log({ level: 'warn', output: err.toString() })
763
882
  reject(err)
764
883
  } else {
765
- resolve({
884
+ const result = {
766
885
  isNew: false,
767
886
  data,
768
887
  total: total || data.length
769
- })
888
+ }
889
+ log({ level: 'info', output: { ...result } })
890
+ resolve(result)
770
891
  }
771
892
  })
772
893
  })
773
894
  }
774
895
 
775
- findOne({ query }) {
896
+ findOne({ query, systemLog }) {
897
+ const log = _makeLog({
898
+ systemLog,
899
+ label: 'REPO_READ',
900
+ message: `fn ${this._classname}.prototype.findOne`,
901
+ input: [{ query: { ...query }, systemLog: { ...systemLog } }]
902
+ })
776
903
  return new Promise((resolve, reject) => {
777
904
  this.model.findAll(query, this.queryOptions, (err, data) => {
778
905
  if (err) {
779
906
  reject(err)
780
907
  } else if (data.length === 1) {
781
- resolve({
908
+ const result = {
782
909
  isNew: false,
783
910
  data,
784
911
  total: 1
785
- })
912
+ }
913
+ log({ level: 'info', output: { ...result } })
914
+ resolve(result)
786
915
  } else if (data.length === 0) {
787
916
  reject(new Error('record not found'))
788
917
  } else {
789
918
  reject(new Error('more than one is found'))
790
919
  }
791
920
  })
921
+ .catch((err) => {
922
+ log({ level: 'warn', output: err.toString() })
923
+ throw err
924
+ })
792
925
  })
793
926
  }
794
927
 
795
- saveAll({ docs }) {
928
+ saveAll({ docs, systemLog }) {
796
929
  let isNew
797
- return Promise.all(docs.map(async (doc) => {
798
- if (doc) {
799
- const result = await this.saveOne({ doc })
800
- isNew = result.isNew
801
- const _data = result._data || result.data
802
- return _data[0]
803
- }
804
- return null
805
- })).then((savedData) => {
930
+ const log = _makeLog({
931
+ systemLog,
932
+ label: 'REPO_WRITE',
933
+ message: `fn ${this._classname}.prototype.saveAll`,
934
+ input: [{ docs: [...docs], systemLog: { ...systemLog } }]
935
+ })
936
+ const promise = typeof this.model.saveAll === 'function'
937
+ ? this.model.saveAll({ docs })
938
+ : Promise.all(docs.map(async (doc) => {
939
+ if (doc) {
940
+ const result = await this.saveOne({ doc })
941
+ isNew = result.isNew
942
+ const _data = result._data || result.data
943
+ return _data[0]
944
+ }
945
+ return null
946
+ }))
947
+ return promise.then((savedData) => {
806
948
  if (savedData.length !== 1) isNew = null
807
- return {
949
+ const result = {
808
950
  data: savedData,
809
951
  isNew,
810
952
  total: savedData.length
811
953
  }
954
+ log({ level: 'info', output: { ...result } })
955
+ return result
956
+ }).catch((err) => {
957
+ log({ level: 'warn', output: err.toString() })
958
+ throw err
812
959
  })
813
960
  }
814
961
 
815
- saveOne({ doc }) {
962
+ saveOne({ doc, systemLog }) {
963
+ const log = _makeLog({
964
+ systemLog,
965
+ label: 'REPO_WRITE',
966
+ message: `fn ${this._classname}.prototype.saveOne`,
967
+ input: [{ doc: { ...doc }, systemLog: { ...systemLog } }]
968
+ })
816
969
  return new Promise((resolve, reject) => {
817
970
  this.model.saveOne(doc, this.saveOptions, (err, result) => {
818
971
  if (err) {
972
+ log({ level: 'warn', output: err.toString() })
819
973
  reject(err)
820
974
  } else {
975
+ log({ level: 'info', output: { ...result } })
821
976
  resolve(result)
822
977
  }
823
978
  })
@@ -825,6 +980,25 @@ class Repo {
825
980
  }
826
981
  }
827
982
 
983
+ function _makeLog({ systemLog, label, message: message1, input } = {}) {
984
+ return ({ level, messgae: massage2, output } = {}) => {
985
+ if (systemLog && systemLog.systemLogHelper) {
986
+ systemLog.systemLogHelper.log({
987
+ batchId: systemLog.batchId,
988
+ label,
989
+ level,
990
+ message: massage2 || message1,
991
+ data: {
992
+ payload: {
993
+ input,
994
+ output
995
+ }
996
+ }
997
+ })
998
+ }
999
+ }
1000
+ }
1001
+
828
1002
 
829
1003
 
830
1004
  ;// ./lib/models/repo/index.js
@@ -855,16 +1029,16 @@ class Service {
855
1029
  })
856
1030
  }
857
1031
 
858
- async findAll({ query = {} } = {}) {
859
- const result = await this.repo.findAll({ query })
1032
+ async findAll({ query = {}, systemLog } = {}) {
1033
+ const result = await this.repo.findAll({ query, systemLog })
860
1034
  return makeApiResponse({
861
1035
  repo: this.repo,
862
1036
  result
863
1037
  })
864
1038
  }
865
1039
 
866
- async findOne({ query = {} } = {}) {
867
- const result = await this.repo.findOne({ query })
1040
+ async findOne({ query = {}, systemLog } = {}) {
1041
+ const result = await this.repo.findOne({ query, systemLog })
868
1042
  return makeApiResponse({
869
1043
  repo: this.repo,
870
1044
  result
@@ -878,21 +1052,21 @@ class Service {
878
1052
  return arr.map((i) => this.init(i))
879
1053
  }
880
1054
 
881
- async saveAll({ docs = [] } = {}) {
1055
+ async saveAll({ docs = [], systemLog } = {}) {
882
1056
  const copies = docs.map((doc) => {
883
1057
  return this.init(doc)
884
1058
  })
885
- const result = await this.repo.saveAll({ docs: copies })
1059
+ const result = await this.repo.saveAll({ docs: copies, systemLog })
886
1060
  return makeApiResponse({
887
1061
  repo: this.repo,
888
1062
  result
889
1063
  })
890
1064
  }
891
1065
 
892
- async saveOne({ doc = {} } = {}) {
1066
+ async saveOne({ doc = {}, systemLog } = {}) {
893
1067
  const copy = this.init(doc)
894
1068
  if (copy) {
895
- const result = await this.repo.saveOne({ doc: copy })
1069
+ const result = await this.repo.saveOne({ doc: copy, systemLog })
896
1070
  return makeApiResponse({
897
1071
  repo: this.repo,
898
1072
  result
@@ -923,6 +1097,54 @@ function makeService({ repo }) {
923
1097
 
924
1098
 
925
1099
 
1100
+ ;// ./lib/models/uniqueKeyGenerator/uniqueKeyGenerator.js
1101
+
1102
+
1103
+ class UniqueKeyGenerator {
1104
+ static get _classname() {
1105
+ return 'UniqueKeyGenerator'
1106
+ }
1107
+ static get _superclass() {
1108
+ return 'UniqueKeyGenerator'
1109
+ }
1110
+ static makeFormatter({ fieldName, format, options }) {
1111
+ switch (format) {
1112
+ case 'set_code':
1113
+ return _makeSetCode(fieldName, options)
1114
+ default:
1115
+ return _makeSetCode(fieldName, options)
1116
+ }
1117
+ }
1118
+ static makeGenerator(arr) {
1119
+ const fns = arr.map((item) => this.makeFormatter(item))
1120
+ return async (obj) => {
1121
+ const output = await pReduce(fns, async (acc, fn) => {
1122
+ const _obj = await fn(obj)
1123
+ return Object.assign(acc, _obj)
1124
+ }, obj)
1125
+ return output
1126
+ }
1127
+ }
1128
+ }
1129
+
1130
+ function _makeSetCode(fieldName, options) {
1131
+ return async (obj = {}) => {
1132
+ if (obj[fieldName]) {
1133
+ return {}
1134
+ }
1135
+ return {
1136
+ [fieldName]: stringHelper.setCode()
1137
+ }
1138
+ }
1139
+ }
1140
+
1141
+
1142
+
1143
+ ;// ./lib/models/uniqueKeyGenerator/index.js
1144
+
1145
+
1146
+
1147
+
926
1148
  ;// ./lib/models/index.js
927
1149
 
928
1150
 
@@ -931,6 +1153,193 @@ function makeService({ repo }) {
931
1153
 
932
1154
 
933
1155
 
1156
+
1157
+ ;// ./lib/helpers/generalPost/generalPost.js
1158
+
1159
+
1160
+
1161
+
1162
+ async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator, resourceInfo }) {
1163
+ const { resources, data, globalShared = {}, shared = {}, relationship = {} } = body
1164
+ const _resourceInfo = resourceInfo || body.resourceInfo
1165
+ _attachShared(data, globalShared, shared)
1166
+ const obj = await pReduce(resources, async (acc, resource) => {
1167
+ const service = _makeService(resource, _resourceInfo, UniqueKeyGenerator, GeneralModel)
1168
+ _createRelationship(data, relationship[resource], acc)
1169
+ const _data = data[resource]
1170
+ const result = await service.saveAll({ docs: [].concat(_data) })
1171
+ acc[resource] = Array.isArray(_data) ? result._data : result._data[0]
1172
+ return acc
1173
+ }, {})
1174
+ return obj
1175
+ }
1176
+
1177
+ function _attachShared(data, globalShared = {}, shared = {}) {
1178
+ Object.keys(shared).forEach((key) => {
1179
+ const _data = data[key]
1180
+ data[key] = objectHelper.merge({}, _data, globalShared, shared[key] || {})
1181
+ })
1182
+ }
1183
+
1184
+ function _createRelationship(data, relationship = {}, object) {
1185
+ Object.keys(relationship).forEach((key) => {
1186
+ const path = relationship[key]
1187
+ const val = objectHelper.get(object, path)
1188
+ objectHelper.set(data, key, val)
1189
+ })
1190
+ }
1191
+
1192
+ function _makeService(resource, resourceInfo, UniqueKeyGenerator, GeneralModel) {
1193
+ const { collectionName, fields } = resourceInfo[resource]
1194
+ const uniqueKeyGenerator = UniqueKeyGenerator.makeGenerator(fields)
1195
+ const model = new GeneralModel({ collectionName, uniqueKeyGenerator })
1196
+ return makeService({
1197
+ repo: new Repo({ model })
1198
+ })
1199
+ }
1200
+
1201
+
1202
+
1203
+ ;// ./lib/helpers/generalPost/index.js
1204
+
1205
+
1206
+
1207
+
1208
+ ;// ./lib/helpers/padZeros/padZeros.js
1209
+ function padZeros(num, minLength = 6) {
1210
+ num = num.toString()
1211
+ if (num.length < minLength) {
1212
+ return padZeros('0' + num, minLength)
1213
+ }
1214
+ return num
1215
+ }
1216
+
1217
+
1218
+
1219
+ ;// ./lib/helpers/padZeros/index.js
1220
+
1221
+
1222
+
1223
+
1224
+ ;// ./lib/helpers/pReduce/index.js
1225
+
1226
+
1227
+
1228
+
1229
+ ;// ./lib/helpers/stringFormatter/index.js
1230
+
1231
+
1232
+
1233
+
1234
+ ;// ./lib/helpers/stringHelper/stringHelper.js
1235
+ function baseXEncode(num, base = 34) {
1236
+ const charset = getBaseCharset(base)
1237
+ return encode(num, charset)
1238
+ }
1239
+
1240
+ function encode(int, charset) {
1241
+ let byCode = charset.byCode;
1242
+ if (int === 0) {
1243
+ return byCode[0];
1244
+ }
1245
+
1246
+ var res = "",
1247
+ max = charset.length;
1248
+ while (int > 0) {
1249
+ res = byCode[int % max] + res;
1250
+ int = Math.floor(int / max);
1251
+ }
1252
+ return res;
1253
+ }
1254
+
1255
+ function getBaseCharset(base) {
1256
+ let charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZ'
1257
+ if (base === 58) {
1258
+ charset = '9876543210ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz'
1259
+ }
1260
+ return indexCharset(charset)
1261
+ }
1262
+
1263
+ function indexCharset(str) {
1264
+ var byCode = {},
1265
+ byChar = {},
1266
+ length = str.length,
1267
+ i, char;
1268
+ for (i = 0; i < length; i++) {
1269
+ char = str[i];
1270
+ byCode[i] = char;
1271
+ byChar[char] = i;
1272
+ }
1273
+ return { byCode: byCode, byChar: byChar, length: length };
1274
+ }
1275
+
1276
+ function randomString({ len = 16, pattern = 'a1' } = {}) {
1277
+ const A = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
1278
+ const a = 'abcdefghijklmnopqrstuvwxyz'
1279
+ const num = '1234567890'
1280
+ const mark = '~!@#$%^&*_+-='
1281
+ let str = ''
1282
+ if (pattern.includes('A')) {
1283
+ str += A
1284
+ }
1285
+ if (pattern.includes('a')) {
1286
+ str += a
1287
+ }
1288
+ if (pattern.includes('1')) {
1289
+ str += num
1290
+ }
1291
+ if (pattern.includes('#')) {
1292
+ str += mark
1293
+ }
1294
+ const chars = [...str]
1295
+ return [...Array(len)].map(i => {
1296
+ return chars[(Math.random() * chars.length) | 0]
1297
+ }).join``
1298
+ }
1299
+
1300
+ function reverse(str) {
1301
+ if (typeof str !== 'string') {
1302
+ str = str.toString()
1303
+ }
1304
+ const splitString = str.split('')
1305
+ const reverseArray = splitString.reverse()
1306
+ return reverseArray.join('')
1307
+ }
1308
+
1309
+ function setCode(base = 34) {
1310
+ const now = (new Date()).valueOf()
1311
+ const random = randomString({
1312
+ len: 8,
1313
+ pattern: '1'
1314
+ })
1315
+ const str = reverse(`${now}${random}`)
1316
+ // const str = `${now}${random}`
1317
+ return baseXEncode(str, base)
1318
+ }
1319
+
1320
+ const stringHelper = {
1321
+ setCode
1322
+ }
1323
+
1324
+
1325
+ ;// ./lib/helpers/stringHelper/index.js
1326
+
1327
+
1328
+
1329
+
1330
+
1331
+ ;// ./lib/helpers/index.js
1332
+
1333
+
1334
+
1335
+
1336
+
1337
+
1338
+
1339
+
1340
+
1341
+
1342
+
934
1343
  ;// ./lib/index.js
935
1344
 
936
1345
 
@@ -944,12 +1353,17 @@ var __webpack_exports__Metadata = __webpack_exports__.OS;
944
1353
  var __webpack_exports__QMeta = __webpack_exports__.Z8;
945
1354
  var __webpack_exports__Repo = __webpack_exports__.lc;
946
1355
  var __webpack_exports__Service = __webpack_exports__.kl;
1356
+ var __webpack_exports__UniqueKeyGenerator = __webpack_exports__._x;
947
1357
  var __webpack_exports__convertString = __webpack_exports__.l0;
948
1358
  var __webpack_exports__formatDate = __webpack_exports__.Yq;
1359
+ var __webpack_exports__generalPost = __webpack_exports__.zn;
949
1360
  var __webpack_exports__getValidation = __webpack_exports__.G8;
950
1361
  var __webpack_exports__getValueByKeys = __webpack_exports__.pY;
951
1362
  var __webpack_exports__makeApiResponse = __webpack_exports__.su;
952
1363
  var __webpack_exports__makeService = __webpack_exports__.Q6;
1364
+ var __webpack_exports__objectHelper = __webpack_exports__.UI;
1365
+ var __webpack_exports__pReduce = __webpack_exports__.d;
953
1366
  var __webpack_exports__padZeros = __webpack_exports__.Lv;
954
1367
  var __webpack_exports__stringFormatter = __webpack_exports__.Qy;
955
- 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__convertString as convertString, __webpack_exports__formatDate as formatDate, __webpack_exports__getValidation as getValidation, __webpack_exports__getValueByKeys as getValueByKeys, __webpack_exports__makeApiResponse as makeApiResponse, __webpack_exports__makeService as makeService, __webpack_exports__padZeros as padZeros, __webpack_exports__stringFormatter as stringFormatter };
1368
+ var __webpack_exports__stringHelper = __webpack_exports__.yO;
1369
+ 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__UniqueKeyGenerator as UniqueKeyGenerator, __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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@questwork/q-utilities",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Questwork QUtilities",
5
5
  "main": "dist/index.min.js",
6
6
  "type": "module",