module Neo4j::ActiveNode::Query::QueryProxyMethods
rubocop:disable Metrics/ModuleLength
Constants
- FIRST
rubocop:enable Metrics/ModuleLength
- LAST
Public Instance Methods
# File lib/neo4j/active_node/query/query_proxy_methods.rb 20 def as(node_var) 21 new_link(node_var) 22 end
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:
- .. code-block
-
cypher
WHERE (node_var:Teacher:Person OR node_var:Article)
# File lib/neo4j/active_node/query/query_proxy_methods.rb 183 def as_models(models) 184 where_clause = models.map do |model| 185 "`#{identity}`:" + model.mapped_label_names.map do |mapped_label_name| 186 "`#{mapped_label_name}`" 187 end.join(':') 188 end.join(' OR ') 189 190 where("(#{where_clause})") 191 end
@return [Integer] number of nodes of this class
# File lib/neo4j/active_node/query/query_proxy_methods.rb 55 def count(distinct = nil, target = nil) 56 return 0 if unpersisted_start_object? 57 fail(Neo4j::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/neo4j/active_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/neo4j/active_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/neo4j/active_node/query/query_proxy_methods.rb 100 def exists?(node_condition = nil, target = nil) 101 unless [Integer, String, Hash, NilClass].any? { |c| node_condition.is_a?(c) } 102 fail(Neo4j::InvalidParameterError, ':exists? only accepts ids or conditions') 103 end 104 query_with_target(target) do |var| 105 start_q = exists_query_start(node_condition, var) 106 result = start_q.query.reorder.return("ID(#{var}) AS proof_of_life LIMIT 1").first 107 !!result 108 end 109 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/neo4j/active_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/neo4j/active_node/query/query_proxy_methods.rb 151 def find_or_create_by(params) 152 fail 'Method invalid when called on Class objects' unless source_object 153 result = self.where(params).first 154 return result unless result.nil? 155 Neo4j::ActiveBase.run_transaction do 156 node = model.create(params) 157 self << node 158 return node 159 end 160 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 162 def find_or_initialize_by(attributes, &block) 163 find_by(attributes) || initialize_by_current_chain_params(attributes, &block) 164 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 30 def first(target = nil) 31 first_and_last(FIRST, target) 32 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 166 def first_or_initialize(attributes = {}, &block) 167 first || initialize_by_current_chain_params(attributes, &block) 168 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 (ActiveRel
, CypherRelationship, EmbeddedRelationship) or nil.
# File lib/neo4j/active_node/query/query_proxy_methods.rb 137 def first_rel_to(node) 138 self.match_to(node).limit(1).pluck(rel_var).first 139 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/neo4j/active_node/query/query_proxy_methods.rb 202 def having_rel(association_name, rel_properties = {}) 203 association = association_or_fail(association_name) 204 where("(#{identity})#{association.arrow_cypher(nil, rel_properties)}()") 205 end
@param [Neo4j::ActiveNode, Neo4j::Node, String] other An instance of a Neo4j.rb model, a Neo4j-core node, or a string uuid @param [String, Symbol] target An identifier of a link in the Cypher chain @return [Boolean]
# File lib/neo4j/active_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").first.count > 0 97 end 98 end
# File lib/neo4j/active_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/neo4j/active_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?(Neo4j::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 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
. @param [#neo_id, String, Enumerable] node A node, a string representing a node's ID, or an enumerable of nodes or IDs. @return [Neo4j::ActiveNode::Query::QueryProxy] A QueryProxy
object upon which you can build.
# File lib/neo4j/active_node/query/query_proxy_methods.rb 118 def match_to(node) 119 first_node = node.is_a?(Array) ? node.first : node 120 where_arg = if first_node.respond_to?(:neo_id) 121 {neo_id: node.is_a?(Array) ? node.map(&:neo_id) : node} 122 elsif !node.nil? 123 {association_id_key => node.is_a?(Array) ? ids_array(node) : node} 124 else 125 # support for null object pattern 126 '1 = 2' 127 end 128 129 self.where(where_arg) 130 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/neo4j/active_node/query/query_proxy_methods.rb 216 def not_having_rel(association_name, rel_properties = {}) 217 association = association_or_fail(association_name) 218 where_not("(#{identity})#{association.arrow_cypher(nil, rel_properties)}()") 219 end
A shortcut for attaching a new, optional match to the end of a QueryProxy
chain.
# File lib/neo4j/active_node/query/query_proxy_methods.rb 171 def optional(association, node_var = nil, rel_var = nil) 172 self.send(association, node_var, rel_var, optional: true) 173 end
# File lib/neo4j/active_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/neo4j/active_node/query/query_proxy_methods.rb 50 def propagate_context(query_proxy) 51 query_proxy.instance_variable_set(:@distinct, @distinct) 52 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 16 def rel 17 rels.first 18 end
# File lib/neo4j/active_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/neo4j/active_node/query/query_proxy_methods.rb 144 def rels_to(node) 145 self.match_to(node).pluck(rel_var) 146 end
# File lib/neo4j/active_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/neo4j/active_node/query/query_proxy_methods.rb 273 def association_id_key 274 self.association.nil? ? model.primary_key : self.association.target_class.primary_key 275 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 223 def association_or_fail(association_name) 224 model.associations[association_name] || fail(ArgumentError, "No such association #{association_name}") 225 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 287 def exists_query_start(condition, target) 288 case condition 289 when Integer 290 self.where("ID(#{target}) = {exists_condition}").params(exists_condition: condition) 291 when Hash 292 self.where(condition.keys.first => condition.values.first) 293 when String 294 self.where(model.primary_key => condition) 295 else 296 self 297 end 298 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 227 def find_inverse_association!(model, source, association) 228 model.associations.values.find do |reverse_association| 229 association.inverse_of?(reverse_association) || 230 reverse_association.inverse_of?(association) || 231 inverse_relation_of?(source, association, model, reverse_association) 232 end || fail("Could not find reverse association for #{@context}") 233 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 257 def first_and_last(func, target) 258 new_query, pluck_proc = if self.query.clause?(:order) 259 [self.query.with(identity), 260 proc { |var| "#{func}(COLLECT(#{var})) as #{var}" }] 261 else 262 ord_prop = (func == LAST ? {order_property => :DESC} : order_property) 263 [self.order(ord_prop).limit(1), 264 proc { |var| var }] 265 end 266 query_with_target(target) do |var| 267 final_pluck = pluck_proc.call(var) 268 new_query.pluck(final_pluck) 269 end.first 270 end
@param [Enumerable] node An enumerable of nodes or ids. @return [Array] An array after having `id` called on each object
# File lib/neo4j/active_node/query/query_proxy_methods.rb 279 def ids_array(node) 280 node.first.respond_to?(:id) ? node.map(&:id) : node 281 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 242 def initialize_by_current_chain_params(params = {}) 243 result = new(where_clause_params.merge(params)) 244 245 inverse_association = find_inverse_association!(model, source_object.class, association) if source_object 246 result.tap do |m| 247 yield(m) if block_given? 248 m.public_send(inverse_association.name) << source_object if inverse_association 249 end 250 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 235 def inverse_relation_of?(source, source_association, target, target_association) 236 source_association.direction != target_association.direction && 237 source == target_association.target_class && 238 target == source_association.target_class && 239 source_association.relationship_class_name == target_association.relationship_class_name 240 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 283 def query_with_target(target) 284 yield(target || identity) 285 end
# File lib/neo4j/active_node/query/query_proxy_methods.rb 252 def where_clause_params 253 query.clauses.select { |c| c.is_a?(Neo4j::Core::QueryClauses::WhereClause) && c.arg.is_a?(Hash) } 254 .map! { |e| e.arg[identity] }.compact.inject { |a, b| a.merge(b) } || {} 255 end