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

View File

@ -134,6 +134,9 @@ export default {
// Save item in the store // Save item in the store
store.commit(`${item.type}/setItem`, item); store.commit(`${item.type}/setItem`, item);
// Remove circular reference
this.removeCircularReference(item);
// Ensure path uniqueness // Ensure path uniqueness
if (store.getters['workspace/currentWorkspaceHasUniquePaths']) { if (store.getters['workspace/currentWorkspaceHasUniquePaths']) {
this.makePathUnique(item.id); this.makePathUnique(item.id);
@ -162,6 +165,37 @@ export default {
.forEach(item => store.commit('publishLocation/deleteItem', item.id)); .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. * 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 // Build the tree
const parentsMap = {};
Object.entries(nodeMap).forEach(([, node]) => { Object.entries(nodeMap).forEach(([, node]) => {
let parentNode = nodeMap[node.item.parentId]; let parentNode = nodeMap[node.item.parentId];
if (!parentNode || !parentNode.isFolder) { if (!parentNode || !parentNode.isFolder) {
@ -130,18 +129,6 @@ export default {
return; return;
} }
parentNode = rootNode; 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) { if (node.isFolder) {
parentNode.folders.push(node); parentNode.folders.push(node);