superstore 2.4.4 → 2.5.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/.travis.yml +4 -6
- data/Gemfile +2 -3
- data/{Gemfile-rails4.2 → Gemfile.rails6} +2 -3
- data/README.md +4 -34
- data/lib/superstore.rb +17 -18
- data/lib/superstore/adapters/abstract_adapter.rb +1 -27
- data/lib/superstore/adapters/jsonb_adapter.rb +4 -132
- data/lib/superstore/associations.rb +6 -1
- 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/has_many.rb +15 -2
- data/lib/superstore/associations/reflection.rb +8 -2
- data/lib/superstore/attribute_assignment.rb +7 -0
- data/lib/superstore/attribute_methods.rb +1 -109
- data/lib/superstore/attribute_methods/primary_key.rb +20 -11
- data/lib/superstore/attributes.rb +13 -0
- data/lib/superstore/base.rb +8 -33
- data/lib/superstore/core.rb +7 -65
- data/lib/superstore/model_schema.rb +35 -0
- data/lib/superstore/persistence.rb +31 -115
- data/lib/superstore/railtie.rb +3 -11
- data/lib/superstore/relation/scrolling.rb +48 -0
- data/lib/superstore/timestamp.rb +13 -0
- data/lib/superstore/types.rb +11 -9
- data/lib/superstore/types/array_type.rb +3 -7
- 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 +19 -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 +51 -0
- data/lib/superstore/types/string_type.rb +4 -4
- data/lib/superstore/types/time_type.rb +10 -8
- data/superstore.gemspec +4 -3
- data/test/support/jsonb.rb +3 -1
- data/test/support/models.rb +8 -5
- data/test/test_helper.rb +6 -2
- 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 +9 -19
- data/test/unit/persistence_test.rb +17 -54
- 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 +28 -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 +24 -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 -39
- 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.rb +0 -73
- 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/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 -37
- data/test/unit/scoping_test.rb +0 -7
- data/test/unit/types/base_type_test.rb +0 -11
@@ -0,0 +1,51 @@
|
|
1
|
+
module Superstore
|
2
|
+
module Types
|
3
|
+
class RangeType < ActiveModel::Type::Value
|
4
|
+
class_attribute :subtype
|
5
|
+
|
6
|
+
def serialize(range)
|
7
|
+
if range
|
8
|
+
[
|
9
|
+
serialize_for_open_ended(range.begin),
|
10
|
+
serialize_for_open_ended(range.end)
|
11
|
+
]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def deserialize(range_tuple)
|
16
|
+
if range_tuple.is_a? Range
|
17
|
+
range_tuple
|
18
|
+
elsif range_tuple.is_a?(Array)
|
19
|
+
range = convert_min(:deserialize, range_tuple[0]) .. convert_max(:deserialize, range_tuple[1])
|
20
|
+
cast_value(range)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def cast_value(value)
|
25
|
+
if value.is_a?(Range) && value.begin < value.end
|
26
|
+
value
|
27
|
+
elsif value.is_a?(Array) && value.size == 2
|
28
|
+
begin
|
29
|
+
array = convert_min(:cast_value, value[0])..convert_max(:cast_value, value[1])
|
30
|
+
cast_value(array)
|
31
|
+
rescue ArgumentError
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def serialize_for_open_ended(value)
|
39
|
+
subtype.serialize(value)
|
40
|
+
end
|
41
|
+
|
42
|
+
def convert_min(method, value)
|
43
|
+
subtype.send(method, value)
|
44
|
+
end
|
45
|
+
|
46
|
+
def convert_max(method, value)
|
47
|
+
subtype.send(method, value)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Superstore
|
2
2
|
module Types
|
3
|
-
class StringType <
|
4
|
-
def
|
5
|
-
|
3
|
+
class StringType < ActiveModel::Type::Value
|
4
|
+
def serialize(str)
|
5
|
+
return if str.nil?
|
6
6
|
|
7
7
|
unless str.encoding == Encoding::UTF_8
|
8
8
|
(str.frozen? ? str.dup : str).force_encoding('UTF-8')
|
@@ -11,7 +11,7 @@ module Superstore
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def cast_value(value)
|
15
15
|
value.to_s
|
16
16
|
end
|
17
17
|
end
|
@@ -1,16 +1,18 @@
|
|
1
1
|
module Superstore
|
2
2
|
module Types
|
3
|
-
class TimeType <
|
4
|
-
def
|
5
|
-
|
6
|
-
time = time.to_time unless time.is_a?(Time)
|
7
|
-
time.utc.xmlschema(6)
|
3
|
+
class TimeType < ActiveModel::Type::Value
|
4
|
+
def serialize(time)
|
5
|
+
time.utc.xmlschema(6) if time
|
8
6
|
end
|
9
7
|
|
10
|
-
def
|
11
|
-
Time.
|
12
|
-
rescue
|
8
|
+
def deserialize(str)
|
9
|
+
Time.rfc3339(str).in_time_zone if str
|
10
|
+
rescue ArgumentError
|
11
|
+
Time.parse(str).in_time_zone rescue nil
|
12
|
+
end
|
13
13
|
|
14
|
+
def cast_value(value)
|
15
|
+
value.to_time.in_time_zone rescue nil
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
data/superstore.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'superstore'
|
5
|
-
s.version = '2.
|
5
|
+
s.version = '2.5.0'
|
6
6
|
s.description = 'ActiveModel-based JSONB document store'
|
7
7
|
s.summary = 'ActiveModel for JSONB documents'
|
8
8
|
s.authors = ['Michael Koziarski', 'Infogroup']
|
@@ -18,9 +18,10 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
19
19
|
s.require_paths = ['lib']
|
20
20
|
|
21
|
-
s.add_runtime_dependency('activemodel', '>=
|
21
|
+
s.add_runtime_dependency('activemodel', '>= 5.2')
|
22
|
+
s.add_runtime_dependency('activerecord', '>= 5.2')
|
22
23
|
s.add_runtime_dependency('globalid')
|
23
|
-
s.add_runtime_dependency('oj')
|
24
24
|
|
25
25
|
s.add_development_dependency('bundler')
|
26
|
+
s.add_development_dependency('rails')
|
26
27
|
end
|
data/test/support/jsonb.rb
CHANGED
data/test/support/models.rb
CHANGED
@@ -2,19 +2,22 @@ class User < ActiveRecord::Base
|
|
2
2
|
end
|
3
3
|
|
4
4
|
class Label < ActiveRecord::Base
|
5
|
+
belongs_to :issue
|
5
6
|
end
|
6
7
|
|
7
8
|
class Issue < Superstore::Base
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
attribute :description, type: :string
|
10
|
+
attribute :title, type: :string
|
11
|
+
attribute :parent_issue_id, type: :string
|
12
|
+
attribute :comments, type: :json
|
11
13
|
|
12
14
|
before_create { self.description ||= 'funny' }
|
13
15
|
|
14
|
-
has_many :labels
|
16
|
+
has_many :labels, inverse_of: :issue
|
17
|
+
has_many :children_issues, class_name: 'Issue', foreign_key: :parent_issue_id, inverse_of: :parent_issue, superstore: true
|
18
|
+
belongs_to :parent_issue, class_name: 'Issue', superstore: true
|
15
19
|
|
16
20
|
def self.for_key key
|
17
21
|
where_ids(key)
|
18
22
|
end
|
19
23
|
end
|
20
|
-
|
data/test/test_helper.rb
CHANGED
@@ -13,12 +13,16 @@ require 'support/pg'
|
|
13
13
|
require 'support/jsonb'
|
14
14
|
require 'support/models'
|
15
15
|
|
16
|
+
def MiniTest.filter_backtrace(bt)
|
17
|
+
bt
|
18
|
+
end
|
19
|
+
|
16
20
|
module Superstore
|
17
21
|
class TestCase < ActiveSupport::TestCase
|
18
22
|
def temp_object(&block)
|
19
23
|
Class.new(Superstore::Base) do
|
20
24
|
self.table_name = 'issues'
|
21
|
-
|
25
|
+
attribute :force_save, type: :string
|
22
26
|
before_save { self.force_save = 'junk' }
|
23
27
|
|
24
28
|
def self.name
|
@@ -34,7 +38,7 @@ module Superstore
|
|
34
38
|
class TestCase < Superstore::TestCase
|
35
39
|
attr_accessor :type
|
36
40
|
setup do
|
37
|
-
@type = self.class.name.sub(/Test$/, '').constantize.new
|
41
|
+
@type = self.class.name.sub(/Test$/, '').constantize.new
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
@@ -4,7 +4,7 @@ class Superstore::Associations::HasManyTest < Superstore::TestCase
|
|
4
4
|
class TestObject < Issue
|
5
5
|
end
|
6
6
|
|
7
|
-
test 'has_many' do
|
7
|
+
test 'has_many active_record association' do
|
8
8
|
issue = TestObject.create!
|
9
9
|
label = Label.create! name: 'important', issue_id: issue.id
|
10
10
|
|
@@ -13,10 +13,18 @@ class Superstore::Associations::HasManyTest < Superstore::TestCase
|
|
13
13
|
|
14
14
|
test 'create supports preloaded records' do
|
15
15
|
issue = TestObject.create!
|
16
|
-
issue.labels = Label.all
|
16
|
+
issue.labels = Label.all
|
17
17
|
|
18
18
|
issue.labels.create! name: 'blue'
|
19
19
|
|
20
20
|
assert_equal 1, issue.labels.size
|
21
21
|
end
|
22
|
+
|
23
|
+
test 'has_many superstore association' do
|
24
|
+
parent_issue = Issue.create!
|
25
|
+
child_issue = Issue.create! parent_issue: parent_issue
|
26
|
+
|
27
|
+
assert_equal [child_issue], parent_issue.children_issues
|
28
|
+
assert_equal parent_issue.object_id, parent_issue.children_issues.first.parent_issue.object_id
|
29
|
+
end
|
22
30
|
end
|
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
class Superstore::AttributeMethods::DirtyTest < Superstore::TestCase
|
4
4
|
test 'save clears dirty' do
|
5
5
|
record = temp_object do
|
6
|
-
|
6
|
+
attribute :name, type: :string
|
7
7
|
end.new name: 'foo'
|
8
8
|
|
9
9
|
assert record.changed?
|
@@ -16,7 +16,7 @@ class Superstore::AttributeMethods::DirtyTest < Superstore::TestCase
|
|
16
16
|
|
17
17
|
test 'reload clears dirty' do
|
18
18
|
record = temp_object do
|
19
|
-
|
19
|
+
attribute :name, type: :string
|
20
20
|
end.create! name: 'foo'
|
21
21
|
|
22
22
|
record.name = 'bar'
|
@@ -27,9 +27,9 @@ class Superstore::AttributeMethods::DirtyTest < Superstore::TestCase
|
|
27
27
|
assert !record.changed?
|
28
28
|
end
|
29
29
|
|
30
|
-
test '
|
30
|
+
test 'cast_value float before dirty check' do
|
31
31
|
record = temp_object do
|
32
|
-
|
32
|
+
attribute :price, type: :float
|
33
33
|
end.create(price: 5.01)
|
34
34
|
|
35
35
|
record.price = '5.01'
|
@@ -39,9 +39,9 @@ class Superstore::AttributeMethods::DirtyTest < Superstore::TestCase
|
|
39
39
|
assert record.changed?
|
40
40
|
end
|
41
41
|
|
42
|
-
test '
|
42
|
+
test 'cast_value boolean before dirty check' do
|
43
43
|
record = temp_object do
|
44
|
-
|
44
|
+
attribute :awesome, type: :boolean
|
45
45
|
end.create(awesome: false)
|
46
46
|
|
47
47
|
record.awesome = false
|
@@ -51,20 +51,9 @@ class Superstore::AttributeMethods::DirtyTest < Superstore::TestCase
|
|
51
51
|
assert record.changed?
|
52
52
|
end
|
53
53
|
|
54
|
-
test 'unapplied_changes' do
|
55
|
-
record = temp_object do
|
56
|
-
float :price
|
57
|
-
string :color
|
58
|
-
end.create(price: 5.01, color: 'green')
|
59
|
-
|
60
|
-
record.color = 'blue'
|
61
|
-
|
62
|
-
assert_equal({'color' => 'blue'}, record.unapplied_changes)
|
63
|
-
end
|
64
|
-
|
65
54
|
test 'write_attribute' do
|
66
55
|
object = temp_object do
|
67
|
-
|
56
|
+
attribute :name, type: :string
|
68
57
|
end
|
69
58
|
|
70
59
|
expected = {"name"=>[nil, "foo"]}
|
@@ -83,7 +72,7 @@ class Superstore::AttributeMethods::DirtyTest < Superstore::TestCase
|
|
83
72
|
|
84
73
|
test 'dirty and restore to original value' do
|
85
74
|
object = temp_object do
|
86
|
-
|
75
|
+
attribute :name, type: :string
|
87
76
|
end
|
88
77
|
|
89
78
|
record = object.create(name: 'foo')
|
@@ -12,10 +12,6 @@ class Superstore::AttributeMethodsTest < Superstore::TestCase
|
|
12
12
|
assert_equal 'foo', issue.read_attribute(:description)
|
13
13
|
end
|
14
14
|
|
15
|
-
test 'read primary_key' do
|
16
|
-
refute_nil Issue.new[:id]
|
17
|
-
end
|
18
|
-
|
19
15
|
test 'hash accessor aliases' do
|
20
16
|
issue = Issue.new
|
21
17
|
|
@@ -34,32 +30,24 @@ class Superstore::AttributeMethodsTest < Superstore::TestCase
|
|
34
30
|
assert_equal 'foo', issue.description
|
35
31
|
end
|
36
32
|
|
37
|
-
class
|
38
|
-
|
39
|
-
self[:title] = val + ' lol'
|
40
|
-
end
|
41
|
-
end
|
33
|
+
class ModelWithOverride < Superstore::Base
|
34
|
+
attribute :title, type: :string
|
42
35
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
assert_equal 'hey lol', issue.title
|
36
|
+
def title=(v)
|
37
|
+
super "#{v} lol"
|
38
|
+
end
|
47
39
|
end
|
48
40
|
|
49
|
-
|
50
|
-
|
51
|
-
string :system
|
52
|
-
end
|
41
|
+
test 'override' do
|
42
|
+
issue = ModelWithOverride.new(title: 'hey')
|
53
43
|
|
54
|
-
|
55
|
-
r = ReservedWord.new(system: 'hello')
|
56
|
-
assert_equal 'hello', r.system
|
44
|
+
assert_equal 'hey lol', issue.title
|
57
45
|
end
|
58
46
|
|
59
47
|
test 'has_attribute?' do
|
60
|
-
refute Issue.new.
|
48
|
+
refute Issue.new.has_attribute?(:unknown)
|
49
|
+
assert Issue.new.has_attribute?(:description)
|
61
50
|
assert Issue.new(description: nil).has_attribute?(:description)
|
62
|
-
assert Issue.new(description: false).has_attribute?(:description)
|
63
51
|
assert Issue.new(description: 'hey').has_attribute?(:description)
|
64
52
|
end
|
65
53
|
end
|
@@ -1,18 +1,19 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class Superstore::
|
3
|
+
class Superstore::AttributesTest < Superstore::TestCase
|
4
4
|
class TestIssue < Superstore::Base
|
5
5
|
self.table_name = 'issues'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
attribute :enabled, type: :boolean
|
8
|
+
attribute :rating, type: :float
|
9
|
+
attribute :price, type: :integer
|
10
|
+
attribute :orders, type: :json
|
11
|
+
attribute :name, type: :string
|
12
|
+
attribute :age_range, type: :integer_range
|
12
13
|
end
|
13
14
|
|
14
15
|
class TestChildIssue < TestIssue
|
15
|
-
|
16
|
+
attribute :description, type: :string
|
16
17
|
end
|
17
18
|
|
18
19
|
test 'attributes not shared' do
|
@@ -21,15 +22,6 @@ class Superstore::AttributeMethods::TypecastingTest < Superstore::TestCase
|
|
21
22
|
assert_nothing_raised { TestChildIssue.new.description }
|
22
23
|
end
|
23
24
|
|
24
|
-
test 'typecast_attribute' do
|
25
|
-
assert_equal 1, TestIssue.typecast_attribute('price', 1)
|
26
|
-
assert_equal 1, TestIssue.typecast_attribute(:price, 1)
|
27
|
-
|
28
|
-
assert_raise NoMethodError do
|
29
|
-
TestIssue.typecast_attribute('wtf', 1)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
25
|
test 'boolean attribute' do
|
34
26
|
issue = TestIssue.create! enabled: '1'
|
35
27
|
assert_equal true, issue.enabled
|
@@ -76,29 +68,11 @@ class Superstore::AttributeMethods::TypecastingTest < Superstore::TestCase
|
|
76
68
|
assert_equal '42', issue.name
|
77
69
|
end
|
78
70
|
|
79
|
-
test '
|
80
|
-
|
81
|
-
|
82
|
-
end
|
71
|
+
test 'integer_range' do
|
72
|
+
issue = TestIssue.create! age_range: ['70', nil]
|
73
|
+
assert_equal 70..Float::INFINITY, issue.age_range
|
83
74
|
|
84
|
-
|
85
|
-
|
86
|
-
}
|
87
|
-
issue = MultipleAttributesIssue.new :hello => 'hey', :greetings => 'how r u', :bye => 'see ya'
|
88
|
-
|
89
|
-
assert_equal 'how r u', issue.greetings
|
90
|
-
end
|
91
|
-
|
92
|
-
test 'multiple attributes with options' do
|
93
|
-
class MultipleAttributesIssue < Superstore::Base
|
94
|
-
self.table_name = 'issues'
|
95
|
-
end
|
96
|
-
|
97
|
-
MultipleAttributesIssue.expects(:attribute).with(:hello, { :unique => :true, :type => :string })
|
98
|
-
MultipleAttributesIssue.expects(:attribute).with(:world, { :unique => :true, :type => :string })
|
99
|
-
|
100
|
-
class MultipleAttributesIssue < Superstore::Base
|
101
|
-
string :hello, :world, :unique => :true
|
102
|
-
end
|
75
|
+
issue = TestIssue.find issue.id
|
76
|
+
assert_equal 70..Float::INFINITY, issue.age_range
|
103
77
|
end
|
104
78
|
end
|