Class: ActiveGraph::Node::Query::QueryProxy
- Inherits:
 - 
      Object
      
        
- Object
 - ActiveGraph::Node::Query::QueryProxy
 
 
- Includes:
 - Dependent::QueryProxyMethods, QueryProxyEagerLoading, QueryProxyEnumerable, QueryProxyFindInBatches, QueryProxyMethods, QueryProxyMethodsOfMassUpdating
 
- Defined in:
 - lib/active_graph/node/query/query_proxy.rb,
lib/active_graph/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 union)
Constants included from QueryProxyMethods
ActiveGraph::Node::Query::QueryProxyMethods::FIRST, ActiveGraph::Node::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)
 - #init_outer_query_var(var) ⇒ Object
 - 
  
    
      #initialize(model, association = nil, options = {})  ⇒ QueryProxy 
    
    
  
  
  
    constructor
  
  
  
  
  
  
  
    
QueryProxy is Node’s Cypher DSL.
 - #inspect ⇒ Object
 - 
  
    
      #method_missing(method_name, *args, **kwargs, &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 ActiveGraph::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.
 - #union(*args) ⇒ Object
 - #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
#add_rels, #delete, #delete_all, #delete_all_rels, #delete_rels_for_nodes, #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 Node’s Cypher DSL. While the name might imply that it creates queries in a general sense, it is actually referring to ActiveGraph::Core::Query, which is a pure Ruby Cypher DSL provided by the activegraph gem. QueryProxy provides ActiveRecord-like methods for common patterns. When it’s not handling CRUD for relationships and queries, it provides Node’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.
      40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 40 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, **kwargs, &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
      263 264 265 266 267 268 269 270 271 272 273 274 275  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 263 def method_missing(method_name, *args, **kwargs, &block) if @model && @model.respond_to?(method_name) scoping do if RUBY_VERSION < '3' && kwargs.empty? @model.public_send(method_name, *args, &block) else @model.public_send(method_name, *args, **kwargs, &block) end end 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/active_graph/node/query/query_proxy.rb', line 16 def association @association end  | 
  
#context ⇒ Object
Returns the value of attribute context.
      285 286 287  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 285 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/active_graph/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.
      66 67 68  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 66 def node_var @node_var end  | 
  
#query_proxy ⇒ Object (readonly)
Returns the value of attribute query_proxy.
      62 63 64  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 62 def query_proxy @query_proxy end  | 
  
#rel_var ⇒ Object (readonly)
The relationship identifier most recently used by the QueryProxy chain.
      73 74 75  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 73 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/active_graph/node/query/query_proxy.rb', line 16 def source_object @source_object end  | 
  
#start_object ⇒ Object (readonly)
Returns the value of attribute start_object.
      62 63 64  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 62 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/active_graph/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
      188 189 190 191  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 188 def <<(other_node) _create_relation_or_defer(other_node) self end  | 
  
#[](index) ⇒ Object
      214 215 216 217 218  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 214 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
      251 252 253  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 251 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.
      134 135 136 137  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 134 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
      239 240 241 242 243 244 245 246 247 248 249  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 239 def _nodeify!(*args) other_nodes = [args].flatten!.map! do |arg| 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
      121 122 123 124 125 126 127 128 129  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 121 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
      204 205 206 207 208 209 210 211 212  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 204 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
      220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 220 def create(other_nodes, properties = {}) fail 'Can only create relationships on associations' if !@association other_nodes = _nodeify!(*other_nodes) ActiveGraph::Base.transaction do other_nodes.each do |other_node| if other_node.element_id other_node.try(:delete_reverse_has_one_core_rel, association) 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
      67 68 69  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 67 def identity @node_var || _result_string(_chain_level + 1) end  | 
  
#init_outer_query_var(var) ⇒ Object
      108 109 110  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 108 def init_outer_query_var(var) chain.find(&:start_of_subquery?)&.tap { |link| @outer_query_var = link.subquery_var(var) } end  | 
  
#inspect ⇒ Object
      57 58 59 60  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 57 def inspect formatted_nodes = ActiveGraph::Node::NodeListFormatter.new(to_a) "#<QueryProxy #{@context} #{formatted_nodes.inspect}>" end  | 
  
#new_link(node_var = nil) ⇒ Object
      287 288 289 290 291 292  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 287 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
      281 282 283  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 281 def optional? @optional == true end  | 
  
#params(params) ⇒ Object
      80 81 82  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 80 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
      85 86 87  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 85 def query query_as(identity) end  | 
  
#query_as(var, with_labels = true) ⇒ Object
Build a ActiveGraph::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) ActiveGraph::Core::Query.
- .. code-block
 - 
ruby
 
student.lessons.query_as(:l).with('your cypher here...')
  
      96 97 98 99 100 101 102 103 104 105 106  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 96 def query_as(var, with_labels = true) init_outer_query_var(var) var_name = @outer_query_var || var query_obj = if chain.first&.start_of_subquery? && !@association && !starting_query _query else base_query(var_name, with_labels).params(@params) end query_from_chain(chain, query_obj, var_name).tap { |query| query.proxy_chain_level = _chain_level } end  | 
  
#query_from_chain(chain, base_query, var) ⇒ Object
      112 113 114 115 116 117 118 119  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 112 def query_from_chain(chain, base_query, var) chain.inject(base_query) do |query, link| args = link.args(var, rel_var) var = link.update_outer_query_var(var) args.is_a?(Array) ? query.send(link.clause, *args) : query.send(link.clause, args) end end  | 
  
#read_attribute_for_serialization(*args) ⇒ Object
      255 256 257  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 255 def read_attribute_for_serialization(*args) to_a.map { |o| o.read_attribute_for_serialization(*args) } end  | 
  
#rel_identity ⇒ Object
      74 75 76 77 78  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 74 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
      277 278 279  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 277 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.
      150 151 152 153 154 155 156  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 150 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
      182 183 184 185  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 182 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  | 
  
#union(*args) ⇒ Object
      164 165 166 167  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 164 def union(*args) hash_args = {proxy: self, subquery_parts: args, first_clause: @chain.blank?} build_deeper_query_proxy(:union, hash_args) end  | 
  
#unpersisted_start_object? ⇒ Boolean
      294 295 296  | 
    
      # File 'lib/active_graph/node/query/query_proxy.rb', line 294 def unpersisted_start_object? @start_object && @start_object.new_record? end  |