Expand set of entities to validate to include _related_ to issues

This will catch the situation where an edit or undo affects something related without
actually touching the item - for example an undo can cause a connected way to disconnect
from the main graph.
This commit is contained in:
Bryan Housel
2021-08-27 17:20:32 -04:00
parent 1b5bd4d9c3
commit b94151396d
+57 -26
View File
@@ -488,10 +488,10 @@ export function coreValidator(context) {
_headCache.graph = currGraph; // take snapshot
_completeDiff = context.history().difference().complete();
const incrementalDiff = coreDifference(prevGraph, currGraph);
const entityIDs = Object.keys(incrementalDiff.complete());
let entityIDs = Object.keys(incrementalDiff.complete());
entityIDs = _headCache.withAllRelatedEntities(entityIDs); // expand set
// if (!entityIDs.size) {
if (!entityIDs.length) {
if (!entityIDs.size) {
dispatch.call('validated');
return Promise.resolve();
}
@@ -540,8 +540,8 @@ export function coreValidator(context) {
if (!_headCache.graph) _headCache.graph = baseGraph;
if (!_baseCache.graph) _baseCache.graph = baseGraph;
const entityIDs = entities.map(entity => entity.id);
// entityIDs = entityIDsToValidate(entityIDs, baseGraph); // expand set
let entityIDs = entities.map(entity => entity.id);
entityIDs = _baseCache.withAllRelatedEntities(entityIDs); // expand set
validateEntitiesAsync(entityIDs, _baseCache);
});
@@ -629,7 +629,7 @@ export function coreValidator(context) {
// - the user did something to one of the entities involved in the issue
//
// Arguments
// `entityIDs` - Array containing entity IDs.
// `entityIDs` - Array or Set containing entity IDs.
//
function updateResolvedIssues(entityIDs) {
entityIDs.forEach(entityID => {
@@ -656,7 +656,7 @@ export function coreValidator(context) {
// Schedule validation for many entities.
//
// Arguments
// `entityIDs` - Array containing entity IDs.
// `entityIDs` - Array or Set containing entityIDs.
// `graph` - the graph to validate that contains those entities
// `cache` - the cache to store results in (_headCache or _baseCache)
//
@@ -666,7 +666,7 @@ export function coreValidator(context) {
//
function validateEntitiesAsync(entityIDs, cache) {
// Enqueue the work
const jobs = entityIDs.map(entityID => {
const jobs = Array.from(entityIDs).map(entityID => {
if (cache.queuedEntityIDs.has(entityID)) return null; // queued already
cache.queuedEntityIDs.add(entityID);
@@ -795,24 +795,20 @@ function validationCache(which) {
issuesByEntityID: {} // entity.id -> Set(issue.id)
};
cache.cacheIssues = (issues) => {
issues.forEach(issue => {
const entityIDs = issue.entityIds || [];
entityIDs.forEach(entityID => {
if (!cache.issuesByEntityID[entityID]) {
cache.issuesByEntityID[entityID] = new Set();
}
cache.issuesByEntityID[entityID].add(issue.id);
});
cache.issuesByIssueID[issue.id] = issue;
cache.cacheIssue = (issue) => {
(issue.entityIds || []).forEach(entityID => {
if (!cache.issuesByEntityID[entityID]) {
cache.issuesByEntityID[entityID] = new Set();
}
cache.issuesByEntityID[entityID].add(issue.id);
});
cache.issuesByIssueID[issue.id] = issue;
};
cache.uncacheIssue = (issue) => {
// When multiple entities are involved (e.g. crossing_ways),
// remove this issue from the other entity caches too..
const entityIDs = issue.entityIds || [];
entityIDs.forEach(entityID => {
(issue.entityIds || []).forEach(entityID => {
if (cache.issuesByEntityID[entityID]) {
cache.issuesByEntityID[entityID].delete(issue.id);
}
@@ -820,25 +816,33 @@ function validationCache(which) {
delete cache.issuesByIssueID[issue.id];
};
cache.cacheIssues = (issues) => {
issues.forEach(cache.cacheIssue);
};
cache.uncacheIssues = (issues) => {
issues.forEach(cache.uncacheIssue);
};
cache.uncacheIssuesOfType = (type) => {
const issuesOfType = Object.values(cache.issuesByIssueID)
.filter(issue => issue.type === type);
cache.uncacheIssues(issuesOfType);
};
// Remove a single entity and all its related issues from the caches
cache.uncacheEntityID = (entityID) => {
const issueIDs = cache.issuesByEntityID[entityID];
if (issueIDs) {
issueIDs.forEach(issueID => {
const entityIssueIDs = cache.issuesByEntityID[entityID];
if (entityIssueIDs) {
entityIssueIDs.forEach(issueID => {
const issue = cache.issuesByIssueID[issueID];
if (issue) {
cache.uncacheIssue(issue);
} else {
} else { // shouldnt happen, clean up
delete cache.issuesByIssueID[issueID];
}
});
@@ -849,5 +853,32 @@ function validationCache(which) {
};
// Return the expandeded set of entityIDs related to issues for the given entityIDs
//
// Arguments
// `entityIDs` - Array or Set containing entityIDs.
//
cache.withAllRelatedEntities = (entityIDs) => {
let result = new Set();
(entityIDs || []).forEach(entityID => {
result.add(entityID); // include self
const entityIssueIDs = cache.issuesByEntityID[entityID];
if (entityIssueIDs) {
entityIssueIDs.forEach(issueID => {
const issue = cache.issuesByIssueID[issueID];
if (issue) {
(issue.entityIds || []).forEach(relatedID => result.add(relatedID))
} else { // shouldnt happen, clean up
delete cache.issuesByIssueID[issueID];
}
});
}
});
return result;
}
return cache;
}