neo4j 7.2.3 → 8.0.0.alpha.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -46
  3. data/Gemfile +15 -14
  4. data/README.md +21 -14
  5. data/bin/neo4j-jars +1 -1
  6. data/lib/neo4j.rb +12 -1
  7. data/lib/neo4j/active_base.rb +68 -0
  8. data/lib/neo4j/active_base/session_registry.rb +12 -0
  9. data/lib/neo4j/active_node.rb +13 -21
  10. data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +6 -6
  11. data/lib/neo4j/active_node/enum.rb +3 -6
  12. data/lib/neo4j/active_node/has_n.rb +24 -19
  13. data/lib/neo4j/active_node/has_n/association.rb +6 -2
  14. data/lib/neo4j/active_node/has_n/association/rel_factory.rb +1 -1
  15. data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +1 -1
  16. data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +1 -1
  17. data/lib/neo4j/active_node/id_property.rb +52 -15
  18. data/lib/neo4j/active_node/labels.rb +32 -10
  19. data/lib/neo4j/active_node/labels/index.rb +5 -55
  20. data/lib/neo4j/active_node/node_list_formatter.rb +13 -0
  21. data/lib/neo4j/active_node/node_wrapper.rb +39 -37
  22. data/lib/neo4j/active_node/persistence.rb +27 -13
  23. data/lib/neo4j/active_node/query/query_proxy.rb +11 -9
  24. data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +4 -4
  25. data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +1 -0
  26. data/lib/neo4j/active_node/query/query_proxy_link.rb +13 -9
  27. data/lib/neo4j/active_node/query/query_proxy_methods.rb +76 -8
  28. data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +1 -1
  29. data/lib/neo4j/active_node/query_methods.rb +3 -3
  30. data/lib/neo4j/active_node/scope.rb +24 -7
  31. data/lib/neo4j/active_rel.rb +21 -3
  32. data/lib/neo4j/active_rel/initialize.rb +2 -2
  33. data/lib/neo4j/active_rel/persistence.rb +32 -6
  34. data/lib/neo4j/active_rel/persistence/query_factory.rb +3 -3
  35. data/lib/neo4j/active_rel/property.rb +9 -9
  36. data/lib/neo4j/active_rel/query.rb +6 -4
  37. data/lib/neo4j/active_rel/rel_wrapper.rb +24 -16
  38. data/lib/neo4j/active_rel/related_node.rb +5 -1
  39. data/lib/neo4j/active_rel/types.rb +2 -2
  40. data/lib/neo4j/config.rb +0 -1
  41. data/lib/neo4j/errors.rb +3 -0
  42. data/lib/neo4j/migration.rb +90 -71
  43. data/lib/neo4j/migrations.rb +10 -0
  44. data/lib/neo4j/migrations/base.rb +44 -0
  45. data/lib/neo4j/migrations/helpers.rb +101 -0
  46. data/lib/neo4j/migrations/helpers/id_property.rb +75 -0
  47. data/lib/neo4j/migrations/helpers/relationships.rb +66 -0
  48. data/lib/neo4j/migrations/helpers/schema.rb +53 -0
  49. data/lib/neo4j/migrations/migration_file.rb +24 -0
  50. data/lib/neo4j/migrations/runner.rb +110 -0
  51. data/lib/neo4j/migrations/schema_migration.rb +9 -0
  52. data/lib/neo4j/model_schema.rb +100 -0
  53. data/lib/neo4j/railtie.rb +29 -110
  54. data/lib/neo4j/schema/operation.rb +24 -13
  55. data/lib/neo4j/session_manager.rb +137 -0
  56. data/lib/neo4j/shared.rb +20 -11
  57. data/lib/neo4j/shared/attributes.rb +10 -16
  58. data/lib/neo4j/shared/callbacks.rb +3 -3
  59. data/lib/neo4j/shared/cypher.rb +1 -1
  60. data/lib/neo4j/shared/declared_properties.rb +1 -1
  61. data/lib/neo4j/shared/declared_property.rb +1 -1
  62. data/lib/neo4j/shared/enum.rb +6 -18
  63. data/lib/neo4j/shared/identity.rb +27 -21
  64. data/lib/neo4j/shared/persistence.rb +26 -17
  65. data/lib/neo4j/shared/property.rb +5 -2
  66. data/lib/neo4j/shared/query_factory.rb +4 -5
  67. data/lib/neo4j/shared/type_converters.rb +8 -9
  68. data/lib/neo4j/shared/validations.rb +1 -5
  69. data/lib/neo4j/tasks/migration.rake +83 -2
  70. data/lib/neo4j/version.rb +1 -1
  71. data/lib/rails/generators/neo4j/migration/migration_generator.rb +14 -0
  72. data/lib/rails/generators/neo4j/migration/templates/migration.erb +9 -0
  73. data/lib/rails/generators/neo4j/model/model_generator.rb +1 -3
  74. data/lib/rails/generators/neo4j_generator.rb +1 -0
  75. data/neo4j.gemspec +3 -3
  76. metadata +58 -65
  77. data/bin/rake +0 -17
  78. data/lib/neo4j/shared/permitted_attributes.rb +0 -28
