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
data/lib/neo4j/shared.rb
CHANGED
@@ -8,13 +8,17 @@ module Neo4j
|
|
8
8
|
include ActiveModel::Serializers::JSON
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
-
|
11
|
+
attr_writer :neo4j_session_name
|
12
|
+
|
13
|
+
def neo4j_session_name(name)
|
14
|
+
ActiveSupport::Deprecation.warn 'neo4j_session_name is deprecated and may be removed from future releases, use neo4j_session_name= instead.', caller
|
15
|
+
|
12
16
|
@neo4j_session_name = name
|
13
17
|
end
|
14
18
|
|
15
19
|
def neo4j_session
|
16
20
|
if @neo4j_session_name
|
17
|
-
Neo4j::Session.named(@neo4j_session_name) ||
|
21
|
+
Neo4j::Session.named(@neo4j_session_name) || fail("#{self.name} is configured to use a neo4j session named #{@neo4j_session_name}, but no such session is registered with Neo4j::Session")
|
18
22
|
else
|
19
23
|
Neo4j::Session.current!
|
20
24
|
end
|
@@ -29,4 +33,4 @@ module Neo4j
|
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
32
|
-
end
|
36
|
+
end
|
@@ -9,12 +9,20 @@ module Neo4j
|
|
9
9
|
|
10
10
|
included do
|
11
11
|
include ActiveModel::Validations::Callbacks
|
12
|
-
define_model_callbacks :initialize, :find, :
|
12
|
+
define_model_callbacks :initialize, :find, only: :after
|
13
13
|
define_model_callbacks :save, :create, :update, :destroy
|
14
14
|
end
|
15
15
|
|
16
16
|
def destroy #:nodoc:
|
17
|
+
tx = Neo4j::Transaction.new
|
17
18
|
run_callbacks(:destroy) { super }
|
19
|
+
rescue
|
20
|
+
@_deleted = false
|
21
|
+
@attributes = @attributes.dup
|
22
|
+
tx.mark_failed
|
23
|
+
raise
|
24
|
+
ensure
|
25
|
+
tx.close if tx
|
18
26
|
end
|
19
27
|
|
20
28
|
def touch(*) #:nodoc:
|
@@ -28,13 +36,16 @@ module Neo4j
|
|
28
36
|
end
|
29
37
|
|
30
38
|
def create_model #:nodoc:
|
31
|
-
|
39
|
+
Neo4j::Transaction.run do
|
40
|
+
run_callbacks(:create) { super }
|
41
|
+
end
|
32
42
|
end
|
33
43
|
|
34
44
|
def update_model(*) #:nodoc:
|
35
|
-
|
45
|
+
Neo4j::Transaction.run do
|
46
|
+
run_callbacks(:update) { super }
|
47
|
+
end
|
36
48
|
end
|
37
49
|
end
|
38
|
-
|
39
50
|
end
|
40
51
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Neo4j::Shared
|
2
2
|
module Persistence
|
3
|
-
|
4
3
|
extend ActiveSupport::Concern
|
5
4
|
include Neo4j::Shared::TypeConverters
|
6
5
|
|
@@ -8,7 +7,7 @@ module Neo4j::Shared
|
|
8
7
|
|
9
8
|
def update_model
|
10
9
|
if changed_attributes && !changed_attributes.empty?
|
11
|
-
changed_props = attributes.select{|k,
|
10
|
+
changed_props = attributes.select { |k, _| changed_attributes.include?(k) }
|
12
11
|
changed_props = convert_properties_to :db, changed_props
|
13
12
|
_persisted_obj.update_props(changed_props)
|
14
13
|
changed_attributes.clear
|
@@ -34,21 +33,21 @@ module Neo4j::Shared
|
|
34
33
|
def create_or_update
|
35
34
|
# since the same model can be created or updated twice from a relationship we have to have this guard
|
36
35
|
@_create_or_updating = true
|
37
|
-
result =
|
38
|
-
|
39
|
-
Neo4j::Transaction.current.
|
36
|
+
result = _persisted_obj ? update_model : create_model
|
37
|
+
if result == false
|
38
|
+
Neo4j::Transaction.current.failure if Neo4j::Transaction.current
|
40
39
|
false
|
41
40
|
else
|
42
41
|
true
|
43
42
|
end
|
44
43
|
rescue => e
|
45
|
-
Neo4j::Transaction.current.
|
44
|
+
Neo4j::Transaction.current.failure if Neo4j::Transaction.current
|
46
45
|
raise e
|
47
46
|
ensure
|
48
47
|
@_create_or_updating = nil
|
49
48
|
end
|
50
49
|
|
51
|
-
# Returns +true+ if the record is persisted, i.e. it
|
50
|
+
# Returns +true+ if the record is persisted, i.e. it's not a new record and it was not destroyed
|
52
51
|
def persisted?
|
53
52
|
!new_record? && !destroyed?
|
54
53
|
end
|
@@ -58,9 +57,10 @@ module Neo4j::Shared
|
|
58
57
|
!_persisted_obj
|
59
58
|
end
|
60
59
|
|
61
|
-
|
60
|
+
alias_method :new?, :new_record?
|
62
61
|
|
63
62
|
def destroy
|
63
|
+
freeze
|
64
64
|
_persisted_obj && _persisted_obj.del
|
65
65
|
@_deleted = true
|
66
66
|
end
|
@@ -77,12 +77,11 @@ module Neo4j::Shared
|
|
77
77
|
|
78
78
|
# @return [Hash] all defined and none nil properties
|
79
79
|
def props
|
80
|
-
attributes.reject{|
|
80
|
+
attributes.reject { |_, v| v.nil? }.symbolize_keys
|
81
81
|
end
|
82
82
|
|
83
83
|
# @return true if the attributes hash has been frozen
|
84
84
|
def frozen?
|
85
|
-
freeze_if_deleted
|
86
85
|
@attributes.frozen?
|
87
86
|
end
|
88
87
|
|
@@ -91,16 +90,6 @@ module Neo4j::Shared
|
|
91
90
|
self
|
92
91
|
end
|
93
92
|
|
94
|
-
def freeze_if_deleted
|
95
|
-
unless new_record?
|
96
|
-
# TODO - Neo4j::IdentityMap.remove_node_by_id(neo_id)
|
97
|
-
unless self.class.load_entity(neo_id)
|
98
|
-
@_deleted = true
|
99
|
-
freeze
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
93
|
def reload
|
105
94
|
return self if new_record?
|
106
95
|
clear_association_cache
|
@@ -113,7 +102,7 @@ module Neo4j::Shared
|
|
113
102
|
end
|
114
103
|
|
115
104
|
def reload_from_database
|
116
|
-
# TODO - Neo4j::IdentityMap.remove_node_by_id(neo_id)
|
105
|
+
# TODO: - Neo4j::IdentityMap.remove_node_by_id(neo_id)
|
117
106
|
if reloaded = self.class.load_entity(neo_id)
|
118
107
|
send(:attributes=, reloaded.attributes)
|
119
108
|
end
|
@@ -13,11 +13,11 @@ module Neo4j::Shared
|
|
13
13
|
class MultiparameterAssignmentError < StandardError; end
|
14
14
|
class IllegalPropertyError < StandardError; end
|
15
15
|
|
16
|
-
ILLEGAL_PROPS = %w
|
16
|
+
ILLEGAL_PROPS = %w(from_node to_node start_node end_node)
|
17
17
|
|
18
18
|
attr_reader :_persisted_obj
|
19
19
|
|
20
|
-
def initialize(attributes={}, options={})
|
20
|
+
def initialize(attributes = {}, options = {})
|
21
21
|
attributes = process_attributes(attributes)
|
22
22
|
@relationship_props = self.class.extract_association_attributes!(attributes)
|
23
23
|
writer_method_props = extract_writer_methods!(attributes)
|
@@ -39,7 +39,7 @@ module Neo4j::Shared
|
|
39
39
|
|
40
40
|
def default_properties=(properties)
|
41
41
|
keys = self.class.default_properties.keys
|
42
|
-
@default_properties = properties.select {|key| keys.include?(key) }
|
42
|
+
@default_properties = properties.select { |key| keys.include?(key) }
|
43
43
|
end
|
44
44
|
|
45
45
|
def default_property(key)
|
@@ -64,14 +64,12 @@ module Neo4j::Shared
|
|
64
64
|
# Raises an error if there are any keys left which haven't been defined as properties on the model
|
65
65
|
def validate_attributes!(attributes)
|
66
66
|
invalid_properties = attributes.keys.map(&:to_s) - self.attributes.keys
|
67
|
-
|
67
|
+
fail UndefinedPropertyError, "Undefined properties: #{invalid_properties.join(',')}" if invalid_properties.size > 0
|
68
68
|
end
|
69
69
|
|
70
70
|
def extract_writer_methods!(attributes)
|
71
|
-
attributes.keys.
|
71
|
+
attributes.keys.each_with_object({}) do |key, writer_method_props|
|
72
72
|
writer_method_props[key] = attributes.delete(key) if self.respond_to?("#{key}=")
|
73
|
-
|
74
|
-
writer_method_props
|
75
73
|
end
|
76
74
|
end
|
77
75
|
|
@@ -97,7 +95,7 @@ module Neo4j::Shared
|
|
97
95
|
values = (values.keys.min..values.keys.max).map { |i| values[i] }
|
98
96
|
field = self.class.attributes[key.to_sym]
|
99
97
|
new_attributes[key] = instantiate_object(field, values)
|
100
|
-
rescue
|
98
|
+
rescue
|
101
99
|
raise MultiparameterAssignmentError, "error on assignment #{values.inspect} to #{key}"
|
102
100
|
end
|
103
101
|
end
|
@@ -105,14 +103,13 @@ module Neo4j::Shared
|
|
105
103
|
end
|
106
104
|
|
107
105
|
def instantiate_object(field, values_with_empty_parameters)
|
108
|
-
return nil if values_with_empty_parameters.all?
|
106
|
+
return nil if values_with_empty_parameters.all?(&:nil?)
|
109
107
|
values = values_with_empty_parameters.collect { |v| v.nil? ? 1 : v }
|
110
108
|
klass = field[:type]
|
111
109
|
klass ? klass.new(*values) : values
|
112
110
|
end
|
113
111
|
|
114
112
|
module ClassMethods
|
115
|
-
|
116
113
|
# Defines a property on the class
|
117
114
|
#
|
118
115
|
# See active_attr gem for allowed options, e.g which type
|
@@ -141,7 +138,7 @@ module Neo4j::Shared
|
|
141
138
|
# # declare a property which can have any value
|
142
139
|
# property :name, constraint: :unique
|
143
140
|
# end
|
144
|
-
def property(name, options={})
|
141
|
+
def property(name, options = {})
|
145
142
|
check_illegal_prop(name)
|
146
143
|
magic_properties(name, options)
|
147
144
|
attribute(name, options)
|
@@ -149,7 +146,7 @@ module Neo4j::Shared
|
|
149
146
|
end
|
150
147
|
|
151
148
|
def undef_property(name)
|
152
|
-
|
149
|
+
fail ArgumentError, "Argument `#{name}` not an attribute" if not attribute_names.include?(name.to_s)
|
153
150
|
|
154
151
|
attribute_methods(name).each do |method|
|
155
152
|
undef_method(method)
|
@@ -176,12 +173,12 @@ module Neo4j::Shared
|
|
176
173
|
end
|
177
174
|
|
178
175
|
def default_property_values(instance)
|
179
|
-
default_properties.each_with_object({}) do |(key, block),result|
|
176
|
+
default_properties.each_with_object({}) do |(key, block), result|
|
180
177
|
result[key] = block.call(instance)
|
181
178
|
end
|
182
179
|
end
|
183
180
|
|
184
|
-
def attribute!(name, options={})
|
181
|
+
def attribute!(name, options = {})
|
185
182
|
super(name, options)
|
186
183
|
define_method("#{name}=") do |value|
|
187
184
|
typecast_value = typecast_attribute(_attribute_typecaster(name), value)
|
@@ -195,38 +192,28 @@ module Neo4j::Shared
|
|
195
192
|
def constraint_or_index(name, options)
|
196
193
|
# either constraint or index, do not set both
|
197
194
|
if options[:constraint]
|
198
|
-
|
195
|
+
fail "unknown constraint type #{options[:constraint]}, only :unique supported" if options[:constraint] != :unique
|
199
196
|
constraint(name, type: :unique)
|
200
197
|
elsif options[:index]
|
201
|
-
|
198
|
+
fail "unknown index type #{options[:index]}, only :exact supported" if options[:index] != :exact
|
202
199
|
index(name, options) if options[:index] == :exact
|
203
200
|
end
|
204
201
|
end
|
205
202
|
|
206
203
|
def check_illegal_prop(name)
|
207
204
|
if ILLEGAL_PROPS.include?(name.to_s)
|
208
|
-
|
205
|
+
fail IllegalPropertyError, "#{name} is an illegal property"
|
209
206
|
end
|
210
207
|
end
|
211
208
|
|
212
209
|
# Tweaks properties
|
213
210
|
def magic_properties(name, options)
|
214
|
-
|
215
|
-
set_time_as_datetime(options)
|
216
|
-
end
|
217
|
-
|
218
|
-
def set_stamp_type(name, options)
|
219
|
-
options[:type] ||= DateTime if (name.to_sym == :created_at || name.to_sym == :updated_at)
|
220
|
-
end
|
211
|
+
options[:type] ||= DateTime if name.to_sym == :created_at || name.to_sym == :updated_at
|
221
212
|
|
222
|
-
|
223
|
-
|
224
|
-
def set_time_as_datetime(options)
|
213
|
+
# ActiveAttr does not handle "Time", Rails and Neo4j.rb 2.3 did
|
214
|
+
# Convert it to DateTime in the interest of consistency
|
225
215
|
options[:type] = DateTime if options[:type] == Time
|
226
216
|
end
|
227
|
-
|
228
217
|
end
|
229
|
-
|
230
218
|
end
|
231
|
-
|
232
219
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
module Neo4j::Shared
|
2
|
-
|
3
2
|
# This module controls changes to relationship type based on Neo4j::Config.transform_rel_type.
|
4
3
|
# It's used whenever a rel type is automatically determined based on ActiveRel model name or
|
5
4
|
# association type.
|
6
5
|
module RelTypeConverters
|
7
|
-
|
8
6
|
def decorated_rel_type(type)
|
9
7
|
@decorated_rel_type ||= Neo4j::Shared::RelTypeConverters.decorated_rel_type(type)
|
10
8
|
end
|
@@ -41,4 +39,4 @@ module Neo4j::Shared
|
|
41
39
|
end
|
42
40
|
end
|
43
41
|
end
|
44
|
-
end
|
42
|
+
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
module Neo4j::Shared
|
2
2
|
module TypeConverters
|
3
|
-
|
4
3
|
# Converts Date objects to Java long types. Must be timezone UTC.
|
5
4
|
class DateConverter
|
6
5
|
class << self
|
7
|
-
|
8
6
|
def convert_type
|
9
7
|
Date
|
10
8
|
end
|
@@ -18,14 +16,12 @@ module Neo4j::Shared
|
|
18
16
|
return nil if value.nil?
|
19
17
|
Time.at(value).utc.to_date
|
20
18
|
end
|
21
|
-
|
22
19
|
end
|
23
20
|
end
|
24
21
|
|
25
22
|
# Converts DateTime objects to and from Java long types. Must be timezone UTC.
|
26
23
|
class DateTimeConverter
|
27
24
|
class << self
|
28
|
-
|
29
25
|
def convert_type
|
30
26
|
DateTime
|
31
27
|
end
|
@@ -50,18 +46,16 @@ module Neo4j::Shared
|
|
50
46
|
when String
|
51
47
|
DateTime.strptime(value, '%Y-%m-%d %H:%M:%S %z')
|
52
48
|
else
|
53
|
-
|
49
|
+
fail ArgumentError, "Invalid value type for DateType property: #{value.inspect}"
|
54
50
|
end
|
55
51
|
|
56
52
|
DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec)
|
57
53
|
end
|
58
|
-
|
59
54
|
end
|
60
55
|
end
|
61
56
|
|
62
57
|
class TimeConverter
|
63
58
|
class << self
|
64
|
-
|
65
59
|
def convert_type
|
66
60
|
Time
|
67
61
|
end
|
@@ -81,14 +75,12 @@ module Neo4j::Shared
|
|
81
75
|
return nil if value.nil?
|
82
76
|
Time.at(value).utc
|
83
77
|
end
|
84
|
-
|
85
78
|
end
|
86
79
|
end
|
87
80
|
|
88
81
|
# Converts hash to/from YAML
|
89
82
|
class YAMLConverter
|
90
83
|
class << self
|
91
|
-
|
92
84
|
def convert_type
|
93
85
|
Hash
|
94
86
|
end
|
@@ -108,7 +100,6 @@ module Neo4j::Shared
|
|
108
100
|
# Converts hash to/from JSON
|
109
101
|
class JSONConverter
|
110
102
|
class << self
|
111
|
-
|
112
103
|
def convert_type
|
113
104
|
JSON
|
114
105
|
end
|
@@ -130,24 +121,23 @@ module Neo4j::Shared
|
|
130
121
|
def convert_properties_to(medium, properties)
|
131
122
|
# Perform type conversion
|
132
123
|
serialize = self.respond_to?(:serialized_properties) ? self.serialized_properties : {}
|
133
|
-
|
124
|
+
|
125
|
+
properties.each_with_object({}) do |key_value_pair, new_attributes|
|
134
126
|
attr, value = key_value_pair
|
135
127
|
|
136
128
|
# skip "secret" undeclared attributes such as uuid
|
137
129
|
next new_attributes unless self.class.attributes[attr]
|
138
130
|
|
139
|
-
type = serialize.
|
131
|
+
type = serialize.key?(attr.to_sym) ? serialize[attr.to_sym] : self.class._attribute_type(attr)
|
140
132
|
new_attributes[attr] = if TypeConverters.converters[type].nil?
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
new_attributes
|
133
|
+
value
|
134
|
+
else
|
135
|
+
TypeConverters.send "to_#{medium}", value, type
|
136
|
+
end
|
146
137
|
end
|
147
138
|
end
|
148
139
|
|
149
140
|
class << self
|
150
|
-
|
151
141
|
# Converts the value to ruby from a Neo4j database value if there is a converter for given type
|
152
142
|
def to_ruby(value, type = nil)
|
153
143
|
found_converter = converters[type]
|
@@ -162,13 +152,11 @@ module Neo4j::Shared
|
|
162
152
|
|
163
153
|
def converters
|
164
154
|
@converters ||= begin
|
165
|
-
Neo4j::Shared::TypeConverters.constants.
|
166
|
-
Neo4j::Shared::TypeConverters.const_get(
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
ack[t.convert_type] = t
|
171
|
-
ack
|
155
|
+
Neo4j::Shared::TypeConverters.constants.each_with_object({}) do |constant_name, result|
|
156
|
+
constant = Neo4j::Shared::TypeConverters.const_get(constant_name)
|
157
|
+
if constant.respond_to?(:convert_type)
|
158
|
+
result[constant.convert_type] = constant
|
159
|
+
end
|
172
160
|
end
|
173
161
|
end
|
174
162
|
end
|
@@ -14,7 +14,7 @@ module Neo4j
|
|
14
14
|
# @param [Hash] options the options to create a message with.
|
15
15
|
# @option options [true, false] :validate if false no validation will take place
|
16
16
|
# @return [Boolean] true if it saved it successfully
|
17
|
-
def save(options={})
|
17
|
+
def save(options = {})
|
18
18
|
result = perform_validations(options) ? super : false
|
19
19
|
if !result
|
20
20
|
Neo4j::Transaction.current.failure if Neo4j::Transaction.current
|
@@ -31,7 +31,7 @@ module Neo4j
|
|
31
31
|
|
32
32
|
private
|
33
33
|
|
34
|
-
def perform_validations(options={})
|
34
|
+
def perform_validations(options = {})
|
35
35
|
perform_validation = case options
|
36
36
|
when Hash
|
37
37
|
options[:validate] != false
|
@@ -45,4 +45,4 @@ module Neo4j
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
|
-
end
|
48
|
+
end
|