Working rebase

This commit is contained in:
Ansis Brammanis
2013-01-30 12:26:40 -05:00
parent 6c1e4e5b4d
commit ba68a238fe
3 changed files with 74 additions and 63 deletions

View File

@@ -5,15 +5,19 @@ iD.Graph = function(other, mutable) {
var base = other.base();
this.entities = _.assign(Object.create(base.entities), other.entities);
this._parentWays = _.assign(Object.create(base.parentWays), other._parentWays);
this.rebase(other.base(), other.entities);
this.inherited = true;
} else {
this.entities = other || Object.create({});
this._parentWays = Object.create({});
for (var i in this.entities) {
this._updateCalculated(undefined, this.entities[i]);
if (_.isArray(other)) {
var entities = {};
for (var i = 0; i < other.length; i++) {
entities[other[i].id] = other[i];
}
other = entities;
}
this.entities = Object.create({});
this._parentWays = Object.create({});
this.rebase(other || {});
}
this.transients = {};
@@ -43,25 +47,7 @@ iD.Graph.prototype = {
},
parentWays: function(entity) {
var ent, id, parents;
if (!this._parentWays.calculated) {
for (var i in this.entities) {
ent = this.entities[i];
if (ent && ent.type === 'way') {
for (var j = 0; j < ent.nodes.length; j++) {
id = ent.nodes[j];
parents = this._parentWays[id] = this._parentWays[id] || [];
if (parents.indexOf(ent) < 0) {
parents.push(ent);
}
}
}
}
this._parentWays.calculated = true;
}
return this._parentWays[entity.id] || [];
return _.map(this._parentWays[entity.id], _.bind(this.entity, this));
},
isPoi: function(entity) {
@@ -113,13 +99,31 @@ iD.Graph.prototype = {
// is used only during the history operation that merges newly downloaded
// data into each state. To external consumers, it should appear as if the
// graph always contained the newly downloaded data.
rebase: function(base, entities) {
rebase: function(entities) {
var i;
// Merging of data only needed if graph is the base graph
if (!this.inherited) {
_.defaults(this.base().entities, entities);
for (i in entities) {
this._updateCalculated(undefined, entities[i], this.base().parentWays);
}
}
var keys = Object.keys(this._parentWays);
for (i = 0; i < keys.length; i++) {
this._parentWays[keys[i]] = _.unique((this._parentWays[keys[i]] || [])
.concat(this.base().parentWays[keys[i]] || []));
}
},
_updateCalculated: function(oldentity, entity) {
// Updates calculated properties (parentWays, parentRels) for the specified change
_updateCalculated: function(oldentity, entity, parentWays, parentRels) {
parentWays = parentWays || this._parentWays;
parentRels = parentRels || this._parentRels;
var type = entity && entity.type || oldentity && oldentity.type,
removed, added, parentWays, i;
removed, added, ways, i;
if (type === 'way') {
@@ -136,12 +140,12 @@ iD.Graph.prototype = {
added = entity.nodes;
}
for (i = 0; i < removed.length; i++) {
this._parentWays[removed[i]] = _.without(this._parentWays[removed[i]], oldentity.id);
parentWays[removed[i]] = _.without(parentWays[removed[i]], oldentity.id);
}
for (i = 0; i < added.length; i++) {
parentWays = _.without(this._parentWays[added[i]], entity.id);
parentWays.push(entity.id);
this._parentWays[added[i]] = parentWays;
ways = _.without(parentWays[added[i]], entity.id);
ways.push(entity.id);
parentWays[added[i]] = ways;
}
} else if (type === 'node') {
@@ -199,9 +203,12 @@ iD.Graph.prototype = {
},
difference: function (graph) {
var result = [], entity, oldentity, id;
var result = [],
keys = Object.keys(this.entities),
entity, oldentity, id, i;
for (id in this.entities) {
for (i = 0; i < keys.length; i++) {
id = keys[i];
entity = this.entities[id];
oldentity = graph.entities[id];
if (entity !== oldentity) {
@@ -223,7 +230,8 @@ iD.Graph.prototype = {
}
}
for (id in graph.entities) {
keys = Object.keys(graph.entities);
for (i = 0; i < keys.length; i++) {
entity = graph.entities[id];
if (entity && !this.entities.hasOwnProperty(id)) {
result.push(id);
@@ -235,25 +243,25 @@ iD.Graph.prototype = {
},
modified: function() {
var result = [];
var result = [], base = this.base().entities;
_.each(this.entities, function(entity, id) {
if (entity && entity.modified()) result.push(id);
if (entity && base[id]) result.push(id);
});
return result;
},
created: function() {
var result = [];
var result = [], base = this.base().entities;
_.each(this.entities, function(entity, id) {
if (entity && entity.created()) result.push(id);
if (entity && !base[id]) result.push(id);
});
return result;
},
deleted: function() {
var result = [];
var result = [], base = this.base().entities;
_.each(this.entities, function(entity, id) {
if (!entity) result.push(id);
if (!entity && base[id]) result.push(id);
});
return result;
}

View File

@@ -30,16 +30,8 @@ iD.History = function() {
},
merge: function (graph) {
var base = stack[0].graph.base();
_.defaults(base.entities, graph.entities);
for (var i in graph.entities) {
base.parentWays[i] = _.unique((base.parentWays[id] || []).concat(graph._parentWays[i] || []));
}
_.defaults(base.parentWays, graph._parentWays);
for (i = 1; i < stack.length; i++) {
stack[i].graph.rebase(base);
for (var i = 0; i < stack.length; i++) {
stack[i].graph.rebase(graph.base().entities);
}
},

View File

@@ -28,7 +28,7 @@ describe('iD.Graph', function() {
it("rebases on other's base", function () {
var base = iD.Graph(),
graph = iD.Graph(base);
expect(graph.base()).to.equal(base.base());
expect(graph.base().entities).to.equal(base.base().entities);
});
it("freezes by default", function () {
@@ -81,16 +81,27 @@ describe('iD.Graph', function() {
expect(graph.entities).not.to.have.ownProperty('n');
});
xit("updates parentWays", function () {
it("updates parentWays", function () {
var n = iD.Node({id: 'n'}),
w1 = iD.Way({id: 'w1', nodes: ['n']}),
w2 = iD.Way({id: 'w2', nodes: ['n']}),
w3 = iD.Way({id: 'w3', nodes: ['n']}),
graph = iD.Graph([n, w1]);
graph.parentWays(n);
graph.rebase({'w2': w2});
var graph2 = graph.replace(w2);
graph.rebase({ 'w3': w3 });
graph2.rebase({ 'w3': w3 });
expect(graph.parentWays(n)).to.eql([w1, w2]);
expect(graph2.parentWays(n)).to.eql([w1, w2, w3]);
});
it("only sets non-base parentWays when necessary", function () {
var n = iD.Node({id: 'n'}),
w1 = iD.Way({id: 'w1', nodes: ['n']}),
graph = iD.Graph([n, w1]);
graph.rebase({ 'w1': w1 });
expect(graph._parentWays.hasOwnProperty('n')).to.be.false;
expect(graph.parentWays(n)).to.eql([w1]);
});
xit("updates parentRelations", function () {
@@ -244,18 +255,18 @@ describe('iD.Graph', function() {
describe("#modified", function () {
it("returns an Array of ids of modified entities", function () {
var node1 = iD.Node({id: 'n1', _updated: true}),
node2 = iD.Node({id: 'n2'}),
graph = iD.Graph([node1, node2]);
expect(graph.modified()).to.eql([node1.id]);
var node = iD.Node({id: 'n1'}),
node_ = iD.Node({id: 'n1'}),
graph = iD.Graph([node]).replace(node_);
expect(graph.modified()).to.eql([node.id]);
});
});
describe("#created", function () {
it("returns an Array of ids of created entities", function () {
var node1 = iD.Node({id: 'n-1', _updated: true}),
var node1 = iD.Node({id: 'n-1'}),
node2 = iD.Node({id: 'n2'}),
graph = iD.Graph([node1, node2]);
graph = iD.Graph([node2]).replace(node1);
expect(graph.created()).to.eql([node1.id]);
});
});
@@ -270,7 +281,7 @@ describe('iD.Graph', function() {
it("doesn't include created entities that were subsequently deleted", function () {
var node = iD.Node(),
graph = iD.Graph([node]).remove(node);
graph = iD.Graph().replace(node).remove(node);
expect(graph.deleted()).to.eql([]);
});
});