Skip to content

Commit

Permalink
Merge pull request RackHD#469 from VulpesArtificem/rack-fix
Browse files Browse the repository at this point in the history
Fixed bug: a node can be containedBy two rack
  • Loading branch information
benbp authored Oct 11, 2016
2 parents 78309a1 + 34be40d commit 24d5b66
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 130 deletions.
114 changes: 73 additions & 41 deletions lib/services/nodes-api-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,34 +79,29 @@ function nodeApiServiceFactory(
* of a node delete it
* @param {Object} node node whose relation needs to be updated
* @param {String} type relation type that needs to be updated
* @param {String[]} targets - node ids in the relation that needs to be deleted
* @return {Promise} node after removing relation
* @param {String[] | Object[]} targets - nodes or ids in the relation
* that needs to be deleted
* @return {Object} node after removing relation
*/
NodeApiService.prototype._removeRelation = function removeRelation(node, type, targets) {
if (!node || !type || !_.has(node, 'relations')) {
return Promise.resolve();
return;
}

var index = _.findIndex(node.relations, { relationType: type });
if (index === -1 || !_.has(node.relations[index], 'targets')) {
return Promise.resolve();
return;
}

if ((Constants.NodeRelations[type].relationClass === 'component') &&
(type.indexOf('By') !== -1)) {
// Its components need to be deleted
return this.removeNode(node, type);
}
// Remove target node id in relation field
targets = [].concat(targets);
targets = [].concat(targets).map(function(node) {return node.id || node;});
node.relations[index].targets = _.difference(node.relations[index].targets, targets);

// Remove the type of relation if no targets in it
if (node.relations[index].targets.length === 0) {
_.pull(node.relations, node.relations[index]);
}

return waterline.nodes.updateByIdentifier(node.id, {relations: node.relations});
return node;
};

/**
Expand All @@ -115,24 +110,35 @@ function nodeApiServiceFactory(
* create it, otherwise append to the existing one.
* @param {Object} node - node whose relation needs to be updated
* @param {String} type - relation type that needs to be updated
* @param {String | String[]} targets - node ids in relation type that needs to be added
* @return {Promise} a promise to update the node
* @param {String[] | Object[]} targets - nodes or ids in relation type that needs to be added
* @return {Object} the updated node
*/
NodeApiService.prototype._addRelation = function addRelation(node, type, targets) {
if (!(node && type && targets)) {
return Promise.resolve();
return;
}

node.relations = (node.relations || []);
targets = [].concat(targets);

targets = _.map([].concat(targets), function(targetNode) {
targetNode = targetNode.id || targetNode;
if(targetNode === node.id ) {
throw new Error('Node cannot have relationship '+type+' with itself');
}
return targetNode;
});
var index = _.findIndex(node.relations, { relationType: type });
if (index === -1) {
node.relations.push({relationType: type, targets: _.uniq(targets)});
} else {
node.relations[index].targets = _.uniq(node.relations[index].targets.concat(targets));
}
index = index === -1 ? node.relations.length - 1: index;
if (type === 'containedBy' && node.relations[index].targets.length > 1) {
throw new Error("Node "+node.id+" can only be contained by one node");
}

return waterline.nodes.updateByIdentifier(node.id, {relations: node.relations});
return node;
};

/**
Expand Down Expand Up @@ -180,17 +186,34 @@ function nodeApiServiceFactory(
}
// Otherwise update targets node in its "relationType"
return self._findTargetNodes(node.relations, type)
.tap(function(targetNodes) {
return Promise.map(targetNodes, function(node) {
return self._delValidityCheck(node.id);
});
})
.map(function (targetNode) {
return self._removeRelation(
targetNode,
Constants.NodeRelations[type].mapping,
node.id
);
.then(function(targetNodes) {
if(Constants.NodeRelations[type].relationClass === 'component' &&
type.indexOf('By') === -1) {

return Promise.map(targetNodes, function(targetNode) {
return self._delValidityCheck(targetNode.id);
}).then(function() {
return Promise.map(targetNodes, function(targetNode) {
return self.removeNode(
targetNode, Constants.NodeRelations[type].mapping
);
});
});
} else {
return Promise.map(targetNodes, function(targetNode) {
var updatedNode = self._removeRelation(
targetNode,
Constants.NodeRelations[type].mapping,
node.id
);
if (!updatedNode) {
return;
}
return waterline.nodes.updateByIdentifier(
updatedNode.id, {relations: updatedNode.relations}
);
});
}
});
});
})
Expand Down Expand Up @@ -302,7 +325,8 @@ function nodeApiServiceFactory(
};

/**
* Edit the relations of a given node, delegating the updates to the given handler.
* Edit the relations of a given node, delegating object manipulations to the given handler.
* Handle the update with the handler's output
*
* @param {String} id - a node id
* @param {Object} body - an object with relation types as keys and arrays of target
Expand Down Expand Up @@ -330,29 +354,37 @@ function nodeApiServiceFactory(
targetRelations = _.chunk(targetRelations, 2); //divide the array into subArray chunks
//of [[targetNodes], relationType]

var handlerArgs = _.transform(targetRelations, function(result, relationSet) {
var updatedNodes = _.transform(targetRelations, function(result, relationSet) {
var targetNodes = relationSet[0];
var relationType = relationSet[1];
if (!Constants.NodeRelations[relationType]) {
return;
}
result.push(
[
parentNode,
result[parentNode.id] = handler.call(
self,
result[parentNode.id] || parentNode,
relationType,
_.map(targetNodes, function(node) {return node.id;})
]
targetNodes
);

_.forEach(targetNodes, function(node) {
result.push(
[node, Constants.NodeRelations[relationType].mapping, parentNode.id]
result[node.id] = handler.call(
self,
result[node.id] || node,
Constants.NodeRelations[relationType].mapping,
parentNode
);
});
});
return Promise.map(handlerArgs, function(args) {
return handler.apply(self, args);
}, {concurrency: 1}).then(_.compact);
}, {});

return Promise.all(_.compact(_.map(updatedNodes, function(updatedNode) {
if (!updatedNode) {
return;
}
return waterline.nodes.updateByIdentifier(
updatedNode.id, {relations: updatedNode.relations}
);
})));
});
};

Expand Down
Loading

0 comments on commit 24d5b66

Please sign in to comment.