class Neo4j::Core::Query
Allows for generation of cypher queries via ruby method calls (inspired by ActiveRecord / arel syntax)
Can be used to express cypher queries in ruby nicely, or to more easily generate queries programatically.
Also, queries can be passed around an application to progressively build a query across different concerns
See also the following link for full cypher language documentation: docs.neo4j.org/chunked/milestone/cypher-query-lang.html
Constants
- BREAK_METHODS
- CLAUSES
- CLAUSIFY_CLAUSE
- DEFINED_CLAUSES
- EMPTY
Returns a CYPHER query string from the object query representation @example
Query.new.match(p: :Person).where(p: {age: 30}) # => "MATCH (p:Person) WHERE p.age = 30
@return [String] Resulting cypher query string
- METHODS
@method detach_delete *args DETACH DELETE clause @return [Query]
- NEWLINE
Attributes
Public Class Methods
# File lib/neo4j/core/query.rb 70 def initialize(options = {}) 71 @session = options[:session] 72 73 @options = options 74 @clauses = [] 75 @_params = {} 76 @params = Parameters.new 77 end
Public Instance Methods
# File lib/neo4j/core/query.rb 393 def &(other) 394 self.class.new(session: @session).tap do |new_query| 395 new_query.options = options.merge(other.options) 396 new_query.clauses = clauses + other.clauses 397 end.params(other._params) 398 end
Allows what's been built of the query so far to be frozen and the rest built anew. Can be called multiple times in a string of method calls @example
# Creates a query representing the cypher: MATCH (q:Person), r:Car MATCH (p: Person)-->q Query.new.match(q: Person).match('r:Car').break.match('(p: Person)-->q')
# File lib/neo4j/core/query.rb 213 def break 214 build_deeper_query(nil) 215 end
# File lib/neo4j/core/query.rb 409 def clause?(method) 410 clause_class = DEFINED_CLAUSES[method] || CLAUSIFY_CLAUSE.call(method) 411 clauses.any? { |clause| clause.is_a?(clause_class) } 412 end
# File lib/neo4j/core/query.rb 362 def context 363 @options[:context] 364 end
# File lib/neo4j/core/query.rb 400 def copy 401 dup.tap do |query| 402 to_cypher 403 query.instance_variable_set('@params'.freeze, @params.copy) 404 query.instance_variable_set('@partitioned_clauses'.freeze, nil) 405 query.instance_variable_set('@response'.freeze, nil) 406 end 407 end
# File lib/neo4j/core/query.rb 271 def count(var = nil) 272 v = var.nil? ? '*' : var 273 pluck("count(#{v})").first 274 end
# File lib/neo4j/core/query.rb 276 def each 277 response = self.response 278 if defined?(Neo4j::Server::CypherResponse) && response.is_a?(Neo4j::Server::CypherResponse) 279 response.unwrapped! if unwrapped? 280 response.to_node_enumeration 281 elsif defined?(Neo4j::Core::CypherSession::Result) && response.is_a?(Neo4j::Core::CypherSession::Result) 282 response.to_a 283 else 284 Neo4j::Embedded::ResultWrapper.new(response, to_cypher, unwrapped?) 285 end.each { |object| yield object } 286 end
Executes a query without returning the result @return [Boolean] true if successful @raise [Neo4j::Server::CypherResponse::ResponseError] Raises errors from neo4j server
# File lib/neo4j/core/query.rb 297 def exec 298 response 299 300 true 301 end
# File lib/neo4j/core/query.rb 79 def inspect 80 "#<Query CYPHER: #{ANSI::YELLOW}#{to_cypher.inspect}#{ANSI::CLEAR}>" 81 end
# File lib/neo4j/core/query.rb 256 def match_nodes(hash, optional_match = false) 257 hash.inject(self) do |query, (variable, node_object)| 258 neo_id = (node_object.respond_to?(:neo_id) ? node_object.neo_id : node_object) 259 260 match_method = optional_match ? :optional_match : :match 261 query.send(match_method, variable).where(variable => {neo_id: neo_id}) 262 end 263 end
# File lib/neo4j/core/query.rb 265 def optional_match_nodes(hash) 266 match_nodes(hash, true) 267 end
# File lib/neo4j/core/query.rb 366 def parameters 367 to_cypher 368 merge_params 369 end
Allows for the specification of values for params specified in query @example
# Creates a query representing the cypher: MATCH (q: Person {id: {id}}) # Calls to params don't affect the cypher query generated, but the params will be # Passed down when the query is made Query.new.match('(q: Person {id: {id}})').params(id: 12)
# File lib/neo4j/core/query.rb 224 def params(args) 225 copy.tap { |new_query| new_query.instance_variable_get('@params'.freeze).add_params(args) } 226 end
# File lib/neo4j/core/query.rb 371 def partitioned_clauses 372 @partitioned_clauses ||= PartitionedClauses.new(@clauses) 373 end
Return the specified columns as an array. If one column is specified, a one-dimensional array is returned with the values of that column If two columns are specified, a n-dimensional array is returned with the values of those columns
@example
Query.new.match(n: :Person).return(p: :name}.pluck(p: :name) # => Array of names
@example
Query.new.match(n: :Person).return(p: :name}.pluck('p, DISTINCT p.name') # => Array of [node, name] pairs
# File lib/neo4j/core/query.rb 312 def pluck(*columns) 313 fail ArgumentError, 'No columns specified for Query#pluck' if columns.size.zero? 314 315 query = return_query(columns) 316 columns = query.response.columns 317 318 if columns.size == 1 319 column = columns[0] 320 query.map { |row| row[column] } 321 else 322 query.map { |row| columns.map { |column| row[column] } } 323 end 324 end
# File lib/neo4j/core/query.rb 358 def pretty_cypher 359 to_cypher(pretty: true) 360 end
# File lib/neo4j/core/query.rb 375 def print_cypher 376 puts to_cypher(pretty: true).gsub(/\e[^m]+m/, '') 377 end
# File lib/neo4j/core/query.rb 252 def raise_if_cypher_error!(response) 253 response.raise_cypher_error if response.respond_to?(:error?) && response.error? 254 end
Clears out previous order clauses and allows only for those specified by args
# File lib/neo4j/core/query.rb 188 def reorder(*args) 189 query = copy 190 191 query.remove_clause_class(OrderClause) 192 query.order(*args) 193 end
# File lib/neo4j/core/query.rb 241 def response 242 return @response if @response 243 244 @response = if session_is_new_api? 245 @session.query(self, transaction: Transaction.current_for(@session), wrap_level: (:core_entity if unwrapped?)) 246 else 247 @session._query(to_cypher, merge_params, 248 context: @options[:context], pretty_cypher: (pretty_cypher if self.class.pretty_cypher)).tap(&method(:raise_if_cypher_error!)) 249 end 250 end
# File lib/neo4j/core/query.rb 326 def return_query(columns) 327 query = copy 328 query.remove_clause_class(ReturnClause) 329 330 query.return(*columns) 331 end
# File lib/neo4j/core/query.rb 237 def session_is_new_api? 238 defined?(::Neo4j::Core::CypherSession) && @session.is_a?(::Neo4j::Core::CypherSession) 239 end
Works the same as the set method, but when given a nested array it will set properties rather than setting entire objects @example
# Creates a query representing the cypher: MATCH (n:Person) SET n.age = 19 Query.new.match(n: :Person).set_props(n: {age: 19})
# File lib/neo4j/core/query.rb 205 def set_props(*args) # rubocop:disable Naming/AccessorMethodName 206 build_deeper_query(SetClause, args, set_props: true) 207 end
# File lib/neo4j/core/query.rb 340 def to_cypher(options = {}) 341 join_string = options[:pretty] ? NEWLINE : EMPTY 342 343 cypher_string = partitioned_clauses.map do |clauses| 344 clauses_by_class = clauses.group_by(&:class) 345 346 cypher_parts = CLAUSES.map do |clause_class| 347 clause_class.to_cypher(clauses, options[:pretty]) if clauses = clauses_by_class[clause_class] 348 end.compact 349 350 cypher_parts.join(join_string).tap(&:strip!) 351 end.join(join_string) 352 353 cypher_string = "CYPHER #{@options[:parser]} #{cypher_string}" if @options[:parser] 354 cypher_string.tap(&:strip!) 355 end
Returns a CYPHER query specifying the union of the callee object's query and the argument's query
@example
# Generates cypher: MATCH (n:Person) UNION MATCH (o:Person) WHERE o.age = 10 q = Neo4j::Core::Query.new.match(o: :Person).where(o: {age: 10}) result = Neo4j::Core::Query.new.match(n: :Person).union_cypher(q)
@param other [Query] Second half of UNION @param options [Hash] Specify {all: true} to use UNION ALL @return [String] Resulting UNION cypher query string
# File lib/neo4j/core/query.rb 389 def union_cypher(other, options = {}) 390 "#{to_cypher} UNION#{options[:all] ? ' ALL' : ''} #{other.to_cypher}" 391 end
# File lib/neo4j/core/query.rb 228 def unwrapped 229 @_unwrapped_obj = true 230 self 231 end
# File lib/neo4j/core/query.rb 233 def unwrapped? 234 !!@_unwrapped_obj 235 end
Works the same as the where method, but the clause is surrounded by a Cypher NOT() function
# File lib/neo4j/core/query.rb 197 def where_not(*args) 198 build_deeper_query(WhereClause, args, not: true) 199 end
Protected Instance Methods
# File lib/neo4j/core/query.rb 418 def add_clauses(clauses) 419 @clauses += clauses 420 end
# File lib/neo4j/core/query.rb 422 def remove_clause_class(clause_class) 423 @clauses = @clauses.reject { |clause| clause.is_a?(clause_class) } 424 end
Private Instance Methods
# File lib/neo4j/core/query.rb 428 def build_deeper_query(clause_class, args = {}, options = {}) 429 copy.tap do |new_query| 430 new_query.add_clauses [nil] if [nil, WithClause].include?(clause_class) 431 new_query.add_clauses clause_class.from_args(args, new_query.instance_variable_get('@params'.freeze), options) if clause_class 432 end 433 end
SHOULD BE DEPRECATED
# File lib/neo4j/core/query.rb 498 def merge_params 499 @merge_params_base ||= @clauses.compact.inject({}) { |params, clause| params.merge!(clause.params) } 500 @params.to_hash.merge(@merge_params_base) 501 end