module ActiveGraph::Node::Query::QueryProxyMethods
rubocop:disable Metrics/ModuleLength
Constants
- FIRST
rubocop:enable Metrics/ModuleLength
- LAST
Public Instance Methods
# File lib/active_graph/node/query/query_proxy_methods.rb 20 def as(node_var) 21 new_link(node_var) 22 end
Takes an Array of Node
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:
- .. code-block
-
cypher
WHERE (node_var:Teacher:Person OR node_var:Article)
# File lib/active_graph/node/query/query_proxy_methods.rb 184 def as_models(models) 185 where_clause = models.map do |model| 186 "`#{identity}`:" + model.mapped_label_names.map do |mapped_label_name| 187 "`#{mapped_label_name}`" 188 end.join(':') 189 end.join(' OR ') 190 191 where("(#{where_clause})") 192 end
@return [Integer] number of nodes of this class
# File lib/active_graph/node/query/query_proxy_methods.rb 55 def count(distinct = nil, target = nil) 56 return 0 if unpersisted_start_object? 57 fail(ActiveGraph::InvalidParameterError, ':count accepts the `:distinct` symbol or nil as a parameter') unless distinct.nil? || distinct == :distinct 58 query_with_target(target) do |var| 59 q = ensure_distinct(var, !distinct.nil?) 60 limited_query = self.query.clause?(:limit) ? self.query.break.with(var) : self.query.reorder 61 limited_query.pluck("count(#{q}) AS #{var}").first 62 end 63 end
# File lib/active_graph/node/query/query_proxy_methods.rb 44 def distinct 45 new_link.tap do |e| 46 e.instance_variable_set(:@distinct, true) 47 end 48 end
# File lib/active_graph/node/query/query_proxy_methods.rb 78 def empty?(target = nil) 79 return true if unpersisted_start_object? 80 query_with_target(target) { |var| !self.exists?(nil, var) } 81 end
# File lib/active_graph/node/query/query_proxy_methods.rb 101 def exists?(node_condition = nil, target = nil) 102 unless [Integer, String, Hash, NilClass].any? { |c| node_condition.is_a?(c) } 103 fail(ActiveGraph::InvalidParameterError, ':exists? only accepts ids or conditions') 104 end 105 query_with_target(target) do |var| 106 start_q = exists_query_start(node_condition, var) 107 result = start_q.query.reorder.return("ID(#{var}) AS proof_of_life LIMIT 1").first 108 !!result 109 end 110 end
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
# File lib/active_graph/node/query/query_proxy_methods.rb 26 def find(*args) 27 scoping { @model.find(*args) } 28 end
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.
# File lib/active_graph/node/query/query_proxy_methods.rb 152 def find_or_create_by(params) 153 fail 'Method invalid when called on Class objects' unless source_object 154 result = self.where(params).first 155 return result unless result.nil? 156 ActiveGraph::Base.transaction do 157 node = model.create(params) 158 self << node 159 node 160 end 161 end
# File lib/active_graph/node/query/query_proxy_methods.rb 163 def find_or_initialize_by(attributes, &block) 164 find_by(attributes) || initialize_by_current_chain_params(attributes, &block) 165 end
# File lib/active_graph/node/query/query_proxy_methods.rb 30 def first(target = nil) 31 first_and_last(FIRST, target) 32 end
# File lib/active_graph/node/query/query_proxy_methods.rb 167 def first_or_initialize(attributes = {}, &block) 168 first || initialize_by_current_chain_params(attributes, &block) 169 end
Gives you the first relationship between the last link of a QueryProxy
chain and a given node Shorthand for `MATCH (start)--(other_node) WHERE ID(other_node) = #{other_node.neo_id} RETURN r` @param [#neo_id, String, Enumerable] node An object to be sent to `match_to`. See params for that method. @return A relationship (Relationship
, CypherRelationship, EmbeddedRelationship) or nil.
# File lib/active_graph/node/query/query_proxy_methods.rb 138 def first_rel_to(node) 139 self.match_to(node).limit(1).pluck(rel_var).first 140 end
Matches all nodes having at least a relation
@example Load all people having a friend
Person.all.having_rel(:friends).to_a # => Returns a list of `Person`
@example Load all people having a best friend
Person.all.having_rel(:friends, best: true).to_a # => Returns a list of `Person`
@return [QueryProxy] A new QueryProxy
# File lib/active_graph/node/query/query_proxy_methods.rb 203 def having_rel(association_name, rel_properties = {}) 204 association = association_or_fail(association_name) 205 where("(#{identity})#{association.arrow_cypher(nil, rel_properties)}()") 206 end
@param [ActiveGraph::Node, ActiveGraph::Node
, String] other An instance of a Neo4j.rb model, a core node, or a string uuid @param [String, Symbol] target An identifier of a link in the Cypher chain @return [Boolean]
# File lib/active_graph/node/query/query_proxy_methods.rb 88 def include?(other, target = nil) 89 query_with_target(target) do |var| 90 where_filter = if other.respond_to?(:neo_id) || association_id_key == :neo_id 91 "ID(#{var}) = $other_node_id" 92 else 93 "#{var}.#{association_id_key} = $other_node_id" 94 end 95 node_id = other.respond_to?(:neo_id) ? other.neo_id : other 96 self.where(where_filter).params(other_node_id: node_id).query.reorder.return("count(#{var}) as count") 97 .first[:count].positive? 98 end 99 end
# File lib/active_graph/node/query/query_proxy_methods.rb 34 def last(target = nil) 35 first_and_last(LAST, target) 36 end
TODO: update this with public API methods if/when they are exposed
# File lib/active_graph/node/query/query_proxy_methods.rb 72 def limit_value 73 return unless self.query.clause?(:limit) 74 limit_clause = self.query.send(:clauses).find { |clause| clause.is_a?(ActiveGraph::Core::QueryClauses::LimitClause) } 75 limit_clause.instance_variable_get(:@arg) 76 end
Shorthand for `MATCH (start)--(other_node) WHERE ID(other_node) = #{other_node.neo_id}` The `node` param can be a persisted Node
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
. @param [#neo_id, String, Enumerable] node A node, a string representing a node's ID, or an enumerable of nodes or IDs. @return [ActiveGraph::Node::Query::QueryProxy] A QueryProxy
object upon which you can build.
# File lib/active_graph/node/query/query_proxy_methods.rb 119 def match_to(node) 120 first_node = node.is_a?(Array) ? node.first : node 121 where_arg = if first_node.respond_to?(:neo_id) 122 {neo_id: node.is_a?(Array) ? node.map(&:neo_id) : node} 123 elsif !node.nil? 124 {association_id_key => node.is_a?(Array) ? ids_array(node) : node} 125 else 126 # support for null object pattern 127 '1 = 2' 128 end 129 130 self.where(where_arg) 131 end
Matches all nodes not having a certain relation
@example Load all people not having friends
Person.all.not_having_rel(:friends).to_a # => Returns a list of `Person`
@example Load all people not having best friends
Person.all.not_having_rel(:friends, best: true).to_a # => Returns a list of `Person`
@return [QueryProxy] A new QueryProxy
# File lib/active_graph/node/query/query_proxy_methods.rb 217 def not_having_rel(association_name, rel_properties = {}) 218 association = association_or_fail(association_name) 219 where_not("(#{identity})#{association.arrow_cypher(nil, rel_properties)}()") 220 end
A shortcut for attaching a new, optional match to the end of a QueryProxy
chain.
# File lib/active_graph/node/query/query_proxy_methods.rb 172 def optional(association, node_var = nil, rel_var = nil) 173 self.send(association, node_var, rel_var, optional: true) 174 end
# File lib/active_graph/node/query/query_proxy_methods.rb 38 def order_property 39 # This should maybe be based on a setting in the association 40 # rather than a hardcoded `nil` 41 model ? model.id_property_name : nil 42 end
# File lib/active_graph/node/query/query_proxy_methods.rb 50 def propagate_context(query_proxy) 51 query_proxy.instance_variable_set(:@distinct, @distinct) 52 end
# File lib/active_graph/node/query/query_proxy_methods.rb 16 def rel 17 rels.first 18 end
# File lib/active_graph/node/query/query_proxy_methods.rb 10 def rels 11 fail 'Cannot get rels without a relationship variable.' if !@rel_var 12 13 pluck(@rel_var) 14 end
Returns all relationships across a QueryProxy
chain between a given node or array of nodes and the preceeding link. @param [#neo_id, String, Enumerable] node An object to be sent to `match_to`. See params for that method. @return An enumerable of relationship objects.
# File lib/active_graph/node/query/query_proxy_methods.rb 145 def rels_to(node) 146 self.match_to(node).pluck(rel_var) 147 end
# File lib/active_graph/node/query/query_proxy_methods.rb 65 def size 66 result_cache? ? result_cache_for.length : count 67 end
Private Instance Methods
@return [String] The primary key of a the current QueryProxy's model or target class
# File lib/active_graph/node/query/query_proxy_methods.rb 274 def association_id_key 275 self.association.nil? ? model.primary_key : self.association.target_class.primary_key 276 end
# File lib/active_graph/node/query/query_proxy_methods.rb 224 def association_or_fail(association_name) 225 model.associations[association_name] || fail(ArgumentError, "No such association #{association_name}") 226 end
# File lib/active_graph/node/query/query_proxy_methods.rb 288 def exists_query_start(condition, target) 289 case condition 290 when Integer 291 self.where("ID(#{target}) = $exists_condition").params(exists_condition: condition) 292 when Hash 293 self.where(condition.keys.first => condition.values.first) 294 when String 295 self.where(model.primary_key => condition) 296 else 297 self 298 end 299 end
# File lib/active_graph/node/query/query_proxy_methods.rb 228 def find_inverse_association!(model, source, association) 229 model.associations.values.find do |reverse_association| 230 association.inverse_of?(reverse_association) || 231 reverse_association.inverse_of?(association) || 232 inverse_relation_of?(source, association, model, reverse_association) 233 end || fail("Could not find reverse association for #{@context}") 234 end
# File lib/active_graph/node/query/query_proxy_methods.rb 258 def first_and_last(func, target) 259 new_query, pluck_proc = if self.query.clause?(:order) 260 [self.query.with(identity), 261 proc { |var| "#{func}(COLLECT(#{var})) as #{var}" }] 262 else 263 ord_prop = (func == LAST ? {order_property => :DESC} : order_property) 264 [self.order(ord_prop).limit(1), 265 proc { |var| var }] 266 end 267 query_with_target(target) do |var| 268 final_pluck = pluck_proc.call(var) 269 new_query.pluck(final_pluck) 270 end.first 271 end
@param [Enumerable] node An enumerable of nodes or ids. @return [Array] An array after having `id` called on each object
# File lib/active_graph/node/query/query_proxy_methods.rb 280 def ids_array(node) 281 node.first.respond_to?(:id) ? node.map(&:id) : node 282 end
# File lib/active_graph/node/query/query_proxy_methods.rb 243 def initialize_by_current_chain_params(params = {}) 244 result = new(where_clause_params.merge(params)) 245 246 inverse_association = find_inverse_association!(model, source_object.class, association) if source_object 247 result.tap do |m| 248 yield(m) if block_given? 249 m.public_send(inverse_association.name) << source_object if inverse_association 250 end 251 end
# File lib/active_graph/node/query/query_proxy_methods.rb 236 def inverse_relation_of?(source, source_association, target, target_association) 237 source_association.direction != target_association.direction && 238 source == target_association.target_class && 239 target == source_association.target_class && 240 source_association.relationship_class_name == target_association.relationship_class_name 241 end
# File lib/active_graph/node/query/query_proxy_methods.rb 284 def query_with_target(target) 285 yield(target || identity) 286 end
# File lib/active_graph/node/query/query_proxy_methods.rb 253 def where_clause_params 254 query.clauses.select { |c| c.is_a?(ActiveGraph::Core::QueryClauses::WhereClause) && c.arg.is_a?(Hash) } 255 .map! { |e| e.arg[identity] }.compact.inject { |a, b| a.merge(b) } || {} 256 end