References now merge children, fixed infinite reference loops
This commit is contained in:
@@ -116,7 +116,7 @@ function insertPropertyFromNode(nodeId, ancestors, order){
|
|||||||
nodes = [node, ...nodes];
|
nodes = [node, ...nodes];
|
||||||
|
|
||||||
// set libraryNodeIds
|
// set libraryNodeIds
|
||||||
storeLibraryNodeReferences(nodes, nodeId);
|
storeLibraryNodeReferences(nodes);
|
||||||
|
|
||||||
// re-map all the ancestors
|
// re-map all the ancestors
|
||||||
setLineageOfDocs({
|
setLineageOfDocs({
|
||||||
@@ -149,6 +149,7 @@ function insertPropertyFromNode(nodeId, ancestors, order){
|
|||||||
|
|
||||||
function storeLibraryNodeReferences(nodes){
|
function storeLibraryNodeReferences(nodes){
|
||||||
nodes.forEach(node => {
|
nodes.forEach(node => {
|
||||||
|
if (node.libraryNodeId) return;
|
||||||
node.libraryNodeId = node._id;
|
node.libraryNodeId = node._id;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -162,20 +163,11 @@ function reifyNodeReferences(nodes, visitedRefs = new Set(), depth = 0){
|
|||||||
|
|
||||||
// Filter out the reference nodes we replace
|
// Filter out the reference nodes we replace
|
||||||
let resultingNodes = nodes.filter(node => {
|
let resultingNodes = nodes.filter(node => {
|
||||||
|
|
||||||
// We have already visited this ref and replaced it
|
|
||||||
if (visitedRefs.has(node._id)) return false;
|
|
||||||
|
|
||||||
// Already replaced an ancestor node
|
|
||||||
for (let i; i < node.ancestors.length; i++){
|
|
||||||
if (visitedRefs.has(node.ancestors[i].id)) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This isn't a reference node, continue as normal
|
// This isn't a reference node, continue as normal
|
||||||
if (node.type !== 'reference') return true;
|
if (node.type !== 'reference') return true;
|
||||||
|
|
||||||
// We have gone too deep, keep the reference node as an error
|
// We have gone too deep, keep the reference node as an error
|
||||||
if (depth > 10){
|
if (depth >= 10){
|
||||||
if (Meteor.isClient) console.warn('Reference depth limit exceeded');
|
if (Meteor.isClient) console.warn('Reference depth limit exceeded');
|
||||||
node.cache = {error: 'Reference depth limit exceeded'};
|
node.cache = {error: 'Reference depth limit exceeded'};
|
||||||
return true;
|
return true;
|
||||||
@@ -211,26 +203,31 @@ function reifyNodeReferences(nodes, visitedRefs = new Set(), depth = 0){
|
|||||||
oldParent: referencedNode.parent,
|
oldParent: referencedNode.parent,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove all the looped references and descendents from the new nodes
|
// Filter all the looped references
|
||||||
// We can't rely on the reify recursion to do this, since the IDs are
|
addedNodes = addedNodes.filter(addedNode => {
|
||||||
// getting renewed before it is called
|
// Add all non-reference nodes
|
||||||
addedNodes = addedNodes.filter(node => {
|
if (addedNode.type !== 'reference'){
|
||||||
// Exclude removed referenced
|
return true;
|
||||||
if (visitedRefs.has(node._id)) return false;
|
}
|
||||||
|
// If this exact reference has already been resolved before, filter it out
|
||||||
// Exclude descendants of removed references
|
if (visitedRefs.has(addedNode._id)){
|
||||||
for (let i; i < node.ancestors.length; i++){
|
return false;
|
||||||
if (visitedRefs.has(node.ancestors[i].id)) return false;
|
} else {
|
||||||
|
// Otherwise mark it as visited, and keep it
|
||||||
|
visitedRefs.add(addedNode._id);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Force the referencedNode to take the old id of the reference
|
// Before renewing Ids make sure the library node reference is stored
|
||||||
// such that the reference's children can be kept
|
storeLibraryNodeReferences(addedNodes);
|
||||||
|
|
||||||
// Give the new referenced sub-tree new ids
|
// Give the new referenced sub-tree new ids
|
||||||
|
// The referenced node must get the id of the ref node so that the
|
||||||
|
// descendants of the ref node keep their ancestry intact
|
||||||
renewDocIds({
|
renewDocIds({
|
||||||
docArray: addedNodes,
|
docArray: addedNodes,
|
||||||
|
idMap: { [referencedNode._id]: node._id },
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reify the subtree as well with recursion
|
// Reify the subtree as well with recursion
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ export function getAncestry({parentRef, inheritedFields = {}}){
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function setLineageOfDocs({docArray, oldParent, newAncestry}){
|
export function setLineageOfDocs({docArray, oldParent, newAncestry}){
|
||||||
//const oldParent = oldAncestry[oldAncestry.length - 1];
|
|
||||||
const newParent = newAncestry[newAncestry.length - 1];
|
const newParent = newAncestry[newAncestry.length - 1];
|
||||||
docArray.forEach(doc => {
|
docArray.forEach(doc => {
|
||||||
if(doc.parent.id === oldParent.id){
|
if(doc.parent.id === oldParent.id){
|
||||||
@@ -109,6 +108,7 @@ export function setLineageOfDocs({docArray, oldParent, newAncestry}){
|
|||||||
}
|
}
|
||||||
let oldAncestors = doc.ancestors;
|
let oldAncestors = doc.ancestors;
|
||||||
let oldParentIndex = oldAncestors.findIndex(a => a.id === oldParent.id);
|
let oldParentIndex = oldAncestors.findIndex(a => a.id === oldParent.id);
|
||||||
|
if (oldParentIndex === -1) return;
|
||||||
doc.ancestors = [...newAncestry, ...oldAncestors.slice(oldParentIndex + 1)];
|
doc.ancestors = [...newAncestry, ...oldAncestors.slice(oldParentIndex + 1)];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -117,17 +117,15 @@ export function setLineageOfDocs({docArray, oldParent, newAncestry}){
|
|||||||
* Give documents new random ids and transform their references.
|
* Give documents new random ids and transform their references.
|
||||||
* Transform collections of re-IDed docs according to the collection map
|
* Transform collections of re-IDed docs according to the collection map
|
||||||
*/
|
*/
|
||||||
export function renewDocIds({docArray, collectionMap}){
|
export function renewDocIds({docArray, collectionMap, idMap = {}}){
|
||||||
// map of {oldId: newId}
|
// idMap is a map of {oldId: newId}
|
||||||
let idMap = {};
|
|
||||||
|
|
||||||
// Get a random generator that's consistent on client and server
|
// Get a random generator that's consistent on client and server
|
||||||
let randomSrc = DDP.randomStream('renewDocIds');
|
let randomSrc = DDP.randomStream('renewDocIds');
|
||||||
|
|
||||||
// Give new ids and map the changes as {oldId: newId}
|
// Give new ids and map the changes as {oldId: newId}
|
||||||
docArray.forEach(doc => {
|
docArray.forEach(doc => {
|
||||||
let oldId = doc._id;
|
let oldId = doc._id;
|
||||||
let newId = randomSrc.id();
|
let newId = idMap[oldId] || randomSrc.id();
|
||||||
doc._id = newId;
|
doc._id = newId;
|
||||||
idMap[oldId] = newId;
|
idMap[oldId] = newId;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
|||||||
import { assertViewPermission } from '/imports/api/sharing/sharingPermissions.js';
|
import { assertViewPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||||
|
|
||||||
Meteor.publish('selectedLibraryNodes', function(selectedNodeIds){
|
Meteor.publish('selectedLibraryNodes', function(selectedNodeIds){
|
||||||
console.log('attempting selectedLibraryNodes')
|
|
||||||
check(selectedNodeIds, Array);
|
check(selectedNodeIds, Array);
|
||||||
// Limit to 20 selected nodes
|
// Limit to 20 selected nodes
|
||||||
if (selectedNodeIds.length > 20){
|
if (selectedNodeIds.length > 20){
|
||||||
|
|||||||
Reference in New Issue
Block a user