neo4j 7.2.3 → 8.0.0.alpha.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 +30 -46
- data/Gemfile +15 -14
- data/README.md +21 -14
- data/bin/neo4j-jars +1 -1
- data/lib/neo4j.rb +12 -1
- data/lib/neo4j/active_base.rb +68 -0
- data/lib/neo4j/active_base/session_registry.rb +12 -0
- data/lib/neo4j/active_node.rb +13 -21
- data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +6 -6
- data/lib/neo4j/active_node/enum.rb +3 -6
- data/lib/neo4j/active_node/has_n.rb +24 -19
- data/lib/neo4j/active_node/has_n/association.rb +6 -2
- data/lib/neo4j/active_node/has_n/association/rel_factory.rb +1 -1
- data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +1 -1
- data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +1 -1
- data/lib/neo4j/active_node/id_property.rb +52 -15
- data/lib/neo4j/active_node/labels.rb +32 -10
- data/lib/neo4j/active_node/labels/index.rb +5 -55
- data/lib/neo4j/active_node/node_list_formatter.rb +13 -0
- data/lib/neo4j/active_node/node_wrapper.rb +39 -37
- data/lib/neo4j/active_node/persistence.rb +27 -13
- data/lib/neo4j/active_node/query/query_proxy.rb +11 -9
- data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +4 -4
- data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +1 -0
- data/lib/neo4j/active_node/query/query_proxy_link.rb +13 -9
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +76 -8
- data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +1 -1
- data/lib/neo4j/active_node/query_methods.rb +3 -3
- data/lib/neo4j/active_node/scope.rb +24 -7
- data/lib/neo4j/active_rel.rb +21 -3
- data/lib/neo4j/active_rel/initialize.rb +2 -2
- data/lib/neo4j/active_rel/persistence.rb +32 -6
- data/lib/neo4j/active_rel/persistence/query_factory.rb +3 -3
- data/lib/neo4j/active_rel/property.rb +9 -9
- data/lib/neo4j/active_rel/query.rb +6 -4
- data/lib/neo4j/active_rel/rel_wrapper.rb +24 -16
- data/lib/neo4j/active_rel/related_node.rb +5 -1
- data/lib/neo4j/active_rel/types.rb +2 -2
- data/lib/neo4j/config.rb +0 -1
- data/lib/neo4j/errors.rb +3 -0
- data/lib/neo4j/migration.rb +90 -71
- data/lib/neo4j/migrations.rb +10 -0
- data/lib/neo4j/migrations/base.rb +44 -0
- data/lib/neo4j/migrations/helpers.rb +101 -0
- data/lib/neo4j/migrations/helpers/id_property.rb +75 -0
- data/lib/neo4j/migrations/helpers/relationships.rb +66 -0
- data/lib/neo4j/migrations/helpers/schema.rb +53 -0
- data/lib/neo4j/migrations/migration_file.rb +24 -0
- data/lib/neo4j/migrations/runner.rb +110 -0
- data/lib/neo4j/migrations/schema_migration.rb +9 -0
- data/lib/neo4j/model_schema.rb +100 -0
- data/lib/neo4j/railtie.rb +29 -110
- data/lib/neo4j/schema/operation.rb +24 -13
- data/lib/neo4j/session_manager.rb +137 -0
- data/lib/neo4j/shared.rb +20 -11
- data/lib/neo4j/shared/attributes.rb +10 -16
- data/lib/neo4j/shared/callbacks.rb +3 -3
- data/lib/neo4j/shared/cypher.rb +1 -1
- data/lib/neo4j/shared/declared_properties.rb +1 -1
- data/lib/neo4j/shared/declared_property.rb +1 -1
- data/lib/neo4j/shared/enum.rb +6 -18
- data/lib/neo4j/shared/identity.rb +27 -21
- data/lib/neo4j/shared/persistence.rb +26 -17
- data/lib/neo4j/shared/property.rb +5 -2
- data/lib/neo4j/shared/query_factory.rb +4 -5
- data/lib/neo4j/shared/type_converters.rb +8 -9
- data/lib/neo4j/shared/validations.rb +1 -5
- data/lib/neo4j/tasks/migration.rake +83 -2
- data/lib/neo4j/version.rb +1 -1
- data/lib/rails/generators/neo4j/migration/migration_generator.rb +14 -0
- data/lib/rails/generators/neo4j/migration/templates/migration.erb +9 -0
- data/lib/rails/generators/neo4j/model/model_generator.rb +1 -3
- data/lib/rails/generators/neo4j_generator.rb +1 -0
- data/neo4j.gemspec +3 -3
- metadata +58 -65
- data/bin/rake +0 -17
- data/lib/neo4j/shared/permitted_attributes.rb +0 -28
data/lib/neo4j/shared.rb
CHANGED
@@ -10,21 +10,26 @@ module Neo4j
|
|
10
10
|
include ActiveModel::Serializers::JSON
|
11
11
|
|
12
12
|
module ClassMethods
|
13
|
-
|
13
|
+
# TODO: Deprecate neo4j_session_name(name)
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
# remove?
|
16
|
+
def neo4j_session
|
17
|
+
Neo4j::ActiveBase.current_session
|
18
|
+
end
|
17
19
|
|
18
|
-
|
20
|
+
# remove?
|
21
|
+
def current_transaction
|
22
|
+
Neo4j::ActiveBase.current_transaction
|
19
23
|
end
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
66
|
-
|
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
|
-
|
68
|
+
alias []= write_attribute
|
71
69
|
|
72
70
|
def query_attribute(name)
|
73
|
-
if respond_to? "#{name}?"
|
74
|
-
|
75
|
-
|
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
|
-
|
131
|
-
|
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::
|
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
|
-
|
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
|
-
|
58
|
+
self.class.run_transaction do
|
59
59
|
run_callbacks(:update) { super }
|
60
60
|
end
|
61
61
|
end
|
data/lib/neo4j/shared/cypher.rb
CHANGED
@@ -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
|
data/lib/neo4j/shared/enum.rb
CHANGED
@@ -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 = [:
|
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 =
|
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,
|
89
|
-
|
90
|
-
|
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
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
25
|
-
|
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
|
-
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
-
|
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
|
-
|
118
|
+
alias new? new_record?
|
120
119
|
|
121
120
|
def destroy
|
122
121
|
freeze
|
123
|
-
|
122
|
+
|
123
|
+
destroy_query.exec if _persisted_obj
|
124
|
+
|
124
125
|
@_deleted = true
|
125
126
|
end
|
126
127
|
|
127
128
|
def exist?
|
128
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
197
|
-
|
198
|
-
|
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
|
-
|
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.
|
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::
|
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
|
-
|
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
|
-
|
89
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
291
|
+
alias call to_ruby
|
293
292
|
|
294
293
|
def to_db(value)
|
295
294
|
if value.is_a?(Array)
|