Created
February 9, 2017 15:46
-
-
Save tjad/fb779fcbada040b7e4ff455d48875f0c to your computer and use it in GitHub Desktop.
Short hand syntax for retrieving association object graph
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#to recieve the respective associations | |
Person.with_associations( {brothers: {:children [:daughters, :sons] }}) | |
#Outputs all associations as an object graph structure defined above by each associations depth |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Person | |
include Neo4j::ActiveNode | |
#associations to other Person objects | |
has_many :out, :brothers, type: :HAS_BROTHER | |
has_many :out, :children, type: :HAS_CHILD | |
has_many :out, :daughters, type: :HAS_DAUGHTER | |
has_many :out, :sons, type: :HAS_SON | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def with_associations(assoc_conf) | |
object_name = self.name.gsub(/::/, '/'). | |
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). | |
gsub(/([a-z\d])([A-Z])/,'\1_\2'). | |
tr("-", "_"). | |
downcase | |
# Construct paths to represent the query paths for information to be eagerly loaded | |
paths = [] | |
# For reconstructing objects | |
path_directive_class_table = {} | |
path_constructor = lambda do |current_path, path_conf| | |
if path_conf.instance_of? Hash | |
path_conf.each do |k, v| | |
path_constructor.call(current_path+[k], v) | |
end | |
elsif path_conf.instance_of? Array | |
path_conf.each do |path| | |
paths << current_path + [path] | |
end | |
elsif path_conf.instance_of? Symbol # Append to current path and add to paths local variable | |
current_path << path_conf | |
paths << current_path | |
else | |
raise Exception.new("Unhandled path type") | |
end | |
end | |
path_constructor.call([], assoc_conf) | |
# Construct cypher queries | |
match_statements = [] | |
path_directive_class_table[object_name.to_sym] = self | |
paths.each do |path| | |
assoc_class = self | |
query_string = '('+object_name+':'+self.name+')' | |
path.each do |path_directive| | |
relationship_type = assoc_class.associations[path_directive].relationship_type | |
assoc_class = assoc_class.associations[path_directive].target_class | |
path_directive_class_table[path_directive] = assoc_class | |
query_string += '-[:' + relationship_type.to_s + ']->(' + path_directive.to_s + ':' + assoc_class.name + ')' | |
end | |
match_statements << query_string | |
end | |
assoc_chain = [object_name] + paths.first | |
# Perform queries to gather information from database for eager loading | |
matches = Neo4j::Session.current.query.match(match_statements.join(',')) | |
.pluck(assoc_chain) | |
# Embed the nodes correctly within the object in order to reconstruct the model | |
link_nodes = lambda do |match, parent, path| | |
unless path.empty? | |
path_member = path.shift | |
parent[path_member] = link_nodes.call(match, match[assoc_chain.find_index(path_member)].attributes, path) | |
end | |
parent | |
end | |
matches.map do |match| | |
link_nodes.call(match, {}, assoc_chain.dup)[assoc_chain.first] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment