neo4j 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +10 -0
  3. data/Gemfile +6 -16
  4. data/README.md +5 -2
  5. data/bin/neo4j-jars +6 -6
  6. data/lib/neo4j.rb +13 -9
  7. data/lib/neo4j/active_node.rb +9 -9
  8. data/lib/neo4j/active_node/dependent.rb +11 -0
  9. data/lib/neo4j/active_node/dependent/association_methods.rb +28 -0
  10. data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +48 -0
  11. data/lib/neo4j/active_node/has_n.rb +124 -112
  12. data/lib/neo4j/active_node/has_n/association.rb +45 -30
  13. data/lib/neo4j/active_node/id_property.rb +22 -19
  14. data/lib/neo4j/active_node/initialize.rb +2 -4
  15. data/lib/neo4j/active_node/labels.rb +23 -22
  16. data/lib/neo4j/active_node/node_wrapper.rb +5 -8
  17. data/lib/neo4j/active_node/orm_adapter.rb +2 -4
  18. data/lib/neo4j/active_node/persistence.rb +5 -10
  19. data/lib/neo4j/active_node/property.rb +3 -4
  20. data/lib/neo4j/active_node/query.rb +27 -6
  21. data/lib/neo4j/active_node/query/query_proxy.rb +65 -110
  22. data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +67 -0
  23. data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +0 -1
  24. data/lib/neo4j/active_node/query/query_proxy_methods.rb +29 -28
  25. data/lib/neo4j/active_node/query_methods.rb +6 -6
  26. data/lib/neo4j/active_node/reflection.rb +3 -2
  27. data/lib/neo4j/active_node/rels.rb +1 -1
  28. data/lib/neo4j/active_node/scope.rb +13 -8
  29. data/lib/neo4j/active_node/validations.rb +5 -6
  30. data/lib/neo4j/active_rel.rb +1 -2
  31. data/lib/neo4j/active_rel/callbacks.rb +3 -3
  32. data/lib/neo4j/active_rel/persistence.rb +9 -7
  33. data/lib/neo4j/active_rel/property.rb +12 -4
  34. data/lib/neo4j/active_rel/query.rb +6 -8
  35. data/lib/neo4j/active_rel/rel_wrapper.rb +0 -2
  36. data/lib/neo4j/active_rel/related_node.rb +4 -5
  37. data/lib/neo4j/active_rel/types.rb +4 -6
  38. data/lib/neo4j/active_rel/validations.rb +0 -1
  39. data/lib/neo4j/config.rb +11 -23
  40. data/lib/neo4j/core/query.rb +1 -1
  41. data/lib/neo4j/migration.rb +17 -18
  42. data/lib/neo4j/paginated.rb +4 -4
  43. data/lib/neo4j/railtie.rb +19 -19
  44. data/lib/neo4j/shared.rb +7 -3
  45. data/lib/neo4j/shared/callbacks.rb +15 -4
  46. data/lib/neo4j/shared/identity.rb +2 -2
  47. data/lib/neo4j/shared/persistence.rb +10 -21
  48. data/lib/neo4j/shared/property.rb +17 -30
  49. data/lib/neo4j/shared/rel_type_converters.rb +1 -3
  50. data/lib/neo4j/shared/type_converters.rb +13 -25
  51. data/lib/neo4j/shared/validations.rb +3 -3
  52. data/lib/neo4j/tasks/migration.rake +7 -7
  53. data/lib/neo4j/type_converters.rb +1 -1
  54. data/lib/neo4j/version.rb +1 -1
  55. data/lib/rails/generators/neo4j/model/model_generator.rb +16 -12
  56. data/lib/rails/generators/neo4j_generator.rb +18 -18
  57. data/neo4j.gemspec +22 -18
  58. metadata +103 -1
@@ -8,13 +8,17 @@ module Neo4j
8
8
  include ActiveModel::Serializers::JSON
9
9
 
10
10
  module ClassMethods
11
- def neo4j_session_name (name)
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) || raise("#{self.name} is configured to use a neo4j session named #{@neo4j_session_name}, but no such session is registered with Neo4j::Session")
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, :only => :after
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
- run_callbacks(:create) { super }
39
+ Neo4j::Transaction.run do
40
+ run_callbacks(:create) { super }
41
+ end
32
42
  end
33
43
 
34
44
  def update_model(*) #:nodoc:
35
- run_callbacks(:update) { super }
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,7 +1,7 @@
1
1
  module Neo4j::Shared
2
2
  module Identity
3
- def ==(o)
4
- o.class == self.class && o.id == id
3
+ def ==(other)
4
+ other.class == self.class && other.id == id
5
5
  end
6
6
  alias_method :eql?, :==
7
7
 
@@ -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,v| changed_attributes.include?(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 = persisted? ? update_model : create_model
38
- unless result != false
39
- Neo4j::Transaction.current.fail if 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.fail if 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. its not a new record and it was not destroyed
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
- alias :new? :new_record?
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{|k,v| v.nil?}.symbolize_keys
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[from_node to_node start_node end_node]
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
- raise UndefinedPropertyError, "Undefined properties: #{invalid_properties.join(',')}" if invalid_properties.size > 0
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.inject({}) do |writer_method_props, key|
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 => e
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? { |v| v.nil? }
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
- raise ArgumentError, "Argument `#{name}` not an attribute" if not attribute_names.include?(name.to_s)
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
- raise "unknown constraint type #{options[:constraint]}, only :unique supported" if options[:constraint] != :unique
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
- raise "unknown index type #{options[:index]}, only :exact supported" if options[:index] != :exact
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
- raise IllegalPropertyError, "#{name} is an illegal property"
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
- set_stamp_type(name, options)
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
- # ActiveAttr does not handle "Time", Rails and Neo4j.rb 2.3 did
223
- # Convert it to DateTime in the interest of consistency
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
- raise ArgumentError, "Invalid value type for DateType property: #{value.inspect}"
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
- properties = properties.inject({}) do |new_attributes, key_value_pair|
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.has_key?(attr.to_sym) ? serialize[attr.to_sym] : self.class._attribute_type(attr)
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
- value
142
- else
143
- TypeConverters.send "to_#{medium}", value, type
144
- end
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.find_all do |c|
166
- Neo4j::Shared::TypeConverters.const_get(c).respond_to?(:convert_type)
167
- end.map do |c|
168
- Neo4j::Shared::TypeConverters.const_get(c)
169
- end.inject({}) do |ack, t|
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