@@ -10,21 +10,26 @@ module Neo4j
10
10
  include ActiveModel::Serializers::JSON
11
11
 
12
12
  module ClassMethods
13
- attr_writer :neo4j_session_name
13
+ # TODO: Deprecate neo4j_session_name(name)
14
14
 
15
- def neo4j_session_name(name)
16
- ActiveSupport::Deprecation.warn 'neo4j_session_name is deprecated and may be removed from future releases, use neo4j_session_name= instead.', caller
15
+ # remove?
16
+ def neo4j_session
17
+ Neo4j::ActiveBase.current_session
18
+ end
17
19
 
18
- @neo4j_session_name = name
20
+ # remove?
21
+ def current_transaction
22
+ Neo4j::ActiveBase.current_transaction
19
23
  end
20
24
 
21
- def neo4j_session
22
- if @neo4j_session_name
23
- Neo4j::Session.named(@neo4j_session_name) ||
24
- fail("#{self.name} is configured to use a neo4j session named #{@neo4j_session_name}, but no such session is registered with Neo4j::Session")
25
- else
26
- Neo4j::Session.current!
27
- end
25
+ # This should be used everywhere. Should make it easy
26
+ # to support a session-per-model system
27
+ def neo4j_query(*args)
28
+ Neo4j::ActiveBase.query(*args)
29
+ end
30
+
31
+ def new_query
32
+ Neo4j::ActiveBase.new_query
28
33
  end
29
34
  end
30
35
 
@@ -47,5 +52,9 @@ module Neo4j
47
52
  def declared_properties
48
53
  self.class.declared_properties
49
54
  end
55
+
56
+ def neo4j_query(*args)
57
+ self.class.neo4j_query(*args)
58
+ end
50
59
  end
51
60
  end
@@ -61,20 +61,16 @@ module Neo4j::Shared
61
61
  #
62
62
  # @raise [UnknownAttributeError] if the attribute is unknown
63
63
  def write_attribute(name, value)
64
- if respond_to? "#{name}="
65
- send "#{name}=", value
66
- else
67
- fail Neo4j::UnknownAttributeError, "unknown attribute: #{name}"
68
- end
64
+ fail Neo4j::UnknownAttributeError, "unknown attribute: #{name}" if !respond_to? "#{name}="
65
+
66
+ send "#{name}=", value
69
67
  end
70
- alias_method :[]=, :write_attribute
68
+ alias []= write_attribute
71
69
 
72
70
  def query_attribute(name)
73
- if respond_to? "#{name}?"
74
- send "#{name}?"
75
- else
76
- fail Neo4j::UnknownAttributeError, "unknown attribute: #{name}"
77
- end
71
+ fail Neo4j::UnknownAttributeError, "unknown attribute: #{name}" if !respond_to? "#{name}?"
72
+
73
+ send "#{name}?"
78
74
  end
79
75
 
80
76
  private
@@ -126,11 +122,9 @@ module Neo4j::Shared
126
122
  #
