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