lib/neoid/relationship.rb in neoid-0.1.2 vs lib/neoid/relationship.rb in neoid-0.2.0
- old
+ new
@@ -1,7 +1,72 @@
module Neoid
module Relationship
+ class << self
+ def from_hash(hash)
+ relationship = RelationshipLazyProxy.new(hash)
+
+ relationship
+ end
+
+ def included(receiver)
+ receiver.send :include, Neoid::ModelAdditions
+ receiver.send :include, InstanceMethods
+ receiver.extend ClassMethods
+
+ initialize_relationship receiver if Neoid.env_loaded
+
+ Neoid.relationship_models << receiver
+ end
+
+ def meta_data
+ @meta_data ||= {}
+ end
+
+ def 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)
+
+ # 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::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
+
+ # 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)
+
+ # 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)
+ end
+ end
+ end
+
# this is a proxy that delays loading of start_node and end_node from Neo4j until accessed.
# the original Neography Relatioship loaded them on initialization
class RelationshipLazyProxy < ::Neography::Relationship
def start_node
@start_node_from_db ||= @start_node = Neography::Node.load(@start_node, Neoid.db)
@@ -10,45 +75,38 @@
def end_node
@end_node_from_db ||= @end_node = Neography::Node.load(@end_node, Neoid.db)
end
end
- def self.from_hash(hash)
- relationship = RelationshipLazyProxy.new(hash)
-
- relationship
- end
-
-
module ClassMethods
def delete_command
:delete_relationship
end
end
module InstanceMethods
def neo_find_by_id
- results = Neoid.db.get_relationship_auto_index(Neoid::UNIQUE_ID_KEY, self.neo_unique_id)
+ results = Neoid.db.get_relationship_auto_index(Neoid::UNIQUE_ID_KEY, neo_unique_id)
relationship = results.present? ? Neoid::Relationship.from_hash(results[0]) : nil
relationship
end
-
+
def _neo_save
return unless Neoid.enabled?
-
+
options = self.class.neoid_config.relationship_options
-
- start_item = self.send(options[:start_node])
- end_item = self.send(options[:end_node])
-
+
+ start_item = send(options[:start_node])
+ end_item = send(options[:end_node])
+
return unless start_item && end_item
# initialize nodes
start_item.neo_node
end_item.neo_node
- data = self.to_neo.merge(ar_type: self.class.name, ar_id: self.id, Neoid::UNIQUE_ID_KEY => self.neo_unique_id)
+ data = to_neo.merge(ar_type: self.class.name, ar_id: id, Neoid::UNIQUE_ID_KEY => neo_unique_id)
data.reject! { |k, v| v.nil? }
rel_type = options[:type].is_a?(Proc) ? options[:type].call(self) : options[:type]
gremlin_query = <<-GREMLIN
@@ -73,91 +131,33 @@
}
relationship
GREMLIN
- script_vars = {
+ script_vars = {
unique_id_key: Neoid::UNIQUE_ID_KEY,
relationship_data: data,
- unique_id: self.neo_unique_id,
+ unique_id: neo_unique_id,
start_node_unique_id: start_item.neo_unique_id,
end_node_unique_id: end_item.neo_unique_id,
rel_type: rel_type
}
- Neoid::logger.info "Relationship#neo_save #{self.class.name} #{self.id}"
-
+ Neoid::logger.info "Relationship#neo_save #{self.class.name} #{id}"
+
relationship = Neoid.execute_script_or_add_to_batch gremlin_query, script_vars do |value|
Neoid::Relationship.from_hash(value)
end
relationship
end
-
+
def neo_load(hash)
Neoid::Relationship.from_hash(hash)
end
def neo_relationship
_neo_representation
- end
- end
-
- def self.included(receiver)
- receiver.send :include, Neoid::ModelAdditions
- receiver.send :include, InstanceMethods
- receiver.extend ClassMethods
-
- initialize_relationship receiver if Neoid.env_loaded
-
- Neoid.relationship_models << receiver
- end
-
- def self.meta_data
- @meta_data ||= {}
- 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)
-
- # 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::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
-
- # 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)
-
-
- # 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)
end
end
end
end