QueryProxyMethods

Constants

  • FIRST
  • LAST

Methods

#all_rels_to

Returns all relationships across a QueryProxy chain between a given node or array of nodes and the preceeding link.

def rels_to(node)
  self.match_to(node).pluck(rel_var)
end
#as_models

Takes an Array of ActiveNode models and applies the appropriate WHERE clause So for a Teacher model inheriting from a Person model and an Article model if you called .as_models([Teacher, Article]) The where clause would look something like:

WHERE (node_var:Teacher:Person OR node_var:Article)
def as_models(models)
  where_clause = models.map do |model|
    "`#{identity}`:" + model.mapped_label_names.map do |mapped_label_name|
      "`#{mapped_label_name}`"
    end.join(':')
  end.join(' OR ')

  where("(#{where_clause})")
end

#blank?

def empty?(target = nil)
  query_with_target(target) { |var| !self.exists?(nil, var) }
end

#count

def count(distinct = nil, target = nil)
  fail(InvalidParameterError, ':count accepts `distinct` or nil as a parameter') unless distinct.nil? || distinct == :distinct
  query_with_target(target) do |var|
    q = distinct.nil? ? var : "DISTINCT #{var}"
    limited_query = self.query.clause?(:limit) ? self.query.with(var) : self.query.reorder
    limited_query.pluck("count(#{q}) AS #{var}").first
  end
end
#delete

Deletes the relationship between a node and its last link in the QueryProxy chain. Executed in the database, callbacks will not run.

def delete(node)
  self.match_to(node).query.delete(rel_var).exec
  clear_source_object_cache
end
#delete_all

Deletes a group of nodes and relationships within a QP chain. When identifier is omitted, it will remove the last link in the chain. The optional argument must be a node identifier. A relationship identifier will result in a Cypher Error

def delete_all(identifier = nil)
  query_with_target(identifier) do |target|
    begin
      self.query.with(target).optional_match("(#{target})-[#{target}_rel]-()").delete("#{target}, #{target}_rel").exec
    rescue Neo4j::Session::CypherError
      self.query.delete(target).exec
    end
    clear_source_object_cache
  end
end
#delete_all_rels

Deletes the relationships between all nodes for the last step in the QueryProxy chain. Executed in the database, callbacks will not be run.

def delete_all_rels
  return unless start_object && start_object._persisted_obj
  self.query.delete(rel_var).exec
end
#destroy

Returns all relationships between a node and its last link in the QueryProxy chain, destroys them in Ruby. Callbacks will be run.

def destroy(node)
  self.rels_to(node).map!(&:destroy)
  clear_source_object_cache
end

#empty?

def empty?(target = nil)
  query_with_target(target) { |var| !self.exists?(nil, var) }
end

#exists?

def exists?(node_condition = nil, target = nil)
  fail(InvalidParameterError, ':exists? only accepts neo_ids') unless node_condition.is_a?(Integer) || node_condition.is_a?(Hash) || node_condition.nil?
  query_with_target(target) do |var|
    start_q = exists_query_start(node_condition, var)
    start_q.query.reorder.return("COUNT(#{var}) AS count").first.count > 0
  end
end
#find

Give ability to call #find on associations to get a scoped find Doesn’t pass through via method_missing because Enumerable has a #find method

def find(*args)
  scoping { @model.find(*args) }
end
#find_or_create_by

When called, this method returns a single node that satisfies the match specified in the params hash. If no existing node is found to satisfy the match, one is created or associated as expected.

def find_or_create_by(params)
  fail 'Method invalid when called on Class objects' unless source_object
  result = self.where(params).first
  return result unless result.nil?
  Neo4j::Transaction.run do
    node = model.find_or_create_by(params)
    self << node
    return node
  end
end

#first

def first(target = nil)
  first_and_last(FIRST, target)
end
#first_rel_to

