preliminary commit 0.5 API with relations / untested after entity-relation rename, some changes still in queue

This commit is contained in:
Frederik Ramm 2007-08-29 22:00:26 +00:00
parent 02451061ce
commit 78b440ffc1
46 changed files with 1841 additions and 231 deletions

111
app/models/old_relation.rb Normal file
View file

@ -0,0 +1,111 @@
class OldRelation < ActiveRecord::Base
set_table_name 'relations'
belongs_to :user
def self.from_relation(relation)
old_relation = OldRelation.new
old_relation.visible = relation.visible
old_relation.user_id = relation.user_id
old_relation.timestamp = relation.timestamp
old_relation.id = relation.id
old_relation.members = relation.members
old_relation.tags = relation.tags
return old_relation
end
def save_with_dependencies!
# see comment in old_way.rb ;-)
save!
clear_aggregation_cache
clear_association_cache
@attributes.update(OldRelation.find(:first, :conditions => ['id = ? AND timestamp = ?', self.id, self.timestamp]).instance_variable_get('@attributes'))
# ok, you can touch from here on
self.tags.each do |k,v|
tag = OldRelationTag.new
tag.k = k
tag.v = v
tag.id = self.id
tag.version = self.version
tag.save!
end
i = 1
self.members.each do |m|
member = OldRelationMember.new
member.id = self.id
member.member_type = m[0]
member.member_id = m[1]
member.member_role = m[2]
member.version = self.version
member.save!
end
end
def members
unless @members
@members = Array.new
OldRelationMember.find(:all, :conditions => ["id = ? AND version = ?", self.id, self.version]).each do |m|
@members += [[m.type,m.id,m.role]]
end
end
@members
end
def tags
unless @tags
@tags = Hash.new
OldRelationTag.find(:all, :conditions => ["id = ? AND version = ?", self.id, self.version]).each do |tag|
@tags[tag.k] = tag.v
end
end
@tags = Hash.new unless @tags
@tags
end
def members=(s)
@members = s
end
def tags=(t)
@tags = t
end
# has_many :relation_segments, :class_name => 'OldRelationSegment', :foreign_key => 'id'
# has_many :relation_tags, :class_name => 'OldRelationTag', :foreign_key => 'id'
def old_members
OldRelationMember.find(:all, :conditions => ['id = ? AND version = ?', self.id, self.version])
end
def old_tags
OldRelationTag.find(:all, :conditions => ['id = ? AND version = ?', self.id, self.version])
end
def to_xml_node
el1 = XML::Node.new 'relation'
el1['id'] = self.id.to_s
el1['visible'] = self.visible.to_s
el1['timestamp'] = self.timestamp.xmlschema
el1['user'] = self.user.display_name if self.user.data_public?
self.old_members.each do |member|
e = XML::Node.new 'member'
e['type'] = member.member_type.to_s
e['ref'] = member.member_id.to_s # "id" is considered uncool here as it should be unique in XML
e['role'] = member.member_role.to_s
el1 << e
end
self.old_tags.each do |tag|
e = XML::Node.new 'tag'
e['k'] = tag.k
e['v'] = tag.v
el1 << e
end
return el1
end
end

View file

@ -0,0 +1,6 @@
class OldRelationMember < ActiveRecord::Base
belongs_to :user
set_table_name 'relation_members'
end

View file

@ -0,0 +1,6 @@
class OldRelationTag < ActiveRecord::Base
belongs_to :user
set_table_name 'relation_tags'
end

View file

