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.
- 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
|