neo4j 4.0.0 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +10 -0
- data/Gemfile +6 -16
- data/README.md +5 -2
- data/bin/neo4j-jars +6 -6
- data/lib/neo4j.rb +13 -9
- data/lib/neo4j/active_node.rb +9 -9
- data/lib/neo4j/active_node/dependent.rb +11 -0
- data/lib/neo4j/active_node/dependent/association_methods.rb +28 -0
- data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +48 -0
- data/lib/neo4j/active_node/has_n.rb +124 -112
- data/lib/neo4j/active_node/has_n/association.rb +45 -30
- data/lib/neo4j/active_node/id_property.rb +22 -19
- data/lib/neo4j/active_node/initialize.rb +2 -4
- data/lib/neo4j/active_node/labels.rb +23 -22
- data/lib/neo4j/active_node/node_wrapper.rb +5 -8
- data/lib/neo4j/active_node/orm_adapter.rb +2 -4
- data/lib/neo4j/active_node/persistence.rb +5 -10
- data/lib/neo4j/active_node/property.rb +3 -4
- data/lib/neo4j/active_node/query.rb +27 -6
- data/lib/neo4j/active_node/query/query_proxy.rb +65 -110
- data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +67 -0
- data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +0 -1
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +29 -28
- data/lib/neo4j/active_node/query_methods.rb +6 -6
- data/lib/neo4j/active_node/reflection.rb +3 -2
- data/lib/neo4j/active_node/rels.rb +1 -1
- data/lib/neo4j/active_node/scope.rb +13 -8
- data/lib/neo4j/active_node/validations.rb +5 -6
- data/lib/neo4j/active_rel.rb +1 -2
- data/lib/neo4j/active_rel/callbacks.rb +3 -3
- data/lib/neo4j/active_rel/persistence.rb +9 -7
- data/lib/neo4j/active_rel/property.rb +12 -4
- data/lib/neo4j/active_rel/query.rb +6 -8
- data/lib/neo4j/active_rel/rel_wrapper.rb +0 -2
- data/lib/neo4j/active_rel/related_node.rb +4 -5
- data/lib/neo4j/active_rel/types.rb +4 -6
- data/lib/neo4j/active_rel/validations.rb +0 -1
- data/lib/neo4j/config.rb +11 -23
- data/lib/neo4j/core/query.rb +1 -1
- data/lib/neo4j/migration.rb +17 -18
- data/lib/neo4j/paginated.rb +4 -4
- data/lib/neo4j/railtie.rb +19 -19
- data/lib/neo4j/shared.rb +7 -3
- data/lib/neo4j/shared/callbacks.rb +15 -4
- data/lib/neo4j/shared/identity.rb +2 -2
- data/lib/neo4j/shared/persistence.rb +10 -21
- data/lib/neo4j/shared/property.rb +17 -30
- data/lib/neo4j/shared/rel_type_converters.rb +1 -3
- data/lib/neo4j/shared/type_converters.rb +13 -25
- data/lib/neo4j/shared/validations.rb +3 -3
- data/lib/neo4j/tasks/migration.rake +7 -7
- data/lib/neo4j/type_converters.rb +1 -1
- data/lib/neo4j/version.rb +1 -1
- data/lib/rails/generators/neo4j/model/model_generator.rb +16 -12
- data/lib/rails/generators/neo4j_generator.rb +18 -18
- data/neo4j.gemspec +22 -18
- 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
|
@@ -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) { |
|
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) { |
|
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
|
-
|
22
|
-
query_with_target(target) do |
|
23
|
-
q = distinct.nil? ?
|
24
|
-
self.query.reorder.pluck("count(#{q}) AS #{
|
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) { |
|
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
|
-
|
39
|
-
query_with_target(target) do |
|
40
|
-
self.where("ID(#{
|
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
|
-
|
46
|
-
query_with_target(target) do |
|
47
|
-
start_q = exists_query_start(
|
48
|
-
start_q.query.return("COUNT(#{
|
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
|
-
{
|
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
|
-
{
|
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(
|
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(
|
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(
|
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(
|
146
|
-
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
26
|
-
q = distinct.nil? ?
|
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(
|
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
|
-
|
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(%
|
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(%
|
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
|
-
|
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(%
|
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
|
-
|
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(:
|
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 =
|
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(
|
38
|
-
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:
|
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 ||
|
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
|
data/lib/neo4j/active_rel.rb
CHANGED
@@ -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 ||
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
.
|
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
|