Class: Neo4j::ActiveNode::Query::QueryProxy
- Inherits:
-
Object
- Object
- Neo4j::ActiveNode::Query::QueryProxy
- Includes:
- Dependent::QueryProxyMethods, QueryProxyEagerLoading, QueryProxyEnumerable, QueryProxyFindInBatches, QueryProxyMethods, QueryProxyMethodsOfMassUpdating
- Defined in:
- lib/neo4j/active_node/query/query_proxy.rb,
lib/neo4j/active_node/query/query_proxy_link.rb
Overview
rubocop:disable Metrics/ClassLength
Defined Under Namespace
Classes: Link
Constant Summary collapse
- METHODS =
%w(where where_not rel_where rel_where_not rel_order order skip limit)
Constants included from QueryProxyMethods
Neo4j::ActiveNode::Query::QueryProxyMethods::FIRST, Neo4j::ActiveNode::Query::QueryProxyMethods::LAST
Instance Attribute Summary collapse
-
#association ⇒ Object
readonly
The most recent node to start a QueryProxy chain.
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#model ⇒ Object
readonly
The most recent node to start a QueryProxy chain.
-
#node_var ⇒ Object
readonly
The current node identifier on deck, so to speak.
-
#query_proxy ⇒ Object
readonly
Returns the value of attribute query_proxy.
-
#rel_var ⇒ Object
readonly
The relationship identifier most recently used by the QueryProxy chain.
-
#source_object ⇒ Object
readonly
The most recent node to start a QueryProxy chain.
-
#start_object ⇒ Object
readonly
Returns the value of attribute start_object.
-
#starting_query ⇒ Object
readonly
The most recent node to start a QueryProxy chain.
Instance Method Summary collapse
-
#<<(other_node) ⇒ Object
To add a relationship for the node for the association on this QueryProxy.
- #[](index) ⇒ Object
- #_create_relationship(other_node_or_nodes, properties) ⇒ Object
-
#_model_label_string(with_labels = true) ⇒ Object
param [TrueClass, FalseClass] with_labels This param is used by certain QueryProxy methods that already have the neo_id and therefore do not need labels.
- #_nodeify!(*args) ⇒ Object
- #base_query(var, with_labels = true) ⇒ Object
-
#branch { ... } ⇒ QueryProxy
Executes the relation chain specified in the block, while keeping the current scope.
- #create(other_nodes, properties = {}) ⇒ Object
- #identity ⇒ Object (also: #node_identity)
-
#initialize(model, association = nil, options = {}) ⇒ QueryProxy
constructor
QueryProxy is ActiveNode’s Cypher DSL.
- #inspect ⇒ Object
-
#method_missing(method_name, *args, &block) ⇒ Object
QueryProxy objects act as a representation of a model at the class level so we pass through calls This allows us to define class functions for reusable query chaining or for end-of-query aggregation/summarizing.
- #new_link(node_var = nil) ⇒ Object
- #optional? ⇒ Boolean
- #params(params) ⇒ Object
-
#query ⇒ Object
Like calling #query_as, but for when you don’t care about the variable name.
-
#query_as(var, with_labels = true) ⇒ Object
Build a Neo4j::Core::Query object for the QueryProxy.
- #query_from_chain(chain, base_query, var) ⇒ Object
- #read_attribute_for_serialization(*args) ⇒ Object
- #rel_identity ⇒ Object
- #respond_to_missing?(method_name, include_all = false) ⇒ Boolean
-
#scoping ⇒ Object
Scope all queries to the current scope.
-
#to_cypher_with_params(columns = [self.identity]) ⇒ String
Returns a string of the cypher query with return objects and params.
- #unpersisted_start_object? ⇒ Boolean
Methods included from Dependent::QueryProxyMethods
#each_for_destruction, #unique_nodes
Methods included from QueryProxyEagerLoading
#association_tree_class, #first, #perform_query, #pluck_vars, #propagate_context, #with_associations, #with_associations_tree, #with_associations_tree=
Methods included from QueryProxyFindInBatches
Methods included from QueryProxyMethodsOfMassUpdating
#delete, #delete_all, #delete_all_rels, #destroy, #replace_with, #update_all, #update_all_rels
Methods included from QueryProxyMethods
#as, #as_models, #count, #distinct, #empty?, #exists?, #find, #find_or_create_by, #find_or_initialize_by, #first, #first_or_initialize, #first_rel_to, #having_rel, #include?, #last, #limit_value, #match_to, #not_having_rel, #optional, #order_property, #propagate_context, #rel, #rels, #rels_to, #size
Methods included from QueryProxyEnumerable
#==, #each, #each_rel, #each_with_rel, #fetch_result_cache, #pluck, #result, #result_cache?, #result_cache_for
Constructor Details
#initialize(model, association = nil, options = {}) ⇒ QueryProxy
QueryProxy is ActiveNode’s Cypher DSL. While the name might imply that it creates queries in a general sense, it is actually referring to Neo4j::Core::Query, which is a pure Ruby Cypher DSL provided by the neo4j-core gem. QueryProxy provides ActiveRecord-like methods for common patterns. When it’s not handling CRUD for relationships and queries, it provides ActiveNode’s association chaining (‘student.lessons.teachers.where(age: 30).hobbies`) and enjoys long walks on the beach.
It should not ever be necessary to instantiate a new QueryProxy object directly, it always happens as a result of calling a method that makes use of it.
originated. has_many) that created this object. QueryProxy objects are evaluated lazily.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 41 def initialize(model, association = nil, = {}) @model = model @association = association @context = .delete(:context) @options = @associations_spec = [] () @match_type = @optional ? :optional_match : :match @rel_var = [:rel] || _rel_chain_var @chain = [] @params = @query_proxy ? @query_proxy.instance_variable_get('@params') : {} end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_name, *args, &block) ⇒ Object
QueryProxy objects act as a representation of a model at the class level so we pass through calls This allows us to define class functions for reusable query chaining or for end-of-query aggregation/summarizing
247 248 249 250 251 252 253 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 247 def method_missing(method_name, *args, &block) if @model && @model.respond_to?(method_name) scoping { @model.public_send(method_name, *args, &block) } else super end end |
Instance Attribute Details
#association ⇒ Object (readonly)
The most recent node to start a QueryProxy chain. Will be nil when using QueryProxy chains on class methods.
16 17 18 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 16 def association @association end |
#context ⇒ Object
Returns the value of attribute context.
263 264 265 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 263 def context @context end |
#model ⇒ Object (readonly)
The most recent node to start a QueryProxy chain. Will be nil when using QueryProxy chains on class methods.
16 17 18 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 16 def model @model end |
#node_var ⇒ Object (readonly)
The current node identifier on deck, so to speak. It is the object that will be returned by calling each and the last node link in the QueryProxy chain.
67 68 69 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 67 def node_var @node_var end |
#query_proxy ⇒ Object (readonly)
Returns the value of attribute query_proxy.
63 64 65 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 63 def query_proxy @query_proxy end |
#rel_var ⇒ Object (readonly)
The relationship identifier most recently used by the QueryProxy chain.
74 75 76 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 74 def rel_var @rel_var end |
#source_object ⇒ Object (readonly)
The most recent node to start a QueryProxy chain. Will be nil when using QueryProxy chains on class methods.
16 17 18 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 16 def source_object @source_object end |
#start_object ⇒ Object (readonly)
Returns the value of attribute start_object.
63 64 65 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 63 def start_object @start_object end |
#starting_query ⇒ Object (readonly)
The most recent node to start a QueryProxy chain. Will be nil when using QueryProxy chains on class methods.
16 17 18 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 16 def starting_query @starting_query end |
Instance Method Details
#<<(other_node) ⇒ Object
To add a relationship for the node for the association on this QueryProxy
172 173 174 175 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 172 def <<(other_node) _create_relation_or_defer(other_node) self end |
#[](index) ⇒ Object
198 199 200 201 202 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 198 def [](index) # TODO: Maybe for this and other methods, use array if already loaded, otherwise # use OFFSET and LIMIT 1? self.to_a[index] end |
#_create_relationship(other_node_or_nodes, properties) ⇒ Object
235 236 237 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 235 def _create_relationship(other_node_or_nodes, properties) association._create_relationship(@start_object, other_node_or_nodes, properties) end |
#_model_label_string(with_labels = true) ⇒ Object
param [TrueClass, FalseClass] with_labels This param is used by certain QueryProxy methods that already have the neo_id and therefore do not need labels. The @association_labels instance var is set during init and used during association chaining to keep labels out of Cypher queries.
123 124 125 126 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 123 def _model_label_string(with_labels = true) return if !@model || (!with_labels || @association_labels == false) @model.mapped_label_names.map { |label_name| ":`#{label_name}`" }.join end |
#_nodeify!(*args) ⇒ Object
223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 223 def _nodeify!(*args) other_nodes = [args].flatten!.map! do |arg| (arg.is_a?(Integer) || arg.is_a?(String)) ? @model.find_by(id: arg) : arg end.compact if @model && other_nodes.any? { |other_node| !other_node.class.mapped_label_names.include?(@model.mapped_label_name) } fail ArgumentError, "Node must be of the association's class when model is specified" end other_nodes end |
#base_query(var, with_labels = true) ⇒ Object
110 111 112 113 114 115 116 117 118 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 110 def base_query(var, with_labels = true) if @association chain_var = _association_chain_var (_association_query_start(chain_var) & _query).break.send(@match_type, "(#{chain_var})#{_association_arrow}(#{var}#{_model_label_string})") else starting_query ? starting_query : _query_model_as(var, with_labels) end end |
#branch { ... } ⇒ QueryProxy
Executes the relation chain specified in the block, while keeping the current scope
188 189 190 191 192 193 194 195 196 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 188 def branch(&block) fail LocalJumpError, 'no block given' if block.nil? # `as(identity)` is here to make sure we get the right variable # There might be a deeper problem of the variable changing when we # traverse an association as(identity).instance_eval(&block).query.proxy_as(self.model, identity).tap do |new_query_proxy| propagate_context(new_query_proxy) end end |
#create(other_nodes, properties = {}) ⇒ Object
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 204 def create(other_nodes, properties = {}) fail 'Can only create relationships on associations' if !@association other_nodes = _nodeify!(*other_nodes) Neo4j::ActiveBase.run_transaction do other_nodes.each do |other_node| if other_node.neo_id other_node.try(:validate_reverse_has_one_core_rel, association, @start_object) else other_node.save end @start_object.association_proxy_cache.clear _create_relationship(other_node, properties) end end end |
#identity ⇒ Object Also known as: node_identity
68 69 70 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 68 def identity @node_var || _result_string(_chain_level + 1) end |
#inspect ⇒ Object
58 59 60 61 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 58 def inspect formatted_nodes = Neo4j::ActiveNode::NodeListFormatter.new(to_a) "#<QueryProxy #{@context} #{formatted_nodes.inspect}>" end |
#new_link(node_var = nil) ⇒ Object
265 266 267 268 269 270 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 265 def new_link(node_var = nil) self.clone.tap do |new_query_proxy| new_query_proxy.instance_variable_set('@result_cache', nil) new_query_proxy.instance_variable_set('@node_var', node_var) if node_var end end |
#optional? ⇒ Boolean
259 260 261 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 259 def optional? @optional == true end |
#params(params) ⇒ Object
81 82 83 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 81 def params(params) new_link.tap { |new_query| new_query._add_params(params) } end |
#query ⇒ Object
Like calling #query_as, but for when you don’t care about the variable name
86 87 88 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 86 def query query_as(identity) end |
#query_as(var, with_labels = true) ⇒ Object
Build a Neo4j::Core::Query object for the QueryProxy. This is necessary when you want to take an existing QueryProxy chain and work with it from the more powerful (but less friendly) Neo4j::Core::Query.
- .. code-block
-
ruby
student.lessons.query_as(:l).with('your cypher here...')
97 98 99 100 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 97 def query_as(var, with_labels = true) query_from_chain(chain, base_query(var, with_labels).params(@params), var) .tap { |query| query.proxy_chain_level = _chain_level } end |
#query_from_chain(chain, base_query, var) ⇒ Object
102 103 104 105 106 107 108 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 102 def query_from_chain(chain, base_query, var) chain.inject(base_query) do |query, link| args = link.args(var, rel_var) args.is_a?(Array) ? query.send(link.clause, *args) : query.send(link.clause, args) end end |
#read_attribute_for_serialization(*args) ⇒ Object
239 240 241 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 239 def read_attribute_for_serialization(*args) to_a.map { |o| o.read_attribute_for_serialization(*args) } end |
#rel_identity ⇒ Object
75 76 77 78 79 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 75 def rel_identity ActiveSupport::Deprecation.warn 'rel_identity is deprecated and may be removed from future releases, use rel_var instead.', caller @rel_var end |
#respond_to_missing?(method_name, include_all = false) ⇒ Boolean
255 256 257 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 255 def respond_to_missing?(method_name, include_all = false) (@model && @model.respond_to?(method_name, include_all)) || super end |
#scoping ⇒ Object
Scope all queries to the current scope.
- .. code-block
-
ruby
Comment.where(post_id: 1).scoping do
Comment.first
end
TODO: unscoped Please check unscoped if you want to remove all previous scopes (including the default_scope) during the execution of a block.
139 140 141 142 143 144 145 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 139 def scoping previous = @model.current_scope @model.current_scope = self yield ensure @model.current_scope = previous end |
#to_cypher_with_params(columns = [self.identity]) ⇒ String
Returns a string of the cypher query with return objects and params
166 167 168 169 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 166 def to_cypher_with_params(columns = [self.identity]) final_query = query.return_query(columns) "#{final_query.to_cypher} | params: #{final_query.send(:merge_params)}" end |
#unpersisted_start_object? ⇒ Boolean
272 273 274 |
# File 'lib/neo4j/active_node/query/query_proxy.rb', line 272 def unpersisted_start_object? @start_object && @start_object.new_record? end |