activegraph 11.5.0.beta.3 → 12.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +17 -17
  4. data/activegraph.gemspec +1 -1
  5. data/lib/active_graph/base.rb +4 -0
  6. data/lib/active_graph/core/element.rb +142 -0
  7. data/lib/active_graph/core/entity.rb +4 -0
  8. data/lib/active_graph/core/label.rb +5 -166
  9. data/lib/active_graph/core/node.rb +0 -4
  10. data/lib/active_graph/core/query_clauses.rb +4 -4
  11. data/lib/active_graph/core/schema.rb +23 -28
  12. data/lib/active_graph/core/type.rb +13 -0
  13. data/lib/active_graph/migrations/helpers/schema.rb +10 -13
  14. data/lib/active_graph/model_schema.rb +1 -1
  15. data/lib/active_graph/node/has_n.rb +1 -1
  16. data/lib/active_graph/node/labels.rb +15 -12
  17. data/lib/active_graph/node/persistence.rb +0 -11
  18. data/lib/active_graph/node/query/query_proxy/link.rb +15 -4
  19. data/lib/active_graph/node/query/query_proxy.rb +3 -3
  20. data/lib/active_graph/node/query/query_proxy_eager_loading.rb +1 -1
  21. data/lib/active_graph/node/query/query_proxy_enumerable.rb +4 -4
  22. data/lib/active_graph/node/query/query_proxy_methods.rb +14 -16
  23. data/lib/active_graph/node/query/query_proxy_methods_of_mass_updating.rb +1 -5
  24. data/lib/active_graph/node/query.rb +1 -1
  25. data/lib/active_graph/node/query_methods.rb +9 -12
  26. data/lib/active_graph/railtie.rb +11 -10
  27. data/lib/active_graph/relationship/initialize.rb +2 -2
  28. data/lib/active_graph/relationship/persistence.rb +3 -1
  29. data/lib/active_graph/relationship/property.rb +1 -5
  30. data/lib/active_graph/relationship/query.rb +14 -9
  31. data/lib/active_graph/relationship/related_node.rb +4 -8
  32. data/lib/active_graph/relationship/types.rb +8 -0
  33. data/lib/active_graph/relationship/wrapping.rb +1 -1
  34. data/lib/active_graph/relationship.rb +4 -1
  35. data/lib/active_graph/shared/identity.rb +6 -3
  36. data/lib/active_graph/shared/persistence.rb +12 -1
  37. data/lib/active_graph/shared/query_factory.rb +1 -1
  38. data/lib/active_graph/shared/type_converters.rb +3 -2
  39. data/lib/active_graph/version.rb +1 -1
  40. data/lib/active_graph.rb +0 -2
  41. data/lib/rails/generators/migration_helper.rb +0 -3
  42. metadata +22 -26
@@ -108,7 +108,7 @@ module ActiveGraph
108
108
 
109
109
  # Deletes all nodes and connected relationships from Cypher.
110
110
  def delete_all
111
- neo4j_query("MATCH (n:`#{mapped_label_name}`) OPTIONAL MATCH (n)-[r]-() DELETE n,r")
111
+ neo4j_query("MATCH (n:`#{mapped_label_name}`) DETACH DELETE n")
112
112
  end
113
113
 
114
114
  # Returns each node to Ruby and calls `destroy`. Be careful, as this can be a very slow operation if you have many nodes. It will generate at least
@@ -127,11 +127,15 @@ module ActiveGraph
127
127
  @mapped_label_name || label_for_model
128
128
  end
129
129
 
130
+ alias mapped_element_name mapped_label_name
131
+
130
132
  # @return [ActiveGraph::Label] the label for this class
131
133
  def mapped_label
132
134
  ActiveGraph::Core::Label.new(mapped_label_name)
133
135
  end
134
136
 
137
+ alias mapped_element mapped_label
138
+
135
139
  def base_class
136
140
  unless self < ActiveGraph::Node
137
141
  fail "#{name} doesn't belong in a hierarchy descending from Node"
@@ -160,6 +164,7 @@ module ActiveGraph
160
164
 
161
165
  self.mapped_label_name = name