127
123
  # @return [AttributeDefinition] Attribute's definition
128
124
  def attribute(name)
129
- if dangerous_attribute?(name)
130
- fail Neo4j::DangerousAttributeError, %(an attribute method named "#{name}" would conflict with an existing method)
131
- else
132
- attribute!(name)
133
- end
125
+ fail Neo4j::DangerousAttributeError, %(an attribute method named "#{name}" would conflict with an existing method) if dangerous_attribute?(name)
126
+
127
+ attribute!(name)
134
128
  end
135
129
 
136
130
  # Returns an Array of attribute names as Strings
@@ -19,7 +19,7 @@ module Neo4j
19
19
  end
20
20
 
21
21
  def destroy #:nodoc:
22
- tx = Neo4j::Transaction.new
22
+ tx = Neo4j::ActiveBase.new_transaction
23
23
  run_callbacks(:destroy) { super }
24
24
  rescue
25
25
  @_deleted = false
@@ -49,13 +49,13 @@ module Neo4j
49
49
  end
50
50
 
51
51
  def create_model #:nodoc:
52
- Neo4j::Transaction.run do
52
+ self.class.run_transaction do
53
53
  run_callbacks(:create) { super }
54
54
  end
55
55
  end
56
56
 
57
57
  def update_model(*) #:nodoc:
58
- Neo4j::Transaction.run do
58
+ self.class.run_transaction do
59
59
  run_callbacks(:update) { super }
60
60
  end
61
61
  end
@@ -17,7 +17,7 @@ module Neo4j::Shared
17
17
  def creates_unique?
18
18
  !!@creates_unique
19
19
  end
20
- alias_method :unique?, :creates_unique?
20
+ alias unique? creates_unique?
21
21
  end
22
22
 
23
23
  module RelIdentifiers
@@ -156,7 +156,7 @@ module Neo4j::Shared
156
156
 
157
157
  def inject_defaults!(object, props)
158
158
  declared_property_defaults.each_pair do |k, v|
159
- props[k.to_sym] = v if object.send(k).nil? && props[k.to_sym].nil?
159
+ props[k.to_sym] = v.respond_to?(:call) ? v.call : v if object.send(k).nil? && props[k.to_sym].nil?
160
160
  end
161
161
  props
162
162
  end
@@ -66,7 +66,7 @@ module Neo4j::Shared
66
66
  def default_value
67
67
  options[:default]
68
68
  end
69
- alias_method :default, :default_value
69
+ alias default default_value
70
70
 
71
71
  def fail_invalid_options!
72
72
  case
@@ -36,9 +36,6 @@ module Neo4j::Shared
36
36
  # media.video_type!
37
37
  # media.video_type? # => true
38
38
  #
39
- # @example Disable index: :exact for enum elements
40
- # Media.enum type: [:image, :video, :unknown], _index: false
41
- #
42
39
  # @example Define a custom mapping for keys-numbers
43
40
  # Media.enum type: { image: 1, video: 2, unknown: 3 }
44
41
  #
@@ -67,13 +64,11 @@ module Neo4j::Shared
67
64
  end
68
65
  end
69
66
 
70
- VALID_OPTIONS_FOR_ENUMS = [:_index, :_prefix, :_suffix, :_default]
71
- DEFAULT_OPTIONS_FOR_ENUMS = {
72
- _index: true
73
- }
67
+ VALID_OPTIONS_FOR_ENUMS = [:_prefix, :_suffix]
68
+ DEFAULT_OPTIONS_FOR_ENUMS = {}
74
69
 
75
70
  def split_options_and_parameters(parameters)
76
- options = DEFAULT_OPTIONS_FOR_ENUMS.clone
71
+ options = {}
77
72
  new_parameters = {}
78
73
  parameters.each do |k, v|
79
74
  if VALID_OPTIONS_FOR_ENUMS.include? k
@@ -85,16 +80,9 @@ module Neo4j::Shared
85
80
  [options, new_parameters]
86
81
  end
87
82
 
