neo4j 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +10 -0
  3. data/Gemfile +6 -16
  4. data/README.md +5 -2
  5. data/bin/neo4j-jars +6 -6
  6. data/lib/neo4j.rb +13 -9
  7. data/lib/neo4j/active_node.rb +9 -9
  8. data/lib/neo4j/active_node/dependent.rb +11 -0
  9. data/lib/neo4j/active_node/dependent/association_methods.rb +28 -0
  10. data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +48 -0
  11. data/lib/neo4j/active_node/has_n.rb +124 -112
  12. data/lib/neo4j/active_node/has_n/association.rb +45 -30
  13. data/lib/neo4j/active_node/id_property.rb +22 -19
  14. data/lib/neo4j/active_node/initialize.rb +2 -4
  15. data/lib/neo4j/active_node/labels.rb +23 -22
  16. data/lib/neo4j/active_node/node_wrapper.rb +5 -8
  17. data/lib/neo4j/active_node/orm_adapter.rb +2 -4
  18. data/lib/neo4j/active_node/persistence.rb +5 -10
  19. data/lib/neo4j/active_node/property.rb +3 -4
  20. data/lib/neo4j/active_node/query.rb +27 -6
  21. data/lib/neo4j/active_node/query/query_proxy.rb +65 -110
  22. data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +67 -0
  23. data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +0 -1
  24. data/lib/neo4j/active_node/query/query_proxy_methods.rb +29 -28
  25. data/lib/neo4j/active_node/query_methods.rb +6 -6
  26. data/lib/neo4j/active_node/reflection.rb +3 -2
  27. data/lib/neo4j/active_node/rels.rb +1 -1
  28. data/lib/neo4j/active_node/scope.rb +13 -8
  29. data/lib/neo4j/active_node/validations.rb +5 -6
  30. data/lib/neo4j/active_rel.rb +1 -2
  31. data/lib/neo4j/active_rel/callbacks.rb +3 -3
  32. data/lib/neo4j/active_rel/persistence.rb +9 -7
  33. data/lib/neo4j/active_rel/property.rb +12 -4
  34. data/lib/neo4j/active_rel/query.rb +6 -8
  35. data/lib/neo4j/active_rel/rel_wrapper.rb +0 -2
  36. data/lib/neo4j/active_rel/related_node.rb +4 -5
  37. data/lib/neo4j/active_rel/types.rb +4 -6
  38. data/lib/neo4j/active_rel/validations.rb +0 -1
  39. data/lib/neo4j/config.rb +11 -23
  40. data/lib/neo4j/core/query.rb +1 -1
  41. data/lib/neo4j/migration.rb +17 -18
  42. data/lib/neo4j/paginated.rb +4 -4
  43. data/lib/neo4j/railtie.rb +19 -19
  44. data/lib/neo4j/shared.rb +7 -3
  45. data/lib/neo4j/shared/callbacks.rb +15 -4
  46. data/lib/neo4j/shared/identity.rb +2 -2
  47. data/lib/neo4j/shared/persistence.rb +10 -21
  48. data/lib/neo4j/shared/property.rb +17 -30
  49. data/lib/neo4j/shared/rel_type_converters.rb +1 -3
  50. data/lib/neo4j/shared/type_converters.rb +13 -25
  51. data/lib/neo4j/shared/validations.rb +3 -3
  52. data/lib/neo4j/tasks/migration.rake +7 -7
  53. data/lib/neo4j/type_converters.rb +1 -1
  54. data/lib/neo4j/version.rb +1 -1
  55. data/lib/rails/generators/neo4j/model/model_generator.rb +16 -12
  56. data/lib/rails/generators/neo4j_generator.rb +18 -18
  57. data/neo4j.gemspec +22 -18
  58. metadata +103 -1
@@ -22,7 +22,7 @@ module Neo4j
22
22
  # Get an instance by id of the model
23
23
  def get!(id)
24
24
  klass.find(wrap_key(id)).tap do |node|
25
- raise "No record found" if node.nil?
25
+ fail 'No record found' if node.nil?
26
26
  end
27
27
  end
28
28
 
@@ -68,7 +68,7 @@ module Neo4j
68
68
  private
69
69
 
70
70
  def hasherize_order(order)
71
- (order || []).map {|clause| Hash[*clause] }
71
+ (order || []).map { |clause| Hash[*clause] }
72
72
  end
