model-builder.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import { isPlainObject } from 'lodash'
  2. import { Model as SequelizeModel, Sequelize } from 'sequelize'
  3. import { logger } from '@server/helpers/logger'
  4. export class ModelBuilder <T extends SequelizeModel> {
  5. private readonly modelRegistry = new Map<string, T>()
  6. constructor (private readonly sequelize: Sequelize) {
  7. }
  8. createModels (jsonArray: any[], baseModelName: string): T[] {
  9. const result: T[] = []
  10. for (const json of jsonArray) {
  11. const { created, model } = this.createModel(json, baseModelName, json.id + '.' + baseModelName)
  12. if (created) result.push(model)
  13. }
  14. return result
  15. }
  16. private createModel (json: any, modelName: string, keyPath: string) {
  17. if (!json.id) return { created: false, model: null }
  18. const { created, model } = this.createOrFindModel(json, modelName, keyPath)
  19. for (const key of Object.keys(json)) {
  20. const value = json[key]
  21. if (!value) continue
  22. // Child model
  23. if (isPlainObject(value)) {
  24. const { created, model: subModel } = this.createModel(value, key, keyPath + '.' + json.id + '.' + key)
  25. if (!created || !subModel) continue
  26. const Model = this.findModelBuilder(modelName)
  27. const association = Model.associations[key]
  28. if (!association) {
  29. logger.error('Cannot find association %s of model %s', key, modelName, { associations: Object.keys(Model.associations) })
  30. continue
  31. }
  32. if (association.isMultiAssociation) {
  33. if (!Array.isArray(model[key])) model[key] = []
  34. model[key].push(subModel)
  35. } else {
  36. model[key] = subModel
  37. }
  38. }
  39. }
  40. return { created, model }
  41. }
  42. private createOrFindModel (json: any, modelName: string, keyPath: string) {
  43. const registryKey = this.getModelRegistryKey(json, keyPath)
  44. if (this.modelRegistry.has(registryKey)) {
  45. return {
  46. created: false,
  47. model: this.modelRegistry.get(registryKey)
  48. }
  49. }
  50. const Model = this.findModelBuilder(modelName)
  51. if (!Model) {
  52. logger.error(
  53. 'Cannot build model %s that does not exist', this.buildSequelizeModelName(modelName),
  54. { existing: this.sequelize.modelManager.all.map(m => m.name) }
  55. )
  56. return undefined
  57. }
  58. // FIXME: typings
  59. const model = new (Model as any)(json)
  60. this.modelRegistry.set(registryKey, model)
  61. return { created: true, model }
  62. }
  63. private findModelBuilder (modelName: string) {
  64. return this.sequelize.modelManager.getModel(this.buildSequelizeModelName(modelName))
  65. }
  66. private buildSequelizeModelName (modelName: string) {
  67. if (modelName === 'Avatars') return 'ActorImageModel'
  68. if (modelName === 'ActorFollowing') return 'ActorModel'
  69. if (modelName === 'ActorFollower') return 'ActorModel'
  70. if (modelName === 'FlaggedAccount') return 'AccountModel'
  71. return modelName + 'Model'
  72. }
  73. private getModelRegistryKey (json: any, keyPath: string) {
  74. return keyPath + json.id
  75. }
  76. }