neo4j 5.2.15 → 6.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 +17 -19
- data/Gemfile +1 -1
- data/lib/neo4j.rb +4 -1
- data/lib/neo4j/active_node.rb +6 -15
- data/lib/neo4j/active_node/has_n.rb +52 -21
- data/lib/neo4j/active_node/has_n/association.rb +1 -1
- data/lib/neo4j/active_node/id_property.rb +1 -1
- data/lib/neo4j/active_node/id_property/accessor.rb +1 -1
- data/lib/neo4j/active_node/labels.rb +7 -101
- data/lib/neo4j/active_node/labels/index.rb +87 -0
- data/lib/neo4j/active_node/persistence.rb +3 -2
- data/lib/neo4j/active_node/query.rb +1 -1
- data/lib/neo4j/active_node/query/query_proxy.rb +7 -9
- data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +0 -1
- data/lib/neo4j/active_node/query/query_proxy_link.rb +12 -4
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +4 -6
- data/lib/neo4j/active_node/query/query_proxy_unpersisted.rb +4 -8
- data/lib/neo4j/active_node/unpersisted.rb +12 -10
- data/lib/neo4j/active_node/validations.rb +2 -2
- data/lib/neo4j/active_rel.rb +7 -4
- data/lib/neo4j/active_rel/persistence.rb +13 -4
- data/lib/neo4j/active_rel/query.rb +8 -0
- data/lib/neo4j/active_rel/related_node.rb +1 -27
- data/lib/neo4j/errors.rb +2 -0
- data/lib/neo4j/schema/operation.rb +91 -0
- data/lib/neo4j/shared.rb +3 -3
- data/lib/neo4j/shared/callbacks.rb +2 -7
- data/lib/neo4j/shared/{declared_property_manager.rb → declared_properties.rb} +34 -2
- data/lib/neo4j/shared/declared_property.rb +19 -0
- data/lib/neo4j/shared/declared_property/index.rb +37 -0
- data/lib/neo4j/shared/initialize.rb +2 -2
- data/lib/neo4j/shared/persistence.rb +3 -25
- data/lib/neo4j/shared/property.rb +24 -10
- data/lib/neo4j/shared/type_converters.rb +131 -6
- data/lib/neo4j/tasks/migration.rake +3 -3
- data/lib/neo4j/type_converters.rb +1 -1
- data/lib/neo4j/version.rb +1 -1
- data/neo4j.gemspec +2 -2
- metadata +13 -10
data/lib/neo4j/errors.rb
CHANGED
@@ -0,0 +1,91 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Schema
|
3
|
+
class Operation
|
4
|
+
attr_reader :label_name, :property, :options
|
5
|
+
|
6
|
+
def initialize(label_name, property, options = default_options)
|
7
|
+
@label_name = label_name.to_sym
|
8
|
+
@property = property.to_sym
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.incompatible_operation_classes
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
|
16
|
+
def create!
|
17
|
+
drop_incompatible!
|
18
|
+
return if exist?
|
19
|
+
label_object.send(:"create_#{type}", property, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def label_object
|
23
|
+
@label_object ||= Neo4j::Label.create(label_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def incompatible_operation_classes
|
27
|
+
self.class.incompatible_operation_classes
|
28
|
+
end
|
29
|
+
|
30
|
+
def drop!
|
31
|
+
label_object.send(:"drop_#{type}", property, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def drop_incompatible!
|
35
|
+
incompatible_operation_classes.each do |clazz|
|
36
|
+
operation = clazz.new(label_name, property)
|
37
|
+
operation.drop! if operation.exist?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def exist?
|
42
|
+
fail 'Abstract class, not implemented'
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_options
|
46
|
+
{}
|
47
|
+
end
|
48
|
+
|
49
|
+
def type
|
50
|
+
fail 'Abstract class, not implemented'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class ExactIndexOperation < Neo4j::Schema::Operation
|
55
|
+
def self.incompatible_operation_classes
|
56
|
+
[UniqueConstraintOperation]
|
57
|
+
end
|
58
|
+
|
59
|
+
def type
|
60
|
+
'index'
|
61
|
+
end
|
62
|
+
|
63
|
+
def exist?
|
64
|
+
label_object.indexes[:property_keys].include?([property])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class UniqueConstraintOperation < Neo4j::Schema::Operation
|
69
|
+
def self.incompatible_operation_classes
|
70
|
+
[ExactIndexOperation]
|
71
|
+
end
|
72
|
+
|
73
|
+
def type
|
74
|
+
'constraint'
|
75
|
+
end
|
76
|
+
|
77
|
+
def create!
|
78
|
+
return if exist?
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
def exist?
|
83
|
+
Neo4j::Label.constraint?(label_name, property)
|
84
|
+
end
|
85
|
+
|
86
|
+
def default_options
|
87
|
+
{type: :unique}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/neo4j/shared.rb
CHANGED
@@ -28,15 +28,15 @@ module Neo4j
|
|
28
28
|
|
29
29
|
included do
|
30
30
|
self.include_root_in_json = Neo4j::Config.include_root_in_json
|
31
|
-
@
|
31
|
+
@_declared_properties ||= Neo4j::Shared::DeclaredProperties.new(self)
|
32
32
|
|
33
33
|
def self.i18n_scope
|
34
34
|
:neo4j
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
39
|
-
self.class.
|
38
|
+
def declared_properties
|
39
|
+
self.class.declared_properties
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -9,13 +9,8 @@ module Neo4j
|
|
9
9
|
|
10
10
|
included do
|
11
11
|
include ActiveModel::Validations::Callbacks
|
12
|
-
# after_find is triggered by the `find` method defined in lib/neo4j/active_node/id_property.rb
|
13
12
|
define_model_callbacks :initialize, :find, only: :after
|
14
|
-
define_model_callbacks :save, :create, :update, :destroy
|
15
|
-
end
|
16
|
-
|
17
|
-
def initialize(args = nil)
|
18
|
-
run_callbacks(:initialize) { super }
|
13
|
+
define_model_callbacks :save, :create, :update, :destroy
|
19
14
|
end
|
20
15
|
|
21
16
|
def destroy #:nodoc:
|
@@ -30,7 +25,7 @@ module Neo4j
|
|
30
25
|
tx.close if tx
|
31
26
|
end
|
32
27
|
|
33
|
-
def touch #:nodoc:
|
28
|
+
def touch(*) #:nodoc:
|
34
29
|
run_callbacks(:touch) { super }
|
35
30
|
end
|
36
31
|
|
@@ -5,17 +5,26 @@ module Neo4j::Shared
|
|
5
5
|
# a way of separating behavior from the general Active{obj} modules.
|
6
6
|
#
|
7
7
|
# See Neo4j::Shared::DeclaredProperty for definitions of the property objects themselves.
|
8
|
-
class
|
8
|
+
class DeclaredProperties
|
9
9
|
include Neo4j::Shared::TypeConverters
|
10
10
|
|
11
11
|
attr_reader :klass
|
12
|
+
delegate :each, :each_pair, :each_key, :each_value, to: :registered_properties
|
12
13
|
|
13
14
|
# Each class that includes Neo4j::ActiveNode or Neo4j::ActiveRel gets one instance of this class.
|
14
|
-
# @param [#
|
15
|
+
# @param [#declared_properties] klass An object that has the #declared_properties method.
|
15
16
|
def initialize(klass)
|
16
17
|
@klass = klass
|
17
18
|
end
|
18
19
|
|
20
|
+
def [](key)
|
21
|
+
registered_properties[key.to_sym]
|
22
|
+
end
|
23
|
+
|
24
|
+
def property?(key)
|
25
|
+
registered_properties.key?(key.to_sym)
|
26
|
+
end
|
27
|
+
|
19
28
|
# @param [Neo4j::Shared::DeclaredProperty] property An instance of DeclaredProperty, created as the result of calling
|
20
29
|
# #property on an ActiveNode or ActiveRel class. The DeclaredProperty has specifics about the property, but registration
|
21
30
|
# makes the management object aware of it. This is necessary for type conversion, defaults, and inclusion in the nil and string hashes.
|
@@ -27,6 +36,18 @@ module Neo4j::Shared
|
|
27
36
|
declared_property_defaults[property.name] = property.default_value if !property.default_value.nil?
|
28
37
|
end
|
29
38
|
|
39
|
+
def index_or_fail!(key, id_property_name, type = :exact)
|
40
|
+
return if key == id_property_name
|
41
|
+
fail "Cannot index undeclared property #{key}" unless property?(key)
|
42
|
+
registered_properties[key].index!(type)
|
43
|
+
end
|
44
|
+
|
45
|
+
def constraint_or_fail!(key, id_property_name, type = :unique)
|
46
|
+
return if key == id_property_name
|
47
|
+
fail "Cannot constraint undeclared property #{property}" unless property?(key)
|
48
|
+
registered_properties[key].constraint!(type)
|
49
|
+
end
|
50
|
+
|
30
51
|
# The :default option in Neo4j::ActiveNode#property class method allows for setting a default value instead of
|
31
52
|
# nil on declared properties. This holds those values.
|
32
53
|
def declared_property_defaults
|
@@ -37,6 +58,10 @@ module Neo4j::Shared
|
|
37
58
|
@_registered_properties ||= {}
|
38
59
|
end
|
39
60
|
|
61
|
+
def indexed_properties
|
62
|
+
registered_properties.select { |_, p| p.index_or_constraint? }
|
63
|
+
end
|
64
|
+
|
40
65
|
# During object wrap, a hash is needed that contains each declared property with a nil value.
|
41
66
|
# The active_attr dependency is capable of providing this but it is expensive and calculated on the fly
|
42
67
|
# each time it is called. Rather than rely on that, we build this progressively as properties are registered.
|
@@ -113,6 +138,13 @@ module Neo4j::Shared
|
|
113
138
|
@upstream_primitives ||= {}
|
114
139
|
end
|
115
140
|
|
141
|
+
EXCLUDED_TYPES = [Array, Range, Regexp]
|
142
|
+
def value_for_where(key, value)
|
143
|
+
return value unless prop = registered_properties[key]
|
144
|
+
return value_for_db(key, value) if prop.typecaster && prop.typecaster.convert_type == value.class
|
145
|
+
EXCLUDED_TYPES.include?(value.class) ? value : value_for_db(key, value)
|
146
|
+
end
|
147
|
+
|
116
148
|
def value_for_db(key, value)
|
117
149
|
return value unless registered_properties[key]
|
118
150
|
convert_property(key, value, :to_db)
|
@@ -2,6 +2,7 @@ module Neo4j::Shared
|
|
2
2
|
# Contains methods related to the management
|
3
3
|
class DeclaredProperty
|
4
4
|
class IllegalPropertyError < StandardError; end
|
5
|
+
include Neo4j::Shared::DeclaredProperty::Index
|
5
6
|
|
6
7
|
ILLEGAL_PROPS = %w(from_node to_node start_node end_node)
|
7
8
|
attr_reader :name, :name_string, :name_sym, :options, :magic_typecaster
|
@@ -11,6 +12,7 @@ module Neo4j::Shared
|
|
11
12
|
@name = @name_sym = name
|
12
13
|
@name_string = name.to_s
|
13
14
|
@options = options
|
15
|
+
fail_invalid_options!
|
14
16
|
end
|
15
17
|
|
16
18
|
def register
|
@@ -29,8 +31,25 @@ module Neo4j::Shared
|
|
29
31
|
options[:default]
|
30
32
|
end
|
31
33
|
|
34
|
+
def fail_invalid_options!
|
35
|
+
case
|
36
|
+
when index?(:exact) && constraint?(:unique)
|
37
|
+
fail Neo4j::InvalidPropertyOptionsError,
|
38
|
+
"#Uniqueness constraints also provide exact indexes, cannot set both options on property #{name}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
32
42
|
private
|
33
43
|
|
44
|
+
def option_with_value!(key, value)
|
45
|
+
options[key] = value
|
46
|
+
fail_invalid_options!
|
47
|
+
end
|
48
|
+
|
49
|
+
def option_with_value?(key, value)
|
50
|
+
options[key] == value
|
51
|
+
end
|
52
|
+
|
34
53
|
# Tweaks properties
|
35
54
|
def register_magic_properties
|
36
55
|
options[:type] ||= Neo4j::Config.timestamp_type if timestamp_prop?
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Neo4j::Shared
|
2
|
+
class DeclaredProperty
|
3
|
+
# None of these methods interact with the database. They only keep track of property settings in models.
|
4
|
+
# It could (should?) handle the actual indexing/constraining, but that's TBD.
|
5
|
+
module Index
|
6
|
+
def index_or_constraint?
|
7
|
+
index?(:exact) || constraint?(:unique)
|
8
|
+
end
|
9
|
+
|
10
|
+
def index?(type = :exact)
|
11
|
+
options.key?(:index) && options[:index] == type
|
12
|
+
end
|
13
|
+
|
14
|
+
def constraint?(type = :unique)
|
15
|
+
options.key?(:constraint) && options[:constraint] == type
|
16
|
+
end
|
17
|
+
|
18
|
+
def index!(type = :exact)
|
19
|
+
fail Neo4j::InvalidPropertyOptionsError, "Unable to set index on constrainted property #{name}" if constraint?(:unique)
|
20
|
+
options[:index] = type
|
21
|
+
end
|
22
|
+
|
23
|
+
def constraint!(type = :unique)
|
24
|
+
fail Neo4j::InvalidPropertyOptionsError, "Unable to set constraint on indexed property #{name}" if index?(:exact)
|
25
|
+
options[:constraint] = type
|
26
|
+
end
|
27
|
+
|
28
|
+
def unindex!(type = :exact)
|
29
|
+
options.delete(:index) if index?(type)
|
30
|
+
end
|
31
|
+
|
32
|
+
def unconstraint!(type = :unique)
|
33
|
+
options.delete(:constraint) if constraint?(type)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -15,12 +15,12 @@ module Neo4j::Shared
|
|
15
15
|
@attributes ||= Hash[self.class.attributes_nil_hash]
|
16
16
|
stringify_attributes!(@attributes, properties)
|
17
17
|
self.default_properties = properties if respond_to?(:default_properties=)
|
18
|
-
self.class.
|
18
|
+
self.class.declared_properties.convert_properties_to(self, :ruby, @attributes)
|
19
19
|
end
|
20
20
|
|
21
21
|
def stringify_attributes!(attr, properties)
|
22
22
|
properties.each_pair do |k, v|
|
23
|
-
key = self.class.
|
23
|
+
key = self.class.declared_properties.string_key(k)
|
24
24
|
attr[key.freeze] = v
|
25
25
|
end
|
26
26
|
end
|
@@ -82,11 +82,6 @@ module Neo4j::Shared
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
def touch
|
86
|
-
fail 'Cannot touch on a new record object' unless persisted?
|
87
|
-
update_attribute!(:updated_at, Time.now) if respond_to?(:updated_at=)
|
88
|
-
end
|
89
|
-
|
90
85
|
# Returns +true+ if the record is persisted, i.e. it's not a new record and it was not destroyed
|
91
86
|
def persisted?
|
92
87
|
!new_record? && !destroyed?
|
@@ -111,26 +106,9 @@ module Neo4j::Shared
|
|
111
106
|
|
112
107
|
# Returns +true+ if the object was destroyed.
|
113
108
|
def destroyed?
|
114
|
-
@_deleted
|
109
|
+
@_deleted
|
115
110
|
end
|
116
111
|
|
117
|
-
# These two methods should be removed in 6.0.0
|
118
|
-
def _destroyed_double_check?
|
119
|
-
if _active_record_destroyed_behavior?
|
120
|
-
false
|
121
|
-
else
|
122
|
-
(!new_record? && !exist?)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def _active_record_destroyed_behavior?
|
127
|
-
fail 'Remove this workaround in 6.0.0' if Neo4j::VERSION >= '6.0.0'
|
128
|
-
|
129
|
-
!!Neo4j::Config[:_active_record_destroyed_behavior]
|
130
|
-
end
|
131
|
-
# End of two methods which should be removed in 6.0.0
|
132
|
-
|
133
|
-
|
134
112
|
# @return [Hash] all defined and none nil properties
|
135
113
|
def props
|
136
114
|
attributes.reject { |_, v| v.nil? }.symbolize_keys
|
@@ -193,7 +171,7 @@ module Neo4j::Shared
|
|
193
171
|
private
|
194
172
|
|
195
173
|
def props_for_db(props_hash)
|
196
|
-
self.class.
|
174
|
+
self.class.declared_properties.convert_properties_to(self, :db, props_hash)
|
197
175
|
end
|
198
176
|
|
199
177
|
def model_cache_key
|
@@ -222,7 +200,7 @@ module Neo4j::Shared
|
|
222
200
|
end
|
223
201
|
|
224
202
|
def inject_defaults!(properties)
|
225
|
-
self.class.
|
203
|
+
self.class.declared_properties.declared_property_defaults.each_pair do |k, v|
|
226
204
|
properties[k.to_sym] = v if send(k).nil?
|
227
205
|
end
|
228
206
|
properties
|
@@ -108,10 +108,10 @@ module Neo4j::Shared
|
|
108
108
|
module ClassMethods
|
109
109
|
extend Forwardable
|
110
110
|
|
111
|
-
def_delegators :
|
111
|
+
def_delegators :declared_properties, :serialized_properties, :serialized_properties=, :serialize, :declared_property_defaults
|
112
112
|
|
113
113
|
def inherited(other)
|
114
|
-
self.
|
114
|
+
self.declared_properties.registered_properties.each_pair do |prop_key, prop_def|
|
115
115
|
other.property(prop_key, prop_def.options)
|
116
116
|
end
|
117
117
|
super
|
@@ -146,22 +146,36 @@ module Neo4j::Shared
|
|
146
146
|
# property :name, constraint: :unique
|
147
147
|
# end
|
148
148
|
def property(name, options = {})
|
149
|
+
build_property(name, options) do |prop|
|
150
|
+
attribute(name, prop.options)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# @param [Symbol] name The property name
|
155
|
+
# @param [ActiveAttr::AttributeDefinition] active_attr A cloned AttributeDefinition to reuse
|
156
|
+
# @param [Hash] options An options hash to use in the new property definition
|
157
|
+
def inherit_property(name, active_attr, options = {})
|
158
|
+
build_property(name, options) do |prop|
|
159
|
+
attributes[prop.name.to_s] = active_attr
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def build_property(name, options)
|
149
164
|
prop = DeclaredProperty.new(name, options)
|
150
165
|
prop.register
|
151
|
-
|
152
|
-
|
153
|
-
attribute(name, prop.options)
|
166
|
+
declared_properties.register(prop)
|
167
|
+
yield prop
|
154
168
|
constraint_or_index(name, options)
|
155
169
|
end
|
156
170
|
|
157
171
|
def undef_property(name)
|
158
|
-
|
172
|
+
declared_properties.unregister(name)
|
159
173
|
attribute_methods(name).each { |method| undef_method(method) }
|
160
174
|
undef_constraint_or_index(name)
|
161
175
|
end
|
162
176
|
|
163
|
-
def
|
164
|
-
@
|
177
|
+
def declared_properties
|
178
|
+
@_declared_properties ||= DeclaredProperties.new(self)
|
165
179
|
end
|
166
180
|
|
167
181
|
def attribute!(name, options = {})
|
@@ -176,7 +190,7 @@ module Neo4j::Shared
|
|
176
190
|
# @return [Hash] A frozen hash of all model properties with nil values. It is used during node loading and prevents
|
177
191
|
# an extra call to a slow dependency method.
|
178
192
|
def attributes_nil_hash
|
179
|
-
|
193
|
+
declared_properties.attributes_nil_hash
|
180
194
|
end
|
181
195
|
|
182
196
|
private
|
@@ -188,7 +202,7 @@ module Neo4j::Shared
|
|
188
202
|
constraint(name, type: :unique)
|
189
203
|
elsif options[:index]
|
190
204
|
fail "unknown index type #{options[:index]}, only :exact supported" if options[:index] != :exact
|
191
|
-
index(name
|
205
|
+
index(name) if options[:index] == :exact
|
192
206
|
end
|
193
207
|
end
|
194
208
|
end
|
@@ -1,9 +1,128 @@
|
|
1
1
|
require 'date'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'bigdecimal/util'
|
4
|
+
require 'active_support/core_ext/big_decimal/conversions'
|
2
5
|
|
3
6
|
module Neo4j::Shared
|
4
7
|
module TypeConverters
|
8
|
+
class BaseConverter
|
9
|
+
class << self
|
10
|
+
def converted?(value)
|
11
|
+
value.is_a?(db_type)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class IntegerConverter < BaseConverter
|
17
|
+
class << self
|
18
|
+
def convert_type
|
19
|
+
Integer
|
20
|
+
end
|
21
|
+
|
22
|
+
def db_type
|
23
|
+
Integer
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_db(value)
|
27
|
+
value.to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :to_ruby, :to_db
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class FloatConverter < BaseConverter
|
35
|
+
class << self
|
36
|
+
def convert_type
|
37
|
+
Float
|
38
|
+
end
|
39
|
+
|
40
|
+
def db_type
|
41
|
+
Float
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_db(value)
|
45
|
+
value.to_f
|
46
|
+
end
|
47
|
+
alias_method :to_ruby, :to_db
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class BigDecimalConverter < BaseConverter
|
52
|
+
class << self
|
53
|
+
def convert_type
|
54
|
+
BigDecimal
|
55
|
+
end
|
56
|
+
|
57
|
+
def db_type
|
58
|
+
BigDecimal
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_db(value)
|
62
|
+
case value
|
63
|
+
when Rational
|
64
|
+
value.to_f.to_d
|
65
|
+
when respond_to?(:to_d)
|
66
|
+
value.to_d
|
67
|
+
else
|
68
|
+
BigDecimal.new(value.to_s)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
alias_method :to_ruby, :to_db
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class StringConverter < BaseConverter
|
76
|
+
class << self
|
77
|
+
def convert_type
|
78
|
+
String
|
79
|
+
end
|
80
|
+
|
81
|
+
def db_type
|
82
|
+
String
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_db(value)
|
86
|
+
value.to_s
|
87
|
+
end
|
88
|
+
alias_method :to_ruby, :to_db
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class BooleanConverter < BaseConverter
|
93
|
+
FALSE_VALUES = %w(n N no No NO false False FALSE off Off OFF f F)
|
94
|
+
|
95
|
+
class << self
|
96
|
+
def converted?(value)
|
97
|
+
convert_type.include?(value)
|
98
|
+
end
|
99
|
+
|
100
|
+
def convert_type
|
101
|
+
[true, false]
|
102
|
+
end
|
103
|
+
|
104
|
+
def db_type
|
105
|
+
ActiveAttr::Typecasting::Boolean
|
106
|
+
end
|
107
|
+
|
108
|
+
def to_db(value)
|
109
|
+
return false if FALSE_VALUES.include?(value)
|
110
|
+
case value
|
111
|
+
when TrueClass, FalseClass
|
112
|
+
value
|
113
|
+
when Numeric, /^\-?[0-9]/
|
114
|
+
!value.to_f.zero?
|
115
|
+
else
|
116
|
+
value.present?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
alias_method :to_ruby, :to_db
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
5
124
|
# Converts Date objects to Java long types. Must be timezone UTC.
|
6
|
-
class DateConverter
|
125
|
+
class DateConverter < BaseConverter
|
7
126
|
class << self
|
8
127
|
def convert_type
|
9
128
|
Date
|
@@ -24,7 +143,7 @@ module Neo4j::Shared
|
|
24
143
|
end
|
25
144
|
|
26
145
|
# Converts DateTime objects to and from Java long types. Must be timezone UTC.
|
27
|
-
class DateTimeConverter
|
146
|
+
class DateTimeConverter < BaseConverter
|
28
147
|
class << self
|
29
148
|
def convert_type
|
30
149
|
DateTime
|
@@ -61,7 +180,7 @@ module Neo4j::Shared
|
|
61
180
|
end
|
62
181
|
end
|
63
182
|
|
64
|
-
class TimeConverter
|
183
|
+
class TimeConverter < BaseConverter
|
65
184
|
class << self
|
66
185
|
def convert_type
|
67
186
|
Time
|
@@ -95,7 +214,7 @@ module Neo4j::Shared
|
|
95
214
|
end
|
96
215
|
|
97
216
|
# Converts hash to/from YAML
|
98
|
-
class YAMLConverter
|
217
|
+
class YAMLConverter < BaseConverter
|
99
218
|
class << self
|
100
219
|
def convert_type
|
101
220
|
Hash
|
@@ -116,7 +235,7 @@ module Neo4j::Shared
|
|
116
235
|
end
|
117
236
|
|
118
237
|
# Converts hash to/from JSON
|
119
|
-
class JSONConverter
|
238
|
+
class JSONConverter < BaseConverter
|
120
239
|
class << self
|
121
240
|
def convert_type
|
122
241
|
JSON
|
@@ -159,6 +278,7 @@ module Neo4j::Shared
|
|
159
278
|
private
|
160
279
|
|
161
280
|
def converted_property(type, value, converter)
|
281
|
+
return nil if value.nil?
|
162
282
|
TypeConverters.converters[type].nil? ? value : TypeConverters.to_other(converter, value, type)
|
163
283
|
end
|
164
284
|
|
@@ -209,7 +329,12 @@ module Neo4j::Shared
|
|
209
329
|
# @param [#convert_type] found_converter An object that responds to #convert_type, hinting that it is a type converter.
|
210
330
|
# @param value The value for conversion.
|
211
331
|
def formatted_for_db?(found_converter, value)
|
212
|
-
found_converter.respond_to?(:db_type)
|
332
|
+
return false unless found_converter.respond_to?(:db_type)
|
333
|
+
if found_converter.respond_to?(:converted)
|
334
|
+
found_converter.converted?(value)
|
335
|
+
else
|
336
|
+
value.is_a?(found_converter.db_type)
|
337
|
+
end
|
213
338
|
end
|
214
339
|
|
215
340
|
def register_converter(converter)
|