162
166
  end
167
+
163
168
  # rubocop:enable Naming/AccessorMethodName
164
169
 
165
170
  private
@@ -184,20 +189,18 @@ module ActiveGraph
184
189
  end
185
190
 
186
191
  def label_for_model
187
- (self.name.nil? ? object_id.to_s.to_sym : decorated_label_name)
192
+ name.nil? ? object_id.to_s.to_sym : decorated_label_name
188
193
  end
189
194
 
190
195
  def decorated_label_name
191
- name = case ActiveGraph::Config[:module_handling]
192
- when :demodulize
193
- self.name.demodulize
194
- when Proc
195
- ActiveGraph::Config[:module_handling].call self.name
196
- else
197
- self.name
198
- end
199
-
200
- name.to_sym
196
+ case ActiveGraph::Config[:module_handling]
197
+ when :demodulize
198
+ name.demodulize
199
+ when Proc
200
+ ActiveGraph::Config[:module_handling].call name
201
+ else
202
+ name
203
+ end.to_sym
201
204
  end
202
205
  end
203
206
  end
@@ -70,17 +70,6 @@ module ActiveGraph::Node
70
70
  neo4j_query(query, {props: node_props}, wrap: false).to_a[0][:n]
71
71
  end
72
72
 
73
- # As the name suggests, this inserts the primary key (id property) into the properties hash.
74
- # The method called here, `default_property_values`, is a holdover from an earlier version of the gem. It does NOT
75
- # contain the default values of properties, it contains the Default Property, which we now refer to as the ID Property.
76
- # It will be deprecated and renamed in a coming refactor.
77
- # @param [Hash] converted_props A hash of properties post-typeconversion, ready for insertion into the DB.
78
- def inject_primary_key!(converted_props)
79
- self.class.default_property_values(self).tap do |destination_props|
80
- destination_props.merge!(converted_props) if converted_props.is_a?(Hash)
81
- end
82
- end
83
-
84
73
  # @return [Array] Labels to be set on the node during a create event
85
74
  def labels_for_create
86
75
  self.class.mapped_label_names
@@ -147,8 +147,8 @@ module ActiveGraph
147
147
 
148
148
  val = if !model
149
149
  value
150
- elsif key == model.id_property_name && value.is_a?(ActiveGraph::Node)
151
- value.id
150
+ elsif key == model.id_property_name
151
+ try_id(value)
152
152
  else
153
153
  converted_value(model, key, value)
154
154
  end
@@ -156,13 +156,24 @@ module ActiveGraph
156
156
  new(:where, ->(v, _) { {v => {key => val}} })
157
157
  end
158
158
 
159
+ private def try_id(value)
160
+ case value
161
+ when Shared::Identity
162
+ value.id
163
+ when Enumerable
164
+ value.map(&method(:try_id))
165
+ else
166
+ value
167
+ end
168
+ end
169
+
159
170
  def for_association(name, value, n_string, model)
160
171
  neo_id = value.try(:neo_id) || value
161
- fail ArgumentError, "Invalid value for '#{name}' condition" if not neo_id.is_a?(Integer)
172
+ fail ArgumentError, "Invalid value for '#{name}' condition" unless neo_id.is_a?(String)
162
173
 
163
174
  [
164
175
  new(:match, ->(v, _) { "(#{v})#{model.associations[name].arrow_cypher}(#{n_string})" }),
165
- new(:where, ->(_, _) { {"ID(#{n_string})" => neo_id.to_i} })
176
+ new(:where, ->(_, _) { {"elementId(#{n_string})" => neo_id} })
166
177
  ]
167
178
  end
168
179
 
@@ -223,7 +223,7 @@ module ActiveGraph
223
223
 
224
224
  ActiveGraph::Base.transaction do
225
225
  other_nodes.each do |other_node|
226
- if other_node.neo_id
226
+ if other_node.element_id
227
227
  other_node.try(:delete_reverse_has_one_core_rel, association)
228
228
  else
229
229
  other_node.save
@@ -238,7 +238,7 @@ module ActiveGraph
238
238
 
