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
@@ -0,0 +1,67 @@
1
+ module Neo4j
2
+ module ActiveNode
3
+ module Query
4
+ # Methods related to returning nodes and rels from QueryProxy
5
+ module QueryProxyEnumerable
6
+ include Enumerable
7
+
8
+ # Just like every other <tt>each</tt> but it allows for optional params to support the versions that also return relationships.
9
+ # The <tt>node</tt> and <tt>rel</tt> params are typically used by those other methods but there's nothing stopping you from
10
+ # using `your_node.each(true, true)` instead of `your_node.each_with_rel`.
11
+ # @return [Enumerable] An enumerable containing some combination of nodes and rels.
12
+ def each(node = true, rel = nil, &_block)
13
+ if node && rel
14
+ enumerable_query(identity, rel_var).each { |returned_node, returned_rel| yield returned_node, returned_rel }
15
+ else
16
+ pluck_this = !rel ? identity : @rel_var
17
+ enumerable_query(pluck_this).each { |returned_node| yield returned_node }
18
+ end
19
+ end
20
+
21
+ # When called at the end of a QueryProxy chain, it will return the resultant relationship objects intead of nodes.
22
+ # For example, to return the relationship between a given student and their lessons:
23
+ # student.lessons.each_rel do |rel|
24
+ # @return [Enumerable] An enumerable containing any number of applicable relationship objects.
25
+ def each_rel(&block)
26
+ block_given? ? each(false, true, &block) : to_enum(:each, false, true)
27
+ end
28
+
29
+ # When called at the end of a QueryProxy chain, it will return the nodes and relationships of the last link.
30
+ # For example, to return a lesson and each relationship to a given student:
31
+ # student.lessons.each_with_rel do |lesson, rel|
32
+ def each_with_rel(&block)
33
+ block_given? ? each(true, true, &block) : to_enum(:each, true, true)
34
+ end
35
+
36
+ # Does exactly what you would hope. Without it, comparing `bobby.lessons == sandy.lessons` would evaluate to false because it
37
+ # would be comparing the QueryProxy objects, not the lessons themselves.
38
+ def ==(other)
39
+ self.to_a == other
40
+ end
41
+
42
+ # For getting variables which have been defined as part of the association chain
43
+ def pluck(*args)
44
+ self.query.pluck(*args)
45
+ end
46
+
47
+ private
48
+
49
+ # Executes the query against the database if the results are not already present in a node's association cache. This method is
50
+ # shared by <tt>each</tt>, <tt>each_rel</tt>, and <tt>each_with_rel</tt>.
51
+ # @param [String,Symbol] node The string or symbol of the node to return from the database.
52
+ # @param [String,Symbol] rel The string or symbol of a relationship to return from the database.
53
+ def enumerable_query(node, rel = nil)
54
+ pluck_this = rel.nil? ? [node] : [node, rel]
55
+ return self.pluck(*pluck_this) if @association.nil? || caller.nil?
56
+ cypher_string = self.to_cypher_with_params(pluck_this)
57
+ association_collection = caller.association_instance_get(cypher_string, @association)
58
+ if association_collection.nil?
59
+ association_collection = self.pluck(*pluck_this)
60
+ caller.association_instance_set(cypher_string, association_collection, @association) unless association_collection.empty?
61
+ end
62
+ association_collection
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -13,7 +13,6 @@ module Neo4j
13
13
  yield result
14
14
  end
15
15
  end
16
-
17
16
  end
18
17
  end
19
18
  end
@@ -4,12 +4,12 @@ module Neo4j
4
4
  module QueryProxyMethods
5
5
  class InvalidParameterError < StandardError; end
6
6
 
7
- def first(target=nil)
8
- query_with_target(target) { |target| first_and_last("ID(#{target})", target) }
7
+ def first(target = nil)
8
+ query_with_target(target) { |var| first_and_last("ID(#{var})", var) }
9
9
  end
10
10
 
11
- def last(target=nil)
12
- query_with_target(target) { |target| first_and_last("ID(#{target}) DESC", target) }
11
+ def last(target = nil)
12
+ query_with_target(target) { |var| first_and_last("ID(#{var}) DESC", var) }
13
13
  end
14
14
 
15
15
  def first_and_last(order, target)
@@ -17,35 +17,35 @@ module Neo4j
17
17
  end