@ -9,7 +9,7 @@ class OldWay < ActiveRecord::Base
old_way.user_id = way.user_id
old_way.timestamp = way.timestamp
old_way.id = way.id
old_way.segs = way.segs
old_way.nds = way.nds
old_way.tags = way.tags
return old_way
end
@ -39,23 +39,25 @@ class OldWay < ActiveRecord::Base
end
i = 1
self.segs.each do |n|
seg = OldWaySegment.new
seg.id = self.id
seg.segment_id = n
seg.version = self.version
seg.save!
self.nds.each do |n|
nd = OldWayNode.new
nd.id = self.id
nd.node_id = n
nd.sequence_id = i
nd.version = self.version
nd.save!
i += 1
end
end
def segs
unless @segs
@segs = Array.new
OldWaySegment.find(:all, :conditions => ["id = ? AND version = ?", self.id, self.version], :order => "sequence_id").each do |seg|
@segs += [seg.segment_id]
def nds
unless @nds
@nds = Array.new
OldWayNode.find(:all, :conditions => ["id = ? AND version = ?", self.id, self.version], :order => "sequence_id").each do |nd|
@nds += [nd.node_id]
end
end
@segs
@nds
end
def tags
@ -69,19 +71,19 @@ class OldWay < ActiveRecord::Base
@tags
end
def segs=(s)
@segs = s
def nds=(s)
@nds = s
end
def tags=(t)
@tags = t
end
# has_many :way_segments, :class_name => 'OldWaySegment', :foreign_key => 'id'
# has_many :way_nodes, :class_name => 'OldWayNode', :foreign_key => 'id'
# has_many :way_tags, :class_name => 'OldWayTag', :foreign_key => 'id'
def old_segments
OldWaySegment.find(:all, :conditions => ['id = ? AND version = ?', self.id, self.version])
def old_nodes
OldWayNode.find(:all, :conditions => ['id = ? AND version = ?', self.id, self.version])
end
def old_tags
@ -95,9 +97,9 @@ class OldWay < ActiveRecord::Base
el1['timestamp'] = self.timestamp.xmlschema
el1['user'] = self.user.display_name if self.user.data_public?
self.old_segments.each do |seg| # FIXME need to make sure they come back in the right order
e = XML::Node.new 'seg'
e['id'] = seg.segment_id.to_s
self.old_nodes.each do |nd| # FIXME need to make sure they come back in the right order
e = XML::Node.new 'nd'
e['id'] = nd.node_id.to_s
el1 << e
end

View file

@ -0,0 +1,6 @@
class OldWayNode < ActiveRecord::Base
belongs_to :user
set_table_name 'way_nodes'
end

213
app/models/relation.rb Normal file
View file

