Skip to content

Commit

Permalink
Merge pull request #3871 from mstn/3208-cant-create-a-new-master-rela…
Browse files Browse the repository at this point in the history
…tion

Order to-be-created relations by dependencies in the changeset
  • Loading branch information
bhousel authored Mar 11, 2017
2 parents 2b50d96 + 05e5cf9 commit e0157f4
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 1 deletion.
49 changes: 48 additions & 1 deletion modules/services/osm.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,53 @@ export default {
});
return ordered;
}
// sort relations in a changeset by dependencies
function sort(changes) {
// find a referenced relation in the current changeset
function resolve(item){
return _.find(relations, function(relation) {
return item.keyAttributes.type === 'relation'
&& item.keyAttributes.ref === relation['@id'];
});
}
// a new item is an item that has not been already processed
function isNew(item) {
return !sorted[ item['@id'] ] && !_.find(processing, function(proc){
return proc['@id'] === item['@id'];
});
}
var processing = [],
sorted = {},
relations = changes.relation;

if (!relations) return changes;

for (var i = 0; i < relations.length; i++) {

var relation = relations[i];

// skip relation if already sorted
if ( !sorted[relation['@id']] ) {
processing.push( relation );
}

while ( processing.length > 0 ){
var next = processing[0],
deps = _.filter( _.compact(next.member.map(resolve)), isNew);

if ( deps.length === 0 ){
sorted[ next['@id'] ] = next;
processing.shift();
} else {
processing = deps.concat( processing );
}
}

}

changes.relation = _.values(sorted);
return changes;
}

function rep(entity) {
return entity.asJXON(changeset_id);
Expand All @@ -321,7 +368,7 @@ export default {
osmChange: {
'@version': 0.6,
'@generator': 'iD',
'create': nest(changes.created.map(rep), ['node', 'way', 'relation']),
'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
'delete': _.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {'@if-unused': true})
}
Expand Down
29 changes: 29 additions & 0 deletions test/spec/services/osm.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,35 @@ describe('iD.serviceOsm', function () {
]);
});

it('includes creations ordered by dependencies', function() {
var n = iD.Node({loc: [0, 0]}),
w = iD.Way({nodes: [n.id]}),
r1 = iD.Relation({members: [{id: w.id, type: 'way'}]}),
r2 = iD.Relation({members: [{id: r1.id, type: 'relation'}]}),
changes = {created: [r2, r1, w, n], modified: [], deleted: []},
jxon = connection.osmChangeJXON('1234', changes);

expect(d3.entries(jxon.osmChange.create)).to.eql([
{key: 'node', value: [n.asJXON('1234').node]},
{key: 'way', value: [w.asJXON('1234').way]},
{key: 'relation', value: [r1.asJXON('1234').relation, r2.asJXON('1234').relation]},
]);
});

it('includes creations ignoring circular dependencies', function() {
var r1 = iD.Relation(),
r2 = iD.Relation(),
changes, jxon;
r1.addMember({id: r2.id, type: 'relation'});
r2.addMember({id: r1.id, type: 'relation'});
changes = {created: [r1,r2], modified: [], deleted: []};
jxon = connection.osmChangeJXON('1234', changes);

expect(d3.entries(jxon.osmChange.create)).to.eql([
{key: 'relation', value: [r1.asJXON('1234').relation, r2.asJXON('1234').relation]},
]);
});

it('includes modifications', function() {
var n = iD.Node({loc: [0, 0]}),
w = iD.Way(),
Expand Down

0 comments on commit e0157f4

Please sign in to comment.