neo4j 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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