239
239
  def _nodeify!(*args)
240
240
  other_nodes = [args].flatten!.map! do |arg|
241
- (arg.is_a?(Integer) || arg.is_a?(String)) ? @model.find_by(id: arg) : arg
241
+ arg.is_a?(String) ? @model.find_by(id: arg) : arg
242
242
  end.compact
243
243
 
244
244
  if @model && other_nodes.any? { |other_node| !other_node.class.mapped_label_names.include?(@model.mapped_label_name) }
@@ -351,7 +351,7 @@ module ActiveGraph
351
351
  fail 'Crazy error' if !(start_object || @query_proxy)
352
352
 
353
353
  if start_object
354
- :"#{start_object.class.name.gsub('::', '_').downcase}#{start_object.neo_id}"
354
+ :"#{start_object.class.name.gsub('::', '_').downcase}#{start_object.neo_id&.gsub(/[:\-]/, '_')}"
355
355
  else
356
356
  @query_proxy.node_var || :"node#{_chain_level}"
357
357
  end
@@ -62,7 +62,7 @@ module ActiveGraph
62
62
  if rel.is_a?(ActiveGraph::Relationship)
63
63
  rel.instance_variable_set(direction == :in ? '@from_node' : '@to_node', node)
64
64
  end
65
- @_cache[direction == :out ? rel.start_node_id : rel.end_node_id]
65
+ @_cache[direction == :out ? rel.start_node_element_id : rel.end_node_element_id]
66
66
  .association_proxy(element.name).add_to_cache(node, rel)
67
67
  end
68
68
 
@@ -62,22 +62,22 @@ module ActiveGraph
62
62
  # Does exactly what you would hope. Without it, comparing `bobby.lessons == sandy.lessons` would evaluate to false because it
63
63
  # would be comparing the QueryProxy objects, not the lessons themselves.
64
64
  def ==(other)
65
- self.to_a == other
65
+ to_a == other
66
66
  end
67
67
 
68
68
  # For getting variables which have been defined as part of the association chain
69
69
  def pluck(*args)
70
- transformable_attributes = (model ? model.attribute_names : []) + %w(uuid neo_id)
70
+ transformable_attributes = (model ? model.attribute_names + [model.id_property_name.to_s] : []) + %w(uuid neo_id)
71
71
  arg_list = args.map do |arg|
72
72
  arg = ActiveGraph::Node::Query::QueryProxy::Link.converted_key(model, arg)
73
73
  if transformable_attributes.include?(arg.to_s)
74
- {identity => arg}
74
+ { identity => arg }
75
75
  else
76
76
  arg
77
77
  end
78
78
  end
79
79
 
80
- self.query.pluck(*arg_list)
80
+ query.pluck(*arg_list)
81
81
  end
82
82
 
83
83
  protected
@@ -88,7 +88,7 @@ module ActiveGraph
88
88
  def include?(other, target = nil)
89
89
  query_with_target(target) do |var|
90
90
  where_filter = if other.respond_to?(:neo_id) || association_id_key == :neo_id
91
- "ID(#{var}) = $other_node_id"
91
+ "elementId(#{var}) = $other_node_id"
92
92
  else
93
93
  "#{var}.#{association_id_key} = $other_node_id"
94
94
  end
@@ -99,12 +99,12 @@ module ActiveGraph
99
99
  end
100
100
 
101
101
  def exists?(node_condition = nil, target = nil)
102
- unless [Integer, String, Hash, NilClass].any? { |c| node_condition.is_a?(c) }
102
+ unless [String, Hash, NilClass].any? { |c| node_condition.is_a?(c) }
103
103
  fail(ActiveGraph::InvalidParameterError, ':exists? only accepts ids or conditions')
104
104
  end
105
105
  query_with_target(target) do |var|
106
106
  start_q = exists_query_start(node_condition, var)
107
- result = start_q.query.reorder.return("ID(#{var}) AS proof_of_life LIMIT 1").first
107
+ result = start_q.query.reorder.return("elementId(#{var}) AS proof_of_life LIMIT 1").first
108
108
  !!result
109
109
  end
110
110
  end
