+ @tags ||= Hash[relation_tags.collect { |t| [t.k, t.v] }]
+ end
+
+ attr_writer :members
+
+ attr_writer :tags
+
+ def add_member(type, id, role)
+ @members ||= []
+ @members << [type, id.to_i, role]
+ end
+
+ def add_tag_keyval(k, v)
+ @tags = {} unless @tags
+
+ # duplicate tags are now forbidden, so we can't allow values
+ # in the hash to be overwritten.
+ fail OSM::APIDuplicateTagsError.new("relation", id, k) if @tags.include? k
+
+ @tags[k] = v
+ end
+
+ ##
+ # updates the changeset bounding box to contain the bounding box of
+ # the element with given +type+ and +id+. this only works with nodes
+ # and ways at the moment, as they're the only elements to respond to
+ # the :bbox call.
+ def update_changeset_element(type, id)
+ element = Kernel.const_get(type.capitalize).find(id)
+ changeset.update_bbox! element.bbox
+ end
+
+ def delete_with_history!(new_relation, user)
+ unless visible
+ fail OSM::APIAlreadyDeletedError.new("relation", new_relation.id)
+ end
+
+ # need to start the transaction here, so that the database can
+ # provide repeatable reads for the used-by checks. this means it
+ # shouldn't be possible to get race conditions.
+ Relation.transaction do
+ self.lock!
+ check_consistency(self, new_relation, user)
+ # This will check to see if this relation is used by another relation
+ rel = RelationMember.joins(:relation).where("visible = ? AND member_type = 'Relation' and member_id = ? ", true, id).first
+ fail OSM::APIPreconditionFailedError.new("The relation #{new_relation.id} is used in relation #{rel.relation.id}.") unless rel.nil?
+
+ self.changeset_id = new_relation.changeset_id
+ self.tags = {}
+ self.members = []
+ self.visible = false
+ save_with_history!
+ end
+ end
+
+ def update_from(new_relation, user)
+ Relation.transaction do
+ self.lock!
+ check_consistency(self, new_relation, user)
+ unless new_relation.preconditions_ok?(members)
+ fail OSM::APIPreconditionFailedError.new("Cannot update relation #{id}: data or member data is invalid.")