18
18
 
19
19
  # @return [Fixnum] number of nodes of this class
20
- def count(distinct=nil, target=nil)
21
- raise(InvalidParameterError, ':count accepts `distinct` or nil as a parameter') unless distinct.nil? || distinct == :distinct
22
- query_with_target(target) do |target|
23
- q = distinct.nil? ? target : "DISTINCT #{target}"
24
- self.query.reorder.pluck("count(#{q}) AS #{target}").first
20
+ def count(distinct = nil, target = nil)
21
+ fail(InvalidParameterError, ':count accepts `distinct` or nil as a parameter') unless distinct.nil? || distinct == :distinct
22
+ query_with_target(target) do |var|
23
+ q = distinct.nil? ? var : "DISTINCT #{var}"
24
+ self.query.reorder.pluck("count(#{q}) AS #{var}").first
25
25
  end
26
26
  end
27
27
 
28
28
  alias_method :size, :count
29
29
  alias_method :length, :count
30
30
 
31
- def empty?(target=nil)
32
- query_with_target(target) { |target| !self.exists?(nil, target) }
31
+ def empty?(target = nil)
32
+ query_with_target(target) { |var| !self.exists?(nil, var) }
33
33
  end
34
34
 
35
35
  alias_method :blank?, :empty?
36
36
 
37
- def include?(other, target=nil)
38
- raise(InvalidParameterError, ':include? only accepts nodes') unless other.respond_to?(:neo_id)
39
- query_with_target(target) do |target|
40
- self.where("ID(#{target}) = {other_node_id}").params(other_node_id: other.neo_id).query.return("count(#{target}) as count").first.count > 0
37
+ def include?(other, target = nil)
38
+ fail(InvalidParameterError, ':include? only accepts nodes') unless other.respond_to?(:neo_id)
39
+ query_with_target(target) do |var|
40
+ self.where("ID(#{var}) = {other_node_id}").params(other_node_id: other.neo_id).query.return("count(#{var}) as count").first.count > 0
41
41
  end
42
42
  end
43
43
 
44
- def exists?(node_condition=nil, target=nil)
45
- raise(InvalidParameterError, ':exists? only accepts neo_ids') unless node_condition.is_a?(Fixnum) || node_condition.is_a?(Hash) || node_condition.nil?
46
- query_with_target(target) do |target|
47
- start_q = exists_query_start(self, node_condition, target)
48
- start_q.query.return("COUNT(#{target}) AS count").first.count > 0
44
+ def exists?(node_condition = nil, target = nil)
45
+ fail(InvalidParameterError, ':exists? only accepts neo_ids') unless node_condition.is_a?(Fixnum) || node_condition.is_a?(Hash) || node_condition.nil?
46
+ query_with_target(target) do |var|
47
+ start_q = exists_query_start(node_condition, var)
48
+ start_q.query.return("COUNT(#{var}) AS count").first.count > 0
49
49
  end
50
50
  end
51
51
 
@@ -72,11 +72,11 @@ module Neo4j
72
72
  # @return [Neo4j::ActiveNode::Query::QueryProxy] A QueryProxy object upon which you can build.
73
73
  def match_to(node)
74
74
  where_arg = if node.respond_to?(:neo_id)
75
- { neo_id: node.neo_id }
75
+ {neo_id: node.neo_id}
76
76
  elsif !node.nil?
77
77
  id_key = association_id_key
78
78
  node = ids_array(node) if node.is_a?(Array)
79
- { id_key => node }
79
+ {id_key => node}
80
80
  else
81
81
  # support for null object pattern
82
82
  '1 = 2'
@@ -89,20 +89,20 @@ module Neo4j
89
89
  # @param [#neo_id, String, Enumerable] node An object to be sent to `match_to`. See params for that method.
90
90
  # @return A relationship (ActiveRel, CypherRelationship, EmbeddedRelationship) or nil.
91
91
  def first_rel_to(node)
92
- self.match_to(node).limit(1).pluck(rel_identity).first
92
+ self.match_to(node).limit(1).pluck(rel_var).first
93
93
  end
94
94
 
95
95
  # Returns all relationships across a QueryProxy chain between a given node or array of nodes and the preceeding link.
96
96
  # @param [#neo_id, String, Enumerable] node An object to be sent to `match_to`. See params for that method.