@@ -119,9 +119,9 @@ module ActiveGraph
119
119
  def match_to(node)
120
120
  first_node = node.is_a?(Array) ? node.first : node
121
121
  where_arg = if first_node.respond_to?(:neo_id)
122
- {neo_id: node.is_a?(Array) ? node.map(&:neo_id) : node}
122
+ { neo_id: node.is_a?(Array) ? node.map(&:neo_id) : node }
123
123
  elsif !node.nil?
124
- {association_id_key => node.is_a?(Array) ? ids_array(node) : node}
124
+ { association_id_key => node.is_a?(Array) ? ids_array(node) : node }
125
125
  else
126
126
  # support for null object pattern
127
127
  '1 = 2'
@@ -130,7 +130,6 @@ module ActiveGraph
130
130
  self.where(where_arg)
131
131
  end
132
132
 
133
-
134
133
  # Gives you the first relationship between the last link of a QueryProxy chain and a given node
135
134
  # Shorthand for `MATCH (start)-[r]-(other_node) WHERE ID(other_node) = #{other_node.neo_id} RETURN r`
136
135
  # @param [#neo_id, String, Enumerable] node An object to be sent to `match_to`. See params for that method.
@@ -145,6 +144,7 @@ module ActiveGraph
145
144
  def rels_to(node)
146
145
  self.match_to(node).pluck(rel_var)
147
146
  end
147
+
148
148
  alias all_rels_to rels_to
149
149
 
150
150
  # When called, this method returns a single node that satisfies the match specified in the params hash.
@@ -260,7 +260,7 @@ module ActiveGraph
260
260
  [self.query.with(identity),
261
261
  proc { |var| "#{func}(COLLECT(#{var})) as #{var}" }]
262
262
  else
263
- ord_prop = (func == LAST ? {order_property => :DESC} : order_property)
263
+ ord_prop = (func == LAST ? { order_property => :DESC } : order_property)
264
264
  [self.order(ord_prop).limit(1),
265
265
  proc { |var| var }]
266
266
  end
@@ -285,16 +285,14 @@ module ActiveGraph
285
285
  yield(target || identity)
286
286
  end
287
287
 
288
- def exists_query_start(condition, target)
289
- case condition
290
- when Integer
291
- self.where("ID(#{target}) = $exists_condition").params(exists_condition: condition)
292
- when Hash
293
- self.where(condition.keys.first => condition.values.first)
294
- when String
295
- self.where(model.primary_key => condition)
288
+ def exists_query_start(condition, target = nil)
289
+ return self unless condition
290
+ return exists_query_start(model.primary_key => condition) if condition.is_a?(String)
291
+
292
+ if condition.key?(:neo_id)
293
+ where("elementId(#{target}) = $neo_id").params(**condition.slice(:neo_id))
296
294
  else
297
- self
295
+ where(**condition)
298
296
  end
299
297
  end
300
298
  end
@@ -25,11 +25,7 @@ module ActiveGraph
25
25
  # @param identifier [String,Symbol] the optional identifier of the link in the chain to delete.
26
26
  def delete_all(identifier = nil)
27
27
  query_with_target(identifier) do |target|
28
- begin
29
- self.query.with(target).optional_match("(#{target})-[#{target}_rel]-()").delete("#{target}, #{target}_rel").exec
30
- rescue Neo4j::Driver::Exceptions::ClientException # <=- Seems hacky
31
- self.query.delete(target).exec
32
- end
28
+ query.detach_delete(target).exec
33
29
  clear_source_object_cache
34
30
  end
35
31
  end
@@ -16,7 +16,7 @@ module ActiveGraph
16
16
  # @param node_var [Symbol, String] The variable name to specify in the query
17
17
  # @return [ActiveGraph::Core::Query]
18
18
  def query_as(node_var)
19
- self.class.query_as(node_var, false).where("ID(#{node_var})" => self.neo_id)
19
+ self.class.query_as(node_var, false).where("elementId(#{node_var})" => neo_id)
20
20
  end
21
21
 
22
22
  # Starts a new QueryProxy with the starting identifier set to the given argument and QueryProxy source_object set to the node instance.
