+ ##
+ # the bounding box around a node, which is used for determining the changeset's
+ # bounding box
+ def bbox
+ [ 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)
+ way = WayNode.find(:first, :joins => :way,
+ :conditions => [ "current_ways.visible = ? AND current_way_nodes.node_id = ?", true, self.id ])
+ raise OSM::APIPreconditionFailedError.new("Node #{self.id} is still used by way #{way.way.id}.") unless way.nil?
+
+ rel = RelationMember.find(:first, :joins => :relation,
+ :conditions => [ "visible = ? AND member_type='Node' and member_id=? ", true, self.id])
+ raise OSM::APIPreconditionFailedError.new("Node #{self.id} is still used by relation #{rel.relation.id}.") unless rel.nil?
+
+ self.changeset_id = new_node.changeset_id
+ 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!