+ ##
+ # the bounding box around a node, which is used for determining the changeset's
+ # bounding box
+ def bbox
+ BoundingBox.new(longitude, latitude, longitude, latitude)
+ end
+
+ # Should probably be renamed delete_from to come in line with update
+ def delete_with_history!(new_node, user)
+ unless self.visible
+ raise OSM::APIAlreadyDeletedError.new("node", new_node.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.
+ Node.transaction do
+ self.lock!
+ check_consistency(self, new_node, user)
+ ways = Way.joins(:way_nodes).where(:visible => true, :current_way_nodes => { :node_id => id }).order(:id)
+ raise OSM::APIPreconditionFailedError.new("Node #{self.id} is still used by ways #{ways.collect { |w| w.id }.join(",")}.") unless ways.empty?
+
+ rels = Relation.joins(:relation_members).where(:visible => true, :current_relation_members => { :member_type => "Node", :member_id => id }).order(:id)
+ raise OSM::APIPreconditionFailedError.new("Node #{self.id} is still used by relations #{rels.collect { |r| r.id }.join(",")}.") unless rels.empty?
+
+ self.changeset_id = new_node.changeset_id
+ self.tags = {}
+ self.visible = false
+
+ # update the changeset with the deleted position
+ changeset.update_bbox!(bbox)
+
+ save_with_history!
+ end
+ end
+
+ def update_from(new_node, user)
+ Node.transaction do
+ self.lock!
+ check_consistency(self, new_node, user)
+
+ # update changeset first
+ self.changeset_id = new_node.changeset_id
+ self.changeset = new_node.changeset
+
+ # update changeset bbox with *old* position first
+ changeset.update_bbox!(bbox);
+
+ # FIXME logic needs to be double checked
+ self.latitude = new_node.latitude
+ self.longitude = new_node.longitude
+ self.tags = new_node.tags
+ self.visible = true
+
+ # update changeset bbox with *new* position
+ changeset.update_bbox!(bbox);
+
+ save_with_history!