Gives you the first relationship between the last link of a QueryProxy chain and a given node Shorthand for MATCH (start)-[r]-(other_node) WHERE ID(other_node) = #{other_node.neo_id} RETURN r

def first_rel_to(node)
  self.match_to(node).limit(1).pluck(rel_var).first
end

#include?

def include?(other, target = nil)
  query_with_target(target) do |var|
    where_filter = if other.respond_to?(:neo_id)
                     "ID(#{var}) = {other_node_id}"
                   else
                     "#{var}.#{association_id_key} = {other_node_id}"
                   end
    node_id = other.respond_to?(:neo_id) ? other.neo_id : other
    self.where(where_filter).params(other_node_id: node_id).query.return("count(#{var}) as count").first.count > 0
  end
end

#last

def last(target = nil)
  first_and_last(LAST, target)
end

#length

def count(distinct = nil, target = nil)
  fail(InvalidParameterError, ':count accepts `distinct` or nil as a parameter') unless distinct.nil? || distinct == :distinct
  query_with_target(target) do |var|
    q = distinct.nil? ? var : "DISTINCT #{var}"
    limited_query = self.query.clause?(:limit) ? self.query.with(var) : self.query.reorder
    limited_query.pluck("count(#{q}) AS #{var}").first
  end
end
#limit_value

TODO: update this with public API methods if/when they are exposed

def limit_value
  return unless self.query.clause?(:limit)
  limit_clause = self.query.send(:clauses).find { |clause| clause.is_a?(Neo4j::Core::QueryClauses::LimitClause) }
  limit_clause.instance_variable_get(:@arg)
end
#match_to

Shorthand for MATCH (start)-[r]-(other_node) WHERE ID(other_node) = #{other_node.neo_id} The node param can be a persisted ActiveNode instance, any string or integer, or nil. When it’s a node, it’ll use the object’s neo_id, which is fastest. When not nil, it’ll figure out the primary key of that model. When nil, it uses 1 = 2 to prevent matching all records, which is the default behavior when nil is passed to where in QueryProxy.

def match_to(node)
  first_node = node.is_a?(Array) ? node.first : node
  where_arg = if first_node.respond_to?(:neo_id)
                {neo_id: node.is_a?(Array) ? node.map(&:neo_id) : node}
              elsif !node.nil?
                {association_id_key => node.is_a?(Array) ? ids_array(node) : node}
              else
                # support for null object pattern
                '1 = 2'
              end

  self.where(where_arg)
end
#optional

A shortcut for attaching a new, optional match to the end of a QueryProxy chain.

def optional(association, node_var = nil, rel_var = nil)
  self.send(association, node_var, rel_var, optional: true)
end

#order_property

def order_property
  # This should maybe be based on a setting in the association
  # rather than a hardcoded `nil`
  model ? model.id_property_name : nil
end

#rel

def rel
  rels.first
end

#rels

def rels
  fail 'Cannot get rels without a relationship variable.' if !@rel_var

  pluck(@rel_var)
end
#rels_to

Returns all relationships across a QueryProxy chain between a given node or array of nodes and the preceeding link.

def rels_to(node)
  self.match_to(node).pluck(rel_var)
end
#replace_with

Deletes the relationships between all nodes for the last step in the QueryProxy chain and replaces them with relationships to the given nodes. Executed in the database, callbacks will not be run.

def replace_with(node_or_nodes)
  nodes = Array(node_or_nodes)

  self.delete_all_rels
  nodes.each { |node| self << node }
end

#size

def count(distinct = nil, target = nil)
  fail(InvalidParameterError, ':count accepts `distinct` or nil as a parameter') unless distinct.nil? || distinct == :distinct
  query_with_target(target) do |var|
    q = distinct.nil? ? var : "DISTINCT #{var}"
    limited_query = self.query.clause?(:limit) ? self.query.with(var) : self.query.reorder
    limited_query.pluck("count(#{q}) AS #{var}").first
  end
end