@ -0,0 +1,213 @@
class Relation < ActiveRecord::Base
require 'xml/libxml'
belongs_to :user
has_many :relation_members, :foreign_key => 'id'
has_many :relation_tags, :foreign_key => 'id'
has_many :old_relations, :foreign_key => 'id', :order => 'version'
set_table_name 'current_relations'
def self.from_xml(xml, create=false)
begin
p = XML::Parser.new
p.string = xml
doc = p.parse
relation = Relation.new
doc.find('//osm/relation').each do |pt|
if !create and pt['id'] != '0'
relation.id = pt['id'].to_i
end
if create
relation.timestamp = Time.now
relation.visible = true
else
if pt['timestamp']
relation.timestamp = Time.parse(pt['timestamp'])
end
end
pt.find('tag').each do |tag|
relation.add_tag_keyval(tag['k'], tag['v'])
end
pt.find('member').each do |member|
relation.add_member(member['type'], member['ref'], member['role'])
end
end
rescue
relation = nil
end
return relation
end
def to_xml
doc = OSM::API.new.get_xml_doc
doc.root << to_xml_node()
return doc
end
def to_xml_node(user_display_name_cache = nil)
el1 = XML::Node.new 'relation'
el1['id'] = self.id.to_s
el1['visible'] = self.visible.to_s
el1['timestamp'] = self.timestamp.xmlschema
user_display_name_cache = {} if user_display_name_cache.nil?
if user_display_name_cache and user_display_name_cache.key?(self.user_id)
# use the cache if available
elsif self.user.data_public?
user_display_name_cache[self.user_id] = self.user.display_name
else
user_display_name_cache[self.user_id] = nil
end
el1['user'] = user_display_name_cache[self.user_id] unless user_display_name_cache[self.user_id].nil?
self.relation_members.each do |member|
p=0
#if visible_members
# # if there is a list of visible members then use that to weed out deleted segments
# if visible_members[member.member_type][member.member_id]
# p=1
# end
#else
# otherwise, manually go to the db to check things
if member.member.visible?
p=1
end
#end
if p
e = XML::Node.new 'member'
e['type'] = member.member_type
e['ref'] = member.member_id.to_s
e['role'] = member.member_role
el1 << e
end
end
self.relation_tags.each do |tag|
e = XML::Node.new 'tag'
e['k'] = tag.k
e['v'] = tag.v
el1 << e
end
return el1
end
# FIXME is this really needed?
def members
unless @members
@members = Array.new
self.relation_members.each do |member|
@members += [[member.member_type,member.member_id,member.member_role]]
end
end
@members
end
def tags
unless @tags
@tags = Hash.new
self.relation_tags.each do |tag|
@tags[tag.k] = tag.v
end
end
@tags
end
def members=(m)
@members = m
end
def tags=(t)
@tags = t
end
def add_member(type,id,role)
@members = Array.new unless @members
@members += [[type,id,role]]
end
def add_tag_keyval(k, v)
@tags = Hash.new unless @tags
@tags[k] = v
end
def save_with_history
begin
Relation.transaction do
t = Time.now
self.timestamp = t
self.save!
tags = self.tags
RelationTag.delete_all(['id = ?', self.id])
tags.each do |k,v|
tag = RelationTag.new
tag.k = k
tag.v = v
tag.id = self.id
tag.save!
end
members = self.members
RelationMember.delete_all(['id = ?', self.id])
members.each do |n|
mem = RelationMember.new
mem.id = self.id
mem.member_type = n[0];
mem.member_id = n[1];
mem.member_role = n[2];
mem.save!
end
old_relation = OldRelation.from_relation(self)
old_relation.timestamp = t
old_relation.save_with_dependencies!
end
return true
rescue Exception => ex
return nil
end
end
def preconditions_ok?
self.members.each do |m|
if (m[0] == "node")
n = Node.find(:first, :conditions => ["id = ?", m[1]])
unless n and n.visible
return false
end
elsif (m[0] == "way")
w = Way.find(:first, :conditions => ["id = ?", m[1]])
unless w and w.visible and w.preconditions_ok?
return false
end
elsif (m[0] == "relation")
e = Relation.find(:first, :conditions => ["id = ?", m[1]])
unless e and e.visible and e.preconditions_ok?
return false
end
else
return false
end
end
return true
rescue
return false
end
end

View file

@ -0,0 +1,30 @@
class RelationMember < ActiveRecord::Base
set_table_name 'current_relation_members'
# problem with RelationMember is that it may link to any one
# object (a node, a way, another relation), and belongs_to is
# not flexible enough for that. So we do this, which is ugly,
# but fortunately rails won't actually run the SQL behind that
# unless someone really accesses .node, .way, or
# .relation - which is what we do below based on member_type.
# (and no: the :condition on belongs_to doesn't work here as
# it is a condition on the *referenced* object not the
# *referencing* object!)
belongs_to :node, :foreign_key => "member_id"
belongs_to :way, :foreign_key => "member_id"
belongs_to :relation, :foreign_key => "member_id"
# so we define this "member" function that returns whatever it
# is.
def member()
return (member_type == "node") ? node : (member_type == "way") ? way : relation
end
# NOTE - relations are SUBJECTS of memberships. The fact that nodes,
# ways, and relations can be the OBJECT of a membership,
# i.e. a node/way/relation can be referenced throgh a
# RelationMember object, is NOT modelled in rails, i.e. these links
# have to be resolved manually, on demand.
end

View file

@ -0,0 +1,6 @@
class RelationTag < ActiveRecord::Base
set_table_name 'current_relation_tags'
belongs_to :relation, :foreign_key => 'id'
end

View file

