+ @tags ||= relation_tags.to_h { |t| [t.k, t.v] }
+ end
+
+ attr_writer :members, :tags
+
+ def add_member(type, id, role)
+ @members ||= []
+ @members << [type, id.to_i, role]
+ end
+
+ def add_tag_keyval(k, v)
+ @tags ||= {}
+
+ # duplicate tags are now forbidden, so we can't allow values
+ # in the hash to be overwritten.
+ raise 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)
+ raise OSM::APIAlreadyDeletedError.new("relation", new_relation.id) unless visible
+
+ # 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
+ lock!
+ check_update_element_consistency(self, new_relation, user)
+ # This will check to see if this relation is used by another relation
+ rel = RelationMember.joins(:relation).find_by("visible = ? AND member_type = 'Relation' and member_id = ? ", true, id)
+ raise OSM::APIPreconditionFailedError, "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!