neo4j 5.2.15 → 6.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.
- 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)
|