neo4j 4.0.0.rc.1 → 4.0.0.rc.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +13 -0
- data/lib/neo4j.rb +1 -0
- data/lib/neo4j/active_node/has_n.rb +3 -6
- data/lib/neo4j/active_node/query/query_proxy.rb +39 -18
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +63 -15
- data/lib/neo4j/core/query.rb +19 -0
- data/lib/neo4j/shared/serialized_properties.rb +4 -0
- data/lib/neo4j/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28fe8a8c4370fbe08721a8ebd9f88665439a71f2
|
4
|
+
data.tar.gz: 802a04febb895b8a561e4c82b9324b159c4eb68a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37cbe5595a4991d3f13f44411c71e2c2ec4e3587489cdaec51f639668d94e3819dae84d4fc1213573fb76bac3e6f592ca3919617ea5fa1b9be840b767bf2fd41
|
7
|
+
data.tar.gz: 61781492746a92e307d2bc5769ce7d0db389c06a16864c750cec5981067594fc553d0cd0330984b9fd009b76817380cf9f6cd4224334f4c8b60572472d67b241
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
== 4.0.0.rc.3
|
2
|
+
Released minutes after rc.2 to catch one late addition!
|
3
|
+
* Adds serialization support for QueryProxy.
|
4
|
+
|
5
|
+
== 4.0.0.rc.2
|
6
|
+
This release builds on features introduced in the first RC. We are releasing this as another RC because the API may be tweaked before release.
|
7
|
+
* New `proxy_as` for Core::Query to build QueryProxy chains onto Core::Query objects!
|
8
|
+
* Using `proxy_as`, new `optional` method in QueryProxy to use the `OPTIONAL MATCH` Cypher function.
|
9
|
+
* `match_to` and methods that depend on it now support arrays of nodes or IDs.
|
10
|
+
* New `rels_to`/`all_rels_to` methods.
|
11
|
+
* New `delete` and `destroy` methods in QueryProxy to easily remove relationships.
|
12
|
+
* Serialized objects will include IDs by default.
|
13
|
+
|
1
14
|
== 4.0.0.rc.1
|
2
15
|
This release introduces API changes that may be considered breaking under certain conditions. See See https://github.com/neo4jrb/neo4j/wiki/Neo4j.rb-v4-Introduction.
|
3
16
|
Please use https://github.com/neo4jrb/neo4j/issues for support regarding this update! You can also reach us on Twitter: @neo4jrb (Brian) and @subvertallmedia (Chris).
|
data/lib/neo4j.rb
CHANGED
@@ -119,7 +119,7 @@ module HasN
|
|
119
119
|
|
120
120
|
instance_eval(%Q{
|
121
121
|
def #{name}(node = nil, rel = nil, proxy_obj = nil)
|
122
|
-
query_proxy = proxy_obj || Neo4j::ActiveNode::Query::QueryProxy.new(#{self.name}, nil, {
|
122
|
+
query_proxy = proxy_obj || Neo4j::ActiveNode::Query::QueryProxy.new(#{self.name}, nil, {
|
123
123
|
session: self.neo4j_session, query_proxy: nil, context: '#{self.name}' + '##{name}'
|
124
124
|
})
|
125
125
|
context = (query_proxy && query_proxy.context ? query_proxy.context : '#{self.name}') + '##{name}'
|
@@ -131,6 +131,7 @@ module HasN
|
|
131
131
|
node: node,
|
132
132
|
rel: rel,
|
133
133
|
context: context,
|
134
|
+
optional: query_proxy.optional?,
|
134
135
|
caller: query_proxy.caller
|
135
136
|
})
|
136
137
|
end}, __FILE__, __LINE__)
|
@@ -167,11 +168,7 @@ module HasN
|
|
167
168
|
result = #{name}_query_proxy(node: node, rel: rel, context: '#{self.name}##{name}')
|
168
169
|
association = self.class.reflect_on_association(__method__)
|
169
170
|
query_return = association_instance_get(result.to_cypher_with_params, association)
|
170
|
-
|
171
|
-
association_instance_set(result.to_cypher_with_params, result.first, association)
|
172
|
-
else
|
173
|
-
query_return
|
174
|
-
end
|
171
|
+
query_return || association_instance_set(result.to_cypher_with_params, result.first, association)
|
175
172
|
end}, __FILE__, __LINE__)
|
176
173
|
|
177
174
|
instance_eval(%Q{
|
@@ -9,7 +9,7 @@ module Neo4j
|
|
9
9
|
|
10
10
|
# The most recent node to start a QueryProxy chain.
|
11
11
|
# Will be nil when using QueryProxy chains on class methods.
|
12
|
-
attr_reader :caller, :association, :model
|
12
|
+
attr_reader :caller, :association, :model, :starting_query
|
13
13
|
|
14
14
|
# QueryProxy is ActiveNode's Cypher DSL. While the name might imply that it creates queries in a general sense,
|
15
15
|
# it is actually referring to <tt>Neo4j::Core::Query</tt>, which is a pure Ruby Cypher DSL provided by the <tt>neo4j-core</tt> gem.
|
@@ -42,13 +42,15 @@ module Neo4j
|
|
42
42
|
@session = options[:session]
|
43
43
|
@caller = options[:caller]
|
44
44
|
@chain = []
|
45
|
+
@starting_query = options[:starting_query]
|
46
|
+
@optional = options[:optional]
|
45
47
|
@params = options[:query_proxy] ? options[:query_proxy].instance_variable_get('@params') : {}
|
46
48
|
end
|
47
49
|
|
48
50
|
# The current node identifier on deck, so to speak. It is the object that will be returned by calling `each` and the last node link
|
49
51
|
# in the QueryProxy chain.
|
50
52
|
def identity
|
51
|
-
@node_var ||
|
53
|
+
@node_var || _result_string
|
52
54
|
end
|
53
55
|
alias_method :node_identity, :identity
|
54
56
|
|
@@ -142,20 +144,18 @@ module Neo4j
|
|
142
144
|
# student.lessons.query_as(:l).with('your cypher here...')
|
143
145
|
def query_as(var)
|
144
146
|
query = if @association
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
147
|
+
chain_var = _association_chain_var
|
148
|
+
label_string = @model && ":`#{@model.mapped_label_name}`"
|
149
|
+
(_association_query_start(chain_var) & _query_model_as(var)).send(_match_type, "#{chain_var}#{_association_arrow}(#{var}#{label_string})")
|
150
|
+
else
|
151
|
+
starting_query ? (starting_query & _query_model_as(var)) : _query_model_as(var)
|
152
|
+
end
|
152
153
|
# Build a query chain via the chain, return the result
|
153
154
|
@chain.inject(query.params(@params)) do |query, (method, arg)|
|
154
155
|
query.send(method, arg.respond_to?(:call) ? arg.call(var) : arg)
|
155
156
|
end
|
156
157
|
end
|
157
158
|
|
158
|
-
|
159
159
|
# Scope all queries to the current scope.
|
160
160
|
#
|
161
161
|
# Comment.where(post_id: 1).scoping do
|
@@ -182,7 +182,7 @@ module Neo4j
|
|
182
182
|
# Returns a string of the cypher query with return objects and params
|
183
183
|
# @param [Array] columns array containing symbols of identifiers used in the query
|
184
184
|
# @return [String]
|
185
|
-
def to_cypher_with_params(columns = [
|
185
|
+
def to_cypher_with_params(columns = [self.identity])
|
186
186
|
final_query = query.return_query(columns)
|
187
187
|
"#{final_query.to_cypher} | params: #{final_query.send(:merge_params)}"
|
188
188
|
end
|
@@ -232,6 +232,10 @@ module Neo4j
|
|
232
232
|
end
|
233
233
|
end
|
234
234
|
|
235
|
+
def read_attribute_for_serialization(*args)
|
236
|
+
to_a.map {|o| o.read_attribute_for_serialization(*args) }
|
237
|
+
end
|
238
|
+
|
235
239
|
# QueryProxy objects act as a representation of a model at the class level so we pass through calls
|
236
240
|
# This allows us to define class functions for reusable query chaining or for end-of-query aggregation/summarizing
|
237
241
|
def method_missing(method_name, *args, &block)
|
@@ -243,6 +247,10 @@ module Neo4j
|
|
243
247
|
end
|
244
248
|
end
|
245
249
|
|
250
|
+
def optional?
|
251
|
+
@optional == true
|
252
|
+
end
|
253
|
+
|
246
254
|
attr_reader :context
|
247
255
|
attr_reader :node_var
|
248
256
|
|
@@ -259,12 +267,23 @@ module Neo4j
|
|
259
267
|
|
260
268
|
def _query_model_as(var)
|
261
269
|
match_arg = if @model
|
262
|
-
|
263
|
-
|
270
|
+
label = @model.respond_to?(:mapped_label_name) ? @model.mapped_label_name : @model
|
271
|
+
{ var => label }
|
272
|
+
else
|
273
|
+
var
|
274
|
+
end
|
275
|
+
_session.query(context: @context).send(_match_type, match_arg)
|
276
|
+
end
|
277
|
+
|
278
|
+
# TODO: Refactor this. Too much happening here.
|
279
|
+
def _result_string
|
280
|
+
if self.association
|
281
|
+
"result_#{self.association.name}".to_sym
|
282
|
+
elsif self.model
|
283
|
+
"result_#{self.model.name.tr!(':', '')}".to_sym
|
264
284
|
else
|
265
|
-
|
285
|
+
:result
|
266
286
|
end
|
267
|
-
_session.query(context: @context).match(match_arg)
|
268
287
|
end
|
269
288
|
|
270
289
|
def _session
|
@@ -276,9 +295,7 @@ module Neo4j
|
|
276
295
|
end
|
277
296
|
|
278
297
|
def _chain_level
|
279
|
-
if @options[:
|
280
|
-
1
|
281
|
-
elsif query_proxy = @options[:query_proxy]
|
298
|
+
if query_proxy = @options[:query_proxy]
|
282
299
|
query_proxy._chain_level + 1
|
283
300
|
else
|
284
301
|
1
|
@@ -309,6 +326,10 @@ module Neo4j
|
|
309
326
|
:"rel#{_chain_level - 1}"
|
310
327
|
end
|
311
328
|
|
329
|
+
def _match_type
|
330
|
+
@optional ? :optional_match : :match
|
331
|
+
end
|
332
|
+
|
312
333
|
attr_writer :context
|
313
334
|
|
314
335
|
private
|
@@ -59,7 +59,7 @@ module Neo4j
|
|
59
59
|
rescue Neo4j::Session::CypherError
|
60
60
|
self.query.delete(target).exec
|
61
61
|
end
|
62
|
-
|
62
|
+
clear_caller_cache
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -68,36 +68,84 @@ module Neo4j
|
|
68
68
|
# When it's a node, it'll use the object's neo_id, which is fastest. When not nil, it'll figure out the
|
69
69
|
# primary key of that model. When nil, it uses `1 = 2` to prevent matching all records, which is the default
|
70
70
|
# behavior when nil is passed to `where` in QueryProxy.
|
71
|
+
# @param [#neo_id, String, Enumerable] node A node, a string representing a node's ID, or an enumerable of nodes or IDs.
|
71
72
|
# @return [Neo4j::ActiveNode::Query::QueryProxy] A QueryProxy object upon which you can build.
|
72
73
|
def match_to(node)
|
73
|
-
if node.respond_to?(:neo_id)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
74
|
+
where_arg = if node.respond_to?(:neo_id)
|
75
|
+
{ neo_id: node.neo_id }
|
76
|
+
elsif !node.nil?
|
77
|
+
id_key = association_id_key
|
78
|
+
node = ids_array(node) if node.is_a?(Array)
|
79
|
+
{ id_key => node }
|
80
|
+
else
|
81
|
+
# support for null object pattern
|
82
|
+
'1 = 2'
|
83
|
+
end
|
84
|
+
self.where(where_arg)
|
82
85
|
end
|
83
86
|
|
84
87
|
# Gives you the first relationship between the last link of a QueryProxy chain and a given node
|
85
88
|
# Shorthand for `MATCH (start)-[r]-(other_node) WHERE ID(other_node) = #{other_node.neo_id} RETURN r`
|
89
|
+
# @param [#neo_id, String, Enumerable] node An object to be sent to `match_to`. See params for that method.
|
90
|
+
# @return A relationship (ActiveRel, CypherRelationship, EmbeddedRelationship) or nil.
|
86
91
|
def first_rel_to(node)
|
87
92
|
self.match_to(node).limit(1).pluck(rel_identity).first
|
88
93
|
end
|
89
94
|
|
95
|
+
# Returns all relationships across a QueryProxy chain between a given node or array of nodes and the preceeding link.
|
96
|
+
# @param [#neo_id, String, Enumerable] node An object to be sent to `match_to`. See params for that method.
|
97
|
+
# @return An enumerable of relationship objects.
|
98
|
+
def rels_to(node)
|
99
|
+
self.match_to(node).pluck(rel_identity)
|
100
|
+
end
|
101
|
+
alias_method :all_rels_to, :rels_to
|
102
|
+
|
103
|
+
# Deletes the relationship between a node and its last link in the QueryProxy chain. Executed in the database, callbacks will not run.
|
104
|
+
def delete(node)
|
105
|
+
self.match_to(node).query.delete(rel_identity).exec
|
106
|
+
clear_caller_cache
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns all relationships between a node and its last link in the QueryProxy chain, destroys them in Ruby. Callbacks will be run.
|
110
|
+
def destroy(node)
|
111
|
+
self.rels_to(node).map!(&:destroy)
|
112
|
+
clear_caller_cache
|
113
|
+
end
|
114
|
+
|
115
|
+
# A shortcut for attaching a new, optional match to the end of a QueryProxy chain.
|
116
|
+
# TODO: It's silly that we have to call constantize here. There should be a better way of finding the target class of the destination.
|
117
|
+
def optional(association, node_id = nil)
|
118
|
+
target_qp = self.send(association)
|
119
|
+
model = target_qp.name.constantize
|
120
|
+
var = node_id || target_qp.identity
|
121
|
+
self.query.proxy_as(model, var, true)
|
122
|
+
end
|
123
|
+
|
90
124
|
private
|
91
125
|
|
92
|
-
def
|
93
|
-
|
126
|
+
def clear_caller_cache
|
127
|
+
self.caller.clear_association_cache if self.caller.respond_to?(:clear_association_cache)
|
128
|
+
end
|
129
|
+
|
130
|
+
# @return [String] The primary key of a the current QueryProxy's model or target class
|
131
|
+
def association_id_key
|
132
|
+
self.association.nil? ? model.primary_key : self.association.target_class.primary_key
|
133
|
+
end
|
134
|
+
|
135
|
+
# @param [Enumerable] node An enumerable of nodes or ids.
|
136
|
+
# @return [Array] An array after having `id` called on each object
|
137
|
+
def ids_array(node)
|
138
|
+
node.first.respond_to?(:id) ? node.map!(&:id) : node
|
139
|
+
end
|
140
|
+
|
141
|
+
def query_with_target(target)
|
142
|
+
yield(target || identity)
|
94
143
|
end
|
95
144
|
|
96
145
|
def exists_query_start(origin, condition, target)
|
97
|
-
|
98
|
-
when condition.class == Fixnum
|
146
|
+
if condition.class == Fixnum
|
99
147
|
self.where("ID(#{target}) = {exists_condition}").params(exists_condition: condition)
|
100
|
-
|
148
|
+
elsif condition.class == Hash
|
101
149
|
self.where(condition.keys.first => condition.values.first)
|
102
150
|
else
|
103
151
|
self
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Neo4j::Core
|
2
|
+
class Query
|
3
|
+
# Creates a Neo4j::ActiveNode::Query::QueryProxy object that builds off of a Core::Query object.
|
4
|
+
#
|
5
|
+
# @param [Class] model An ActiveNode model to be used as the start of a new QueryuProxy chain
|
6
|
+
# @param [Symbol] var The variable to be used to refer to the object from within the new QueryProxy
|
7
|
+
# @param [Boolean] optional Indicate whether the new QueryProxy will use MATCH or OPTIONAL MATCH.
|
8
|
+
# @return [Neo4j::ActiveNode::Query::QueryProxy] A QueryProxy object.
|
9
|
+
def proxy_as(model, var, optional = false)
|
10
|
+
# TODO: Discuss whether it's necessary to call `break` on the query or if this should be left to the user.
|
11
|
+
Neo4j::ActiveNode::Query::QueryProxy.new(model, nil, { starting_query: self.break, node: var, optional: optional })
|
12
|
+
end
|
13
|
+
|
14
|
+
# Calls proxy_as with `optional` set true. This doesn't offer anything different from calling `proxy_as` directly but it may be more readable.
|
15
|
+
def proxy_as_optional(model, var)
|
16
|
+
proxy_as(model, var, true)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/neo4j/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neo4j
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.0.rc.
|
4
|
+
version: 4.0.0.rc.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Ronge
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: orm_adapter
|
@@ -143,6 +143,7 @@ files:
|
|
143
143
|
- lib/neo4j/active_rel/types.rb
|
144
144
|
- lib/neo4j/active_rel/validations.rb
|
145
145
|
- lib/neo4j/config.rb
|
146
|
+
- lib/neo4j/core/query.rb
|
146
147
|
- lib/neo4j/migration.rb
|
147
148
|
- lib/neo4j/paginated.rb
|
148
149
|
- lib/neo4j/railtie.rb
|