class Neo4j::ActiveRel::Persistence::QueryFactory

This class builds and executes a Cypher query, using information from the graph objects to determine

whether they need to be created simultaneously.
It keeps the rel instance from being responsible for inspecting the nodes or talking with Shared::QueryFactory.

Constants

NODE_SYMBOLS

Attributes

from_node[R]
rel[R]
to_node[R]
unwrapped_rel[R]

Public Class Methods

new(from_node, to_node, rel) click to toggle source
   # File lib/neo4j/active_rel/persistence/query_factory.rb
 9 def initialize(from_node, to_node, rel)
10   @from_node = from_node
11   @to_node = to_node
12   @rel = rel
13 end

Public Instance Methods

build!() click to toggle source

TODO: This feels like it should also wrap the rel, but that is handled in Neo4j::ActiveRel::Persistence at the moment. Builds and executes the query using the objects giving during init. It holds the process:

  • Execute node callbacks if needed

  • Create and execute the query

  • Mix the query response into the unpersisted objects given during init

   # File lib/neo4j/active_rel/persistence/query_factory.rb
21 def build!
22   node_before_callbacks! do
23     res = query_factory(rel, rel_id, iterative_query).query.unwrapped.return(*unpersisted_return_ids).first
24     node_symbols.each { |n| wrap!(send(n), res, n) }
25     @unwrapped_rel = res.send(rel_id)
26   end
27 end

Private Instance Methods

iterative_query() click to toggle source

Each node must be either created or matched before the relationship can be created. This class does not know or care about

how that happens, it just knows that it needs a usable Neo4j::Core::Query object to do that.

This method is “iterative” because it creates one factory for each node but the second builds upon the first.

   # File lib/neo4j/active_rel/persistence/query_factory.rb
57 def iterative_query
58   node_symbols.inject(false) do |iterative_query, sym|
59     obj = send(sym)
60     query_factory(obj, sym, iterative_query)
61   end
62 end
node_before_callbacks!() { || ... } click to toggle source

Node callbacks only need to be executed if the node is not persisted. We let the `conditional_callback` method do the work,

we only have to give it the type of callback we expect to be run and the condition which, if true, will prevent it from executing.
   # File lib/neo4j/active_rel/persistence/query_factory.rb
37 def node_before_callbacks!
38   validate_unpersisted_nodes!
39   from_node.conditional_callback(:create, from_node.persisted?) do
40     to_node.conditional_callback(:create, to_node.persisted?) do
41       yield
42     end
43   end
44 end
node_symbols() click to toggle source
   # File lib/neo4j/active_rel/persistence/query_factory.rb
91 def node_symbols
92   self.class::NODE_SYMBOLS
93 end
query_factory(obj, sym, factory = false) click to toggle source

Isolates the dependency to the shared class. This has an awareness of Neo4j::Core::Query and will match or create

based on the current state of the object passed in.
   # File lib/neo4j/active_rel/persistence/query_factory.rb
66 def query_factory(obj, sym, factory = false)
67   Neo4j::Shared::QueryFactory.create(obj, sym).tap do |factory_instance|
68     factory_instance.base_query = factory.blank? ? false : factory.query
69   end
70 end
rel_id() click to toggle source
   # File lib/neo4j/active_rel/persistence/query_factory.rb
31 def rel_id
32   @rel_id ||= rel.rel_identifier
33 end
unpersisted_return_ids() click to toggle source

@return [Array<Symbol>] The Cypher identifiers that will be returned from the query. We only need to return objects from our query that were created during it, otherwise we impact performance.

   # File lib/neo4j/active_rel/persistence/query_factory.rb
74 def unpersisted_return_ids
75   [rel_id].tap do |result|
76     node_symbols.each { |k| result << k unless send(k).persisted? }
77   end
78 end
validate_unpersisted_nodes!() click to toggle source
   # File lib/neo4j/active_rel/persistence/query_factory.rb
46 def validate_unpersisted_nodes!
47   node_symbols.each do |s|
48     obj = send(s)
49     next if obj.persisted?
50     fail RelCreateFailedError, "Cannot create rel with unpersisted, invalid #{s}" unless obj.valid?
51   end
52 end
wrap!(node, res, key) click to toggle source

@param [Neo4j::ActiveNode] node A node, persisted or unpersisted @param [Struct] res The result of calling `return` on a Neo4j::Core::Query object. It responds to the same keys

as our graph objects. If the object is unpersisted and was created during the query, the unwrapped node is mixed
in, making the object reflect as "persisted".

@param [Symbol] key :from_node or :to_node, the object to request from the response.

   # File lib/neo4j/active_rel/persistence/query_factory.rb
85 def wrap!(node, res, key)
86   return if node.persisted? || !res.respond_to?(key)
87   unwrapped = res.send(key)
88   node.init_on_load(unwrapped, unwrapped.props)
89 end