UNPKG

5.13 kBJavaScriptView Raw
1'use strict';
2function Relationship(config) {
3 this.ORM = config.ORM;
4 this.tableName = config.tableName;
5 this.type = config.type;
6 this.modelFactoryName = config.modelFactoryName;
7 this.identifer = {
8 parent: config.parentIdentifer,
9 child: config.childIdentifer
10 };
11 if(this.type === Relationship.Types.belongsToMany) {
12 this.throughTableName = config.throughTableName;
13 this.throughModel = Relationship.createThroughModelFactory(
14 this.ORM,
15 this.tableName,
16 this.throughTableName,
17 this.identifer
18 );
19 }
20}
21
22Relationship.Types = {
23 belongsToOne: 'BELONGS_TO_ONE',
24 belongsToMany: 'BELONGS_TO_MANY',
25 hasOne: 'HAS_ONE',
26 hasMany: 'HAS_MANY'
27};
28
29//
30// Private
31//
32Relationship.createThroughModelFactory = function(ORM, table, throughTable, identifer) {
33 // Base model
34 var model = {
35 attributes: {}
36 };
37 // Create table attribute
38 model.attributes[identifer.child] = {};
39 // Create relation
40 model.attributes[table] = function(context) {
41 return context.belongsToOne(table, identifer.parent, identifer.child);
42 };
43 // Create new factory if it doesn't exist
44 // If it does, update the factory's attributes to include identifer
45 if(!ORM.models.hasOwnProperty(throughTable)) {
46 ORM.Model.extend(throughTable, model);
47 } else {
48 ORM.models[throughTable].addTableAttributes(model.attributes);
49 }
50 // Return
51 return ORM.models[throughTable];
52};
53
54//
55// Create
56//
57
58Relationship.prototype.createBelongsToOne = function(attributes, options) {
59 return this.ORM.models[this.modelFactoryName].create(attributes, options);
60};
61
62Relationship.prototype.createHasOne = function(attributes, parentModel, options) {
63 var newAttributes = Object.assign({}, attributes, {
64 [this.identifer.child]: parentModel[this.identifer.parent]
65 });
66 return this.ORM.models[this.modelFactoryName].create(newAttributes, options);
67};
68
69//
70// Attach
71//
72
73Relationship.prototype.attachAsAttribute = function(attributes, parentModel) {
74 var newAttributes = {};
75 newAttributes[this.identifer.child] = parentModel[this.identifer.parent];
76 return Object.assign(attributes, newAttributes);
77};
78
79// Note: parameter parentModel needs to be renamed,
80// in many-to-many the related models are siblings.
81// Parent should be refering to the Through table only.
82Relationship.prototype.attach = function(childModel, parentModels, options) {
83 var promises = [];
84 parentModels.forEach(function(parentModel) {
85 let targetIdentifer = this.getTargetModel().identifer;
86 var attributes = {
87 [targetIdentifer.child]: parentModel[targetIdentifer.parent],
88 [this.identifer.child]: childModel[this.identifer.parent]
89 };
90 var promise = this.ORM.models[this.throughTableName].create(attributes, options);
91 promises.push(promise);
92 }, this);
93 return Promise.all(promises);
94};
95
96//
97// Include
98//
99
100Relationship.prototype.include = function(table, childModel) {
101 var self = this;
102 var promises = [];
103 var query = {};
104 var promise;
105 switch(self.type) {
106 case Relationship.Types.hasOne:
107 case Relationship.Types.belongsToOne: {
108 if(childModel[self.identifer.child]) {
109 query[self.identifer.parent] = childModel[self.identifer.child];
110 promise = self.ORM.models[self.modelFactoryName].findOne(query);
111 } else {
112 promise = Promise.resolve(null);
113 }
114 break;
115 }
116 case Relationship.Types.belongsToMany : {
117 query = {};
118 // selfThroughIdentifer, selfIdentifer
119 promise = new Promise(function(resolve, reject) {
120 var models = [];
121 query[self.identifer.child] = childModel[self.identifer.parent];
122 // Get all through models
123 self.ORM.models[self.throughTableName].find(query, {
124 include: [{ relation: self.modelFactoryName }]
125 })
126 // Extract desired model in through model
127 .then(function(throughModels) {
128 throughModels.forEach(function(throughModel) {
129 models.push(throughModel[self.modelFactoryName]);
130 });
131 resolve(models);
132 })
133 .catch(function(error) {
134 reject(error);
135 });
136 });
137 promises.push(promise);
138 break;
139 }
140 case Relationship.Types.hasMany: {
141 query = {};
142 query[self.identifer.child] = childModel[self.identifer.parent];
143 promise = self.ORM.models[self.modelFactoryName].find(query);
144 promises.push(promise);
145 break;
146 }
147 }
148 return promise.then((model) => {
149 if(model) {
150 childModel[table] = model;
151 }
152 return childModel;
153 });
154};
155
156//
157// Helper
158//
159Relationship.prototype.getThroughTable = function() {
160 return (this.type === Relationship.Types.belongsToMany)
161 ? this.throughTableName
162 : this.modelFactoryName;
163};
164
165Relationship.prototype.getThroughModel = function() {
166 return this.throughModel;
167};
168
169Relationship.prototype.getTargetModel = function() {
170 return this.throughModel.relationships[this.modelFactoryName];
171};
172
173module.exports = Relationship;
\No newline at end of file