@questwork/q-utilities 0.1.2 → 0.1.3

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.
@@ -52,13 +52,13 @@ __webpack_require__.d(__webpack_exports__, {
52
52
  ApiResponse: () => (/* reexport */ ApiResponse),
53
53
  KeyValueObject: () => (/* reexport */ KeyValueObject),
54
54
  Metadata: () => (/* reexport */ Metadata),
55
+ QMeta: () => (/* reexport */ QMeta),
55
56
  Repo: () => (/* reexport */ Repo),
56
57
  Service: () => (/* reexport */ Service),
57
58
  convertString: () => (/* reexport */ convertString),
58
59
  formatDate: () => (/* reexport */ formatDate),
59
60
  getValidation: () => (/* reexport */ getValidation),
60
61
  getValueByKeys: () => (/* reexport */ getValueByKeys),
61
- jwtHelper: () => (/* reexport */ jwtHelper),
62
62
  makeApiResponse: () => (/* reexport */ makeApiResponse),
63
63
  makeService: () => (/* reexport */ makeService),
64
64
  padZeros: () => (/* reexport */ padZeros),
@@ -289,284 +289,6 @@ function getValueByKeys(keys, data) {
289
289
  ;// ./lib/helpers/getValueByKeys/index.js
290
290
 
291
291
 
292
- ;// ./lib/helpers/jwtHelper/jwtHelper.js
293
- // 'use strict'
294
-
295
- /* eslint-disable new-cap */
296
- /* eslint-disable camelcase */
297
- /* eslint-disable no-mixed-operators */
298
- /* eslint-disable no-useless-escape */
299
- /* eslint-disable no-param-reassign */
300
-
301
- /* eslint func-names: 0 */
302
-
303
- // const Buffer = require('buffer/').Buffer
304
-
305
- const EXPIRY = 3600 // in second
306
- const ALGORITHM = 'HS256'
307
- const SECRET = 'ab1234cd'
308
-
309
- const _hasBuffer = typeof Buffer === 'function'
310
-
311
- const jwtHelper = {
312
- create(obj, { secret, algorithm, expiry } = {}) {
313
- const sAlgorithm = algorithm || ALGORITHM
314
- const sSecret = secret || SECRET
315
- const exp = expiry || getTimeInSecond() + EXPIRY
316
- const payload = {
317
- ...obj,
318
- exp
319
- }
320
- return encode(payload, sSecret, sAlgorithm)
321
- },
322
- createByUser(loginAccount) {
323
- const exp = getTimeInSecond() + EXPIRY
324
- const payload = {
325
- loginAccount,
326
- exp
327
- }
328
- return this.encode(payload)
329
- },
330
- encode(payload, algorithm) {
331
- return encode(payload, SECRET, algorithm)
332
- },
333
- decode(token, algorithm) {
334
- const noVerify = !this.verify(token)
335
- return decode(token, SECRET, noVerify, algorithm) // if noVerify = true, may skip verification
336
- },
337
- getPayload(token) {
338
- const payload = getPayload(token)
339
- return {
340
- payload
341
- }
342
- },
343
- getPayloadIdByKey(token, key) {
344
- const payload = getPayload(token)
345
- const id = payload[key] ? payload[key].id : null
346
- return {
347
- id,
348
- jwtToken: token
349
- }
350
- },
351
- resolve(token, secret, algorithm) {
352
- const sSecret = secret || SECRET
353
- return decode(token, sSecret, false, algorithm) // need verification
354
- },
355
- verify(token) {
356
- const payload = getPayload(token)
357
- const today = getTimeInSecond()
358
- return (payload.exp && (today <= payload.exp)) || false
359
- }
360
- }
361
-
362
- /**
363
- * Private functions
364
- */
365
-
366
- const getPayload = (token) => decode(token, SECRET, true)
367
-
368
- const getTimeInSecond = () => Math.floor(Date.now() / 1000)
369
-
370
- /**
371
- * Private functions, based on jwt-simple 0.2.0
372
- */
373
-
374
- const { cryptoHelper } = require('../cryptoHelper')
375
-
376
- const algorithmMap = {
377
- HS256: 'sha256',
378
- HS384: 'sha384',
379
- HS512: 'sha512',
380
- RS256: 'RSA-SHA256'
381
- }
382
-
383
- const typeMap = {
384
- HS256: 'hmac',
385
- HS384: 'hmac',
386
- HS512: 'hmac',
387
- RS256: 'sign'
388
- }
389
-
390
-
391
- /**
392
- * Decode jwt
393
- *
394
- * @param {Object} token
395
- * @param {String} key
396
- * @param {Boolean} noVerify
397
- * @param {String} algorithm
398
- * @return {Object} payload
399
- * @api public
400
- */
401
- const decode = function jwt_decode(token, key, noVerify, algorithm) {
402
- // check token
403
- if (!token) {
404
- throw new Error('No token supplied')
405
- }
406
- // check segments
407
- const segments = token.split('.')
408
- if (segments.length !== 3) {
409
- throw new Error('Not enough or too many segments')
410
- }
411
-
412
- // All segment should be base64
413
- const headerSeg = segments[0]
414
- const payloadSeg = segments[1]
415
- const signatureSeg = segments[2]
416
-
417
- // base64 decode and parse JSON
418
- const header = JSON.parse(base64urlDecode(headerSeg))
419
-
420
- const payload = JSON.parse(base64urlDecode(payloadSeg))
421
-
422
- if (!noVerify) {
423
- const signingMethod = algorithmMap[algorithm || header.alg]
424
- const signingType = typeMap[algorithm || header.alg]
425
- if (!signingMethod || !signingType) {
426
- throw new Error('Algorithm not supported')
427
- }
428
-
429
- // verify signature. `sign` will return base64 string.
430
- const signingInput = [headerSeg, payloadSeg].join('.')
431
- if (!verify(signingInput, key, signingMethod, signingType, signatureSeg)) {
432
- throw new Error('Signature verification failed')
433
- }
434
- }
435
-
436
- return payload
437
- }
438
-
439
-
440
- /**
441
- * Encode jwt
442
- *
443
- * @param {Object} payload
444
- * @param {String} key
445
- * @param {String} algorithm
446
- * @return {String} token
447
- * @api public
448
- */
449
- const encode = function jwt_encode(payload, key, algorithm) {
450
- // Check key
451
- if (!key) {
452
- throw new Error('Require key')
453
- }
454
-
455
- // Check algorithm, default is HS256
456
- if (!algorithm) {
457
- algorithm = ALGORITHM
458
- }
459
-
460
- const signingMethod = algorithmMap[algorithm]
461
- const signingType = typeMap[algorithm]
462
- if (!signingMethod || !signingType) {
463
- throw new Error('Algorithm not supported')
464
- }
465
-
466
- // header, typ is fixed value.
467
- const header = { typ: 'JWT', alg: algorithm }
468
-
469
- // create segments, all segments should be base64 string
470
- const segments = []
471
- segments.push(base64urlEncode(JSON.stringify(header)))
472
- segments.push(base64urlEncode(JSON.stringify(payload)))
473
- segments.push(sign(segments.join('.'), key, signingMethod, signingType))
474
-
475
- return segments.join('.')
476
- }
477
-
478
-
479
- /**
480
- * private util functions
481
- */
482
-
483
- function verify(input, key, method, type, signature) {
484
- if (type === 'hmac') {
485
- return (signature === sign(input, key, method, type))
486
- } else if (type === 'sign') {
487
- try {
488
- return cryptoHelper.createStringVerify({
489
- algorithm: method,
490
- data: input,
491
- object: key,
492
- signature: base64urlUnescape(signature),
493
- signatureEncoding: 'base64'
494
- })
495
- } catch (error) {
496
- throw new Error('createStringVerify failed')
497
- }
498
- }
499
- throw new Error('Algorithm type not recognized')
500
- }
501
-
502
- function sign(input, key, method, type) {
503
- let base64str
504
- if (type === 'hmac') {
505
- base64str = cryptoHelper.createStringHmac({
506
- algorithm: method,
507
- key,
508
- data: input,
509
- outputEncoding: 'base64'
510
- })
511
- } else if (type === 'sign') {
512
- try {
513
- base64str = cryptoHelper.createSignature({
514
- algorithm: method,
515
- data: input,
516
- privateKey: key,
517
- outputEncoding: 'base64'
518
- })
519
- } catch (error) {
520
- throw new Error('createSignature failed')
521
- }
522
- } else {
523
- throw new Error('Algorithm type not recognized')
524
- }
525
- return base64urlEscape(base64str)
526
- }
527
-
528
- function _decode(str) {
529
- if (_hasBuffer) {
530
- return Buffer.from(base64urlUnescape(str), 'base64').toString('utf8')
531
- }
532
- return atob(base64urlUnescape(str))
533
- }
534
-
535
- function _encode(str) {
536
- if (_hasBuffer) {
537
- return base64urlEscape(Buffer.from(str, 'utf8').toString('base64'))
538
- }
539
- return base64urlEscape(btoa(str))
540
- }
541
-
542
- function base64urlDecode(str) {
543
- // fixed bug if decode string is incorrect
544
- // return (new Buffer.from(base64urlUnescape(str), 'base64')).toString() || '{}'
545
- return _decode(str)
546
- }
547
-
548
- function base64urlUnescape(str) {
549
- str += new Array(5 - str.length % 4).join('=')
550
- return str.replace(/\-/g, '+').replace(/_/g, '/')
551
- }
552
-
553
- function base64urlEncode(str) {
554
- // return base64urlEscape(new Buffer.from((str)).toString('base64'))
555
- return _encode(str)
556
- }
557
-
558
- function base64urlEscape(str) {
559
- return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
560
- }
561
-
562
-
563
-
564
- ;// ./lib/helpers/jwtHelper/index.js
565
-
566
-
567
-
568
-
569
-
570
292
  ;// ./lib/helpers/padZeros/padZeros.js
571
293
  function padZeros(num, minLength = 6) {
572
294
  num = num.toString()
@@ -603,7 +325,6 @@ function stringFormatter(str) {
603
325
 
604
326
 
605
327
 
606
-
607
328
  ;// ./lib/models/apiResponse/apiResponse.js
608
329
  class ApiResponse {
609
330
  constructor(options = {}) {
@@ -933,13 +654,86 @@ class Metadata extends KeyValueObject {
933
654
 
934
655
 
935
656
 
657
+ ;// ./lib/models/qMeta/qMeta.js
658
+
659
+
660
+ const updateAllowedProps = [
661
+ 'attributes',
662
+ 'ref'
663
+ ]
664
+
665
+ class QMeta {
666
+ constructor(options = {}) {
667
+ options = options || {}
668
+ this.attributes = KeyValueObject.initOnlyValidFromArray(options.attributes)
669
+ this.ref = options.ref || {}
670
+ }
671
+
672
+ static get _classname() {
673
+ return 'QMeta'
674
+ }
675
+ static get _superclass() {
676
+ return 'QMeta'
677
+ }
678
+
679
+ // Class methods
680
+ static init(options = {}) {
681
+ if (options instanceof QMeta) {
682
+ return options
683
+ }
684
+ return new QMeta(options)
685
+ }
686
+
687
+ // instance methods
688
+ addAttribute(obj) {
689
+ const kvObject = KeyValueObject.init(obj)
690
+ if (!kvObject) {
691
+ throw new Error('invalid meta attribute')
692
+ }
693
+ this.attributes.push(kvObject)
694
+ return this
695
+ }
696
+
697
+ update(obj) {
698
+ Object.keys(obj).forEach((key) => {
699
+ if (updateAllowedProps.includes(key)) {
700
+ if (key === 'attributes') {
701
+ this[key] = KeyValueObject.initOnlyValidFromArray(obj[key])
702
+ } else {
703
+ this[key] = obj[key]
704
+ }
705
+ }
706
+ })
707
+ return this
708
+ }
709
+ }
710
+
711
+
712
+
713
+ ;// ./lib/models/qMeta/index.js
714
+
715
+
716
+
717
+
936
718
  ;// ./lib/models/repo/repo.js
937
719
  class Repo {
938
720
  constructor(options) {
721
+ options = options || {}
939
722
  this.model = options.model
940
- this.dbTransaction = options.dbTransaction
723
+ this._sharedOptions = options._sharedOptions // { session: this.dbTransaction }
724
+ this._queryOptions = options._queryOptions
725
+ this._saveOptions = options._saveOptions
726
+ this._Class = options._constructor && options._constructor._Class
727
+ ? options._constructor._Class
728
+ : null
729
+ }
730
+ static init(options = {}) {
731
+ if (options instanceof this) {
732
+ return options
733
+ }
734
+ const instance = new this(options)
735
+ return instance.isValid ? instance : null
941
736
  }
942
-
943
737
  static get _classname() {
944
738
  return 'Repo'
945
739
  }
@@ -947,8 +741,40 @@ class Repo {
947
741
  return 'Repo'
948
742
  }
949
743
 
744
+ get _classname() {
745
+ return 'Repo'
746
+ }
747
+
748
+ get _superclass() {
749
+ return 'Repo'
750
+ }
751
+
752
+ get isValid() {
753
+ return this.model
754
+ && (typeof this.model.deleteOne === 'function')
755
+ && (typeof this.model.findAll === 'function')
756
+ && (typeof this.model.saveOne === 'function')
757
+ }
758
+
759
+ get queryOptions() {
760
+ return {
761
+ ...this._sharedOptions,
762
+ ...this._queryOptions,
763
+ }
764
+ }
765
+
766
+ get saveOptions() {
767
+ return {
768
+ ...this._sharedOptions,
769
+ ...this._saveOptions,
770
+ }
771
+ }
772
+
950
773
  init(options) {
951
- throw new Error('subclass should implement .init(options)')
774
+ if (this._Class && typeof this._Class.init === 'function') {
775
+ return this._Class.init(options)
776
+ }
777
+ return options
952
778
  }
953
779
 
954
780
  async deleteOne({ id }) {
@@ -965,9 +791,8 @@ class Repo {
965
791
  }
966
792
 
967
793
  findAll({ query }) {
968
- const options = {}
969
794
  return new Promise((resolve, reject) => {
970
- this.model.findAll(query, options, (err, data, total) => {
795
+ this.model.findAll(query, this.queryOptions, (err, data, total) => {
971
796
  if (err) {
972
797
  reject(err)
973
798
  } else {
@@ -982,9 +807,8 @@ class Repo {
982
807
  }
983
808
 
984
809
  findOne({ query }) {
985
- const options = { session: this.dbTransaction }
986
810
  return new Promise((resolve, reject) => {
987
- this.model.findAll(query, options, (err, data) => {
811
+ this.model.findAll(query, this.queryOptions, (err, data) => {
988
812
  if (err) {
989
813
  reject(err)
990
814
  } else if (data.length === 1) {
@@ -1003,13 +827,13 @@ class Repo {
1003
827
  }
1004
828
 
1005
829
  saveAll({ docs }) {
1006
- const self = this
1007
830
  let isNew
1008
831
  return Promise.all(docs.map(async (doc) => {
1009
832
  if (doc) {
1010
- const result = await self.saveOne({ doc })
833
+ const result = await this.saveOne({ doc })
1011
834
  isNew = result.isNew
1012
- return result.data[0]
835
+ const _data = result._data || result.data
836
+ return _data[0]
1013
837
  }
1014
838
  return null
1015
839
  })).then((savedData) => {
@@ -1023,9 +847,8 @@ class Repo {
1023
847
  }
1024
848
 
1025
849
  saveOne({ doc }) {
1026
- const options = { session: this.dbTransaction }
1027
850
  return new Promise((resolve, reject) => {
1028
- this.model.saveOne(doc, options, (err, result) => {
851
+ this.model.saveOne(doc, this.saveOptions, (err, result) => {
1029
852
  if (err) {
1030
853
  reject(err)
1031
854
  } else {
@@ -1121,9 +944,9 @@ function makeService({ repo }) {
1121
944
  if (repo === undefined) {
1122
945
  throw new Error('repo is required.')
1123
946
  }
1124
- // if (!(repo instanceof Repo)) {
1125
- // throw new Error('repo is not an instance of Repo.')
1126
- // }
947
+ if (repo._superclass !== Repo._superclass) {
948
+ throw new Error('repo is not an instance of Repo.')
949
+ }
1127
950
  return new Service({ repo })
1128
951
  }
1129
952
 
@@ -1141,6 +964,7 @@ function makeService({ repo }) {
1141
964
 
1142
965
 
1143
966
 
967
+
1144
968
  ;// ./lib/index.js
1145
969
 
1146
970
 
package/dist/index.min.js CHANGED
@@ -27,13 +27,13 @@ __webpack_require__.d(__webpack_exports__, {
27
27
  sh: () => (/* reexport */ ApiResponse),
28
28
  Yc: () => (/* reexport */ KeyValueObject),
29
29
  OS: () => (/* reexport */ Metadata),
30
+ Z8: () => (/* reexport */ QMeta),
30
31
  lc: () => (/* reexport */ Repo),
31
32
  kl: () => (/* reexport */ Service),
32
33
  l0: () => (/* reexport */ convertString),
33
34
  Yq: () => (/* reexport */ formatDate),
34
35
  G8: () => (/* reexport */ getValidation),
35
36
  pY: () => (/* reexport */ getValueByKeys),
36
- Q_: () => (/* reexport */ jwtHelper),
37
37
  su: () => (/* reexport */ makeApiResponse),
38
38
  Q6: () => (/* reexport */ makeService),
39
39
  Lv: () => (/* reexport */ padZeros),
@@ -264,284 +264,6 @@ function getValueByKeys(keys, data) {
264
264
  ;// ./lib/helpers/getValueByKeys/index.js
265
265
 
266
266
 
267
- ;// ./lib/helpers/jwtHelper/jwtHelper.js
268
- // 'use strict'
269
-
270
- /* eslint-disable new-cap */
271
- /* eslint-disable camelcase */
272
- /* eslint-disable no-mixed-operators */
273
- /* eslint-disable no-useless-escape */
274
- /* eslint-disable no-param-reassign */
275
-
276
- /* eslint func-names: 0 */
277
-
278
- // const Buffer = require('buffer/').Buffer
279
-
280
- const EXPIRY = 3600 // in second
281
- const ALGORITHM = 'HS256'
282
- const SECRET = 'ab1234cd'
283
-
284
- const _hasBuffer = typeof Buffer === 'function'
285
-
286
- const jwtHelper = {
287
- create(obj, { secret, algorithm, expiry } = {}) {
288
- const sAlgorithm = algorithm || ALGORITHM
289
- const sSecret = secret || SECRET
290
- const exp = expiry || getTimeInSecond() + EXPIRY
291
- const payload = {
292
- ...obj,
293
- exp
294
- }
295
- return encode(payload, sSecret, sAlgorithm)
296
- },
297
- createByUser(loginAccount) {
298
- const exp = getTimeInSecond() + EXPIRY
299
- const payload = {
300
- loginAccount,
301
- exp
302
- }
303
- return this.encode(payload)
304
- },
305
- encode(payload, algorithm) {
306
- return encode(payload, SECRET, algorithm)
307
- },
308
- decode(token, algorithm) {
309
- const noVerify = !this.verify(token)
310
- return decode(token, SECRET, noVerify, algorithm) // if noVerify = true, may skip verification
311
- },
312
- getPayload(token) {
313
- const payload = getPayload(token)
314
- return {
315
- payload
316
- }
317
- },
318
- getPayloadIdByKey(token, key) {
319
- const payload = getPayload(token)
320
- const id = payload[key] ? payload[key].id : null
321
- return {
322
- id,
323
- jwtToken: token
324
- }
325
- },
326
- resolve(token, secret, algorithm) {
327
- const sSecret = secret || SECRET
328
- return decode(token, sSecret, false, algorithm) // need verification
329
- },
330
- verify(token) {
331
- const payload = getPayload(token)
332
- const today = getTimeInSecond()
333
- return (payload.exp && (today <= payload.exp)) || false
334
- }
335
- }
336
-
337
- /**
338
- * Private functions
339
- */
340
-
341
- const getPayload = (token) => decode(token, SECRET, true)
342
-
343
- const getTimeInSecond = () => Math.floor(Date.now() / 1000)
344
-
345
- /**
346
- * Private functions, based on jwt-simple 0.2.0
347
- */
348
-
349
- const { cryptoHelper } = require('../cryptoHelper')
350
-
351
- const algorithmMap = {
352
- HS256: 'sha256',
353
- HS384: 'sha384',
354
- HS512: 'sha512',
355
- RS256: 'RSA-SHA256'
356
- }
357
-
358
- const typeMap = {
359
- HS256: 'hmac',
360
- HS384: 'hmac',
361
- HS512: 'hmac',
362
- RS256: 'sign'
363
- }
364
-
365
-
366
- /**
367
- * Decode jwt
368
- *
369
- * @param {Object} token
370
- * @param {String} key
371
- * @param {Boolean} noVerify
372
- * @param {String} algorithm
373
- * @return {Object} payload
374
- * @api public
375
- */
376
- const decode = function jwt_decode(token, key, noVerify, algorithm) {
377
- // check token
378
- if (!token) {
379
- throw new Error('No token supplied')
380
- }
381
- // check segments
382
- const segments = token.split('.')
383
- if (segments.length !== 3) {
384
- throw new Error('Not enough or too many segments')
385
- }
386
-
387
- // All segment should be base64
388
- const headerSeg = segments[0]
389
- const payloadSeg = segments[1]
390
- const signatureSeg = segments[2]
391
-
392
- // base64 decode and parse JSON
393
- const header = JSON.parse(base64urlDecode(headerSeg))
394
-
395
- const payload = JSON.parse(base64urlDecode(payloadSeg))
396
-
397
- if (!noVerify) {
398
- const signingMethod = algorithmMap[algorithm || header.alg]
399
- const signingType = typeMap[algorithm || header.alg]
400
- if (!signingMethod || !signingType) {
401
- throw new Error('Algorithm not supported')
402
- }
403
-
404
- // verify signature. `sign` will return base64 string.
405
- const signingInput = [headerSeg, payloadSeg].join('.')
406
- if (!verify(signingInput, key, signingMethod, signingType, signatureSeg)) {
407
- throw new Error('Signature verification failed')
408
- }
409
- }
410
-
411
- return payload
412
- }
413
-
414
-
415
- /**
416
- * Encode jwt
417
- *
418
- * @param {Object} payload
419
- * @param {String} key
420
- * @param {String} algorithm
421
- * @return {String} token
422
- * @api public
423
- */
424
- const encode = function jwt_encode(payload, key, algorithm) {
425
- // Check key
426
- if (!key) {
427
- throw new Error('Require key')
428
- }
429
-
430
- // Check algorithm, default is HS256
431
- if (!algorithm) {
432
- algorithm = ALGORITHM
433
- }
434
-
435
- const signingMethod = algorithmMap[algorithm]
436
- const signingType = typeMap[algorithm]
437
- if (!signingMethod || !signingType) {
438
- throw new Error('Algorithm not supported')
439
- }
440
-
441
- // header, typ is fixed value.
442
- const header = { typ: 'JWT', alg: algorithm }
443
-
444
- // create segments, all segments should be base64 string
445
- const segments = []
446
- segments.push(base64urlEncode(JSON.stringify(header)))
447
- segments.push(base64urlEncode(JSON.stringify(payload)))
448
- segments.push(sign(segments.join('.'), key, signingMethod, signingType))
449
-
450
- return segments.join('.')
451
- }
452
-
453
-
454
- /**
455
- * private util functions
456
- */
457
-
458
- function verify(input, key, method, type, signature) {
459
- if (type === 'hmac') {
460
- return (signature === sign(input, key, method, type))
461
- } else if (type === 'sign') {
462
- try {
463
- return cryptoHelper.createStringVerify({
464
- algorithm: method,
465
- data: input,
466
- object: key,
467
- signature: base64urlUnescape(signature),
468
- signatureEncoding: 'base64'
469
- })
470
- } catch (error) {
471
- throw new Error('createStringVerify failed')
472
- }
473
- }
474
- throw new Error('Algorithm type not recognized')
475
- }
476
-
477
- function sign(input, key, method, type) {
478
- let base64str
479
- if (type === 'hmac') {
480
- base64str = cryptoHelper.createStringHmac({
481
- algorithm: method,
482
- key,
483
- data: input,
484
- outputEncoding: 'base64'
485
- })
486
- } else if (type === 'sign') {
487
- try {
488
- base64str = cryptoHelper.createSignature({
489
- algorithm: method,
490
- data: input,
491
- privateKey: key,
492
- outputEncoding: 'base64'
493
- })
494
- } catch (error) {
495
- throw new Error('createSignature failed')
496
- }
497
- } else {
498
- throw new Error('Algorithm type not recognized')
499
- }
500
- return base64urlEscape(base64str)
501
- }
502
-
503
- function _decode(str) {
504
- if (_hasBuffer) {
505
- return Buffer.from(base64urlUnescape(str), 'base64').toString('utf8')
506
- }
507
- return atob(base64urlUnescape(str))
508
- }
509
-
510
- function _encode(str) {
511
- if (_hasBuffer) {
512
- return base64urlEscape(Buffer.from(str, 'utf8').toString('base64'))
513
- }
514
- return base64urlEscape(btoa(str))
515
- }
516
-
517
- function base64urlDecode(str) {
518
- // fixed bug if decode string is incorrect
519
- // return (new Buffer.from(base64urlUnescape(str), 'base64')).toString() || '{}'
520
- return _decode(str)
521
- }
522
-
523
- function base64urlUnescape(str) {
524
- str += new Array(5 - str.length % 4).join('=')
525
- return str.replace(/\-/g, '+').replace(/_/g, '/')
526
- }
527
-
528
- function base64urlEncode(str) {
529
- // return base64urlEscape(new Buffer.from((str)).toString('base64'))
530
- return _encode(str)
531
- }
532
-
533
- function base64urlEscape(str) {
534
- return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
535
- }
536
-
537
-
538
-
539
- ;// ./lib/helpers/jwtHelper/index.js
540
-
541
-
542
-
543
-
544
-
545
267
  ;// ./lib/helpers/padZeros/padZeros.js
546
268
  function padZeros(num, minLength = 6) {
547
269
  num = num.toString()
@@ -578,7 +300,6 @@ function stringFormatter(str) {
578
300
 
579
301
 
580
302
 
581
-
582
303
  ;// ./lib/models/apiResponse/apiResponse.js
583
304
  class ApiResponse {
584
305
  constructor(options = {}) {
@@ -908,13 +629,86 @@ class Metadata extends KeyValueObject {
908
629
 
909
630
 
910
631
 
632
+ ;// ./lib/models/qMeta/qMeta.js
633
+
634
+
635
+ const updateAllowedProps = [
636
+ 'attributes',
637
+ 'ref'
638
+ ]
639
+
640
+ class QMeta {
641
+ constructor(options = {}) {
642
+ options = options || {}
643
+ this.attributes = KeyValueObject.initOnlyValidFromArray(options.attributes)
644
+ this.ref = options.ref || {}
645
+ }
646
+
647
+ static get _classname() {
648
+ return 'QMeta'
649
+ }
650
+ static get _superclass() {
651
+ return 'QMeta'
652
+ }
653
+
654
+ // Class methods
655
+ static init(options = {}) {
656
+ if (options instanceof QMeta) {
657
+ return options
658
+ }
659
+ return new QMeta(options)
660
+ }
661
+
662
+ // instance methods
663
+ addAttribute(obj) {
664
+ const kvObject = KeyValueObject.init(obj)
665
+ if (!kvObject) {
666
+ throw new Error('invalid meta attribute')
667
+ }
668
+ this.attributes.push(kvObject)
669
+ return this
670
+ }
671
+
672
+ update(obj) {
673
+ Object.keys(obj).forEach((key) => {
674
+ if (updateAllowedProps.includes(key)) {
675
+ if (key === 'attributes') {
676
+ this[key] = KeyValueObject.initOnlyValidFromArray(obj[key])
677
+ } else {
678
+ this[key] = obj[key]
679
+ }
680
+ }
681
+ })
682
+ return this
683
+ }
684
+ }
685
+
686
+
687
+
688
+ ;// ./lib/models/qMeta/index.js
689
+
690
+
691
+
692
+
911
693
  ;// ./lib/models/repo/repo.js
912
694
  class Repo {
913
695
  constructor(options) {
696
+ options = options || {}
914
697
  this.model = options.model
915
- this.dbTransaction = options.dbTransaction
698
+ this._sharedOptions = options._sharedOptions // { session: this.dbTransaction }
699
+ this._queryOptions = options._queryOptions
700
+ this._saveOptions = options._saveOptions
701
+ this._Class = options._constructor && options._constructor._Class
702
+ ? options._constructor._Class
703
+ : null
704
+ }
705
+ static init(options = {}) {
706
+ if (options instanceof this) {
707
+ return options
708
+ }
709
+ const instance = new this(options)
710
+ return instance.isValid ? instance : null
916
711
  }
917
-
918
712
  static get _classname() {
919
713
  return 'Repo'
920
714
  }
@@ -922,8 +716,40 @@ class Repo {
922
716
  return 'Repo'
923
717
  }
924
718
 
719
+ get _classname() {
720
+ return 'Repo'
721
+ }
722
+
723
+ get _superclass() {
724
+ return 'Repo'
725
+ }
726
+
727
+ get isValid() {
728
+ return this.model
729
+ && (typeof this.model.deleteOne === 'function')
730
+ && (typeof this.model.findAll === 'function')
731
+ && (typeof this.model.saveOne === 'function')
732
+ }
733
+
734
+ get queryOptions() {
735
+ return {
736
+ ...this._sharedOptions,
737
+ ...this._queryOptions,
738
+ }
739
+ }
740
+
741
+ get saveOptions() {
742
+ return {
743
+ ...this._sharedOptions,
744
+ ...this._saveOptions,
745
+ }
746
+ }
747
+
925
748
  init(options) {
926
- throw new Error('subclass should implement .init(options)')
749
+ if (this._Class && typeof this._Class.init === 'function') {
750
+ return this._Class.init(options)
751
+ }
752
+ return options
927
753
  }
928
754
 
929
755
  async deleteOne({ id }) {
@@ -940,9 +766,8 @@ class Repo {
940
766
  }
941
767
 
942
768
  findAll({ query }) {
943
- const options = {}
944
769
  return new Promise((resolve, reject) => {
945
- this.model.findAll(query, options, (err, data, total) => {
770
+ this.model.findAll(query, this.queryOptions, (err, data, total) => {
946
771
  if (err) {
947
772
  reject(err)
948
773
  } else {
@@ -957,9 +782,8 @@ class Repo {
957
782
  }
958
783
 
959
784
  findOne({ query }) {
960
- const options = { session: this.dbTransaction }
961
785
  return new Promise((resolve, reject) => {
962
- this.model.findAll(query, options, (err, data) => {
786
+ this.model.findAll(query, this.queryOptions, (err, data) => {
963
787
  if (err) {
964
788
  reject(err)
965
789
  } else if (data.length === 1) {
@@ -978,13 +802,13 @@ class Repo {
978
802
  }
979
803
 
980
804
  saveAll({ docs }) {
981
- const self = this
982
805
  let isNew
983
806
  return Promise.all(docs.map(async (doc) => {
984
807
  if (doc) {
985
- const result = await self.saveOne({ doc })
808
+ const result = await this.saveOne({ doc })
986
809
  isNew = result.isNew
987
- return result.data[0]
810
+ const _data = result._data || result.data
811
+ return _data[0]
988
812
  }
989
813
  return null
990
814
  })).then((savedData) => {
@@ -998,9 +822,8 @@ class Repo {
998
822
  }
999
823
 
1000
824
  saveOne({ doc }) {
1001
- const options = { session: this.dbTransaction }
1002
825
  return new Promise((resolve, reject) => {
1003
- this.model.saveOne(doc, options, (err, result) => {
826
+ this.model.saveOne(doc, this.saveOptions, (err, result) => {
1004
827
  if (err) {
1005
828
  reject(err)
1006
829
  } else {
@@ -1096,9 +919,9 @@ function makeService({ repo }) {
1096
919
  if (repo === undefined) {
1097
920
  throw new Error('repo is required.')
1098
921
  }
1099
- // if (!(repo instanceof Repo)) {
1100
- // throw new Error('repo is not an instance of Repo.')
1101
- // }
922
+ if (repo._superclass !== Repo._superclass) {
923
+ throw new Error('repo is not an instance of Repo.')
924
+ }
1102
925
  return new Service({ repo })
1103
926
  }
1104
927
 
@@ -1116,6 +939,7 @@ function makeService({ repo }) {
1116
939
 
1117
940
 
1118
941
 
942
+
1119
943
  ;// ./lib/index.js
1120
944
 
1121
945
 
@@ -1126,15 +950,15 @@ function makeService({ repo }) {
1126
950
  var __webpack_exports__ApiResponse = __webpack_exports__.sh;
1127
951
  var __webpack_exports__KeyValueObject = __webpack_exports__.Yc;
1128
952
  var __webpack_exports__Metadata = __webpack_exports__.OS;
953
+ var __webpack_exports__QMeta = __webpack_exports__.Z8;
1129
954
  var __webpack_exports__Repo = __webpack_exports__.lc;
1130
955
  var __webpack_exports__Service = __webpack_exports__.kl;
1131
956
  var __webpack_exports__convertString = __webpack_exports__.l0;
1132
957
  var __webpack_exports__formatDate = __webpack_exports__.Yq;
1133
958
  var __webpack_exports__getValidation = __webpack_exports__.G8;
1134
959
  var __webpack_exports__getValueByKeys = __webpack_exports__.pY;
1135
- var __webpack_exports__jwtHelper = __webpack_exports__.Q_;
1136
960
  var __webpack_exports__makeApiResponse = __webpack_exports__.su;
1137
961
  var __webpack_exports__makeService = __webpack_exports__.Q6;
1138
962
  var __webpack_exports__padZeros = __webpack_exports__.Lv;
1139
963
  var __webpack_exports__stringFormatter = __webpack_exports__.Qy;
1140
- export { __webpack_exports__ApiResponse as ApiResponse, __webpack_exports__KeyValueObject as KeyValueObject, __webpack_exports__Metadata as Metadata, __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__jwtHelper as jwtHelper, __webpack_exports__makeApiResponse as makeApiResponse, __webpack_exports__makeService as makeService, __webpack_exports__padZeros as padZeros, __webpack_exports__stringFormatter as stringFormatter };
964
+ 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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@questwork/q-utilities",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Questwork QUtilities",
5
5
  "main": "dist/index.min.js",
6
6
  "type": "module",
@@ -10,6 +10,11 @@
10
10
  "default": "./dist/index.min.js"
11
11
  }
12
12
  },
13
+ "scripts": {
14
+ "build": "cross-env NODE_ENV=production minimize=false gulp",
15
+ "lint": "eslint .",
16
+ "test:models": "NODE_ENV=test mocha --exit 'lib/models/test.setup.js' 'lib/models/**/*.spec.js'"
17
+ },
13
18
  "author": {
14
19
  "name": "Questwork Consulting Limited",
15
20
  "email": "info@questwork.com",
@@ -40,10 +45,5 @@
40
45
  },
41
46
  "engines": {
42
47
  "node": ">=10.0.0"
43
- },
44
- "scripts": {
45
- "build": "cross-env NODE_ENV=production minimize=false gulp",
46
- "lint": "eslint .",
47
- "test:models": "NODE_ENV=test mocha --exit 'lib/models/test.setup.js' 'lib/models/**/*.spec.js'"
48
48
  }
49
- }
49
+ }