neo4j 4.1.5 → 5.0.0.rc.1
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.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
|