88
- def define_property(property_name, enum_keys, options)
89
- property_options = build_property_options(enum_keys, options)
90
- property property_name, property_options
91
- serialize property_name, Neo4j::Shared::TypeConverters::EnumConverter.new(enum_keys, property_options)
92
- end
93
-
94
- def build_property_options(_enum_keys, options = {})
95
- {
96
- default: options[:_default]
97
- }
83
+ def define_property(property_name, enum_keys, _options)
84
+ property property_name, default: enum_keys.keys.first # .merge(options)
85
+ serialize property_name, Neo4j::Shared::TypeConverters::EnumConverter.new(enum_keys)
98
86
  end
99
87
 
100
88
  def define_enum_methods(property_name, enum_keys, options)
@@ -1,28 +1,34 @@
1
- module Neo4j::Shared
2
- module Identity
3
- def ==(other)
4
- other.class == self.class && other.id == id
5
- end
6
- alias_method :eql?, :==
1
+ module Neo4j
2
+ module Shared
3
+ module Identity
4
+ def ==(other)
5
+ other.class == self.class && other.id == id
6
+ end
7
+ alias eql? ==
7
8
 
8
- # Returns an Enumerable of all (primary) key attributes
9
- # or nil if model.persisted? is false
10
- def to_key
11
- _persisted_obj ? [id] : nil
12
- end
9
+ # Returns an Enumerable of all (primary) key attributes
10
+ # or nil if model.persisted? is false
11
+ def to_key
12
+ _persisted_obj ? [id] : nil
13
+ end
13
14
 
14
- # @return [Integer, nil] the neo4j id of the node if persisted or nil
15
- def neo_id
16
- _persisted_obj ? _persisted_obj.neo_id : nil
17
- end
15
+ # @return [Integer, nil] the neo4j id of the node if persisted or nil
16
+ def neo_id
17
+ _persisted_obj ? _persisted_obj.neo_id : nil
18
+ end
18
19
 
19
- def id
20
- id = neo_id
21
- id.is_a?(Integer) ? id : nil
22
- end
20
+ def id
21
+ if self.class.id_property_name
22
+ send(self.class.id_property_name)
23
+ else
24
+ # ActiveRel
25
+ neo_id
26
+ end
27
+ end
23
28
 
24
- def hash
25
- id.hash
29
+ def hash
30
+ id.hash
31
+ end
26
32
  end
27
33
  end
28
34
  end
@@ -9,7 +9,7 @@ module Neo4j::Shared
9
9
 
10
10
  def update_model
11
11
  return if !changed_attributes || changed_attributes.empty?
12
- _persisted_obj.update_props(props_for_update)
12
+ neo4j_query(query_as(:n).set(n: props_for_update))
13
13
  changed_attributes.clear
14
14
  end
15
15
 
@@ -81,14 +81,13 @@ module Neo4j::Shared
81
81
  @_create_or_updating = true
82
82
  apply_default_values
83
83
  result = _persisted_obj ? update_model : create_model
84
- if result == false
85
- Neo4j::Transaction.current.failure if Neo4j::Transaction.current
86
- false
87
- else
88
- true
89
- end
84
+ current_transaction = Neo4j::ActiveBase.current_transaction
85
+
86
+ current_transaction.mark_failed if result == false && current_transaction
87
+
88
+ result != false
90
89
  rescue => e
91
- Neo4j::Transaction.current.failure if Neo4j::Transaction.current
90
+ current_transaction.mark_failed if current_transaction
92
91
  raise e
93
92
  ensure
94
93
  @_create_or_updating = nil
@@ -97,7 +96,7 @@ module Neo4j::Shared
97
96
  def apply_default_values
98
97
  return if self.class.declared_property_defaults.empty?
99
98
  self.class.declared_property_defaults.each_pair do |key, value|
100
- self.send("#{key}=", value) if self.send(key).nil?
99
+ self.send("#{key}=", value.respond_to?(:call) ? value.call : value) if self.send(key).nil?
101
100
  end
102
101
  end
103
102
 
@@ -116,16 +115,20 @@ module Neo4j::Shared
116
115
  !_persisted_obj