73
73
 
74
74
  def extract_id!(conditions)
@@ -76,8 +76,6 @@ module Neo4j
76
76
  conditions[klass.id_property_name.to_sym] = id
77
77
  end
78
78
  end
79
-
80
79
  end
81
80
  end
82
81
  end
83
-
@@ -1,12 +1,11 @@
1
1
  module Neo4j::ActiveNode
2
2
  module Persistence
3
-
4
3
  class RecordInvalidError < RuntimeError
5
4
  attr_reader :record
6
5
 
7
6
  def initialize(record)
8
7
  @record = record
9
- super(@record.errors.full_messages.join(", "))
8
+ super(@record.errors.full_messages.join(', '))
10
9
  end
11
10
  end
12
11
 
@@ -18,7 +17,7 @@ module Neo4j::ActiveNode
18
17
  # If the model is new a record gets created in the database, otherwise the existing record gets updated.
19
18
  # If perform_validation is true validations run.
20
19
  # If any of them fail the action is cancelled and save returns false. If the flag is false validations are bypassed altogether. See ActiveRecord::Validations for more information.
21
- # Theres a series of callbacks associated with save. If any of the before_* callbacks return false the action is cancelled and save returns false.
20
+ # There's a series of callbacks associated with save. If any of the before_* callbacks return false the action is cancelled and save returns false.
22
21
  def save(*)
23
22
  update_magic_properties
24
23
  clear_association_cache
@@ -36,9 +35,7 @@ module Neo4j::ActiveNode
36
35
  # @see Neo4j::Rails::Validations Neo4j::Rails::Validations - for the :validate parameter
37
36
  # @see Neo4j::Rails::Callbacks Neo4j::Rails::Callbacks - for callbacks
38
37
  def save!(*args)
39
- unless save(*args)
40
- raise RecordInvalidError.new(self)
41
- end
38
+ fail RecordInvalidError, self unless save(*args)
42
39
  end
43
40
 
44
41
  # Creates a model with values matching those of the instance attributes and returns its id.
@@ -70,7 +67,7 @@ module Neo4j::ActiveNode
70
67
  module ClassMethods
71
68
  # Creates and saves a new node
72
69
  # @param [Hash] props the properties the new node should have
73
- def create(props = {}, &block)
70
+ def create(props = {})
74
71
  association_props = extract_association_attributes!(props)
75
72
 
76
73
  new(props).tap do |obj|
@@ -83,7 +80,7 @@ module Neo4j::ActiveNode
83
80
  end
84
81
 
85
82
  # Same as #create, but raises an error if there is a problem during save.
86
- def create!(*args, &block)
83
+ def create!(*args)
87
84
  props = args[0] || {}
88
85
  association_props = extract_association_attributes!(props)
89
86
 
@@ -109,10 +106,8 @@ module Neo4j::ActiveNode
109
106
  def load_entity(id)
110
107
  Neo4j::Node.load(id)
111
108
  end
112
-
113
109
  end
114
110
 
115
111
  private
116
-
117
112
  end
118
113
  end
@@ -3,19 +3,18 @@ module Neo4j::ActiveNode
3
3
  extend ActiveSupport::Concern
4
4
  include Neo4j::Shared::Property
5
5
 
6
- def initialize(attributes={}, options={})
6
+ def initialize(attributes = {}, options = {})
7
7
  super(attributes, options)
8
8
 
9
- send_props(@relationship_props) if persisted? and not @relationship_props.nil?
9
+ send_props(@relationship_props) if persisted? && !@relationship_props.nil?
10
10
  end
11
11
 
12
12
  module ClassMethods
13
-
14
13
  # Extracts keys from attributes hash which are relationships of the model
15
14
  # TODO: Validate separately that relationships are getting the right values? Perhaps also store the values and persist relationships on save?
16
15
  def extract_association_attributes!(attributes)
17
16
  attributes.keys.each_with_object({}) do |key, association_props|
18
- association_props[key] = attributes.delete(key) if self.has_association?(key)
17
+ association_props[key] = attributes.delete(key) if self.association?(key)
19
18
  end
20
19
  end
21
20
  end
@@ -1,6 +1,5 @@
1
1
  module Neo4j
2
2
  module ActiveNode
3
-
4
3
  # Helper methods to return Neo4j::Core::Query objects. A query object can be used to successively build a cypher query
