lib/neoid/relationship.rb in neoid-0.0.2 vs lib/neoid/relationship.rb in neoid-0.0.5.alpha

- old
+ new

@@ -1,24 +1,33 @@ module Neoid module Relationship module InstanceMethods def neo_find_by_id Neoid.db.get_relationship_index(self.class.neo_index_name, :ar_id, self.id) + rescue Neography::NotFoundException + nil end def neo_create - options = self.class.neoidable_options + return unless Neoid.enabled? + @_neo_destroyed = false + options = self.class.neoid_config.relationship_options + start_node = self.send(options[:start_node]) end_node = self.send(options[:end_node]) return unless start_node && end_node + + data = self.to_neo.merge(ar_type: self.class.name, ar_id: self.id) + data.reject! { |k, v| v.nil? } relationship = Neography::Relationship.create( - options[:type], + options[:type].is_a?(Proc) ? options[:type].call(self) : options[:type], start_node.neo_node, - end_node.neo_node + end_node.neo_node, + data ) Neoid.db.add_relationship_to_index(self.class.neo_index_name, :ar_id, self.id, relationship) Neoid::logger.info "Relationship#neo_create #{self.class.name} #{self.id}, index = #{self.class.neo_index_name}" @@ -29,25 +38,91 @@ def neo_load(relationship) Neography::Relationship.load(relationship) end def neo_destroy + return if @_neo_destroyed + @_neo_destroyed = true return unless neo_relationship Neoid.db.remove_relationship_from_index(self.class.neo_index_name, neo_relationship) neo_relationship.del + _reset_neo_representation + + Neoid::logger.info "Relationship#neo_destroy #{self.class.name} #{self.id}, index = #{self.class.neo_index_name}" + + true end + def neo_update + Neoid.db.set_relationship_properties(neo_relationship, self.to_neo) if neo_relationship + end + def neo_relationship _neo_representation end end def self.included(receiver) - receiver.extend Neoid::ModelAdditions::ClassMethods - receiver.send :include, Neoid::ModelAdditions::InstanceMethods + receiver.send :include, Neoid::ModelAdditions receiver.send :include, InstanceMethods receiver.after_create :neo_create receiver.after_destroy :neo_destroy + receiver.after_update :neo_update + + if Neoid.env_loaded + initialize_relationship receiver + else + Neoid.relationship_models << receiver + end end + + def self.initialize_relationship(rel_model) + rel_model.reflect_on_all_associations(:belongs_to).each do |belongs_to| + return if belongs_to.options[:polymorphic] + + # e.g. all has_many on User class + all_has_many = belongs_to.klass.reflect_on_all_associations(:has_many) + + # has_many (without through) on the side of the relationship that removes a relationship. e.g. User has_many :likes + this_has_many = all_has_many.find { |o| o.klass == rel_model } + next unless this_has_many + + # e.g. User has_many :likes, after_remove: ... + full_callback_name = "after_remove_for_#{this_has_many.name}" + belongs_to.klass.send(full_callback_name) << :neo_after_relationship_remove if belongs_to.klass.method_defined?(full_callback_name) + # belongs_to.klass.send(:has_many, this_has_many.name, this_has_many.options.merge(after_remove: :neo_after_relationship_remove)) + + # has_many (with through) on the side of the relationship that removes a relationship. e.g. User has_many :movies, through :likes + many_to_many = all_has_many.find { |o| o.options[:through] == this_has_many.name } + next unless many_to_many + + return if many_to_many.options[:as] # polymorphic are not supported here yet + + # user_id + foreign_key_of_owner = many_to_many.through_reflection.foreign_key + + # movie_id + foreign_key_of_record = many_to_many.source_reflection.foreign_key + + (Neoid.config[:relationship_meta_data] ||= {}).tap do |data| + (data[belongs_to.klass.name.to_s] ||= {}).tap do |model_data| + model_data[many_to_many.klass.name.to_s] = [rel_model.name.to_s, foreign_key_of_owner, foreign_key_of_record] + end + end + + # puts Neoid.config[:relationship_meta_data].inspect + + # e.g. User has_many :movies, through: :likes, before_remove: ... + full_callback_name = "before_remove_for_#{many_to_many.name}" + belongs_to.klass.send(full_callback_name) << :neo_before_relationship_through_remove if belongs_to.klass.method_defined?(full_callback_name) + # belongs_to.klass.send(:has_many, many_to_many.name, many_to_many.options.merge(before_remove: :neo_after_relationship_remove)) + + + # e.g. User has_many :movies, through: :likes, after_remove: ... + full_callback_name = "after_remove_for_#{many_to_many.name}" + belongs_to.klass.send(full_callback_name) << :neo_after_relationship_through_remove if belongs_to.klass.method_defined?(full_callback_name) + # belongs_to.klass.send(:has_many, many_to_many.name, many_to_many.options.merge(after_remove: :neo_after_relationship_remove)) + end + end end -end \ No newline at end of file +end