117
116
  end
118
117
 
119
- alias_method :new?, :new_record?
118
+ alias new? new_record?
120
119
 
121
120
  def destroy
122
121
  freeze
123
- _persisted_obj && _persisted_obj.del
122
+
123
+ destroy_query.exec if _persisted_obj
124
+
124
125
  @_deleted = true
125
126
  end
126
127
 
127
128
  def exist?
128
- _persisted_obj && _persisted_obj.exist?
129
+ return if !_persisted_obj
130
+
131
+ neo4j_query(query_as(:n).return('ID(n)')).any?
129
132
  end
130
133
 
131
134
  # Returns +true+ if the object was destroyed.
@@ -170,14 +173,14 @@ module Neo4j::Shared
170
173
  self.attributes = process_attributes(attributes)
171
174
  save
172
175
  end
173
- alias_method :update_attributes, :update
176
+ alias update_attributes update
174
177
 
175
178
  # Same as {#update_attributes}, but raises an exception if saving fails.
176
179
  def update!(attributes)
177
180
  self.attributes = process_attributes(attributes)
178
181
  save!
179
182
  end
180
- alias_method :update_attributes!, :update!
183
+ alias update_attributes! update!
181
184
 
182
185
  def cache_key
183
186
  if self.new_record?
@@ -189,13 +192,19 @@ module Neo4j::Shared
189
192
  end
190
193
  end
191
194
 
195
+ module ClassMethods
196
+ def run_transaction(run_in_tx = true)
197
+ Neo4j::ActiveBase.run_transaction(run_in_tx) { |tx| yield tx }
198
+ end
199
+ end
200
+
192
201
  protected
193
202
 
194
203
  def increment_by_query!(match_query, attribute, by, element_name = :n)
195
204
  new_attribute = match_query.with(element_name)
196
- .set("#{element_name}.`#{attribute}` = COALESCE(#{element_name}.`#{attribute}`, 0) + {by}")
197
- .params(by: by).limit(1)
198
- .pluck("#{element_name}.`#{attribute}`").first
205
+ .set("#{element_name}.`#{attribute}` = COALESCE(#{element_name}.`#{attribute}`, 0) + {by}")
206
+ .params(by: by).limit(1)
207
+ .pluck("#{element_name}.`#{attribute}`").first
199
208
  return false unless new_attribute
200
209
  self[attribute] = new_attribute
201
210
  changed_attributes.delete(attribute)
@@ -37,7 +37,7 @@ module Neo4j::Shared
37
37
  def read_attribute(name)
38
38
  respond_to?(name) ? send(name) : nil
39
39
  end
40
- alias_method :[], :read_attribute
40
+ alias [] read_attribute
41
41
 
42
42
  def send_props(hash)
43
43
  return hash if hash.blank?
@@ -58,7 +58,7 @@ module Neo4j::Shared
58
58
  return attributes if attributes.blank?
59
59
  invalid_properties = attributes.keys.map(&:to_s) - self.attributes.keys
60
60
  invalid_properties.reject! { |name| self.respond_to?("#{name}=") }
61
- fail UndefinedPropertyError, "Undefined properties: #{invalid_properties.join(',')}" if invalid_properties.size > 0
61
+ fail UndefinedPropertyError, "Undefined properties: #{invalid_properties.join(',')}" if !invalid_properties.empty?
62
62
  end
63
63
 
64
64
  def extract_writer_methods!(attributes)
@@ -113,6 +113,7 @@ module Neo4j::Shared
113
113
 
114
114
  def_delegators :declared_properties, :serialized_properties, :serialized_properties=, :serialize, :declared_property_defaults
115
115
 
116
+ VALID_PROPERTY_OPTIONS = %w(type default index constraint serializer typecaster null).map(&:to_sym)
116
117
  # Defines a property on the class
117
118
  #
118
119
  # See active_attr gem for allowed options, e.g which type
@@ -142,6 +143,8 @@ module Neo4j::Shared
142
143
  # property :name, constraint: :unique
143
144
  # end
144
145
  def property(name, options = {})
