mixin.js
4.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
'use strict';
const _ = require('lodash');
const HasOne = require('./has-one');
const HasMany = require('./has-many');
const BelongsToMany = require('./belongs-to-many');
const BelongsTo = require('./belongs-to');
function isModel(model, sequelize) {
return model
&& model.prototype
&& model.prototype instanceof sequelize.Sequelize.Model;
}
const Mixin = {
hasMany(target, options = {}) {
if (!isModel(target, this.sequelize)) {
throw new Error(`${this.name}.hasMany called with something that's not a subclass of Sequelize.Model`);
}
const source = this;
// Since this is a mixin, we'll need a unique letiable name for hooks (since Model will override our hooks option)
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks;
Object.assign(options, _.omit(source.options, ['hooks']));
if (options.useHooks) {
this.runHooks('beforeAssociate', { source, target, type: HasMany }, options);
}
// the id is in the foreign table or in a connecting table
const association = new HasMany(source, target, options);
source.associations[association.associationAccessor] = association;
association._injectAttributes();
association.mixin(source.prototype);
if (options.useHooks) {
this.runHooks('afterAssociate', { source, target, type: HasMany, association }, options);
}
return association;
},
belongsToMany(target, options = {}) {
if (!isModel(target, this.sequelize)) {
throw new Error(`${this.name}.belongsToMany called with something that's not a subclass of Sequelize.Model`);
}
const source = this;
// Since this is a mixin, we'll need a unique letiable name for hooks (since Model will override our hooks option)
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks;
options.timestamps = options.timestamps === undefined ? this.sequelize.options.timestamps : options.timestamps;
Object.assign(options, _.omit(source.options, ['hooks', 'timestamps', 'scopes', 'defaultScope']));
if (options.useHooks) {
this.runHooks('beforeAssociate', { source, target, type: BelongsToMany }, options);
}
// the id is in the foreign table or in a connecting table
const association = new BelongsToMany(source, target, options);
source.associations[association.associationAccessor] = association;
association._injectAttributes();
association.mixin(source.prototype);
if (options.useHooks) {
this.runHooks('afterAssociate', { source, target, type: BelongsToMany, association }, options);
}
return association;
},
getAssociations(target) {
return Object.values(this.associations).filter(association => association.target.name === target.name);
},
getAssociationForAlias(target, alias) {
// Two associations cannot have the same alias, so we can use find instead of filter
return this.getAssociations(target).find(association => association.verifyAssociationAlias(alias)) || null;
}
};
// The logic for hasOne and belongsTo is exactly the same
function singleLinked(Type) {
return function(target, options = {}) {
// eslint-disable-next-line no-invalid-this
const source = this;
if (!isModel(target, source.sequelize)) {
throw new Error(`${source.name}.${_.lowerFirst(Type.name)} called with something that's not a subclass of Sequelize.Model`);
}
// Since this is a mixin, we'll need a unique letiable name for hooks (since Model will override our hooks option)
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks;
if (options.useHooks) {
source.runHooks('beforeAssociate', { source, target, type: Type }, options);
}
// the id is in the foreign table
const association = new Type(source, target, Object.assign(options, source.options));
source.associations[association.associationAccessor] = association;
association._injectAttributes();
association.mixin(source.prototype);
if (options.useHooks) {
source.runHooks('afterAssociate', { source, target, type: Type, association }, options);
}
return association;
};
}
Mixin.hasOne = singleLinked(HasOne);
Mixin.belongsTo = singleLinked(BelongsTo);
module.exports = Mixin;
module.exports.Mixin = Mixin;
module.exports.default = Mixin;