Fixed circular reference issues

This commit is contained in:
Benoit Schweblin 2018-08-19 13:23:33 +01:00
parent d4624eba9d
commit 3fc974c14c
4 changed files with 45 additions and 21 deletions

View File

@ -133,11 +133,15 @@ const localDbSvc = {
return new Promise((resolve, reject) => {
// Create the DB transaction
this.connection.createTx((tx) => {
const { lastTx } = this;
// Look for DB changes and apply them to the store
this.readAll(tx, (storeItemMap) => {
// Sanitize the workspace
workspaceSvc.ensureUniquePaths();
workspaceSvc.ensureUniqueLocations();
// Sanitize the workspace if changes have been applied
if (lastTx !== this.lastTx) {
workspaceSvc.sanitizeWorkspace();
}
// Persist all the store changes into the DB
this.writeAll(storeItemMap, tx);
// Sync the localStorage
@ -156,7 +160,7 @@ const localDbSvc = {
let { lastTx } = this;
const dbStore = tx.objectStore(dbStoreName);
const index = dbStore.index('tx');
const range = window.IDBKeyRange.lowerBound(this.lastTx, true);
const range = IDBKeyRange.lowerBound(this.lastTx, true);
const changes = [];
index.openCursor(range).onsuccess = (event) => {
const cursor = event.target.result;
@ -225,7 +229,7 @@ const localDbSvc = {
tx: incrementedTx,
});
delete this.hashMap[type][id];
this.lastTx = incrementedTx; // No need to read what we just wrote
this.lastTx = incrementedTx;
}));
});
@ -239,7 +243,7 @@ const localDbSvc = {
};
dbStore.put(item);
this.hashMap[item.type][item.id] = item.hash;
this.lastTx = incrementedTx; // No need to read what we just wrote
this.lastTx = incrementedTx;
}
});
},

View File

@ -185,8 +185,7 @@ const applyChanges = (changes) => {
store.dispatch('data/setSyncDataById', syncDataById);
// Sanitize the workspace
workspaceSvc.ensureUniquePaths(idsToKeep);
workspaceSvc.ensureUniqueLocations(idsToKeep);
workspaceSvc.sanitizeWorkspace(idsToKeep);
}
};

View File

@ -134,6 +134,9 @@ export default {
// Save item in the store
store.commit(`${item.type}/setItem`, item);
// Remove circular reference
this.removeCircularReference(item);
// Ensure path uniqueness
if (store.getters['workspace/currentWorkspaceHasUniquePaths']) {
this.makePathUnique(item.id);
@ -162,6 +165,37 @@ export default {
.forEach(item => store.commit('publishLocation/deleteItem', item.id));
},
/**
* Sanitize the whole workspace.
*/
sanitizeWorkspace(idsToKeep) {
// Detect and remove circular references for all folders.
store.getters['folder/items'].forEach(folder => this.removeCircularReference(folder));
this.ensureUniquePaths(idsToKeep);
this.ensureUniqueLocations(idsToKeep);
},
/**
* Detect and remove circular reference for an item.
*/
removeCircularReference(item) {
const foldersById = store.state.folder.itemsById;
for (
let parentFolder = foldersById[item.parentId];
parentFolder;
parentFolder = foldersById[parentFolder.parentId]
) {
if (parentFolder.id === item.id) {
store.commit('folder/patchItem', {
id: item.id,
parentId: null,
});
break;
}
}
},
/**
* Ensure two files/folders don't have the same path if the workspace doesn't allow it.
*/

View File

@ -122,7 +122,6 @@ export default {
});
// Build the tree
const parentsMap = {};
Object.entries(nodeMap).forEach(([, node]) => {
let parentNode = nodeMap[node.item.parentId];
if (!parentNode || !parentNode.isFolder) {
@ -130,18 +129,6 @@ export default {
return;
}
parentNode = rootNode;
} else if (node.isFolder) {
// Detect circular reference
const parentParents = parentsMap[node.item.parentId] || {};
if (parentParents[node.item.id]) {
// Node is already a parent of its supposed parent
parentNode = rootNode;
} else {
parentsMap[node.item.id] = {
...parentParents,
[node.item.parentId]: true,
};
}
}
if (node.isFolder) {
parentNode.folders.push(node);