146
+ invalid_option_keys = options.keys.map(&:to_sym) - VALID_PROPERTY_OPTIONS
147
+ fail ArgumentError, "Invalid options for property `#{name}` on `#{self.name}`: #{invalid_option_keys.join(', ')}" if invalid_option_keys.any?
145
148
  build_property(name, options) do |prop|
146
149
  attribute(prop)
147
150
  end
@@ -36,7 +36,7 @@ module Neo4j::Shared
36
36
  end
37
37
 
38
38
  def base_query
39
- @base_query || Neo4j::Session.current.query
39
+ @base_query || Neo4j::ActiveBase.new_query
40
40
  end
41
41
 
42
42
  protected
@@ -69,8 +69,7 @@ module Neo4j::Shared
69
69
 
70
70
  def create_query
71
71
  return match_query if graph_object.persisted?
72
- labels = graph_object.labels_for_create.map { |l| ":`#{l}`" }.join
73
- base_query.create("(#{identifier}#{labels} {#{identifier}_params})").params(identifier_params => graph_object.props_for_create)
72
+ base_query.create(identifier => {graph_object.labels_for_create => graph_object.props_for_create})
74
73
  end
75
74
  end
76
75
 
@@ -85,8 +84,8 @@ module Neo4j::Shared
85
84
  return match_query if graph_object.persisted?
86
85
  create_props, set_props = filtered_props
87
86
  base_query.send(graph_object.create_method, query_string).break
88
- .set(identifier => set_props)
89
- .params(:"#{identifier}_create_props" => create_props)
87
+ .set(identifier => set_props)
88
+ .params(:"#{identifier}_create_props" => create_props)
90
89
  end
91
90
 
92
91
  private
@@ -38,7 +38,7 @@ module Neo4j::Shared
38
38
  value.to_i
39
39
  end
40
40
 
41
- alias_method :to_ruby, :to_db
41
+ alias to_ruby to_db
42
42
  end
43
43
  end
44
44
 
@@ -55,7 +55,7 @@ module Neo4j::Shared
55
55
  def to_db(value)
56
56
  value.to_f
57
57
  end
58
- alias_method :to_ruby, :to_db
58
+ alias to_ruby to_db
59
59
  end
60
60
  end
61
61
 
@@ -79,7 +79,7 @@ module Neo4j::Shared
79
79
  BigDecimal.new(value.to_s)
80
80
  end
81
81
  end
82
- alias_method :to_ruby, :to_db
82
+ alias to_ruby to_db
83
83
  end
84
84
  end
85
85
 
@@ -96,7 +96,7 @@ module Neo4j::Shared
96
96
  def to_db(value)
97
97
  value.to_s
98
98
  end
99
- alias_method :to_ruby, :to_db
99
+ alias to_ruby to_db
100
100
  end
101
101
  end
102
102
 
@@ -116,7 +116,7 @@ module Neo4j::Shared
116
116
  Neo4j::Shared::Boolean
117
117
  end
118
118
 
119
- alias_method :convert_type, :db_type
119
+ alias convert_type db_type
120
120
 
121
121
  def to_db(value)
122
122
  return false if FALSE_VALUES.include?(value)
@@ -130,7 +130,7 @@ module Neo4j::Shared
130
130
  end
131
131
  end
132
132
 
133
- alias_method :to_ruby, :to_db
133
+ alias to_ruby to_db
134
134
  end
135
135
  end
136
136
 
@@ -264,9 +264,8 @@ module Neo4j::Shared
264
264
  end
265
265
 
266
266
  class EnumConverter
267
- def initialize(enum_keys, options)
267
+ def initialize(enum_keys)
268
268
  @enum_keys = enum_keys
269
- @options = options
270
269
  end
271
270
 
272
271
  def converted?(value)
@@ -289,7 +288,7 @@ module Neo4j::Shared
289
288
  @enum_keys.key(value) unless value.nil?
290
289
  end
291
290
 
292
- alias_method :call, :to_ruby
291
+ alias call to_ruby
293
292
 
294
293
  def to_db(value)
295
294
  if value.is_a?(Array)