97
97
  # @return An enumerable of relationship objects.
98
98
  def rels_to(node)
99
- self.match_to(node).pluck(rel_identity)
99
+ self.match_to(node).pluck(rel_var)
100
100
  end
101
101
  alias_method :all_rels_to, :rels_to
102
102
 
103
103
  # Deletes the relationship between a node and its last link in the QueryProxy chain. Executed in the database, callbacks will not run.
104
104
  def delete(node)
105
- self.match_to(node).query.delete(rel_identity).exec
105
+ self.match_to(node).query.delete(rel_var).exec
106
106
  clear_caller_cache
107
107
  end
108
108
 
@@ -142,10 +142,11 @@ module Neo4j
142
142
  yield(target || identity)
143
143
  end
144
144
 
145
- def exists_query_start(origin, condition, target)
146
- if condition.class == Fixnum
145
+ def exists_query_start(condition, target)
146
+ case condition
147
+ when Fixnum
147
148
  self.where("ID(#{target}) = {exists_condition}").params(exists_condition: condition)
148
- elsif condition.class == Hash
149
+ when Hash
149
150
  self.where(condition.keys.first => condition.values.first)
150
151
  else
151
152
  self
@@ -3,11 +3,11 @@ module Neo4j
3
3
  module QueryMethods
4
4
  class InvalidParameterError < StandardError; end
5
5
 
6
- def exists?(node_condition=nil)
7
- raise(InvalidParameterError, ':exists? only accepts ids or conditions') unless node_condition.is_a?(Fixnum) || node_condition.is_a?(Hash) || node_condition.nil?
6
+ def exists?(node_condition = nil)
7
+ fail(InvalidParameterError, ':exists? only accepts ids or conditions') unless node_condition.is_a?(Fixnum) || node_condition.is_a?(Hash) || node_condition.nil?
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
- start_q.return("COUNT(n) AS count").first.count > 0
10
+ start_q.return('COUNT(n) AS count').first.count > 0
11
11
  end
12
12
 
13
13
  # Returns the first node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs.
@@ -22,8 +22,8 @@ module Neo4j
22
22
 
23
23
  # @return [Fixnum] number of nodes of this class
24
24
  def count(distinct = nil)
25
- raise(InvalidParameterError, ':count accepts `distinct` or nil as a parameter') unless distinct.nil? || distinct == :distinct
26
- q = distinct.nil? ? "n" : "DISTINCT n"
25
+ fail(InvalidParameterError, ':count accepts `distinct` or nil as a parameter') unless distinct.nil? || distinct == :distinct
26
+ q = distinct.nil? ? 'n' : 'DISTINCT n'
27
27
  self.query_as(:n).return("count(#{q}) AS count").first.count
28
28
  end
29
29
 
@@ -53,7 +53,7 @@ module Neo4j
53
53
  def exists_query_start(node_condition)
54
54
  case node_condition
55
55
  when Fixnum
56
- self.query_as(:n).where("ID(n)" => node_condition)
56
+ self.query_as(:n).where('ID(n)' => node_condition)
57
57
  when Hash
58
58
  self.where(node_condition.keys.first => node_condition.values.first)
59
59
  else
@@ -15,8 +15,9 @@ module Neo4j::ActiveNode
15
15
  # @param macro [Symbol] the association type, :has_many or :has_one
16
16
  # @param name [Symbol] the association name
17
17
  # @param association_object [Neo4j::ActiveNode::HasN::Association] the association object created in the course of creating this reflection
18
- def create_reflection(macro, name, association_object)
18
+ def create_reflection(macro, name, association_object, model)
19
19
  self.reflections = self.reflections.merge(name => AssociationReflection.new(macro, name, association_object))
20
+ association_object.add_destroy_callbacks(model)
20
21
  end
21
22
 
22
23
  private :create_reflection
@@ -82,4 +83,4 @@ module Neo4j::ActiveNode
82
83
  end
83
84
  end
84
85
  end
85
- end
86
+ end
@@ -4,7 +4,7 @@ module Neo4j::ActiveNode
4
4
  def_delegators :_rels_delegator, :rel?, :rel, :rels, :node, :nodes, :create_rel
5
5
 
6
6
  def _rels_delegator