@@ -2,12 +2,12 @@ module ActiveGraph
2
2
  module Node
3
3
  module QueryMethods
4
4
  def exists?(node_condition = nil)
5
- unless [Integer, String, Hash, NilClass].any? { |c| node_condition.is_a?(c) }
5
+ unless [String, Hash, NilClass].any? { |c| node_condition.is_a?(c) }
6
6
  fail(ActiveGraph::InvalidParameterError, ':exists? only accepts ids or conditions')
7
7
  end
8
8
  query_start = exists_query_start(node_condition)
9
9
  start_q = query_start.respond_to?(:query_as) ? query_start.query_as(:n) : query_start
10
- result = start_q.return('ID(n) AS proof_of_life LIMIT 1').first
10
+ result = start_q.return('elementId(n) AS proof_of_life LIMIT 1').first
11
11
  !!result
12
12
  end
13
13
 
@@ -18,7 +18,7 @@ module ActiveGraph
18
18
 
19
19
  # Returns the last node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs.
20
20
  def last
21
- self.query_as(:n).limit(1).order(n: {primary_key => :desc}).pluck(:n).first
21
+ self.query_as(:n).limit(1).order(n: { primary_key => :desc }).pluck(:n).first
22
22
  end
23
23
 
24
24
  # @return [Integer] number of nodes of this class
@@ -51,16 +51,13 @@ module ActiveGraph
51
51
 
52
52
  private
53
53
 
54
- def exists_query_start(node_condition)
55
- case node_condition
56
- when Integer
57
- self.query_as(:n).where('ID(n)' => node_condition)
58
- when String
59
- self.query_as(:n).where(n: {primary_key => node_condition})
60
- when Hash
61
- self.where(node_condition.keys.first => node_condition.values.first)
54
+ def exists_query_start(condition)
55
+ return exists_query_start(primary_key => condition) if condition&.is_a?(String)
56
+
57
+ if condition&.key?(:neo_id)
58
+ query_as(:n).where('elementId(n)' => condition[:neo_id])
62
59
  else
63
- self.query_as(:n)
60
+ where(**condition)
64
61
  end
65
62
  end
66
63
  end
@@ -1,8 +1,16 @@
1
- # Need the action_dispatch railtie to have action_dispatch.rescue_responses initialized correctly
2
- require 'action_dispatch/railtie'
3
- require 'rails/railtie'
4
1
  require 'active_graph'
5
2
 
3
+ if defined?(Rails)
4
+ # Need the action_dispatch railtie to have action_dispatch.rescue_responses initialized correctly
5
+ require 'action_dispatch/railtie'
6
+ require 'rails/generators'
7
+ require 'rails/generators/active_model'
8
+ require 'rails/generators/named_base'
9
+ require 'rails/railtie'
10
+ require File.expand_path('../rails/generators/migration_helper.rb', __dir__)
11
+ Rails::Generators::GeneratedAttribute.include ActiveGraph::Generators::GeneratedAttribute
12
+ end
13
+
6
14
  module ActiveGraph
7
15
  class Railtie < ::Rails::Railtie
8
16
  def empty_config
@@ -39,13 +47,6 @@ module ActiveGraph
39
47
  ActiveGraph::Config[:verbose_query_logs] = false
40
48
  end
41
49
 
42
- # By default, Rails loads generators from load path.
43
- # However, if we want to place generators at a different location we have to use "generators" hook
44
- # https://api.rubyonrails.org/classes/Rails/Railtie.html
45
- generators do
46
- require File.expand_path('../rails/generators/migration_helper.rb', __dir__)
47
- end
48
-
49
50
  # Starting Neo after :load_config_initializers allows apps to
50
51
  # register migrations in config/initializers
51
52
  initializer 'neo4j.start', after: :load_config_initializers do |app|
@@ -19,8 +19,8 @@ module ActiveGraph::Relationship
19
19
  def init_on_reload(unwrapped_reloaded)
20
20
  @attributes = nil