@ -3,7 +3,7 @@ class Way < ActiveRecord::Base
belongs_to :user
has_many :way_segments, :foreign_key => 'id', :order => 'sequence_id'
has_many :way_nodes, :foreign_key => 'id', :order => 'sequence_id'
has_many :way_tags, :foreign_key => 'id'
has_many :old_ways, :foreign_key => 'id', :order => 'version'
@ -36,8 +36,8 @@ class Way < ActiveRecord::Base
way.add_tag_keyval(tag['k'], tag['v'])
end
pt.find('seg').each do |seg|
way.add_seg_num(seg['id'])
pt.find('nd').each do |nd|
way.add_nd_num(nd['id'])
end
end
rescue
@ -53,7 +53,7 @@ class Way < ActiveRecord::Base
return doc
end
def to_xml_node(visible_segments = nil, user_display_name_cache = nil)
def to_xml_node(visible_nodes = nil, user_display_name_cache = nil)
el1 = XML::Node.new 'way'
el1['id'] = self.id.to_s
el1['visible'] = self.visible.to_s
@ -71,26 +71,26 @@ class Way < ActiveRecord::Base
el1['user'] = user_display_name_cache[self.user_id] unless user_display_name_cache[self.user_id].nil?
# make sure segments are output in sequence_id order
ordered_segments = []
self.way_segments.each do |seg|
if visible_segments
# if there is a list of visible segments then use that to weed out deleted segments
if visible_segments[seg.segment_id]
ordered_segments[seg.sequence_id] = seg.segment_id.to_s
# make sure nodes are output in sequence_id order
ordered_nodes = []
self.way_nodes.each do |nd|
if visible_nodes
# if there is a list of visible nodes then use that to weed out deleted nodes
if visible_nodes[nd.node_id]
ordered_nodes[nd.sequence_id] = nd.node_id.to_s
end
else
# otherwise, manually go to the db to check things
if seg.segment.visible? and seg.segment.from_node.visible? and seg.segment.to_node.visible?
ordered_segments[seg.sequence_id] = seg.segment_id.to_s
if nd.node.visible? and nd.node.visible?
ordered_nodes[nd.sequence_id] = nd.node_id.to_s
end
end
end
ordered_segments.each do |seg_id|
if seg_id and seg_id != '0'
e = XML::Node.new 'seg'
e['id'] = seg_id
ordered_nodes.each do |nd_id|
if nd_id and nd_id != '0'
e = XML::Node.new 'nd'
e['id'] = nd_id
el1 << e
end
end
@ -104,14 +104,14 @@ class Way < ActiveRecord::Base
return el1
end
def segs
unless @segs
@segs = Array.new
self.way_segments.each do |seg|
@segs += [seg.segment_id]
def nds
unless @nds
@nds = Array.new
self.way_nodes.each do |nd|
@nds += [nd.node_id]
end
end
@segs
@nds
end
def tags
@ -124,17 +124,17 @@ class Way < ActiveRecord::Base
@tags
end
def segs=(s)
@segs = s
def nds=(s)
@nds = s
end
def tags=(t)
@tags = t
end
def add_seg_num(n)
@segs = Array.new unless @segs
@segs << n.to_i
def add_nd_num(n)
@nds = Array.new unless @nds
@nds << n.to_i
end
def add_tag_keyval(k, v)
@ -161,17 +161,17 @@ class Way < ActiveRecord::Base
tag.save!
end
segs = self.segs
nds = self.nds
WaySegment.delete_all(['id = ?', self.id])
WayNode.delete_all(['id = ?', self.id])
i = 1
segs.each do |n|
seg = WaySegment.new
seg.id = self.id
seg.segment_id = n
seg.sequence_id = i
seg.save!
nds.each do |n|
nd = WayNode.new
nd.id = self.id
nd.node_id = n
nd.sequence_id = i
nd.save!
i += 1
end
@ -181,16 +181,17 @@ class Way < ActiveRecord::Base
end
return true
rescue
rescue => ex
puts ex
return nil
end
end
def preconditions_ok?
return false if self.segs.empty?
self.segs.each do |n|
segment = Segment.find(:first, :conditions => ["id = ?", n])
unless segment and segment.visible and segment.preconditions_ok?
return false if self.nds.empty?
self.nds.each do |n|
node = Node.find(:first, :conditions => ["id = ?", n])
unless node and node.visible
return false
end
end

5
app/models/way_node.rb Normal file
View file

@ -0,0 +1,5 @@
class WayNode < ActiveRecord::Base
set_table_name 'current_way_nodes'
belongs_to :node
end