5
4
  #
6
5
  # person.query_as(:n).match('n-[:friend]-o').return(o: :name) # Return the names of all the person's friends
@@ -12,12 +11,25 @@ module Neo4j
12
11
  #
13
12
  # @example Return the names of all of Mike's friends
14
13
  # # Generates: MATCH (mike:Person), mike-[:friend]-friend WHERE ID(mike) = 123 RETURN friend.name
15
- # mike.query_as(:mike).match('mike-[:friend]-friend').return(friend: :name)
14
+ # mike.query_as(:mike).match('mike-[:friend]-friend').return(friend: :name)
16
15
  #
17
16
  # @param var [Symbol, String] The variable name to specify in the query
18
17
  # @return [Neo4j::Core::Query]
19
- def query_as(var)
20
- self.class.query_as(var).where("ID(#{var})" => self.neo_id)
18
+ def query_as(node_var)
19
+ self.class.query_as(node_var).where("ID(#{node_var})" => self.neo_id)
20
+ end
21
+
22
+ # Starts a new QueryProxy with the starting identifier set to the given argument and QueryProxy caller set to the node instance.
23
+ # This method does not exist within QueryProxy and can only be used to start a new chain.
24
+ #
25
+ # @example Start a new QueryProxy chain with the first identifier set manually
26
+ # # Generates: MATCH (s:`Student`), (l:`Lesson`), s-[rel1:`ENROLLED_IN`]->(l:`Lesson`) WHERE ID(s) = {neo_id_17963}
27
+ # student.as(:s).lessons(:l)
28
+ #
29
+ # @param [String, Symbol] node_var The identifier to use within the QueryProxy object
30
+ # @return [Neo4j::ActiveNode::Query::QueryProxy]
31
+ def as(node_var)
32
+ self.class.query_proxy(node: node_var, caller: self).match_to(self)
21
33
  end
22
34
 
23
35
  module ClassMethods
@@ -34,7 +46,7 @@ module Neo4j
34
46
  end
35
47
 
36
48
  Neo4j::ActiveNode::Query::QueryProxy::METHODS.each do |method|