21
21
  init_on_load(unwrapped_reloaded,
22
- unwrapped_reloaded.start_node_id,
23
- unwrapped_reloaded.end_node_id,
22
+ unwrapped_reloaded.start_node_element_id,
23
+ unwrapped_reloaded.end_node_element_id,
24
24
  unwrapped_reloaded.type)
25
25
  self
26
26
  end
@@ -5,7 +5,9 @@ module ActiveGraph::Relationship
5
5
  include ActiveGraph::Shared::Persistence
6
6
 
7
7
  class RelInvalidError < RuntimeError; end
8
+
8
9
  class ModelClassInvalidError < RuntimeError; end
10
+
9
11
  class RelCreateFailedError < RuntimeError; end
10
12
 
11
13
  def from_node_identifier
@@ -84,7 +86,7 @@ module ActiveGraph::Relationship
84
86
  end
85
87
 
86
88
  def query_as(neo_id, var = :r)
87
- ActiveGraph::Base.new_query.match("()-[#{var}]->()").where(var => {neo_id: neo_id})
89
+ ActiveGraph::Base.new_query.match("()-[#{var}]->()").where(var => { neo_id: })
88
90
  end
89
91
  end
90
92
 
@@ -15,7 +15,7 @@ module ActiveGraph::Relationship
15
15
  alias end_node to_node
16
16
 
17
17
  %w(start_node end_node).each do |direction|
18
- define_method("#{direction}_id") { send(direction).neo_id if direction }
18
+ define_method("#{direction}_element_id") { send(direction).neo_id if direction }
19
19
  end
20
20
 
21
21
  # @return [String] a string representing the relationship type that will be created
@@ -45,10 +45,6 @@ module ActiveGraph::Relationship
45
45
  end
46
46
  end
47
47
 
48
- def id_property_name
49
- false
50
- end
51
-
52
48
  %w(to_class from_class).each do |direction|
53
49
  define_method(direction.to_s) do |argument = nil|
54
50
  if !argument.nil?
@@ -6,18 +6,17 @@ module ActiveGraph::Relationship
6
6
 
7
7
  module ClassMethods
8
8
  # Returns the object with the specified neo4j id.
9
- # @param [String,Integer] id of node to find
9
+ # @param [String] id of node to find
10
10
  def find(id)
11
- fail "Unknown argument #{id.class} in find method (expected String or Integer)" if !(id.is_a?(String) || id.is_a?(Integer))
12
- find_by_id(id)
11
+ fail "Unknown argument #{id.class} in find method (expected String)" unless [Integer, String].any?(&id.method(:is_a?))
12
+ find_by_id(id) || fail(RecordNotFound.new("Couldn't find #{name} with 'id'=#{id.inspect}", name, id))
13
13
  end
14
14
 
15
15
  # Loads the relationship using its neo_id.
16
16
  def find_by_id(key)
17
17
  query = ActiveGraph::Base.new_query
18
- result = query.match('()-[r]-()').where('ID(r)' => key.to_i).limit(1).return(:r).first
19
- fail RecordNotFound.new("Couldn't find #{name} with 'id'=#{key.inspect}", name, key) if result.blank?
20
- result[:r]
18
+ result = query.match('()-[r]-()').where("r.#{id_property_name}" => key).limit(1).return(:r).first
19
+ result&.send(:[], :r)
21
20
  end
22
21
 
23
22
  # Performs a very basic match on the relationship.
@@ -29,6 +28,10 @@ module ActiveGraph::Relationship
29
28
  where_query.where(where_string(args)).pluck(:r1)
30
29
  end
31
30
 
31
+ def find_by(args)
32
+ where(args).first
33
+ end
34
+
32
35
  # Performs a basic match on the relationship, returning all results.
33
36
  # This is not executed lazily, it will immediately return matching objects.
34
37
  def all
@@ -36,11 +39,11 @@ module ActiveGraph::Relationship
36
39
  end
37
40
 
38
41
  def first
39
- all_query.limit(1).order('ID(r1)').pluck(:r1).first
42
+ all_query.limit(1).order('r1.created_at').pluck(:r1).first
40
43
  end
41
44
 
42
45
  def last
