-
Notifications
You must be signed in to change notification settings - Fork 48
/
common.js
246 lines (220 loc) · 7.42 KB
/
common.js
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/**
* Copyright (c) 2016, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or
* https://opensource.org/licenses/BSD-3-Clause
*/
/**
* db/helpers/common.js
*
* Common utility file used by all the models
*/
'use strict'; // eslint-disable-line strict
const pub = require('../../pubsub').pub;
const dbconf = require('../../config').db;
const channelName = require('../../config').redis.channelName;
const logDB = require('../../utils/loggingUtil').logDB;
// jsonSchema keys for relatedLink
const jsonSchemaProperties = {
relatedlink: ['name', 'url'],
};
// change types for logs.
const changeType = {
add: 'ADD',
upd: 'UPDATE',
del: 'DELETE',
};
/**
* Takes a sample instance and enhances it with the subject instance and
* aspect instance
* @param {Sequelize} seq - A reference to Sequelize to have access to the
* the Promise class.
* @param {Instance} inst - The Sample Instance.
* @returns {Promise} - Returns a promise which resolves to sample instance
* enhanced with subject instance and aspect instance information.
*/
function augmentSampleWithSubjectAspectInfo(seq, inst) {
return new seq.Promise((resolve, reject) => {
inst.getSubject()
.then((sub) => {
inst.dataValues.subject = sub;
// adding absolutePath to sample instance
if (sub) {
inst.dataValues.absolutePath = sub.absolutePath;
}
inst.subject = sub;
}).then(() => inst.getAspect())
.then((asp) => {
inst.dataValues.aspect = asp;
resolve(inst);
})
.catch((err) => reject(err));
});
} // augmentSampleWithSubjectAspectInfo
/**
* This function checks if the aspect and subject associated with the sample
* are published or not. It resolves to true when both the aspect and
* the subject are published or false otherwise.
*
* @param {Sequelize} seq - A reference to Sequelize to have access to the
* the Promise class.
* @param {Instance} inst - The Sample Instance.
* @returns {Promise} - Returns a promise which resolves to true when both the
* aspect and the subject are published or false otherwise.
*/
function sampleAspectAndSubjectArePublished(seq, inst) {
return new seq.Promise((resolve, reject) => {
let asp;
let sub;
inst.getSubject()
.then((s) => {
sub = s;
})
.then(() => inst.getAspect())
.then((a) => {
asp = a;
})
.then(() => resolve(sub && asp && sub.isPublished && asp.isPublished))
.catch((err) => reject(err));
});
} // sampleAspectAndSubjectArePublished
/**
* Create db log. Changed values will be empty in case of post.
* @param {Object} inst - Model instance in case of post,
* { old: old_inst, new: new_inst} in case of update
* @param {Object} eventType - event type
* @param {Array} changedKeys - An array containing the fields of the model
* that were changed
* @param {Array} ignoreAttributes - An array containing the fields of the
* model that should be ignored
*/
function createDBLog(inst, eventType, changedKeys, ignoreAttributes) {
let objNameLog;
let objIDLog;
// get name and id of instance
if (inst.old) {
objNameLog = `Name=${inst.old.name}`;
} else {
objNameLog = `Name=${inst.name}`;
}
if (inst.old) {
objIDLog = ` ID=${inst.old.id}`;
} else {
objIDLog = ` ID=${inst.id}`;
}
const instance = `${objNameLog} ${objIDLog}`;
let changedVals = '';
// If an update, log all changed attributes
if (Array.isArray(changedKeys) && Array.isArray(ignoreAttributes)) {
const ignoreSet = new Set(ignoreAttributes);
for (let i = 0; i < changedKeys.length; i++) {
if (!ignoreSet.has(changedKeys[i])) {
changedVals += `${changedKeys[i]}:` +
`${inst._previousDataValues[changedKeys[i]]} => ` +
`${inst.get()[changedKeys[i]]} ;`;
}
}
}
logDB(instance, eventType, changedVals);
}
/**
* This function returns an object to be published via redis channel
* @param {Object} inst - Model instance
@param {[Array]} changedKeys - An array containing the fields of the model
* that were changed
* @param {[Array]} ignoreAttributes An array containing the fields of the
* model that should be ignored
* @returns {Object} - Returns an object that is ready to be published Or null
* if there are no changedfields.
*/
function prepareToPublish(inst, changedKeys, ignoreAttributes) {
// prepare the data iff changed fields are not in ignoreAttributes
const ignoreSet = new Set(ignoreAttributes);
for (let i = 0; i < changedKeys.length; i++) {
if (!ignoreSet.has(changedKeys[i])) {
return {
old: inst._previousDataValues,
new: inst.get(),
};
}
}
return null;
} // prepareToPublish
/**
* This function publishes an created, updated or a deleted model instance to
* the redis channel and returns the object that was published
*
* @param {Object} inst - Model instance to be published
* @param {String} event - Type of the event that is being published
* @param {[Array]} changedKeys - An array containing the fields of the model
* that were changed
* @param {[Array]} ignoreAttributes An array containing the fields of the
* model that should be ignored
* @returns {Object} - object that was published
*/
function publishChange(inst, event, changedKeys, ignoreAttributes) {
const obj = {};
obj[event] = inst.get();
/**
* The shape of the object required for update events are a bit different.
* changedKeys and ignoreAttributes are passed in as arrays by the
* afterUpdate hooks of the models, which are passed to the prepareToPublish
* to get the object just for update events.
*/
if (Array.isArray(changedKeys) && Array.isArray(ignoreAttributes)) {
obj[event] = prepareToPublish(inst, changedKeys, ignoreAttributes);
}
if (obj[event]) {
pub.publish(channelName, JSON.stringify(obj));
}
return obj;
} // publishChange
/**
* The Json format of the relatedLink is validated against a pre-defined
* schema. Validation to check the uniqueness of relatedLinks by name is
* done
* @param {Object} value - Array of Json object that needed to be validated
* against a predefined schema
* @returns {undefined} OK
*/
function validateJsonSchema(value) {
const relLinkNameSet = new Set();
for (let i = 0; i < value.length; i++) {
const relLink = value[i];
if (Object.keys(relLink).length > jsonSchemaProperties.relatedlink.length) {
throw new Error('A relatedlinks can only have' +
jsonSchemaProperties.relatedlink.length + ' properties: ' +
jsonSchemaProperties.relatedlink);
}
if (relLinkNameSet.has(relLink.name)) {
throw new Error('Name of the relatedlinks should be unique');
} else {
relLinkNameSet.add(relLink.name);
}
}
}
/**
* Sets the instance's isDeleted field.
*
* @param {Promise} Promise -The Sequelize Promise class
* @param {Instance} inst - The instance being deleted
* @returns {Promise} which resolves undefined if OK or rejects if an error
* was encountered trying to update the instance's isDeleted field
*/
function setIsDeleted(Promise, inst) {
return new Promise((resolve, reject) =>
inst.update({ isDeleted: Date.now() })
.then(() => resolve())
.catch((err) => reject(err)));
} // setIsDeleted
module.exports = {
dbconf,
setIsDeleted,
publishChange,
sampleAspectAndSubjectArePublished,
augmentSampleWithSubjectAspectInfo,
validateJsonSchema,
createDBLog,
changeType,
}; // exports