database-utils.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import * as retry from 'async/retry'
  2. import * as Bluebird from 'bluebird'
  3. import { Model } from 'sequelize-typescript'
  4. import { logger } from './logger'
  5. import { Transaction } from 'sequelize'
  6. function retryTransactionWrapper <T, A, B, C> (
  7. functionToRetry: (arg1: A, arg2: B, arg3: C) => Promise<T> | Bluebird<T>,
  8. arg1: A,
  9. arg2: B,
  10. arg3: C
  11. ): Promise<T>
  12. function retryTransactionWrapper <T, A, B> (
  13. functionToRetry: (arg1: A, arg2: B) => Promise<T> | Bluebird<T>,
  14. arg1: A,
  15. arg2: B
  16. ): Promise<T>
  17. function retryTransactionWrapper <T, A> (
  18. functionToRetry: (arg1: A) => Promise<T> | Bluebird<T>,
  19. arg1: A
  20. ): Promise<T>
  21. function retryTransactionWrapper <T> (
  22. functionToRetry: () => Promise<T> | Bluebird<T>
  23. ): Promise<T>
  24. function retryTransactionWrapper <T> (
  25. functionToRetry: (...args: any[]) => Promise<T> | Bluebird<T>,
  26. ...args: any[]
  27. ): Promise<T> {
  28. return transactionRetryer<T>(callback => {
  29. functionToRetry.apply(null, args)
  30. .then((result: T) => callback(null, result))
  31. .catch(err => callback(err))
  32. })
  33. .catch(err => {
  34. logger.error(`Cannot execute ${functionToRetry.name} with many retries.`, { err })
  35. throw err
  36. })
  37. }
  38. function transactionRetryer <T> (func: (err: any, data: T) => any) {
  39. return new Promise<T>((res, rej) => {
  40. retry(
  41. {
  42. times: 5,
  43. errorFilter: err => {
  44. const willRetry = (err.name === 'SequelizeDatabaseError')
  45. logger.debug('Maybe retrying the transaction function.', { willRetry, err })
  46. return willRetry
  47. }
  48. },
  49. func,
  50. (err, data) => err ? rej(err) : res(data)
  51. )
  52. })
  53. }
  54. function updateInstanceWithAnother <T extends Model<T>> (instanceToUpdate: Model<T>, baseInstance: Model<T>) {
  55. const obj = baseInstance.toJSON()
  56. for (const key of Object.keys(obj)) {
  57. instanceToUpdate[key] = obj[key]
  58. }
  59. }
  60. function resetSequelizeInstance (instance: Model<any>, savedFields: object) {
  61. Object.keys(savedFields).forEach(key => {
  62. instance[key] = savedFields[key]
  63. })
  64. }
  65. function afterCommitIfTransaction (t: Transaction, fn: Function) {
  66. if (t) return t.afterCommit(() => fn())
  67. return fn()
  68. }
  69. function deleteNonExistingModels <T extends { hasSameUniqueKeysThan (other: T): boolean } & Model<T>> (
  70. fromDatabase: T[],
  71. newModels: T[],
  72. t: Transaction
  73. ) {
  74. return fromDatabase.filter(f => !newModels.find(newModel => newModel.hasSameUniqueKeysThan(f)))
  75. .map(f => f.destroy({ transaction: t }))
  76. }
  77. // ---------------------------------------------------------------------------
  78. export {
  79. resetSequelizeInstance,
  80. retryTransactionWrapper,
  81. transactionRetryer,
  82. updateInstanceWithAnother,
  83. afterCommitIfTransaction,
  84. deleteNonExistingModels
  85. }