43
- all_query.limit(1).order('ID(r1) DESC').pluck(:r1).first
46
+ all_query.limit(1).order('r1.created_at DESC').pluck(:r1).first
44
47
  end
45
48
 
46
49
  private
@@ -89,7 +92,9 @@ module ActiveGraph::Relationship
89
92
  def where_string(args)
90
93
  case args
91
94
  when Hash
92
- args.map { |k, v| v.is_a?(Integer) ? "r1.#{k} = #{v}" : "r1.#{k} = '#{v}'" }.join(', ')
95
+ args.transform_keys { |key| key == :neo_id ? 'elementId(r1)' : "r1.#{key}" }
96
+ .transform_values { |v| v.is_a?(Integer) ? v : "'#{v}'" }
97
+ .map { |k, v| "#{k} = #{v}" }.join(', ')
93
98
  else
94
99
  args
95
100
  end
@@ -17,7 +17,7 @@ module ActiveGraph::Relationship
17
17
 
18
18
  # Loads the node if needed, then conducts comparison.
19
19
  def ==(other)
20
- loaded if @node.is_a?(Integer)
20
+ loaded if @node.is_a?(String)
21
21
  @node == other
22
22
  end
23
23
 
@@ -62,15 +62,11 @@ module ActiveGraph::Relationship
62
62
  end
63
63
 
64
64
  def method_missing(*args, **kwargs, &block)
65
- if RUBY_VERSION < '3' && kwargs.empty?
66
- loaded.send(*args, &block)
67
- else
68
- loaded.send(*args, **kwargs, &block)
69
- end
65
+ loaded.send(*args, **kwargs, &block)
70
66
  end
71
67
 
72
68
  def respond_to_missing?(method_name, include_private = false)
73
- loaded if @node.is_a?(Numeric)
69
+ loaded if @node.is_a?(String)
74
70
  @node.respond_to?(method_name) ? true : super
75
71
  end
76
72
 
@@ -85,7 +81,7 @@ module ActiveGraph::Relationship
85
81
  end
86
82
 
87
83
  def valid_node_param?(node)
88
- node.nil? || node.is_a?(Integer) || node.respond_to?(:neo_id)
84
+ node.nil? || node.is_a?(String) || node.respond_to?(:neo_id)
89
85
  end
90
86
  end
91
87
  end
@@ -67,6 +67,14 @@ module ActiveGraph
67
67
  !!@type
68
68
  end
69
69
 
70
+ def mapped_element_name
71
+ @type
72
+ end
73
+
74
+ def mapped_element
75
+ Core::Type.new(mapped_element_name)
76
+ end
77
+
70
78
  private
71
79
 
72
80
  def assign_type!(given_type, auto)
@@ -13,7 +13,7 @@ module ActiveGraph
13
13
 
14
14
  return rel
15
15
  end.tap do |wrapped_rel|
16
- wrapped_rel.init_on_load(rel, rel.start_node_id, rel.end_node_id, rel.type)
16
+ wrapped_rel.init_on_load(rel, rel.start_node_element_id, rel.end_node_element_id, rel.type)
17
17
  end
18
18
  end
19
19
 
@@ -10,6 +10,7 @@ module ActiveGraph
10
10
  include ActiveGraph::Relationship::Initialize
11
11
  include ActiveGraph::Shared::Identity
12
12
  include ActiveGraph::Shared::Marshal
13
+ include ActiveGraph::Node::IdProperty
13
14
  include ActiveGraph::Shared::SerializedProperties
14
15
  include ActiveGraph::Relationship::Property
15
16
  include ActiveGraph::Relationship::Persistence
@@ -24,6 +25,8 @@ module ActiveGraph
24
25
  class FrozenRelError < ActiveGraph::Error; end
25
26
 
26
27
  def initialize(from_node = nil, to_node = nil, args = nil)
28
+ self.class.ensure_id_property_info! # So that we make sure all objects have an id_property
29
+
27
30
  load_nodes(node_or_nil(from_node), node_or_nil(to_node))
28
31
  resolved_args = hash_or_nil(from_node, args)
29
32
  symbol_args = sanitize_input_parameters(resolved_args)
