old_verbose=$VERBOSE $VERBOSE=false require 'active_record' $VERBOSE=old_verbose module RTM::AR # The Active Record TMDM backend module TMDM # Moves all fields in a collection to another owner (for classes using belongs_to in AR::Base class) module Movable # Takes a list of [field,from, to] arguments. # RTM::AR::TMDM::ItemIdentifier.move_all( # ["topic_map_construct_id", other.__getobj__.id, self.__getobj__.id], # ["topic_map_construct_type", other.__getobj__.class.name, self.__getobj__.class.name] # ) # or # RTM::AR::TMDM::Variant.move_all(["topic_name_id", other.__getobj__.id, self.__getobj__.id]) # def move_all(*args) raise "All parameters must have a size of 3: [field_name, from, to]" unless args.all?{|a| a.size == 3} set_part = "" where_part = "" args.each do |field, from, to| set_part += ", " unless set_part.empty? where_part += " and " unless where_part.empty? from = "'#{from}'" unless from.is_a? Numeric to = "'#{to}'" unless to.is_a? Numeric where_part += "#{field} = #{from}" set_part += "#{field} = #{to}" end #puts "setpart: #{set_part.inspect}\nwherepart: #{where_part.inspect}" res = self.update_all(set_part, where_part) #puts "result: #{res.inspect}" end end class TopicMapConstruct < ActiveRecord::Base self.store_full_sti_class = false extend Movable class << self def abstract_class? self == TopicMapConstruct end def alias_ar_relation(new,old) alias_method new, old alias_method "#{new}=", "#{old}=" end alias :alias_belongs_to :alias_ar_relation alias :alias_has_many :alias_ar_relation def belongs_to_with_alias(name, synonym) belongs_to name alias_belongs_to synonym, name end def has_many_with_alias(name, synonym, *args) has_many name, *args alias_has_many synonym, name end def belongs_to_parent(parent) belongs_to parent alias_belongs_to :parent, parent end def this_is_a_typed_object belongs_to :ttype, :class_name => "Topic", :foreign_key => :ttype_id module_eval(<<-EOS, "(__RTM_AR_TMDM_TYPED_OBJECT__)", 1) def type=(ptype) self.ttype=ptype end def type self.ttype end EOS end end has_many :item_identifiers, :as => :topic_map_construct, :dependent => :destroy def topic_map parent.topic_map end def move_to(new_parent) self.parent = new_parent end end class Reifiable < TopicMapConstruct def self.abstract_class? self == Reifiable end has_one :reifier, :class_name => "Topic", :as => :reified end class ScopedObject < Reifiable def self.abstract_class? self == ScopedObject end has_many :scoped_objects_topics, :as => :scoped_object, :dependent => :destroy has_many :scope, :through => :scoped_objects_topics, :source => :topic # def scope # self.scoped_objects_topics.map { |sot| sot.topic } # end # def add_scoping_topic(topic) # this is not ruby-ish but at least it works, would need a complete association proxy instead... # sot = ScopedObjectsTopic.create :topic => topic, :scoped_object => self # self # # sot = ScopedObjectsTopic.new :topic => topic, :scoped_object => self # # self.scoped_objects_topics << sot # # self # end # def remove_scoping_topic(topic) # this is not ruby-ish but at least it works, would need a complete association proxy instead... # self.scoped_objects_topics.select { |sot| sot.topic == topic }.destroy # self # end end class ScopedObjectsTopic < ActiveRecord::Base self.store_full_sti_class = false extend Movable belongs_to :topic belongs_to :scoped_object, :polymorphic => true belongs_to :association, :class_name => 'RTM::AR::TMDM::Association', :foreign_key => "scoped_object_id" belongs_to :topic_name, :class_name => 'RTM::AR::TMDM::TopicName', :foreign_key => "scoped_object_id" belongs_to :variant, :class_name => 'RTM::AR::TMDM::Variant', :foreign_key => "scoped_object_id" belongs_to :occurrence, :class_name => 'RTM::AR::TMDM::Occurrence', :foreign_key => "scoped_object_id" end class Locator < ActiveRecord::Base self.store_full_sti_class = false extend Movable class << self def abstract_class? self == Locator end end belongs_to :topic_map end class ItemIdentifier < Locator belongs_to :topic_map_construct, :polymorphic => true def to_s self.reference end def move_to(new_tmc) #puts "\n\nmoving\n\t#{self.inspect}\n\nto\n\t#{new_tmc.inspect}" #self.update_all "topic_map_construct_id = #{new_tmc.id}, topic_map_construct_type = '#{new_tmc.class.name}'", #puts "changing id" #puts self.topic_map_construct_id = new_tmc.id #puts "changing type" #puts self.topic_map_construct_type = new_tmc.class.name self.topic_map_construct = new_tmc #puts "saving" self.save # # das geht!!! #self.class.update( self.id, "topic_map_construct_id" => new_tmc.id) end end class SubjectLocator < Locator belongs_to :topic def to_s self.reference end end class SubjectIdentifier < Locator belongs_to :topic def to_s self.reference end end # http://www.isotopicmaps.org/sam/sam-model/#d0e736 class Topic < TopicMapConstruct belongs_to :reified, :polymorphic => true belongs_to_parent :topic_map has_many :subject_locators, :dependent => :destroy has_many :subject_identifiers, :dependent => :destroy has_many :occurrences, :dependent => :destroy has_many_with_alias :topic_names, :names, :dependent => :destroy has_many_with_alias :association_roles, :roles, :include => :association has_many :associations, :through => :association_roles #has_many :played_types, :through => :association_roles, :source => :type has_many :associations_typed, :class_name => "Association", :foreign_key => :ttype_id has_many :association_roles_typed, :class_name => "AssociationRole", :foreign_key => :ttype_id has_many :topic_names_typed, :class_name => "TopicName", :foreign_key => :ttype_id has_many :occurrences_typed, :class_name => "Occurrence", :foreign_key => :ttype_id has_many :scoped_objects_topics has_many :scoped_associations, :through => :scoped_objects_topics, :source => :association, :conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Association'" has_many :scoped_topic_names, :through => :scoped_objects_topics, :source => :topic_name, :conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::TopicName'" has_many :scoped_variants, :through => :scoped_objects_topics, :source => :variant, :conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Variant'" has_many :scoped_occurrences, :through => :scoped_objects_topics, :source => :occurrence, :conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Occurrence'" # def scoped_objects # self.scoped_objects_topics.collect { |a| a.scoped_object } # temporary hack polymorphic has_many_through # end def scoped_objects scoped_associations + scoped_topic_names + scoped_variants + scoped_occurrences end end class AssociationRole < Reifiable belongs_to_parent :association belongs_to_with_alias :topic, :player this_is_a_typed_object end class TopicName < ScopedObject belongs_to_parent :topic this_is_a_typed_object has_many :variants, :dependent => :destroy end class Association < ScopedObject belongs_to_parent :topic_map this_is_a_typed_object has_many_with_alias :association_roles, :roles, :dependent => :destroy def create_role(rplayer, ttype) AssociationRole.create :parent => self, :player => rplayer, :ttype => ttype end alias :create_association_role :create_role has_many :role_players, :through => :association_roles, :source => :topic has_many :role_types, :through => :association_roles, :source => :ttype end class AssociationCache < TopicMapConstruct set_table_name "associations_cache" belongs_to_parent :topic_map this_is_a_typed_object has_many_with_alias :association_roles, :roles belongs_to :role1, :class_name => "RTM::AR::TMDM::AssociationRole", :foreign_key => "role1_id" belongs_to :player1, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "player1_id" belongs_to :type1, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "type1_id" belongs_to :role2, :class_name => "RTM::AR::TMDM::AssociationRole", :foreign_key => "role2_id" belongs_to :player2, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "player2_id" belongs_to :type2, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "type2_id" # rolecount -> rcnt end class Occurrence < ScopedObject belongs_to_parent :topic this_is_a_typed_object end class Variant < ScopedObject belongs_to_parent :topic_name end class TopicMap < Reifiable # real properties has_many :topics, :dependent => :destroy, :include => [:subject_identifiers, :subject_locators] has_many :associations, :dependent => :destroy, :include => :association_roles # access to subproperties has_many :locators, :class_name => "ItemIdentifier", :dependent => :destroy has_many :subject_locators, :dependent => :destroy has_many :subject_identifiers, :dependent => :destroy has_many :topic_names, :through => :topics alias :names :topic_names has_many :occurrences, :through => :topics has_many :association_roles, :through => :associations alias :roles :association_roles %w[association association_role topic_name occurrence].each do |m| module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET__)", 1) def #{m}_types topics.select{|t| t.#{m}s_typed.size > 0} end EOS end #typing # has_many :association_types, :class_name => "Association", :foreign_key => :ttype_id # has_many :association_role_types, :class_name => "AssociationRole", :foreign_key => :ttype_id # has_many :topic_name_types, :class_name => "TopicName", :foreign_key => :ttype_id # has_many :occurrence_types, :class_name => "Occurrence", :foreign_key => :ttype_id # has_many :association_types, :aka => :at, :type => :Topic, :wrap => true # has_many :association_role_types, :aka => [:role_types,:art,:rt], :type => :Topic, :wrap => true # has_many :topic_name_types, :aka => [:name_types,:tnt,:nt], :type => :Topic, :wrap => true # has_many :occurrence_types, :aka => :ot, :type => :Topic, :wrap => true def topic_map self end # # Creates a new Locator in this TopicMap # def create_locator(reference, notation=nil) # if notation # ItemIdentifier.create :reference => reference, :notation => notation # else # ItemIdentifier.create :reference => reference # is there a better way to preserve the database default notation if none given? # end # end end end end