neo4j 4.1.5 → 5.0.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +584 -0
- data/CONTRIBUTORS +7 -28
- data/Gemfile +6 -1
- data/README.md +54 -8
- data/lib/neo4j.rb +5 -0
- data/lib/neo4j/active_node.rb +1 -0
- data/lib/neo4j/active_node/dependent/association_methods.rb +35 -17
- data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +21 -19
- data/lib/neo4j/active_node/has_n.rb +377 -132
- data/lib/neo4j/active_node/has_n/association.rb +77 -38
- data/lib/neo4j/active_node/id_property.rb +46 -28
- data/lib/neo4j/active_node/initialize.rb +18 -6
- data/lib/neo4j/active_node/labels.rb +69 -35
- data/lib/neo4j/active_node/node_wrapper.rb +37 -30
- data/lib/neo4j/active_node/orm_adapter.rb +5 -4
- data/lib/neo4j/active_node/persistence.rb +53 -10
- data/lib/neo4j/active_node/property.rb +13 -5
- data/lib/neo4j/active_node/query.rb +11 -10
- data/lib/neo4j/active_node/query/query_proxy.rb +126 -153
- data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +15 -25
- data/lib/neo4j/active_node/query/query_proxy_link.rb +89 -0
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +72 -19
- data/lib/neo4j/active_node/query_methods.rb +3 -1
- data/lib/neo4j/active_node/scope.rb +17 -21
- data/lib/neo4j/active_node/validations.rb +8 -2
- data/lib/neo4j/active_rel/initialize.rb +1 -2
- data/lib/neo4j/active_rel/persistence.rb +21 -33
- data/lib/neo4j/active_rel/property.rb +4 -2
- data/lib/neo4j/active_rel/types.rb +20 -8
- data/lib/neo4j/config.rb +16 -6
- data/lib/neo4j/core/query.rb +2 -2
- data/lib/neo4j/errors.rb +10 -0
- data/lib/neo4j/migration.rb +57 -46
- data/lib/neo4j/paginated.rb +3 -1
- data/lib/neo4j/railtie.rb +26 -14
- data/lib/neo4j/shared.rb +7 -1
- data/lib/neo4j/shared/declared_property.rb +62 -0
- data/lib/neo4j/shared/declared_property_manager.rb +150 -0
- data/lib/neo4j/shared/persistence.rb +15 -8
- data/lib/neo4j/shared/property.rb +64 -49
- data/lib/neo4j/shared/rel_type_converters.rb +13 -12
- data/lib/neo4j/shared/serialized_properties.rb +0 -15
- data/lib/neo4j/shared/type_converters.rb +53 -47
- data/lib/neo4j/shared/typecaster.rb +49 -0
- data/lib/neo4j/version.rb +1 -1
- data/lib/rails/generators/neo4j/model/model_generator.rb +3 -3
- data/lib/rails/generators/neo4j_generator.rb +5 -12
- data/neo4j.gemspec +4 -3
- metadata +30 -11
- data/CHANGELOG +0 -545
@@ -17,42 +17,51 @@ module Neo4j
|
|
17
17
|
apply_vars_from_options(options)
|
18
18
|
end
|
19
19
|
|
20
|
-
def target_class_option(
|
21
|
-
|
20
|
+
def target_class_option(model_class)
|
21
|
+
case model_class
|
22
|
+
when nil
|
22
23
|
if @target_class_name_from_name
|
23
|
-
"::#{@target_class_name_from_name}"
|
24
|
+
"#{association_model_namespace}::#{@target_class_name_from_name}"
|
24
25
|
else
|
25
26
|
@target_class_name_from_name
|
26
27
|
end
|
27
|
-
|
28
|
+
when Array
|
29
|
+
model_class.map { |sub_model_class| target_class_option(sub_model_class) }
|
30
|
+
when false
|
28
31
|
false
|
29
32
|
else
|
30
|
-
"::#{
|
33
|
+
"::#{model_class}"
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
34
37
|
# Return cypher partial query string for the relationship part of a MATCH (arrow / relationship definition)
|
35
|
-
def arrow_cypher(var = nil, properties = {}, create = false)
|
38
|
+
def arrow_cypher(var = nil, properties = {}, create = false, reverse = false)
|
36
39
|
validate_origin!
|
37
|
-
|
38
|
-
relationship_name_cypher = ":`#{relationship_type}`" if relationship_type
|
39
|
-
properties_string = get_properties_string(properties)
|
40
|
-
relationship_cypher = get_relationship_cypher(var, relationship_name_cypher, properties_string)
|
41
|
-
get_direction(relationship_cypher, create)
|
40
|
+
direction_cypher(get_relationship_cypher(var, properties, create), create, reverse)
|
42
41
|
end
|
43
42
|
|
44
|
-
def
|
45
|
-
@
|
43
|
+
def target_class_names
|
44
|
+
@target_class_names ||= if @target_class_option.is_a?(Array)
|
45
|
+
@target_class_option.map(&:to_s)
|
46
|
+
elsif @target_class_option
|
47
|
+
[@target_class_option.to_s]
|
48
|
+
end
|
46
49
|
end
|
47
50
|
|
48
|
-
def
|
49
|
-
@
|
51
|
+
def target_classes_or_nil
|
52
|
+
@target_classes_or_nil ||= discovered_model if target_class_names
|
53
|
+
end
|
54
|
+
|
55
|
+
def discovered_model
|
56
|
+
target_class_names.map(&:constantize).select do |constant|
|
57
|
+
constant.ancestors.include?(::Neo4j::ActiveNode)
|
58
|
+
end
|
50
59
|
end
|
51
60
|
|
52
61
|
def target_class
|
53
62
|
return @target_class if @target_class
|
54
63
|
|
55
|
-
@target_class =
|
64
|
+
@target_class = target_class_names[0].constantize if target_class_names && target_class_names.size == 1
|
56
65
|
rescue NameError
|
57
66
|
raise ArgumentError, "Could not find `#{@target_class}` class and no :model_class specified"
|
58
67
|
end
|
@@ -83,7 +92,7 @@ module Neo4j
|
|
83
92
|
|
84
93
|
def relationship_class_type
|
85
94
|
@relationship_class = @relationship_class.constantize if @relationship_class.class == String || @relationship_class == Symbol
|
86
|
-
@relationship_class._type
|
95
|
+
@relationship_class._type.to_sym
|
87
96
|
end
|
88
97
|
|
89
98
|
def relationship_class_name
|
@@ -110,11 +119,18 @@ module Neo4j
|
|
110
119
|
@origin ? origin_association.unique? : !!@unique
|
111
120
|
end
|
112
121
|
|
122
|
+
def create_method
|
123
|
+
unique? ? :create_unique : :create
|
124
|
+
end
|
125
|
+
|
113
126
|
private
|
114
127
|
|
115
|
-
def
|
116
|
-
|
117
|
-
|
128
|
+
def association_model_namespace
|
129
|
+
Neo4j::Config.association_model_namespace_string
|
130
|
+
end
|
131
|
+
|
132
|
+
def direction_cypher(relationship_cypher, create, reverse = false)
|
133
|
+
case get_direction(create, reverse)
|
118
134
|
when :out
|
119
135
|
"-#{relationship_cypher}->"
|
120
136
|
when :in
|
@@ -124,7 +140,24 @@ module Neo4j
|
|
124
140
|
end
|
125
141
|
end
|
126
142
|
|
127
|
-
def
|
143
|
+
def get_direction(create, reverse = false)
|
144
|
+
dir = (create && @direction == :both) ? :out : @direction
|
145
|
+
if reverse
|
146
|
+
case dir
|
147
|
+
when :in then :out
|
148
|
+
when :out then :in
|
149
|
+
else :both
|
150
|
+
end
|
151
|
+
else
|
152
|
+
dir
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def get_relationship_cypher(var, properties, create)
|
157
|
+
relationship_type = relationship_type(create)
|
158
|
+
relationship_name_cypher = ":`#{relationship_type}`" if relationship_type
|
159
|
+
properties_string = get_properties_string(properties)
|
160
|
+
|
128
161
|
"[#{var}#{relationship_name_cypher}#{properties_string}]"
|
129
162
|
end
|
130
163
|
|
@@ -146,41 +179,41 @@ module Neo4j
|
|
146
179
|
private
|
147
180
|
|
148
181
|
def apply_vars_from_options(options)
|
149
|
-
@target_class_option = target_class_option(options)
|
182
|
+
@target_class_option = target_class_option(options[:model_class])
|
150
183
|
@callbacks = {before: options[:before], after: options[:after]}
|
151
184
|
@origin = options[:origin] && options[:origin].to_sym
|
152
185
|
@relationship_class = options[:rel_class]
|
153
186
|
@relationship_type = options[:type] && options[:type].to_sym
|
154
|
-
@dependent = options[:dependent]
|
187
|
+
@dependent = options[:dependent].try(:to_sym)
|
155
188
|
@unique = options[:unique]
|
156
189
|
end
|
157
190
|
|
158
191
|
# Return basic details about association as declared in the model
|
159
192
|
# @example
|
160
|
-
# has_many :in, :bands
|
193
|
+
# has_many :in, :bands, type: :has_band
|
161
194
|
def base_declaration
|
162
195
|
"#{type} #{direction.inspect}, #{name.inspect}"
|
163
196
|
end
|
164
197
|
|
165
198
|
def validate_init_arguments(type, direction, options)
|
166
199
|
validate_option_combinations(options)
|
200
|
+
validate_dependent(options[:dependent].try(:to_sym))
|
167
201
|
check_valid_type_and_dir(type, direction)
|
168
202
|
end
|
169
203
|
|
170
204
|
def check_valid_type_and_dir(type, direction)
|
171
|
-
fail ArgumentError, "Invalid association type: #{type.inspect} (valid value: :has_many and :has_one)" if
|
172
|
-
fail ArgumentError, "Invalid direction: #{direction.inspect} (valid value: :out, :in, and :both)" if
|
205
|
+
fail ArgumentError, "Invalid association type: #{type.inspect} (valid value: :has_many and :has_one)" if ![:has_many, :has_one].include?(type.to_sym)
|
206
|
+
fail ArgumentError, "Invalid direction: #{direction.inspect} (valid value: :out, :in, and :both)" if ![:out, :in, :both].include?(direction.to_sym)
|
173
207
|
end
|
174
208
|
|
175
209
|
def validate_option_combinations(options)
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
fail ArgumentError, "Invalid dependent value: #{value.inspect}" if not VALID_DEPENDENT_TYPES.include?(value)
|
210
|
+
[[:type, :origin],
|
211
|
+
[:type, :rel_class],
|
212
|
+
[:origin, :rel_class]].each do |key1, key2|
|
213
|
+
if options[key1] && options[key2]
|
214
|
+
fail ArgumentError, "Cannot specify both :#{key1} and :#{key2} (#{base_declaration})"
|
215
|
+
end
|
216
|
+
end
|
184
217
|
end
|
185
218
|
|
186
219
|
# Determine if model class as derived from the association name would be different than the one specified via the model_class key
|
@@ -197,12 +230,18 @@ module Neo4j
|
|
197
230
|
def validate_origin!
|
198
231
|
return if not @origin
|
199
232
|
|
200
|
-
fail ArgumentError, 'Cannot use :origin without a model_class (implied or explicit)' if not target_class
|
201
|
-
|
202
233
|
association = origin_association
|
203
|
-
fail ArgumentError, "Origin `#{@origin.inspect}` association not found for #{target_class} (specified in #{base_declaration})" if not association
|
204
234
|
|
205
|
-
|
235
|
+
message = case
|
236
|
+
when !target_class
|
237
|
+
'Cannot use :origin without a model_class (implied or explicit)'
|
238
|
+
when !association
|
239
|
+
"Origin `#{@origin.inspect}` association not found for #{target_class} (specified in #{base_declaration})"
|
240
|
+
when @direction == association.direction
|
241
|
+
"Origin `#{@origin.inspect}` (specified in #{base_declaration}) has same direction `#{@direction}`)"
|
242
|
+
end
|
243
|
+
|
244
|
+
fail ArgumentError, message if message
|
206
245
|
end
|
207
246
|
end
|
208
247
|
end
|
@@ -20,27 +20,52 @@ module Neo4j::ActiveNode
|
|
20
20
|
# end
|
21
21
|
# end
|
22
22
|
#
|
23
|
+
# @example using already exsting ids that you don't want a constraint added to
|
24
|
+
# class Person
|
25
|
+
# include Neo4j::ActiveNode
|
26
|
+
# property :title
|
27
|
+
# validates :title, :presence => true
|
28
|
+
# id_property :id, on: :id_builder, constraint: false
|
29
|
+
#
|
30
|
+
# def id_builder
|
31
|
+
# # only need to fill this out if you're gonna write to the db
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
23
35
|
module IdProperty
|
24
36
|
extend ActiveSupport::Concern
|
25
37
|
|
26
38
|
|
27
39
|
module TypeMethods
|
28
40
|
def define_id_methods(clazz, name, conf)
|
29
|
-
|
41
|
+
validate_conf!(conf)
|
42
|
+
|
30
43
|
if conf[:on]
|
31
44
|
define_custom_method(clazz, name, conf[:on])
|
32
45
|
elsif conf[:auto]
|
33
|
-
fail "only :uuid auto id_property allowed, got #{conf[:auto]}" unless conf[:auto] == :uuid
|
34
46
|
define_uuid_method(clazz, name)
|
35
47
|
elsif conf.empty?
|
36
48
|
define_property_method(clazz, name)
|
37
|
-
else
|
38
|
-
fail "Illegal value #{conf.inspect} for id_property, expected :on or :auto"
|
39
49
|
end
|
40
50
|
end
|
41
51
|
|
42
52
|
private
|
43
53
|
|
54
|
+
def validate_conf!(conf)
|
55
|
+
fail "Expected a Hash, got #{conf.class} (#{conf}) for id_property" if !conf.is_a?(Hash)
|
56
|
+
|
57
|
+
return if conf[:on]
|
58
|
+
|
59
|
+
if conf[:auto]
|
60
|
+
fail "only :uuid auto id_property allowed, got #{conf[:auto]}" if conf[:auto] != :uuid
|
61
|
+
return
|
62
|
+
end
|
63
|
+
|
64
|
+
return if conf.empty?
|
65
|
+
|
66
|
+
fail "Illegal value #{conf.inspect} for id_property, expected :on or :auto"
|
67
|
+
end
|
68
|
+
|
44
69
|
def define_property_method(clazz, name)
|
45
70
|
clear_methods(clazz, name)
|
46
71
|
|
@@ -90,17 +115,8 @@ module Neo4j::ActiveNode
|
|
90
115
|
end
|
91
116
|
|
92
117
|
def clear_methods(clazz, name)
|
93
|
-
if clazz.method_defined?(name)
|
94
|
-
|
95
|
-
undef_method :#{name}
|
96
|
-
), __FILE__, __LINE__)
|
97
|
-
end
|
98
|
-
|
99
|
-
if clazz.attribute_names.include?(name.to_s)
|
100
|
-
clazz.module_eval(%(
|
101
|
-
undef_property :#{name}
|
102
|
-
), __FILE__, __LINE__)
|
103
|
-
end
|
118
|
+
clazz.module_eval(%(undef_method :#{name}), __FILE__, __LINE__) if clazz.method_defined?(name)
|
119
|
+
clazz.module_eval(%(undef_property :#{name}), __FILE__, __LINE__) if clazz.attribute_names.include?(name.to_s)
|
104
120
|
end
|
105
121
|
|
106
122
|
extend self
|
@@ -121,22 +137,12 @@ module Neo4j::ActiveNode
|
|
121
137
|
end
|
122
138
|
|
123
139
|
def id_property(name, conf = {})
|
124
|
-
|
125
|
-
if id_property?
|
126
|
-
unless mapped_label.uniqueness_constraints[:property_keys].include?([name])
|
127
|
-
drop_constraint(id_property_name, type: :unique)
|
128
|
-
end
|
129
|
-
end
|
130
|
-
rescue Neo4j::Server::CypherResponse::ResponseError
|
131
|
-
end
|
132
|
-
|
140
|
+
id_property_constraint(name)
|
133
141
|
@id_property_info = {name: name, type: conf}
|
134
142
|
TypeMethods.define_id_methods(self, name, conf)
|
135
|
-
constraint name, type: :unique
|
143
|
+
constraint name, type: :unique unless conf[:constraint] == false
|
136
144
|
|
137
|
-
self.define_singleton_method(:find_by_id)
|
138
|
-
self.where(name => key).first
|
139
|
-
end
|
145
|
+
self.define_singleton_method(:find_by_id) { |key| self.where(name => key).first }
|
140
146
|
end
|
141
147
|
|
142
148
|
# rubocop:disable Style/PredicateName
|
@@ -160,6 +166,18 @@ module Neo4j::ActiveNode
|
|
160
166
|
end
|
161
167
|
|
162
168
|
alias_method :primary_key, :id_property_name
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def id_property_constraint(name)
|
173
|
+
if id_property?
|
174
|
+
unless mapped_label.uniqueness_constraints[:property_keys].include?([name])
|
175
|
+
# Neo4j Embedded throws a crazy error when a constraint can't be dropped
|
176
|
+
drop_constraint(id_property_name, type: :unique)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
rescue Neo4j::Server::CypherResponse::ResponseError, Java::OrgNeo4jCypher::CypherExecutionException
|
180
|
+
end
|
163
181
|
end
|
164
182
|
end
|
165
183
|
end
|
@@ -1,19 +1,15 @@
|
|
1
1
|
module Neo4j::ActiveNode::Initialize
|
2
2
|
extend ActiveSupport::Concern
|
3
|
-
include Neo4j::Shared::TypeConverters
|
4
3
|
attr_reader :called_by
|
5
4
|
|
6
5
|
# called when loading the node from the database
|
7
6
|
# @param [Neo4j::Node] persisted_node the node this class wraps
|
8
7
|
# @param [Hash] properties of the persisted node.
|
9
8
|
def init_on_load(persisted_node, properties)
|
10
|
-
|
9
|
+
self.class.extract_association_attributes!(properties)
|
11
10
|
@_persisted_obj = persisted_node
|
12
|
-
@association_cache = {}
|
13
11
|
changed_attributes && changed_attributes.clear
|
14
|
-
@attributes =
|
15
|
-
self.default_properties = properties
|
16
|
-
@attributes = convert_properties_to :ruby, @attributes
|
12
|
+
@attributes = convert_and_assign_attributes(properties)
|
17
13
|
end
|
18
14
|
|
19
15
|
# Implements the Neo4j::Node#wrapper and Neo4j::Relationship#wrapper method
|
@@ -22,4 +18,20 @@ module Neo4j::ActiveNode::Initialize
|
|
22
18
|
def wrapper
|
23
19
|
self
|
24
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def convert_and_assign_attributes(properties)
|
25
|
+
@attributes ||= self.class.attributes_nil_hash.dup
|
26
|
+
stringify_attributes!(@attributes, properties)
|
27
|
+
self.default_properties = properties
|
28
|
+
self.class.declared_property_manager.convert_properties_to(self, :ruby, @attributes)
|
29
|
+
end
|
30
|
+
|
31
|
+
def stringify_attributes!(attr, properties)
|
32
|
+
properties.each_pair do |k, v|
|
33
|
+
key = self.class.declared_property_manager.string_key(k)
|
34
|
+
attr[key] = v
|
35
|
+
end
|
36
|
+
end
|
25
37
|
end
|
@@ -5,6 +5,19 @@ module Neo4j
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
WRAPPED_CLASSES = []
|
8
|
+
MODELS_FOR_LABELS_CACHE = {}
|
9
|
+
MODELS_FOR_LABELS_CACHE.clear
|
10
|
+
|
11
|
+
included do |model|
|
12
|
+
def self.inherited(model)
|
13
|
+
add_wrapped_class(model)
|
14
|
+
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
Neo4j::ActiveNode::Labels.add_wrapped_class(model) unless Neo4j::ActiveNode::Labels._wrapped_classes.include?(model)
|
19
|
+
end
|
20
|
+
|
8
21
|
class InvalidQueryError < StandardError; end
|
9
22
|
class RecordNotFound < StandardError; end
|
10
23
|
|
@@ -32,59 +45,59 @@ module Neo4j
|
|
32
45
|
@_persisted_obj.remove_label(*label)
|
33
46
|
end
|
34
47
|
|
35
|
-
def self.
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.add_wrapped_class(klass)
|
40
|
-
_wrapped_classes << klass
|
41
|
-
@_wrapped_labels = nil
|
48
|
+
def self.add_wrapped_class(model)
|
49
|
+
_wrapped_classes << model
|
42
50
|
end
|
43
51
|
|
44
52
|
def self._wrapped_classes
|
45
53
|
Neo4j::ActiveNode::Labels::WRAPPED_CLASSES
|
46
54
|
end
|
47
55
|
|
48
|
-
|
49
|
-
|
50
|
-
# Only for testing purpose
|
51
|
-
# @private
|
52
|
-
def self._wrapped_labels=(wl)
|
53
|
-
@_wrapped_labels = (wl)
|
56
|
+
def self.model_for_labels(labels)
|
57
|
+
MODELS_FOR_LABELS_CACHE[labels] || model_cache(labels)
|
54
58
|
end
|
55
59
|
|
56
|
-
def self.
|
57
|
-
|
58
|
-
|
59
|
-
a[clazz.mapped_label_name.to_sym] = clazz if clazz.respond_to?(:mapped_label_name)
|
60
|
-
end
|
60
|
+
def self.model_cache(labels)
|
61
|
+
models = WRAPPED_CLASSES.select do |model|
|
62
|
+
(model.mapped_label_names - labels).size == 0
|
61
63
|
end
|
64
|
+
|
65
|
+
MODELS_FOR_LABELS_CACHE[labels] = models.max do |model|
|
66
|
+
(model.mapped_label_names & labels).size
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.clear_model_for_label_cache
|
71
|
+
MODELS_FOR_LABELS_CACHE.clear
|
62
72
|
end
|
63
73
|
|
74
|
+
def self.clear_wrapped_models
|
75
|
+
WRAPPED_CLASSES.clear
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
64
80
|
module ClassMethods
|
65
81
|
include Neo4j::ActiveNode::QueryMethods
|
66
82
|
|
67
|
-
# Find all nodes/objects of this class
|
68
|
-
def all
|
69
|
-
Neo4j::ActiveNode::Query::QueryProxy.new(self, nil, {})
|
70
|
-
end
|
71
|
-
|
72
83
|
# Returns the object with the specified neo4j id.
|
73
84
|
# @param [String,Integer] id of node to find
|
74
85
|
def find(id)
|
75
86
|
map_id = proc { |object| object.respond_to?(:id) ? object.send(:id) : object }
|
76
87
|
|
77
|
-
if id.is_a?(Array)
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
88
|
+
result = if id.is_a?(Array)
|
89
|
+
find_by_ids(id.map { |o| map_id.call(o) })
|
90
|
+
else
|
91
|
+
find_by_id(map_id.call(id))
|
92
|
+
end
|
93
|
+
fail Neo4j::RecordNotFound if result.blank?
|
94
|
+
result
|
82
95
|
end
|
83
96
|
|
84
97
|
# Finds the first record matching the specified conditions. There is no implied ordering so if order matters, you should specify it yourself.
|
85
98
|
# @param Hash args of arguments to find
|
86
99
|
def find_by(values)
|
87
|
-
|
100
|
+
all.query_as(:n).where(n: values).limit(1).pluck(:n).first
|
88
101
|
end
|
89
102
|
|
90
103
|
# Like find_by, except that if no record is found, raises a RecordNotFound error.
|
@@ -94,14 +107,14 @@ module Neo4j
|
|
94
107
|
|
95
108
|
# Deletes all nodes and connected relationships from Cypher.
|
96
109
|
def delete_all
|
97
|
-
self.neo4j_session._query("MATCH (n:`#{mapped_label_name}`)-[r]-() DELETE n,r")
|
110
|
+
self.neo4j_session._query("MATCH (n:`#{mapped_label_name}`) OPTIONAL MATCH n-[r]-() DELETE n,r")
|
98
111
|
self.neo4j_session._query("MATCH (n:`#{mapped_label_name}`) DELETE n")
|
99
112
|
end
|
100
113
|
|
101
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
|
102
115
|
# one database query per node in the database, more if callbacks require them.
|
103
116
|
def destroy_all
|
104
|
-
|
117
|
+
all.each(&:destroy)
|
105
118
|
end
|
106
119
|
|
107
120
|
# Creates a Neo4j index on given property
|
@@ -140,8 +153,10 @@ module Neo4j
|
|
140
153
|
#
|
141
154
|
def constraint(property, constraints)
|
142
155
|
Neo4j::Session.on_session_available do |session|
|
143
|
-
|
144
|
-
|
156
|
+
unless Neo4j::Label.constraint?(mapped_label_name, property)
|
157
|
+
label = Neo4j::Label.create(mapped_label_name)
|
158
|
+
label.create_constraint(property, constraints, session)
|
159
|
+
end
|
145
160
|
end
|
146
161
|
end
|
147
162
|
|
@@ -163,7 +178,7 @@ module Neo4j
|
|
163
178
|
|
164
179
|
# @return [Symbol] the label that this class has which corresponds to a Ruby class
|
165
180
|
def mapped_label_name
|
166
|
-
@mapped_label_name ||
|
181
|
+
@mapped_label_name || label_for_model
|
167
182
|
end
|
168
183
|
|
169
184
|
# @return [Neo4j::Label] the label for this class
|
@@ -214,11 +229,30 @@ module Neo4j
|
|
214
229
|
|
215
230
|
# rubocop:disable Style/AccessorMethodName
|
216
231
|
def set_mapped_label_name(name)
|
217
|
-
ActiveSupport::Deprecation.warn 'set_mapped_label_name is deprecated
|
232
|
+
ActiveSupport::Deprecation.warn 'set_mapped_label_name is deprecated, use self.mapped_label_name= instead.', caller
|
218
233
|
|
219
234
|
self.mapped_label_name = name
|
220
235
|
end
|
221
236
|
# rubocop:enable Style/AccessorMethodName
|
237
|
+
|
238
|
+
private
|
239
|
+
|
240
|
+
def label_for_model
|
241
|
+
(self.name.nil? ? object_id.to_s.to_sym : decorated_label_name)
|
242
|
+
end
|
243
|
+
|
244
|
+
def decorated_label_name
|
245
|
+
name = case Neo4j::Config[:module_handling]
|
246
|
+
when :demodulize
|
247
|
+
self.name.demodulize
|
248
|
+
when Proc
|
249
|
+
Neo4j::Config[:module_handling].call self.name
|
250
|
+
else
|
251
|
+
self.name
|
252
|
+
end
|
253
|
+
|
254
|
+
name.to_sym
|
255
|
+
end
|
222
256
|
end
|
223
257
|
end
|
224
258
|
end
|