@@ -58,7 +61,7 @@ module ActiveGraph
58
61
  private
59
62
 
60
63
  def node_or_nil(node)
61
- node.is_a?(ActiveGraph::Node) || node.is_a?(Integer) ? node : nil
64
+ node.is_a?(ActiveGraph::Node) || node.is_a?(String) ? node : nil
62
65
  end
63
66
 
64
67
  def hash_or_nil(node_or_hash, hash_or_nil)
@@ -4,6 +4,7 @@ module ActiveGraph
4
4
  def ==(other)
5
5
  other.class == self.class && other.id == id
6
6
  end
7
+
7
8
  alias eql? ==
8
9
 
9
10
  # Returns an Enumerable of all (primary) key attributes
@@ -12,11 +13,13 @@ module ActiveGraph
12
13
  _persisted_obj ? [id] : nil
13
14
  end
14
15
 
15
- # @return [Integer, nil] the neo4j id of the node if persisted or nil
16
- def neo_id
17
- _persisted_obj ? _persisted_obj.id : nil
16
+ # @return [String, nil] the neo4j id of the node if persisted or nil
17
+ def element_id
18
+ _persisted_obj&.element_id
18
19
  end
19
20
 
21
+ alias neo_id element_id
22
+
20
23
  def id
21
24
  if self.class.id_property_name
22
25
  send(self.class.id_property_name)
@@ -134,7 +134,7 @@ module ActiveGraph::Shared
134
134
  def exist?
135
135
  return if !_persisted_obj
136
136
 
137
- neo4j_query(query_as(:n).return('ID(n)')).any?
137
+ neo4j_query(query_as(:n).return('elementId(n)')).any?
138
138
  end
139
139
 
140
140
  # Returns +true+ if the object was destroyed.
@@ -223,6 +223,17 @@ module ActiveGraph::Shared
223
223
  end
224
224
  end
225
225
 
226
+ # As the name suggests, this inserts the primary key (id property) into the properties hash.
227
+ # The method called here, `default_property_values`, is a holdover from an earlier version of the gem. It does NOT
228
+ # contain the default values of properties, it contains the Default Property, which we now refer to as the ID Property.
229
+ # It will be deprecated and renamed in a coming refactor.
230
+ # @param [Hash] converted_props A hash of properties post-typeconversion, ready for insertion into the DB.
231
+ def inject_primary_key!(converted_props)
232
+ self.class.default_property_values(self).tap do |destination_props|
233
+ destination_props.merge!(converted_props) if converted_props.is_a?(Hash)
234
+ end
235
+ end
236
+
226
237
  protected
227
238
 
228
239
  def increment_by_query!(match_query, attribute, by, element_name = :n)
@@ -47,7 +47,7 @@ module ActiveGraph::Shared
47
47
 
48
48
  def match_query
49
49
  base_query
50
- .match(match_string).where("ID(#{identifier}) = $#{identifier_id}")
50
+ .match(match_string).where("elementId(#{identifier}) = $#{identifier_id}")
51
51
  .params(identifier_id.to_sym => graph_object.neo_id)
52
52
  end
53
53
 
@@ -389,7 +389,7 @@ module ActiveGraph::Shared
389
389
  def included(_)
390
390
  ActiveGraph::Shared::TypeConverters.constants.each do |constant_name|
391
391
  constant = ActiveGraph::Shared::TypeConverters.const_get(constant_name)
392
- register_converter(constant) if constant.respond_to?(:convert_type)
392
+ register_converter(constant, force: false) if constant.respond_to?(:convert_type)
393
393
  end
394
394
  end
395
395
 
@@ -425,7 +425,8 @@ module ActiveGraph::Shared
425
425
  found_converter.respond_to?(:converted?) ? found_converter.converted?(value) : value.is_a?(found_converter.db_type)
426
426
  end
427
427
 
428
- def register_converter(converter)
428
+ def register_converter(converter, force: true)
429
+ return if CONVERTERS.key?(converter.convert_type) && !force
429
430
  CONVERTERS[converter.convert_type] = converter
430
431
  end
431
432
  end