7
- raise "Can't access relationship on a non persisted node" unless _persisted_obj
7
+ fail "Can't access relationship on a non persisted node" unless _persisted_obj
8
8
  _persisted_obj
9
9
  end
10
10
  end
@@ -5,7 +5,6 @@ module Neo4j::ActiveNode
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
-
9
8
  # Similar to ActiveRecord scope
10
9
  #
11
10
  # @example without argument
@@ -38,7 +37,7 @@ module Neo4j::ActiveNode
38
37
  def scope(name, proc)
39
38
  _scope[name.to_sym] = proc
40
39
 
41
- module_eval(%Q{
40
+ module_eval(%{
42
41
  def #{name}(query_params=nil, _=nil, query_proxy=nil)
43
42
  eval_context = ScopeEvalContext.new(self, query_proxy || self.class.query_proxy)
44
43
  proc = self.class._scope[:"#{name}"]
@@ -46,7 +45,7 @@ module Neo4j::ActiveNode
46
45
  end
47
46
  }, __FILE__, __LINE__)
48
47
 
49
- instance_eval(%Q{
48
+ instance_eval(%{
50
49
  def #{name}(query_params=nil, _=nil, query_proxy=nil)
51
50
  eval_context = ScopeEvalContext.new(self, query_proxy || self.query_proxy)
52
51
  proc = _scope[:"#{name}"]
@@ -55,8 +54,16 @@ module Neo4j::ActiveNode
55
54
  }, __FILE__, __LINE__)
56
55
  end
57
56
 
57
+ # rubocop:disable Style/PredicateName
58
58
  def has_scope?(name)
59
- _scope.has_key?(name.to_sym)
59
+ ActiveSupport::Deprecation.warn 'has_scope? is deprecated and may be removed from future releases, use scope? instead.', caller
60
+
61
+ scope?(name)
62
+ end
63
+ # rubocop:enable Style/PredicateName
64
+
65
+ def scope?(name)
66
+ _scope.key?(name.to_sym)
60
67
  end
61
68
 
62
69
  def _scope
@@ -88,7 +95,6 @@ module Neo4j::ActiveNode
88
95
  self.as(:n)
89
96
  end
90
97
  end
91
-
92
98
  end
93
99
 
94
100
  class ScopeEvalContext
@@ -98,7 +104,7 @@ module Neo4j::ActiveNode
98
104
  end
99
105
 
100
106
  Neo4j::ActiveNode::Query::QueryProxy::METHODS.each do |method|
101
- module_eval(%Q{
107
+ module_eval(%{
102
108
  def #{method}(params={})
103
109
  @target.all.scoping do
104
110
  (@query_proxy || @target).#{method}(params)
@@ -135,10 +141,9 @@ module Neo4j::ActiveNode
135
141
 
136
142
  def raise_invalid_scope_type!(scope_type)
137
143
  if !VALID_SCOPE_TYPES.include?(scope_type)
138
- raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
144
+ fail ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
139
145
  end
140
146
  end
141
147
  end
142
-
143
148
  end
144
149
  end
@@ -22,24 +22,24 @@ module Neo4j
22
22
 
23
23
  class UniquenessValidator < ::ActiveModel::EachValidator
24
24
  def initialize(options)
25
- super(options.reverse_merge(:case_sensitive => true))
25
+ super(options.reverse_merge(case_sensitive: true))
26
26
  end
27
27
 
28
28
  def validate_each(record, attribute, value)
29
29
  conditions = scope_conditions(record)
30
30
 
31
31
  # TODO: Added as find(:name => nil) throws error
32
- value = "" if value == nil
32
+ value = '' if value.nil?
33
33
 
34
34
  conditions[attribute] = options[:case_sensitive] ? value : /^#{Regexp.escape(value.to_s)}$/i
35
35
 
36
36
  found = record.class.as(:result).where(conditions)
37
- found = found.where("NOT ID(result) = {record_neo_id}").params(record_neo_id: record.neo_id) if record.persisted?
38
- record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value)) if found.exists?
37
+ found = found.where('NOT ID(result) = {record_neo_id}').params(record_neo_id: record.neo_id) if record.persisted?
38
+ record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(value: value)) if found.exists?
39
39
  end
40
40
 
41
41
  def message(instance)
42
- super || "has already been taken"
42
+ super || 'has already been taken'
43
43
  end
44
44
 
45
45
  def scope_conditions(instance)
@@ -48,7 +48,6 @@ module Neo4j
48
48
  end
49
49
  end
50
50
  end
51
-
52
51
  end
53
52
  end
54
53
  end
@@ -1,5 +1,4 @@
1
1
  module Neo4j
2
-
3
2
  # Makes Neo4j Relationships more or less act like ActiveRecord objects.
4
3
  # See documentation at https://github.com/neo4jrb/neo4j/wiki/Neo4j%3A%3AActiveRel
5
4
  module ActiveRel
@@ -24,7 +23,7 @@ module Neo4j
24
23
  end
25
24
 
26
25
  def neo4j_obj
27
- _persisted_obj || raise("Tried to access native neo4j object on a non persisted object")
26
+ _persisted_obj || fail('Tried to access native neo4j object on a non persisted object')
28
27
  end
29
28
 
30
29
  included do
@@ -6,10 +6,10 @@ module Neo4j
6
6
 
7
7
  def save(*args)
8
8
  unless self.persisted? || (from_node.respond_to?(:neo_id) && to_node.respond_to?(:neo_id))
9
- raise Neo4j::ActiveRel::Persistence::RelInvalidError, 'from_node and to_node must be node objects'
10
- end
9
+ fail Neo4j::ActiveRel::Persistence::RelInvalidError, 'from_node and to_node must be node objects'
10
+ end
11
11
  super(*args)
12
12
  end
13
13
  end
14
14
  end
15
- end
15
+ end
@@ -15,7 +15,7 @@ module Neo4j::ActiveRel
15
15
  end
16
16
 
17
17
  def save!(*args)
18
- raise RelInvalidError.new(self) unless save(*args)
18
+ fail RelInvalidError, self unless save(*args)
19
19
  end
20
20
 
21
21
  def create_model(*)
@@ -30,7 +30,6 @@ module Neo4j::ActiveRel
30
30
  end
31
31
 
32
32
  module ClassMethods
33
-
34
33
  # Creates a new relationship between objects
35
34
  # @param [Hash] props the properties the new relationship should have
36
35
  def create(props = {})
@@ -45,7 +44,7 @@ module Neo4j::ActiveRel
45
44
 
46
45
  # Same as #create, but raises an error if there is a problem during save.
47
46
  def create!(*args)
48
- raise RelInvalidError.new(self) unless create(*args)
47
+ fail RelInvalidError, self unless create(*args)
49
48
  end
50
49
  end
51
50
 
@@ -55,7 +54,7 @@ module Neo4j::ActiveRel
55
54
  [from_node, to_node].each do |node|
56
55
  type = from_node == node ? :_from_class : :_to_class
57
56
  next if allows_any_class?(type)
58
- raise ModelClassInvalidError, "Node class was #{node.class}, expected #{self.class.send(type)}" unless class_as_constant(type) == node.class || node.class.ancestors.include?(class_as_constant(type))
57
+ fail ModelClassInvalidError, "Node class was #{node.class}, expected #{self.class.send(type)}" unless class_as_constant(type) == node.class || node.class.ancestors.include?(class_as_constant(type))
59
58
  end
60
59
  end
61
60
 
@@ -92,12 +91,15 @@ module Neo4j::ActiveRel
92
91
  .where("n1.#{from_class.primary_key} = {from_node_id}")
93
92
  .where("n2.#{to_class.primary_key} = {to_node_id}")
94
93
  .params(from_node_id: from_node.id, to_node_id: to_node.id)
95
- .create("(n1)-[r:`#{type}`]->(n2)")
94
+ .send(create_method, ("(n1)-[r:`#{type}`]->(n2)"))
96
95
  .with('r').set(r: props).return(:r).first.r
97
- rescue NoMethodError
98
- raise RelCreateFailedError, "Unable to create relationship. from_node: #{from_node}, to_node: #{to_node}"
96
+ rescue NoMethodError => e
97
+ raise RelCreateFailedError, "Unable to create relationship. from_node: #{from_node}, to_node: #{to_node}, error: #{e}"
99
98
  end
100
99
  end
101
100
 
101
+ def create_method
102
+ self.class.unique? ? :create_unique : :create
103
+ end
102
104
  end
103
105
  end