superstore 2.4.3 → 3.0.0
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 +5 -5
- data/.github/workflows/ruby.yml +40 -0
- data/.gitignore +1 -0
- data/.simplecov +3 -0
- data/Gemfile +2 -3
- data/LICENSE +1 -1
- data/MIT-LICENSE +1 -1
- data/README.md +4 -34
- data/lib/superstore/adapters/abstract_adapter.rb +1 -27
- data/lib/superstore/adapters/jsonb_adapter.rb +4 -132
- data/lib/superstore/associations/association.rb +6 -0
- data/lib/superstore/associations/association_scope.rb +20 -0
- data/lib/superstore/associations/belongs_to.rb +3 -1
- data/lib/superstore/associations/builder/association.rb +1 -1
- data/lib/superstore/associations/has_many.rb +15 -2
- data/lib/superstore/associations/reflection.rb +8 -2
- data/lib/superstore/associations.rb +9 -4
- data/lib/superstore/attribute_assignment.rb +7 -0
- data/lib/superstore/attribute_methods/primary_key.rb +20 -11
- data/lib/superstore/attribute_methods.rb +1 -109
- data/lib/superstore/attributes.rb +13 -0
- data/lib/superstore/base.rb +6 -34
- data/lib/superstore/core.rb +7 -65
- data/lib/superstore/model_schema.rb +35 -0
- data/lib/superstore/persistence.rb +26 -115
- data/lib/superstore/railtie.rb +3 -11
- data/lib/superstore/relation/scrolling.rb +48 -0
- data/lib/superstore/types/array_type.rb +3 -7
- data/lib/superstore/types/base.rb +9 -0
- data/lib/superstore/types/boolean_type.rb +7 -12
- data/lib/superstore/types/date_range_type.rb +7 -0
- data/lib/superstore/types/date_type.rb +7 -10
- data/lib/superstore/types/float_type.rb +3 -11
- data/lib/superstore/types/geo_point_type.rb +30 -0
- data/lib/superstore/types/integer_range_type.rb +15 -0
- data/lib/superstore/types/integer_type.rb +8 -14
- data/lib/superstore/types/json_type.rb +1 -1
- data/lib/superstore/types/range_type.rb +58 -0
- data/lib/superstore/types/string_type.rb +4 -4
- data/lib/superstore/types/time_type.rb +10 -8
- data/lib/superstore/types.rb +11 -9
- data/lib/superstore.rb +17 -19
- data/superstore.gemspec +8 -10
- data/test/support/jsonb.rb +3 -1
- data/test/support/models.rb +10 -4
- data/test/test_helper.rb +7 -3
- data/test/unit/adapters/adapter_test.rb +1 -3
- data/test/unit/associations/belongs_to_test.rb +1 -1
- data/test/unit/associations/has_many_test.rb +10 -2
- data/test/unit/attribute_methods/dirty_test.rb +8 -19
- data/test/unit/attribute_methods/primary_key_test.rb +1 -1
- data/test/unit/attribute_methods_test.rb +10 -22
- data/test/unit/{attribute_methods/typecasting_test.rb → attributes_test.rb} +13 -39
- data/test/unit/base_test.rb +4 -0
- data/test/unit/caching_test.rb +1 -1
- data/test/unit/callbacks_test.rb +4 -4
- data/test/unit/core_test.rb +15 -20
- data/test/unit/persistence_test.rb +36 -44
- data/test/unit/{scope/batches_test.rb → relation/scrolling_test.rb} +9 -5
- data/test/unit/serialization_test.rb +10 -2
- data/test/unit/{timestamps_test.rb → timestamp_test.rb} +5 -5
- data/test/unit/types/array_type_test.rb +3 -18
- data/test/unit/types/boolean_type_test.rb +7 -21
- data/test/unit/types/date_range_type_test.rb +29 -0
- data/test/unit/types/date_type_test.rb +15 -6
- data/test/unit/types/float_type_test.rb +4 -19
- data/test/unit/types/geo_point_type_test.rb +28 -0
- data/test/unit/types/integer_range_type_test.rb +28 -0
- data/test/unit/types/integer_type_test.rb +7 -16
- data/test/unit/types/string_type_test.rb +9 -13
- data/test/unit/types/time_type_test.rb +17 -11
- data/test/unit/validations_test.rb +2 -2
- metadata +39 -53
- data/.travis.yml +0 -13
- data/Gemfile-rails4.2 +0 -11
- data/lib/superstore/attribute_methods/definition.rb +0 -17
- data/lib/superstore/attribute_methods/dirty.rb +0 -52
- data/lib/superstore/attribute_methods/typecasting.rb +0 -53
- data/lib/superstore/caching.rb +0 -13
- data/lib/superstore/callbacks.rb +0 -29
- data/lib/superstore/connection.rb +0 -24
- data/lib/superstore/errors.rb +0 -10
- data/lib/superstore/inspect.rb +0 -25
- data/lib/superstore/model.rb +0 -38
- data/lib/superstore/schema.rb +0 -20
- data/lib/superstore/scope/batches.rb +0 -27
- data/lib/superstore/scope/finder_methods.rb +0 -51
- data/lib/superstore/scope/query_methods.rb +0 -52
- data/lib/superstore/scope.rb +0 -73
- data/lib/superstore/scoping.rb +0 -30
- data/lib/superstore/timestamps.rb +0 -19
- data/lib/superstore/type.rb +0 -16
- data/lib/superstore/types/base_type.rb +0 -23
- data/lib/superstore/validations.rb +0 -44
- data/test/unit/attribute_methods/definition_test.rb +0 -16
- data/test/unit/inspect_test.rb +0 -26
- data/test/unit/schema_test.rb +0 -15
- data/test/unit/scope/finder_methods_test.rb +0 -62
- data/test/unit/scope/query_methods_test.rb +0 -36
- data/test/unit/scoping_test.rb +0 -7
- data/test/unit/types/base_type_test.rb +0 -11
@@ -1,117 +1,9 @@
|
|
1
1
|
module Superstore
|
2
2
|
module AttributeMethods
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
include ActiveModel::AttributeMethods
|
5
4
|
|
6
5
|
included do
|
7
|
-
|
8
|
-
|
9
|
-
# (Alias for the protected read_attribute method).
|
10
|
-
def [](attr_name)
|
11
|
-
read_attribute(attr_name)
|
12
|
-
end
|
13
|
-
|
14
|
-
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
|
15
|
-
# (Alias for the protected write_attribute method).
|
16
|
-
def []=(attr_name, value)
|
17
|
-
write_attribute(attr_name, value)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
module ClassMethods
|
22
|
-
def inherited(child_class)
|
23
|
-
child_class.define_attribute_methods
|
24
|
-
super
|
25
|
-
end
|
26
|
-
|
27
|
-
def define_attribute_methods
|
28
|
-
return if attribute_methods_generated?
|
29
|
-
super(attribute_definitions.keys)
|
30
|
-
@attribute_methods_generated = true
|
31
|
-
end
|
32
|
-
|
33
|
-
def attribute_methods_generated?
|
34
|
-
@attribute_methods_generated ||= false
|
35
|
-
end
|
36
|
-
|
37
|
-
def dangerous_attribute_method?(name)
|
38
|
-
false
|
39
|
-
end
|
40
|
-
|
41
|
-
def has_attribute?(attr_name)
|
42
|
-
attribute_definitions.key?(attr_name.to_s)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def write_attribute(name, value)
|
47
|
-
@attributes[name.to_s] = self.class.typecast_attribute(name, value)
|
48
|
-
end
|
49
|
-
|
50
|
-
def read_attribute(name)
|
51
|
-
name = name.to_s unless name.is_a?(String)
|
52
|
-
|
53
|
-
if name == self.class.primary_key
|
54
|
-
send(name)
|
55
|
-
else
|
56
|
-
@attributes[name]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
alias_method :_read_attribute, :read_attribute
|
60
|
-
|
61
|
-
def attribute_present?(attribute)
|
62
|
-
value = _read_attribute(attribute)
|
63
|
-
!value.nil? && !(value.respond_to?(:empty?) && value.empty?)
|
6
|
+
include PrimaryKey
|
64
7
|
end
|
65
|
-
|
66
|
-
def has_attribute?(name)
|
67
|
-
@attributes.key?(name.to_s)
|
68
|
-
end
|
69
|
-
alias_method :attribute_exists?, :has_attribute?
|
70
|
-
|
71
|
-
def attributes
|
72
|
-
results = {}
|
73
|
-
@attributes.each_key do |key|
|
74
|
-
results[key] = read_attribute(key)
|
75
|
-
end
|
76
|
-
results
|
77
|
-
end
|
78
|
-
|
79
|
-
def attributes=(attributes)
|
80
|
-
attributes.each do |(name, value)|
|
81
|
-
send("#{name}=", value)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def method_missing(method_id, *args, &block)
|
86
|
-
self.class.define_attribute_methods unless self.class.attribute_methods_generated?
|
87
|
-
|
88
|
-
match = if ActiveRecord.version >= Gem::Version.new('5.0')
|
89
|
-
# Active Record 5.0
|
90
|
-
matched_attribute_method(method_id.to_s)
|
91
|
-
else
|
92
|
-
# Active Record 4.2
|
93
|
-
match_attribute_method?(method_id.to_s)
|
94
|
-
end
|
95
|
-
match ? attribute_missing(match, *args, &block) : super
|
96
|
-
end
|
97
|
-
|
98
|
-
def respond_to?(*args)
|
99
|
-
self.class.define_attribute_methods unless self.class.attribute_methods_generated?
|
100
|
-
super
|
101
|
-
end
|
102
|
-
|
103
|
-
protected
|
104
|
-
def attribute_method?(name)
|
105
|
-
!!attribute_definitions[name.to_s]
|
106
|
-
end
|
107
|
-
|
108
|
-
private
|
109
|
-
def attribute(name)
|
110
|
-
read_attribute(name)
|
111
|
-
end
|
112
|
-
|
113
|
-
def attribute=(name, value)
|
114
|
-
write_attribute(name, value)
|
115
|
-
end
|
116
8
|
end
|
117
9
|
end
|
data/lib/superstore/base.rb
CHANGED
@@ -1,44 +1,16 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
require 'superstore/types'
|
4
2
|
|
5
3
|
module Superstore
|
6
|
-
class Base
|
7
|
-
|
8
|
-
extend ActiveModel::Naming
|
9
|
-
include ActiveModel::Conversion
|
10
|
-
extend ActiveSupport::DescendantsTracker
|
11
|
-
include ActiveModel::Serializers::JSON
|
12
|
-
include GlobalID::Identification
|
13
|
-
|
14
|
-
extend ActiveRecord::Delegation::DelegateCache
|
15
|
-
extend ActiveRecord::ConnectionHandling
|
16
|
-
include ActiveRecord::Persistence
|
17
|
-
include ActiveRecord::ModelSchema
|
18
|
-
include ActiveRecord::Inheritance
|
19
|
-
include ActiveRecord::Attributes
|
20
|
-
include ActiveRecord::Associations
|
21
|
-
include ActiveRecord::AutosaveAssociation
|
22
|
-
include ActiveRecord::Reflection
|
23
|
-
|
24
|
-
include Model
|
4
|
+
class Base < ActiveRecord::Base
|
5
|
+
self.abstract_class = true
|
25
6
|
include Core
|
26
|
-
include Connection
|
27
|
-
include Identity
|
28
|
-
include Inspect
|
29
7
|
include Persistence
|
8
|
+
include ModelSchema
|
9
|
+
include AttributeAssignment
|
10
|
+
include Attributes
|
30
11
|
include AttributeMethods
|
31
|
-
include Validations
|
32
|
-
include AttributeMethods::Dirty
|
33
|
-
include AttributeMethods::PrimaryKey
|
34
|
-
include AttributeMethods::Typecasting
|
35
12
|
include Associations
|
36
|
-
include Callbacks
|
37
|
-
include Timestamps
|
38
|
-
include Scoping
|
39
|
-
include Caching
|
40
13
|
|
14
|
+
include Identity
|
41
15
|
end
|
42
16
|
end
|
43
|
-
|
44
|
-
ActiveSupport.run_load_hooks(:superstore, Superstore::Base)
|
data/lib/superstore/core.rb
CHANGED
@@ -2,76 +2,18 @@ module Superstore
|
|
2
2
|
module Core
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
if self == Base
|
8
|
-
super
|
9
|
-
else
|
10
|
-
attr_list = attribute_definitions.keys * ', '
|
11
|
-
"#{super}(#{attr_list.truncate(140 * 1.7337)})"
|
12
|
-
end
|
13
|
-
end
|
5
|
+
def inspect
|
6
|
+
inspection = ["#{self.class.primary_key}: #{id.inspect}"]
|
14
7
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
8
|
+
(self.class.attribute_names - [self.class.primary_key]).each do |name|
|
9
|
+
value = send(name)
|
18
10
|
|
19
|
-
|
20
|
-
|
21
|
-
mod = const_set(:GeneratedAssociationMethods, Module.new)
|
22
|
-
include mod
|
23
|
-
mod
|
11
|
+
if value.present? || value === false
|
12
|
+
inspection << "#{name}: #{attribute_for_inspect(name)}"
|
24
13
|
end
|
25
14
|
end
|
26
15
|
|
27
|
-
|
28
|
-
@arel_table ||= Arel::Table.new(table_name, self)
|
29
|
-
end
|
30
|
-
|
31
|
-
def subclass_from_attributes?(attrs)
|
32
|
-
false
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def initialize(attributes=nil)
|
37
|
-
@new_record = true
|
38
|
-
@destroyed = false
|
39
|
-
@association_cache = {}
|
40
|
-
|
41
|
-
@attributes = {}
|
42
|
-
self.attributes = attributes || {}
|
43
|
-
|
44
|
-
yield self if block_given?
|
45
|
-
end
|
46
|
-
|
47
|
-
def initialize_dup(other)
|
48
|
-
@attributes = other.attributes
|
49
|
-
@attributes['created_at'] = nil
|
50
|
-
@attributes['updated_at'] = nil
|
51
|
-
@attributes.delete(self.class.primary_key)
|
52
|
-
@id = nil
|
53
|
-
@new_record = true
|
54
|
-
@destroyed = false
|
55
|
-
@association_cache = {}
|
56
|
-
super
|
57
|
-
end
|
58
|
-
|
59
|
-
def to_param
|
60
|
-
id
|
61
|
-
end
|
62
|
-
|
63
|
-
def hash
|
64
|
-
id.hash
|
65
|
-
end
|
66
|
-
|
67
|
-
def ==(comparison_object)
|
68
|
-
comparison_object.equal?(self) ||
|
69
|
-
(comparison_object.instance_of?(self.class) &&
|
70
|
-
comparison_object.id == id)
|
71
|
-
end
|
72
|
-
|
73
|
-
def eql?(comparison_object)
|
74
|
-
self == (comparison_object)
|
16
|
+
"#<#{self.class} #{inspection * ', '}>"
|
75
17
|
end
|
76
18
|
end
|
77
19
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Superstore
|
2
|
+
module ModelSchema
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :superstore_column, default: 'document'
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def attributes_builder # :nodoc:
|
11
|
+
@attributes_builder ||= ActiveModel::AttributeSet::Builder.new(attribute_types, _default_attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_schema! # :nodoc:
|
15
|
+
@columns_hash = {}
|
16
|
+
|
17
|
+
attributes_to_define_after_schema_loads.each do |name, (type, options)|
|
18
|
+
if type.is_a?(Symbol)
|
19
|
+
type = ActiveRecord::Type.lookup(type, **options.except(:default))
|
20
|
+
end
|
21
|
+
|
22
|
+
define_attribute(name, type, **options.slice(:default))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def attribute_names
|
27
|
+
attribute_types.keys
|
28
|
+
end
|
29
|
+
|
30
|
+
def column_names
|
31
|
+
attribute_names
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -2,140 +2,51 @@ module Superstore
|
|
2
2
|
module Persistence
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
included do
|
6
|
-
class_attribute :batch_statements
|
7
|
-
end
|
8
|
-
|
9
5
|
module ClassMethods
|
10
|
-
def
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
def delete_all
|
15
|
-
adapter.execute "TRUNCATE #{table_name}"
|
6
|
+
def find_by_id(id)
|
7
|
+
find_by(id: id)
|
16
8
|
end
|
17
9
|
|
18
|
-
def
|
19
|
-
|
20
|
-
end
|
10
|
+
def _insert_record(attributes)
|
11
|
+
id = attributes.fetch(primary_key)
|
21
12
|
|
22
|
-
|
23
|
-
adapter.update table_name, id, encode_attributes(attributes)
|
13
|
+
adapter.insert table_name, id, serialize_attributes(attributes)
|
24
14
|
end
|
25
15
|
|
26
|
-
def
|
27
|
-
|
28
|
-
end
|
16
|
+
def _update_record(attributes, constraints)
|
17
|
+
id = constraints.fetch(primary_key)
|
29
18
|
|
30
|
-
|
31
|
-
adapter.batch(&block)
|
19
|
+
adapter.update table_name, id, serialize_attributes(attributes)
|
32
20
|
end
|
33
21
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
object.instance_variable_set("@attributes", typecast_persisted_attributes(attributes))
|
40
|
-
object.instance_variable_set("@association_cache", {})
|
22
|
+
def serialize_attributes(attributes)
|
23
|
+
serialized = {}
|
24
|
+
attributes.each do |attr_name, value|
|
25
|
+
next if attr_name == primary_key
|
26
|
+
serialized[attr_name] = attribute_types[attr_name].serialize(value)
|
41
27
|
end
|
42
|
-
|
43
|
-
|
44
|
-
def encode_attributes(attributes)
|
45
|
-
encoded = {}
|
46
|
-
attributes.each do |column_name, value|
|
47
|
-
if value.nil?
|
48
|
-
encoded[column_name] = nil
|
49
|
-
else
|
50
|
-
encoded[column_name] = attribute_definitions[column_name].type.encode(value)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
encoded
|
28
|
+
serialized
|
54
29
|
end
|
55
30
|
|
56
31
|
private
|
57
32
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
def typecast_persisted_attributes(attributes)
|
63
|
-
result = {}
|
64
|
-
|
65
|
-
attributes.each do |key, value|
|
66
|
-
if definition = attribute_definitions[key]
|
67
|
-
result[key] = definition.instantiate(value)
|
68
|
-
end
|
33
|
+
def instantiate_instance_of(klass, attributes, column_types = {}, &block)
|
34
|
+
if attributes[superstore_column].is_a?(String)
|
35
|
+
attributes = JSON.parse(attributes[superstore_column]).merge('id' => attributes['id'])
|
69
36
|
end
|
70
37
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
def new_record?
|
76
|
-
@new_record
|
77
|
-
end
|
78
|
-
|
79
|
-
def destroyed?
|
80
|
-
@destroyed
|
81
|
-
end
|
82
|
-
|
83
|
-
def persisted?
|
84
|
-
!(new_record? || destroyed?)
|
85
|
-
end
|
86
|
-
|
87
|
-
def save(*)
|
88
|
-
create_or_update
|
89
|
-
end
|
90
|
-
|
91
|
-
def destroy
|
92
|
-
self.class.delete(id)
|
93
|
-
@destroyed = true
|
94
|
-
end
|
95
|
-
|
96
|
-
def update_attribute(name, value)
|
97
|
-
name = name.to_s
|
98
|
-
send("#{name}=", value)
|
99
|
-
save(validate: false)
|
100
|
-
end
|
101
|
-
|
102
|
-
def update(attributes)
|
103
|
-
self.attributes = attributes
|
104
|
-
save
|
105
|
-
end
|
38
|
+
if inheritance_column && attribute_types.key?(inheritance_column)
|
39
|
+
klass = find_sti_class(attributes[inheritance_column])
|
40
|
+
end
|
106
41
|
|
107
|
-
|
42
|
+
attributes.each_key { |k, v| attributes.delete(k) unless klass.attribute_types.key?(k) }
|
108
43
|
|
109
|
-
|
110
|
-
|
111
|
-
save!
|
112
|
-
end
|
113
|
-
|
114
|
-
alias update_attributes! update!
|
44
|
+
super(klass, attributes, column_types, &block)
|
45
|
+
end
|
115
46
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
self
|
47
|
+
def adapter
|
48
|
+
@adapter ||= Superstore::Adapters::JsonbAdapter.new
|
49
|
+
end
|
120
50
|
end
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
def create_or_update
|
125
|
-
new_record? ? create_self : update_self
|
126
|
-
end
|
127
|
-
|
128
|
-
def create_self
|
129
|
-
write :insert_record
|
130
|
-
end
|
131
|
-
|
132
|
-
def update_self
|
133
|
-
write :update_record
|
134
|
-
end
|
135
|
-
|
136
|
-
def write(method)
|
137
|
-
@new_record = false
|
138
|
-
self.class.send(method, id, unapplied_changes)
|
139
|
-
end
|
140
51
|
end
|
141
52
|
end
|
data/lib/superstore/railtie.rb
CHANGED
@@ -1,17 +1,9 @@
|
|
1
1
|
module Superstore
|
2
2
|
class Railtie < Rails::Railtie
|
3
3
|
initializer "superstore.config" do |app|
|
4
|
-
ActiveSupport.on_load :
|
5
|
-
|
6
|
-
|
7
|
-
config = ERB.new(pathname.read).result
|
8
|
-
config = YAML.load(config)
|
9
|
-
|
10
|
-
if config = config[Rails.env]
|
11
|
-
self.config = config.symbolize_keys!
|
12
|
-
else
|
13
|
-
raise "Missing environment #{Rails.env} in superstore.yml"
|
14
|
-
end
|
4
|
+
ActiveSupport.on_load :active_record do
|
5
|
+
ActiveRecord::Relation.class_eval do
|
6
|
+
include Superstore::Relation::Scrolling
|
15
7
|
end
|
16
8
|
end
|
17
9
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Superstore
|
2
|
+
module Relation
|
3
|
+
module Scrolling
|
4
|
+
def scroll_each(options = {})
|
5
|
+
batch_size = options[:batch_size] || 1000
|
6
|
+
|
7
|
+
scroll_results(batch_size) do |attributes|
|
8
|
+
yield klass.instantiate(attributes)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def scroll_in_batches(options = {})
|
13
|
+
batch_size = options[:batch_size] || 1000
|
14
|
+
batch = []
|
15
|
+
|
16
|
+
scroll_each(options) do |record|
|
17
|
+
batch << record
|
18
|
+
|
19
|
+
if batch.size == batch_size
|
20
|
+
yield batch
|
21
|
+
batch = []
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
yield(batch) if batch.any?
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def scroll_results(batch_size)
|
31
|
+
statement = to_sql
|
32
|
+
cursor_name = "cursor_#{SecureRandom.hex(6)}"
|
33
|
+
fetch_sql = "FETCH FORWARD #{batch_size} FROM #{cursor_name}"
|
34
|
+
|
35
|
+
connection.transaction do
|
36
|
+
connection.execute "DECLARE #{cursor_name} NO SCROLL CURSOR FOR (#{statement})"
|
37
|
+
|
38
|
+
while (batch = connection.execute(fetch_sql)).any?
|
39
|
+
batch.each do |result|
|
40
|
+
yield result
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,20 +1,15 @@
|
|
1
1
|
module Superstore
|
2
2
|
module Types
|
3
|
-
class BooleanType <
|
3
|
+
class BooleanType < Base
|
4
4
|
TRUE_VALS = [true, 'true', '1']
|
5
|
-
FALSE_VALS = [false, 'false', '0'
|
6
|
-
VALID_VALS = TRUE_VALS + FALSE_VALS
|
5
|
+
FALSE_VALS = [false, 'false', '0']
|
7
6
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
7
|
+
def cast_value(value)
|
8
|
+
if TRUE_VALS.include?(value)
|
9
|
+
true
|
10
|
+
elsif FALSE_VALS.include?(value)
|
11
|
+
false
|
11
12
|
end
|
12
|
-
|
13
|
-
TRUE_VALS.include?(bool)
|
14
|
-
end
|
15
|
-
|
16
|
-
def decode(str)
|
17
|
-
TRUE_VALS.include?(str)
|
18
13
|
end
|
19
14
|
end
|
20
15
|
end
|
@@ -1,21 +1,18 @@
|
|
1
1
|
module Superstore
|
2
2
|
module Types
|
3
|
-
class DateType <
|
3
|
+
class DateType < Base
|
4
4
|
FORMAT = '%Y-%m-%d'
|
5
|
-
REGEX = /\A\d{4}-\d{2}-\d{2}\Z/
|
6
5
|
|
7
|
-
def
|
8
|
-
|
9
|
-
value.strftime(FORMAT)
|
6
|
+
def serialize(value)
|
7
|
+
value.strftime(FORMAT) if value
|
10
8
|
end
|
11
9
|
|
12
|
-
def
|
13
|
-
|
14
|
-
Date.parse(str)
|
10
|
+
def deserialize(str)
|
11
|
+
Date.strptime(str, FORMAT) if str
|
15
12
|
end
|
16
13
|
|
17
|
-
def
|
18
|
-
value.to_date
|
14
|
+
def cast_value(value)
|
15
|
+
value.to_date rescue nil
|
19
16
|
end
|
20
17
|
end
|
21
18
|
end
|
@@ -1,16 +1,8 @@
|
|
1
1
|
module Superstore
|
2
2
|
module Types
|
3
|
-
class FloatType <
|
4
|
-
def
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
def decode(str)
|
9
|
-
str.to_f unless str.empty?
|
10
|
-
end
|
11
|
-
|
12
|
-
def typecast(value)
|
13
|
-
value.to_f
|
3
|
+
class FloatType < Base
|
4
|
+
def cast_value(value)
|
5
|
+
Float(value) rescue nil
|
14
6
|
end
|
15
7
|
end
|
16
8
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Superstore
|
4
|
+
module Types
|
5
|
+
class GeoPointType < Base
|
6
|
+
def deserialize(value)
|
7
|
+
{lat: value[:lat] || value['lat'], lon: value[:lon] || value['lon']} if value
|
8
|
+
end
|
9
|
+
|
10
|
+
def cast_value(value)
|
11
|
+
case value
|
12
|
+
when String
|
13
|
+
cast_value value.split(/[,\s]+/)
|
14
|
+
when Array
|
15
|
+
to_float_or_nil(lat: value[0], lon: value[1])
|
16
|
+
when Hash
|
17
|
+
to_float_or_nil(lat: value[:lat] || value['lat'], lon: value[:lon] || value['lon'])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def to_float_or_nil(coords)
|
24
|
+
if coords[:lat] && coords[:lon]
|
25
|
+
coords.transform_values!(&:to_f)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|