Class: ActiveGraph::Core::Query
- Inherits:
-
Object
- Object
- ActiveGraph::Core::Query
- Includes:
- QueryClauses, QueryFindInBatches, Enumerable
- Defined in:
- lib/active_graph/core/query.rb,
lib/active_graph/core/query_ext.rb
Overview
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
Defined Under Namespace
Classes: Parameters, PartitionedClauses
Constant Summary collapse
- DEFINED_CLAUSES =
{}
- METHODS =
DETACH DELETE clause
%w[start match optional_match call using where create create_unique merge set on_create_set on_match_set remove unwind delete detach_delete with with_distinct return order skip limit]
- BREAK_METHODS =
rubocop:disable Metrics/LineLength
%(with with_distinct call)
- CLAUSIFY_CLAUSE =
proc { |method| const_get(method.to_s.split('_').map(&:capitalize).join + 'Clause') }
- CLAUSES =
METHODS.map(&CLAUSIFY_CLAUSE)
- EMPTY =
Returns a CYPHER query string from the object query representation
' '
- NEWLINE =
"\n"
Class Attribute Summary collapse
-
.pretty_cypher ⇒ Object
Returns the value of attribute pretty_cypher.
Instance Attribute Summary collapse
-
#clauses ⇒ Object
Returns the value of attribute clauses.
-
#proxy_chain_level ⇒ Object
For instances where you turn a QueryProxy into a Query and then back to a QueryProxy with `#proxy_as`.
Instance Method Summary collapse
- #&(other) ⇒ Object
-
#break ⇒ Object
Allows what's been built of the query so far to be frozen and the rest built anew.
- #clause?(method) ⇒ Boolean
- #context ⇒ Object
- #copy ⇒ Object
- #count(var = nil) ⇒ Object
-
#create(*args) ⇒ Query
CREATE clause.
-
#create_unique(*args) ⇒ Query
CREATE UNIQUE clause.
-
#delete(*args) ⇒ Query
DELETE clause.
-
#detach_delete(*args) ⇒ Query
DETACH DELETE clause.
- #each ⇒ Object
-
#exec ⇒ Boolean
Executes a query without returning the result.
-
#initialize(options = {}) ⇒ Query
constructor
A new instance of Query.
- #inspect ⇒ Object
-
#limit(*args) ⇒ Query
LIMIT clause.
-
#match(*args) ⇒ Query
MATCH clause.
- #match_nodes(hash, optional_match = false) ⇒ Object
-
#merge(*args) ⇒ Query
MERGE clause.
-
#on_create_set(*args) ⇒ Query
ON CREATE SET clause.
-
#on_match_set(*args) ⇒ Query
ON MATCH SET clause.
-
#optional_match(*args) ⇒ Query
OPTIONAL MATCH clause.
- #optional_match_nodes(hash) ⇒ Object
-
#order(*args) ⇒ Query
(also: #order_by)
ORDER BY clause.
- #parameters ⇒ Object
-
#params(args) ⇒ Object
Allows for the specification of values for params specified in query.
- #partitioned_clauses ⇒ Object
-
#pluck(*columns) ⇒ Object
Return the specified columns as an array.
- #pretty_cypher ⇒ Object
- #print_cypher ⇒ Object
-
#proxy_as(model, var, optional = false) ⇒ ActiveGraph::Node::Query::QueryProxy
Creates a ActiveGraph::Node::Query::QueryProxy object that builds off of a Core::Query object.
-
#proxy_as_optional(model, var) ⇒ Object
Calls proxy_as with `optional` set true.
- #raise_if_cypher_error!(response) ⇒ Object
-
#remove(*args) ⇒ Query
REMOVE clause.
-
#reorder(*args) ⇒ Object
Clears out previous order clauses and allows only for those specified by args.
- #response ⇒ Object
-
#return(*args) ⇒ Query
RETURN clause.
- #return_query(columns) ⇒ Object
-
#set(*args) ⇒ Query
SET clause.
-
#set_props(*args) ⇒ Object
Works the same as the #set method, but when given a nested array it will set properties rather than setting entire objects.
-
#skip(*args) ⇒ Query
(also: #offset)
SKIP clause.
-
#start(*args) ⇒ Query
START clause.
-
#to_a ⇒ Array
Class is Enumerable.
- #to_cypher(options = {}) ⇒ Object (also: #cypher)
-
#union_cypher(other, options = {}) ⇒ String
Returns a CYPHER query specifying the union of the callee object's query and the argument's query.
-
#unwind(*args) ⇒ Query
UNWIND clause.
- #unwrapped ⇒ Object
- #unwrapped? ⇒ Boolean
-
#using(*args) ⇒ Query
USING clause.
-
#where(*args) ⇒ Query
WHERE clause.
-
#where_not(*args) ⇒ Object
Works the same as the #where method, but the clause is surrounded by a Cypher NOT() function.
-
#with(*args) ⇒ Query
WITH clause.
-
#with_distinct(*args) ⇒ Query
WITH clause with DISTINCT specified.
Methods included from QueryFindInBatches
Constructor Details
#initialize(options = {}) ⇒ Query
Returns a new instance of Query.
70 71 72 73 74 75 |
# File 'lib/active_graph/core/query.rb', line 70 def initialize( = {}) @options = @clauses = [] @_params = {} @params = Parameters.new end |
Class Attribute Details
.pretty_cypher ⇒ Object
Returns the value of attribute pretty_cypher.
67 68 69 |
# File 'lib/active_graph/core/query.rb', line 67 def pretty_cypher @pretty_cypher end |
Instance Attribute Details
#clauses ⇒ Object
Returns the value of attribute clauses.
21 22 23 |
# File 'lib/active_graph/core/query.rb', line 21 def clauses @clauses end |
#proxy_chain_level ⇒ Object
For instances where you turn a QueryProxy into a Query and then back to a QueryProxy with `#proxy_as`
21 22 23 |
# File 'lib/active_graph/core/query_ext.rb', line 21 def proxy_chain_level @proxy_chain_level end |
Instance Method Details
#&(other) ⇒ Object
374 375 376 377 378 379 |
# File 'lib/active_graph/core/query.rb', line 374 def &(other) self.class.new.tap do |new_query| new_query. = .merge(other.) new_query.clauses = clauses + other.clauses end.params(other._params) end |
#break ⇒ Object
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
211 212 213 |
# File 'lib/active_graph/core/query.rb', line 211 def break build_deeper_query(nil) end |
#clause?(method) ⇒ Boolean
390 391 392 393 |
# File 'lib/active_graph/core/query.rb', line 390 def clause?(method) clause_class = DEFINED_CLAUSES[method] || CLAUSIFY_CLAUSE.call(method) clauses.any? { |clause| clause.is_a?(clause_class) } end |
#context ⇒ Object
343 344 345 |
# File 'lib/active_graph/core/query.rb', line 343 def context @options[:context] end |
#copy ⇒ Object
381 382 383 384 385 386 387 388 |
# File 'lib/active_graph/core/query.rb', line 381 def copy dup.tap do |query| to_cypher query.instance_variable_set('@params'.freeze, @params.copy) query.instance_variable_set('@partitioned_clauses'.freeze, nil) query.instance_variable_set('@response'.freeze, nil) end end |
#count(var = nil) ⇒ Object
260 261 262 263 |
# File 'lib/active_graph/core/query.rb', line 260 def count(var = nil) v = var.nil? ? '*' : var pluck("count(#{v})").first end |
#create_unique(*args) ⇒ Query
CREATE UNIQUE clause
|
# File 'lib/active_graph/core/query.rb', line 141
|
#detach_delete(*args) ⇒ Query
DETACH DELETE clause
165 |
# File 'lib/active_graph/core/query.rb', line 165 METHODS = %w[start match optional_match call using where create create_unique merge set on_create_set on_match_set remove unwind delete detach_delete with with_distinct return order skip limit] |
#each ⇒ Object
265 266 267 |
# File 'lib/active_graph/core/query.rb', line 265 def each response.each { |object| yield object } end |
#exec ⇒ Boolean
Executes a query without returning the result
278 279 280 281 282 |
# File 'lib/active_graph/core/query.rb', line 278 def exec response true end |
#inspect ⇒ Object
77 78 79 |
# File 'lib/active_graph/core/query.rb', line 77 def inspect "#<Query CYPHER: #{ANSI::YELLOW}#{to_cypher.inspect}#{ANSI::CLEAR}>" end |
#match_nodes(hash, optional_match = false) ⇒ Object
245 246 247 248 249 250 251 252 |
# File 'lib/active_graph/core/query.rb', line 245 def match_nodes(hash, optional_match = false) hash.inject(self) do |query, (variable, node_object)| neo_id = (node_object.respond_to?(:neo_id) ? node_object.neo_id : node_object) match_method = optional_match ? :optional_match : :match query.send(match_method, variable).where(variable => {neo_id: neo_id}) end end |
#on_create_set(*args) ⇒ Query
ON CREATE SET clause
|
# File 'lib/active_graph/core/query.rb', line 149
|
#optional_match(*args) ⇒ Query
OPTIONAL MATCH clause
|
# File 'lib/active_graph/core/query.rb', line 89
|
#optional_match_nodes(hash) ⇒ Object
254 255 256 |
# File 'lib/active_graph/core/query.rb', line 254 def optional_match_nodes(hash) match_nodes(hash, true) end |
#order(*args) ⇒ Query Also known as: order_by
ORDER BY clause
|
# File 'lib/active_graph/core/query.rb', line 109
|
#parameters ⇒ Object
347 348 349 350 |
# File 'lib/active_graph/core/query.rb', line 347 def parameters to_cypher merge_params end |
#params(args) ⇒ Object
Allows for the specification of values for params specified in query
222 223 224 |
# File 'lib/active_graph/core/query.rb', line 222 def params(args) copy.tap { |new_query| new_query.instance_variable_get('@params'.freeze).add_params(args) } end |
#partitioned_clauses ⇒ Object
352 353 354 |
# File 'lib/active_graph/core/query.rb', line 352 def partitioned_clauses @partitioned_clauses ||= PartitionedClauses.new(@clauses) end |
#pluck(*columns) ⇒ Object
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
293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/active_graph/core/query.rb', line 293 def pluck(*columns) fail ArgumentError, 'No columns specified for Query#pluck' if columns.size.zero? query = return_query(columns) columns = query.response.keys if columns.size == 1 column = columns[0] query.map { |row| row[column] } else query.map { |row| columns.map { |column| row[column] } } end end |
#pretty_cypher ⇒ Object
339 340 341 |
# File 'lib/active_graph/core/query.rb', line 339 def pretty_cypher to_cypher(pretty: true) end |
#print_cypher ⇒ Object
356 357 358 |
# File 'lib/active_graph/core/query.rb', line 356 def print_cypher puts to_cypher(pretty: true).gsub(/\e[^m]+m/, '') end |
#proxy_as(model, var, optional = false) ⇒ ActiveGraph::Node::Query::QueryProxy
Creates a ActiveGraph::Node::Query::QueryProxy object that builds off of a Core::Query object.
10 11 12 13 |
# File 'lib/active_graph/core/query_ext.rb', line 10 def proxy_as(model, var, optional = false) # TODO: Discuss whether it's necessary to call `break` on the query or if this should be left to the user. ActiveGraph::Node::Query::QueryProxy.new(model, nil, node: var, optional: optional, starting_query: self, chain_level: @proxy_chain_level) end |
#proxy_as_optional(model, var) ⇒ Object
Calls proxy_as with `optional` set true. This doesn't offer anything different from calling `proxy_as` directly but it may be more readable.
16 17 18 |
# File 'lib/active_graph/core/query_ext.rb', line 16 def proxy_as_optional(model, var) proxy_as(model, var, true) end |
#raise_if_cypher_error!(response) ⇒ Object
241 242 243 |
# File 'lib/active_graph/core/query.rb', line 241 def raise_if_cypher_error!(response) response.raise_cypher_error if response.respond_to?(:error?) && response.error? end |
#reorder(*args) ⇒ Object
Clears out previous order clauses and allows only for those specified by args
186 187 188 189 190 191 |
# File 'lib/active_graph/core/query.rb', line 186 def reorder(*args) query = copy query.remove_clause_class(OrderClause) query.order(*args) end |
#response ⇒ Object
235 236 237 238 239 |
# File 'lib/active_graph/core/query.rb', line 235 def response return @response if @response @response = ActiveGraph::Base.query(self, wrap: !unwrapped?) end |
#return_query(columns) ⇒ Object
307 308 309 310 311 312 |
# File 'lib/active_graph/core/query.rb', line 307 def return_query(columns) query = copy query.remove_clause_class(ReturnClause) query.return(*columns) end |
#set_props(*args) ⇒ Object
Works the same as the #set method, but when given a nested array it will set properties rather than setting entire objects
203 204 205 |
# File 'lib/active_graph/core/query.rb', line 203 def set_props(*args) # rubocop:disable Naming/AccessorMethodName build_deeper_query(SetClause, args, set_props: true) end |
#skip(*args) ⇒ Query Also known as: offset
SKIP clause
|
# File 'lib/active_graph/core/query.rb', line 117
|
#to_a ⇒ Array
Class is Enumerable. Each yield is a Hash with the key matching the variable returned and the value being the value for that key from the response
|
# File 'lib/active_graph/core/query.rb', line 269
|
#to_cypher(options = {}) ⇒ Object Also known as: cypher
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/active_graph/core/query.rb', line 321 def to_cypher( = {}) join_string = [:pretty] ? NEWLINE : EMPTY cypher_string = partitioned_clauses.map do |clauses| clauses_by_class = clauses.group_by(&:class) cypher_parts = CLAUSES.map do |clause_class| clause_class.to_cypher(clauses, [:pretty]) if clauses = clauses_by_class[clause_class] end.compact cypher_parts.join(join_string).tap(&:strip!) end.join(join_string) cypher_string = "CYPHER #{@options[:parser]} #{cypher_string}" if @options[:parser] cypher_string.tap(&:strip!) end |
#union_cypher(other, options = {}) ⇒ String
Returns a CYPHER query specifying the union of the callee object's query and the argument's query
370 371 372 |
# File 'lib/active_graph/core/query.rb', line 370 def union_cypher(other, = {}) "#{to_cypher} UNION#{[:all] ? ' ALL' : ''} #{other.to_cypher}" end |
#unwrapped ⇒ Object
226 227 228 229 |
# File 'lib/active_graph/core/query.rb', line 226 def unwrapped @_unwrapped_obj = true self end |
#unwrapped? ⇒ Boolean
231 232 233 |
# File 'lib/active_graph/core/query.rb', line 231 def unwrapped? !!@_unwrapped_obj end |
#where_not(*args) ⇒ Object
Works the same as the #where method, but the clause is surrounded by a Cypher NOT() function
195 196 197 |
# File 'lib/active_graph/core/query.rb', line 195 def where_not(*args) build_deeper_query(WhereClause, args, not: true) end |
#with_distinct(*args) ⇒ Query
WITH clause with DISTINCT specified
|
# File 'lib/active_graph/core/query.rb', line 105
|