37
- module_eval(%Q{
49
+ module_eval(%{
38
50
  def #{method}(*args)
39
51
  self.query_proxy.#{method}(*args)
40
52
  end}, __FILE__, __LINE__)
@@ -44,10 +56,19 @@ module Neo4j
44
56
  Neo4j::ActiveNode::Query::QueryProxy.new(self, nil, options)
45
57
  end
46
58
 
59
+ # Start a new QueryProxy with the starting identifier set to the given argument.
60
+ # This method does not exist within QueryProxy, it can only be called at the class level to create a new QP object.
61
+ # To set an identifier within a QueryProxy chain, give it as the first argument to a chained association.
62
+ #
63
+ # @example Start a new QueryProxy where the first identifier is set manually.
64
+ # # Generates: MATCH (s:`Student`), (result_lessons:`Lesson`), s-[rel1:`ENROLLED_IN`]->(result_lessons:`Lesson`)
65
+ # Student.as(:s).lessons
66
+ #
67
+ # @param [String, Symbol] node_var A string or symbol to use as the starting identifier.
68
+ # @return [Neo4j::ActiveNode::Query::QueryProxy]
47
69
  def as(node_var)
48
70
  query_proxy(node: node_var)
49
71
  end
50
-
51
72
  end
52
73
  end
53
74
  end
@@ -2,10 +2,10 @@ module Neo4j
2
2
  module ActiveNode
3
3
  module Query
4
4
  class QueryProxy
5
-
6
- include Enumerable
5
+ include Neo4j::ActiveNode::Query::QueryProxyEnumerable
7
6
  include Neo4j::ActiveNode::Query::QueryProxyMethods
8
7
  include Neo4j::ActiveNode::Query::QueryProxyFindInBatches
8
+ include Neo4j::ActiveNode::Dependent::QueryProxyMethods
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.
@@ -49,82 +49,18 @@ module Neo4j
49
49
 
50
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
51
51
  # in the QueryProxy chain.
52
+ attr_reader :node_var
52
53
  def identity
53
54
  @node_var || _result_string
54
55
  end
55
56
  alias_method :node_identity, :identity
56
57
 
57
58
  # The relationship identifier most recently used by the QueryProxy chain.
59
+ attr_reader :rel_var
58
60
  def rel_identity
59
- @rel_var
60
- end
61
-
62
- # Executes the query against the database if the results are not already present in a node's association cache. This method is
63
- # shared by <tt>each</tt>, <tt>each_rel</tt>, and <tt>each_with_rel</tt>.
64
- # @param [String,Symbol] node The string or symbol of the node to return from the database.
65
- # @param [String,Symbol] rel The string or symbol of a relationship to return from the database.
66
- def enumerable_query(node, rel = nil)
67
- pluck_this = rel.nil? ? [node] : [node, rel]
68
- return self.pluck(*pluck_this) if @association.nil? || caller.nil?
69
- cypher_string = self.to_cypher_with_params(pluck_this)
70
- association_collection = caller.association_instance_get(cypher_string, @association)
71
- if association_collection.nil?
72
- association_collection = self.pluck(*pluck_this)
73
- caller.association_instance_set(cypher_string, association_collection, @association) unless association_collection.empty?
74
- end
75
- association_collection
76
- end
77
-
78
- # Just like every other <tt>each</tt> but it allows for optional params to support the versions that also return relationships.
79
- # The <tt>node</tt> and <tt>rel</tt> params are typically used by those other methods but there's nothing stopping you from
80
- # using `your_node.each(true, true)` instead of `your_node.each_with_rel`.
81
- # @return [Enumerable] An enumerable containing some combination of nodes and rels.
82
- def each(node = true, rel = nil, &block)
83
- if node && rel
84
- enumerable_query(identity, @rel_var).each { |obj, rel| yield obj, rel }
85
- else
86
- pluck_this = !rel ? identity : @rel_var
87
- enumerable_query(pluck_this).each { |obj| yield obj }
88
- end
89
- end
90
-
91
- # When called at the end of a QueryProxy chain, it will return the resultant relationship objects intead of nodes.
92
- # For example, to return the relationship between a given student and their lessons:
93
- # student.lessons.each_rel do |rel|
94
- # @return [Enumerable] An enumerable containing any number of applicable relationship objects.
95
- def each_rel(&block)
96
- block_given? ? each(false, true, &block) : to_enum(:each, false, true)
97
- end
61
+ ActiveSupport::Deprecation.warn 'rel_identity is deprecated and may be removed from future releases, use rel_var instead.', caller
98
62
 
99
- # When called at the end of a QueryProxy chain, it will return the nodes and relationships of the last link.
100
- # For example, to return a lesson and each relationship to a given student:
101
- # student.lessons.each_with_rel do |lesson, rel|
102
- def each_with_rel(&block)
103
- block_given? ? each(true, true, &block) : to_enum(:each, true, true)
104
- end
105
-
106
- # Does exactly what you would hope. Without it, comparing `bobby.lessons == sandy.lessons` would evaluate to false because it
107
- # would be comparing the QueryProxy objects, not the lessons themselves.
108
- def ==(value)
109
- self.to_a == value
110
- end
111
-
112
- METHODS = %w[where rel_where order skip limit]
113
-
114
- METHODS.each do |method|
115
- module_eval(%Q{
116
- def #{method}(*args)
117
- build_deeper_query_proxy(:#{method}, args)
118
- end}, __FILE__, __LINE__)
119
- end
120
- # Since there is a rel_where method, it seems only natural for there to be node_where
121
- alias_method :node_where, :where
122
- alias_method :offset, :skip
123
- alias_method :order_by, :order
124
-
125
- # For getting variables which have been defined as part of the association chain
126
- def pluck(*args)
127
- self.query.pluck(*args)
63
+ @rel_var
128
64
  end
129
65
 
130
66
  def params(params)
@@ -143,15 +79,15 @@ module Neo4j
143
79
  # @param [String,Symbol] var The identifier to use for node at this link of the QueryProxy chain.
144
80
  # student.lessons.query_as(:l).with('your cypher here...')
145
81
  def query_as(var)
146
- query = if @association
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
82
+ base_query = if @association
83
+ chain_var = _association_chain_var
84
+ label_string = @model && ":`#{@model.mapped_label_name}`"
85
+ (_association_query_start(chain_var) & _query_model_as(var)).send(_match_type, "#{chain_var}#{_association_arrow}(#{var}#{label_string})")
86
+ else
87
+ starting_query ? (starting_query & _query_model_as(var)) : _query_model_as(var)
88
+ end
153
89
  # Build a query chain via the chain, return the result
154
- @chain.inject(query.params(@params)) do |query, (method, arg)|
90
+ @chain.inject(base_query.params(@params)) do |query, (method, arg)|
155
91
  query.send(method, arg.respond_to?(:call) ? arg.call(var) : arg)
156
92
  end
157
93
  end
@@ -172,7 +108,18 @@ module Neo4j
172
108
  @model.current_scope = previous
173
109
  end
174
110
 
111
+ METHODS = %w(where rel_where order skip limit)
175
112
 
113
+ METHODS.each do |method|
114
+ module_eval(%{
115
+ def #{method}(*args)
116
+ build_deeper_query_proxy(:#{method}, args)
117
+ end}, __FILE__, __LINE__)
118
+ end
119
+ # Since there is a rel_where method, it seems only natural for there to be node_where
120
+ alias_method :node_where, :where
121
+ alias_method :offset, :skip
122
+ alias_method :order_by, :order
176
123
 
177
124
  # Cypher string for the QueryProxy's query. This will not include params. For the full output, see <tt>to_cypher_with_params</tt>.
178
125
  def to_cypher
@@ -201,7 +148,7 @@ module Neo4j
201
148
  end
202
149
 
203
150
  def create(other_nodes, properties)
204
- raise "Can only create associations on associations" unless @association
151
+ fail 'Can only create associations on associations' unless @association
205
152
  other_nodes = [other_nodes].flatten
206
153
  properties = @association.inject_classname(properties)
207
154
  other_nodes = other_nodes.map do |other_node|
@@ -213,34 +160,34 @@ module Neo4j
213
160
  end
214
161
  end.compact
215
162
 
216
- raise ArgumentError, "Node must be of the association's class when model is specified" if @model && other_nodes.any? {|other_node| !other_node.is_a?(@model) }
163
+ fail ArgumentError, "Node must be of the association's class when model is specified" if @model && other_nodes.any? { |other_node| !other_node.is_a?(@model) }
217
164
  other_nodes.each do |other_node|
218
- #Neo4j::Transaction.run do
219
- other_node.save if not other_node.persisted?
165
+ # Neo4j::Transaction.run do
166
+ other_node.save unless other_node.neo_id
220
167
 
221
- return false if @association.perform_callback(@options[:start_object], other_node, :before) == false
168
+ return false if @association.perform_callback(@options[:start_object], other_node, :before) == false
222
169
 
223
- start_object = @options[:start_object]
224
- start_object.clear_association_cache
225
- _session.query(context: @options[:context])
226
- .match("(start#{match_string(start_object)}), (end#{match_string(other_node)})").where("ID(start) = {start_id} AND ID(end) = {end_id}")
227
- .params(start_id: start_object.neo_id, end_id: other_node.neo_id)
228
- .create("start#{_association_arrow(properties, true)}end").exec
170
+ start_object = @options[:start_object]
171
+ start_object.clear_association_cache
172
+ _session.query(context: @options[:context])
173
+ .match("(start#{match_string(start_object)}), (end#{match_string(other_node)})").where('ID(start) = {start_id} AND ID(end) = {end_id}')
174
+ .params(start_id: start_object.neo_id, end_id: other_node.neo_id)
175
+ .send(create_method, "start#{_association_arrow(properties, true)}end").exec
229
176
 
230
- @association.perform_callback(@options[:start_object], other_node, :after)
231
- #end
177
+ @association.perform_callback(@options[:start_object], other_node, :after)
178
+ # end
232
179
  end
233
180
  end
234
181
 
235
182
  def read_attribute_for_serialization(*args)
236
- to_a.map {|o| o.read_attribute_for_serialization(*args) }
183
+ to_a.map { |o| o.read_attribute_for_serialization(*args) }
237
184
  end
238
185
 
239
186
  # QueryProxy objects act as a representation of a model at the class level so we pass through calls
240
187
  # This allows us to define class functions for reusable query chaining or for end-of-query aggregation/summarizing
241
188
  def method_missing(method_name, *args, &block)
242
189
  if @model && @model.respond_to?(method_name)
243
- args[2] = self if @model.has_association?(method_name) || @model.has_scope?(method_name)
190
+ args[2] = self if @model.association?(method_name) || @model.scope?(method_name)
244
191
  scoping { @model.public_send(method_name, *args, &block) }
245
192
  else
246
193
  super
@@ -252,9 +199,9 @@ module Neo4j
252
199
  end
253
200
 
254
201
  attr_reader :context
255
- attr_reader :node_var
256
202
 
257
203
  protected
204
+
258
205
  # Methods are underscored to prevent conflict with user class methods
259
206
 
260
207
  def _add_params(params)
@@ -268,7 +215,7 @@ module Neo4j
268
215
  def _query_model_as(var)
269
216
  match_arg = if @model
270
217
  label = @model.respond_to?(:mapped_label_name) ? @model.mapped_label_name : @model
271
- { var => label }
218
+ {var => label}
272
219
  else
273
220
  var
274
221
  end
@@ -310,7 +257,7 @@ module Neo4j
310
257
  elsif query_proxy = @options[:query_proxy]
311
258
  query_proxy.node_var || :"node#{_chain_level}"
312
259
  else
313
- raise "Crazy error" # TODO: Better error
260
+ fail 'Crazy error' # TODO: Better error
314
261
  end
315
262
  end
316
263
 
@@ -320,7 +267,7 @@ module Neo4j
320
267
  elsif query_proxy = @options[:query_proxy]
321
268
  query_proxy.query_as(var)
322
269
  else
323
- raise "Crazy error" # TODO: Better error
270
+ fail 'Crazy error' # TODO: Better error
324
271
  end
325
272
  end
326
273
 
@@ -336,6 +283,10 @@ module Neo4j
336
283
 
337
284
  private
338
285
 
286
+ def create_method
287
+ association.unique? ? :create_unique : :create
288
+ end
289
+
339
290
  def build_deeper_query_proxy(method, args)
340
291
  self.dup.tap do |new_query|
341
292
  args.each do |arg|
@@ -359,20 +310,12 @@ module Neo4j
359
310
  result = []
360
311
  if arg.is_a?(Hash)
361
312
  arg.each do |key, value|
362
- if @model && @model.has_association?(key)
363
-
364
- neo_id = value.try(:neo_id) || value
365
- raise ArgumentError, "Invalid value for '#{key}' condition" if not neo_id.is_a?(Integer)
313
+ if @model && @model.association?(key)
314
+ result += links_for_association(key, value, "n#{node_num}")
366
315
 
367
- n_string = "n#{node_num}"
368
- dir = @model.associations[key].direction
369
-
370
- arrow = dir == :out ? '-->' : '<--'
371
- result << [:match, ->(v) { "#{v}#{arrow}(#{n_string})" }]
372
- result << [:where, ->(v) { {"ID(#{n_string})" => neo_id.to_i} }]
373
316
  node_num += 1
374
317
  else
375
- result << [:where, ->(v) { {v => {key => value}}}]
318
+ result << [:where, ->(v) { {v => {key => value}} }]
376
319
  end
377
320
  end
378
321
  elsif arg.is_a?(String)
@@ -382,10 +325,23 @@ module Neo4j
382
325
  end
383
326
  alias_method :links_for_node_where_arg, :links_for_where_arg
384
327
 
328
+ def links_for_association(name, value, n_string)
329
+ neo_id = value.try(:neo_id) || value
330
+ fail ArgumentError, "Invalid value for '#{name}' condition" if not neo_id.is_a?(Integer)
331
+
332
+ dir = @model.associations[name].direction
333
+
334
+ arrow = dir == :out ? '-->' : '<--'
335
+ [
336
+ [:match, ->(v) { "#{v}#{arrow}(#{n_string})" }],
337
+ [:where, ->(_) { {"ID(#{n_string})" => neo_id.to_i} }]
338
+ ]
339
+ end
340
+
385
341
  # We don't accept strings here. If you want to use a string, just use where.
386
342
  def links_for_rel_where_arg(arg)
387
343
  arg.each_with_object([]) do |(key, value), result|
388
- result << [:where, ->(v) {{ rel_identity => { key => value }}}]
344
+ result << [:where, ->(_) { {rel_var => {key => value}} }]
389
345
  end
390
346
  end
391
347
 
@@ -400,4 +356,3 @@ module Neo4j
400
356
  end
401
357
  end
402
358
  end
403
-