second_level_cache 2.5.0 → 2.6.2
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 +34 -0
- data/README.md +1 -1
- data/lib/second_level_cache.rb +1 -0
- data/lib/second_level_cache/active_record.rb +8 -2
- data/lib/second_level_cache/active_record/base.rb +1 -5
- data/lib/second_level_cache/active_record/belongs_to_association.rb +6 -4
- data/lib/second_level_cache/active_record/fetch_by_uniq_key.rb +24 -17
- data/lib/second_level_cache/active_record/finder_methods.rb +44 -42
- data/lib/second_level_cache/active_record/has_one_association.rb +14 -20
- data/lib/second_level_cache/active_record/persistence.rb +6 -2
- data/lib/second_level_cache/active_record/preloader.rb +34 -28
- data/lib/second_level_cache/adapter/paranoia.rb +24 -0
- data/lib/second_level_cache/config.rb +1 -0
- data/lib/second_level_cache/log_subscriber.rb +15 -0
- data/lib/second_level_cache/mixin.rb +0 -12
- data/lib/second_level_cache/record_marshal.rb +7 -40
- data/lib/second_level_cache/version.rb +1 -1
- data/second_level_cache.gemspec +23 -23
- data/test/active_record_test_case_helper.rb +11 -1
- data/test/fetch_by_uniq_key_test.rb +47 -4
- data/test/finder_methods_test.rb +39 -0
- data/test/has_one_association_test.rb +16 -4
- data/test/model/account.rb +2 -2
- data/test/model/animal.rb +1 -1
- data/test/model/application_record.rb +3 -0
- data/test/model/book.rb +6 -1
- data/test/model/contribution.rb +14 -0
- data/test/model/image.rb +1 -1
- data/test/model/order.rb +1 -1
- data/test/model/order_item.rb +1 -1
- data/test/model/paranoid.rb +10 -0
- data/test/model/post.rb +1 -1
- data/test/model/topic.rb +1 -1
- data/test/model/user.rb +7 -7
- data/test/paranoid_test.rb +16 -0
- data/test/{preloader_test.rb → preloader_belongs_to_test.rb} +17 -15
- data/test/preloader_has_many_test.rb +13 -0
- data/test/preloader_has_one_test.rb +69 -0
- data/test/record_marshal_test.rb +1 -1
- data/test/test_helper.rb +3 -4
- metadata +28 -28
data/test/model/order.rb
CHANGED
data/test/model/order_item.rb
CHANGED
data/test/model/post.rb
CHANGED
data/test/model/topic.rb
CHANGED
data/test/model/user.rb
CHANGED
|
@@ -9,8 +9,7 @@ ActiveRecord::Base.connection.create_table(:users, force: true) do |t|
|
|
|
9
9
|
t.integer :status, default: 0
|
|
10
10
|
t.integer :books_count, default: 0
|
|
11
11
|
t.integer :images_count, default: 0
|
|
12
|
-
t.
|
|
13
|
-
t.timestamps null: false
|
|
12
|
+
t.timestamps null: false, precision: 6
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
ActiveRecord::Base.connection.create_table(:forked_user_links, force: true) do |t|
|
|
@@ -26,16 +25,15 @@ ActiveRecord::Base.connection.create_table(:namespaces, force: true) do |t|
|
|
|
26
25
|
t.timestamps null: false
|
|
27
26
|
end
|
|
28
27
|
|
|
29
|
-
class User <
|
|
28
|
+
class User < ApplicationRecord
|
|
30
29
|
CACHE_VERSION = 3
|
|
31
30
|
second_level_cache(version: CACHE_VERSION, expires_in: 3.days)
|
|
32
|
-
acts_as_paranoid
|
|
33
31
|
|
|
34
32
|
serialize :options, Array
|
|
35
33
|
serialize :json_options, JSON if ::ActiveRecord::VERSION::STRING >= "4.1.0"
|
|
36
34
|
store :extras, accessors: %i[tagline gender]
|
|
37
35
|
|
|
38
|
-
has_one :account
|
|
36
|
+
has_one :account, inverse_of: :user
|
|
39
37
|
has_one :forked_user_link, foreign_key: "forked_to_user_id"
|
|
40
38
|
has_one :forked_from_user, through: :forked_user_link
|
|
41
39
|
has_many :namespaces
|
|
@@ -46,13 +44,15 @@ class User < ActiveRecord::Base
|
|
|
46
44
|
enum status: %i[active archived]
|
|
47
45
|
end
|
|
48
46
|
|
|
49
|
-
class Namespace <
|
|
47
|
+
class Namespace < ApplicationRecord
|
|
50
48
|
second_level_cache version: 1, expires_in: 3.days
|
|
51
49
|
|
|
52
50
|
belongs_to :user
|
|
53
51
|
end
|
|
54
52
|
|
|
55
|
-
class ForkedUserLink <
|
|
53
|
+
class ForkedUserLink < ApplicationRecord
|
|
54
|
+
second_level_cache version: 1, expires_in: 1.day
|
|
55
|
+
|
|
56
56
|
belongs_to :forked_from_user, class_name: "User"
|
|
57
57
|
belongs_to :forked_to_user, class_name: "User"
|
|
58
58
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class ParanoidTest < ActiveSupport::TestCase
|
|
6
|
+
def setup
|
|
7
|
+
@paranoid = Paranoid.create
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_should_expire_cache_when_destroy
|
|
11
|
+
@paranoid.destroy
|
|
12
|
+
assert_nil Paranoid.find_by(id: @paranoid.id)
|
|
13
|
+
assert_nil SecondLevelCache.cache_store.read(@paranoid.second_level_cache_key)
|
|
14
|
+
assert_nil User.read_second_level_cache(@paranoid.id)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "test_helper"
|
|
4
4
|
|
|
5
|
-
class
|
|
6
|
-
def
|
|
5
|
+
class PreloaderBelongsToTest < ActiveSupport::TestCase
|
|
6
|
+
def test_preload_caches_includes
|
|
7
7
|
topics = [
|
|
8
8
|
Topic.create(title: "title1", body: "body1"),
|
|
9
9
|
Topic.create(title: "title2", body: "body2"),
|
|
@@ -18,7 +18,7 @@ class PreloaderTest < ActiveSupport::TestCase
|
|
|
18
18
|
assert_equal topics, results.map(&:topic)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def
|
|
21
|
+
def test_when_read_multi_missed_from_cache_ar_will_fetch_missed_records_from_db
|
|
22
22
|
topics = [
|
|
23
23
|
Topic.create(title: "title1", body: "body1"),
|
|
24
24
|
Topic.create(title: "title2", body: "body2"),
|
|
@@ -39,19 +39,21 @@ class PreloaderTest < ActiveSupport::TestCase
|
|
|
39
39
|
assert_equal topics, results.map(&:topic)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
def
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
assert_equal
|
|
42
|
+
def test_preloader_caches_includes_tried_set_inverse_instance
|
|
43
|
+
user_id = Time.current.to_i
|
|
44
|
+
Account.create(site: "foobar", user_id: user_id)
|
|
45
|
+
User.create(id: user_id, name: "foobar", email: "foobar@test.com")
|
|
46
|
+
accounts = Account.includes(:user)
|
|
47
|
+
assert_equal accounts.first.object_id, accounts.first.user.account.object_id
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
def
|
|
51
|
-
user = User.create
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
def test_preloader_from_db_when_exists_scope
|
|
51
|
+
user = User.create
|
|
52
|
+
book = user.books.create
|
|
53
|
+
image = book.images.create
|
|
54
|
+
book.toggle!(:normal)
|
|
55
|
+
assert_queries(:any) do
|
|
56
|
+
assert_nil Image.includes(:imagable).where(id: image.id).first.imagable
|
|
57
|
+
end
|
|
56
58
|
end
|
|
57
59
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class PreloaderHasManyTest < ActiveSupport::TestCase
|
|
6
|
+
def test_preloader_returns_correct_records
|
|
7
|
+
topic = Topic.create(id: 1)
|
|
8
|
+
Post.create(id: 1)
|
|
9
|
+
post = topic.posts.create
|
|
10
|
+
|
|
11
|
+
assert_equal [post], Topic.includes(:posts).find(1).posts
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class PreloaderHasOneTest < ActiveSupport::TestCase
|
|
6
|
+
# def test_preload_caches_includes
|
|
7
|
+
# users = User.create([
|
|
8
|
+
# { name: "foobar1", email: "foobar1@test.com" },
|
|
9
|
+
# { name: "foobar2", email: "foobar2@test.com" },
|
|
10
|
+
# { name: "foobar3", email: "foobar3@test.com" }
|
|
11
|
+
# ])
|
|
12
|
+
# namespaces = users.map { |user| user.create_namespace(name: user.name) }
|
|
13
|
+
|
|
14
|
+
# assert_queries(2) { User.includes(:namespace).order(id: :asc).to_a } # Write cache
|
|
15
|
+
# assert_queries(1) do
|
|
16
|
+
# assert_equal namespaces, User.includes(:namespace).order(id: :asc).map(&:namespace)
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
|
|
20
|
+
# def test_when_read_multi_missed_from_cache_should_will_fetch_missed_records_from_db
|
|
21
|
+
# users = User.create([
|
|
22
|
+
# { name: "foobar1", email: "foobar1@test.com" },
|
|
23
|
+
# { name: "foobar2", email: "foobar2@test.com" },
|
|
24
|
+
# { name: "foobar3", email: "foobar3@test.com" }
|
|
25
|
+
# ])
|
|
26
|
+
# namespaces = users.map { |user| user.create_namespace(name: user.name) }
|
|
27
|
+
# assert_queries(2) { User.includes(:namespace).order(id: :asc).to_a } # Write cache
|
|
28
|
+
# expired_namespace = namespaces.first
|
|
29
|
+
# expired_namespace.expire_second_level_cache
|
|
30
|
+
|
|
31
|
+
# assert_queries(2) do
|
|
32
|
+
# assert_sql(/WHERE\s\"namespaces\".\"kind\"\sIS\sNULL\sAND\s\"namespaces\"\.\"user_id\"\s=\s?/m) do
|
|
33
|
+
# results = User.includes(:namespace).order(id: :asc).to_a
|
|
34
|
+
# assert_equal namespaces, results.map(&:namespace)
|
|
35
|
+
# assert_equal expired_namespace, results.first.namespace
|
|
36
|
+
# end
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
|
|
40
|
+
# def test_preloader_returns_correct_records_after_modify
|
|
41
|
+
# user = User.create(name: "foobar", email: "foobar@test.com")
|
|
42
|
+
|
|
43
|
+
# old_namespace = user.create_namespace(name: "old")
|
|
44
|
+
# assert_queries(2) { User.includes(:namespace).order(id: :asc).to_a } # Write cache
|
|
45
|
+
# assert_queries(1) do
|
|
46
|
+
# assert_equal old_namespace, User.includes(:namespace).first.namespace
|
|
47
|
+
# end
|
|
48
|
+
|
|
49
|
+
# new_namespace = user.create_namespace(name: "new")
|
|
50
|
+
# assert_queries(2) { User.includes(:namespace).order(id: :asc).to_a } # Write cache
|
|
51
|
+
# assert_queries(1) do
|
|
52
|
+
# assert_equal new_namespace, User.includes(:namespace).first.namespace
|
|
53
|
+
# end
|
|
54
|
+
# end
|
|
55
|
+
|
|
56
|
+
# def test_preloader_caches_includes_tried_set_inverse_instance
|
|
57
|
+
# User.create(name: "foobar", email: "foobar@test.com").create_account(site: "foobar")
|
|
58
|
+
# users = User.includes(:account)
|
|
59
|
+
# assert_equal users.first.object_id, users.first.account.user.object_id
|
|
60
|
+
# end
|
|
61
|
+
|
|
62
|
+
def test_has_one_preloader_returns_correct_results
|
|
63
|
+
user = User.create(id: 1)
|
|
64
|
+
Account.create(id: 1)
|
|
65
|
+
account = user.create_account
|
|
66
|
+
|
|
67
|
+
assert_equal account, User.includes(:account).find(1).account
|
|
68
|
+
end
|
|
69
|
+
end
|
data/test/record_marshal_test.rb
CHANGED
|
@@ -25,7 +25,7 @@ class RecordMarshalTest < ActiveSupport::TestCase
|
|
|
25
25
|
dumped = RecordMarshal.dump(@user)
|
|
26
26
|
assert dumped.is_a?(Array)
|
|
27
27
|
assert_equal "User", dumped[0]
|
|
28
|
-
assert_equal
|
|
28
|
+
assert_equal dumped[1], ActiveRecord::Base.connection.select_all(User.where(id: @user.id)).first
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def test_should_load_active_record_object
|
data/test/test_helper.rb
CHANGED
|
@@ -16,6 +16,7 @@ require "second_level_cache"
|
|
|
16
16
|
|
|
17
17
|
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
|
|
18
18
|
|
|
19
|
+
require "model/application_record"
|
|
19
20
|
require "model/user"
|
|
20
21
|
require "model/book"
|
|
21
22
|
require "model/image"
|
|
@@ -25,6 +26,8 @@ require "model/order"
|
|
|
25
26
|
require "model/order_item"
|
|
26
27
|
require "model/account"
|
|
27
28
|
require "model/animal"
|
|
29
|
+
require "model/contribution"
|
|
30
|
+
require "model/paranoid"
|
|
28
31
|
|
|
29
32
|
DatabaseCleaner[:active_record].strategy = :truncation
|
|
30
33
|
|
|
@@ -32,10 +35,6 @@ SecondLevelCache.configure do |config|
|
|
|
32
35
|
config.cache_store = ActiveSupport::Cache::MemoryStore.new
|
|
33
36
|
end
|
|
34
37
|
|
|
35
|
-
SecondLevelCache.logger.level = Logger::ERROR
|
|
36
|
-
ActiveSupport::Cache::MemoryStore.logger = SecondLevelCache.logger
|
|
37
|
-
ActiveRecord::Base.logger = SecondLevelCache.logger
|
|
38
|
-
|
|
39
38
|
module ActiveSupport
|
|
40
39
|
class TestCase
|
|
41
40
|
setup do
|
metadata
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: second_level_cache
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hooopo
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-07-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: activerecord
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
@@ -31,7 +31,7 @@ dependencies:
|
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: '7'
|
|
33
33
|
- !ruby/object:Gem::Dependency
|
|
34
|
-
name:
|
|
34
|
+
name: activesupport
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
@@ -51,21 +51,7 @@ dependencies:
|
|
|
51
51
|
- !ruby/object:Gem::Version
|
|
52
52
|
version: '7'
|
|
53
53
|
- !ruby/object:Gem::Dependency
|
|
54
|
-
name:
|
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
|
56
|
-
requirements:
|
|
57
|
-
- - ">"
|
|
58
|
-
- !ruby/object:Gem::Version
|
|
59
|
-
version: '1.4'
|
|
60
|
-
type: :development
|
|
61
|
-
prerelease: false
|
|
62
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
63
|
-
requirements:
|
|
64
|
-
- - ">"
|
|
65
|
-
- !ruby/object:Gem::Version
|
|
66
|
-
version: '1.4'
|
|
67
|
-
- !ruby/object:Gem::Dependency
|
|
68
|
-
name: rake
|
|
54
|
+
name: database_cleaner
|
|
69
55
|
requirement: !ruby/object:Gem::Requirement
|
|
70
56
|
requirements:
|
|
71
57
|
- - ">="
|
|
@@ -79,7 +65,7 @@ dependencies:
|
|
|
79
65
|
- !ruby/object:Gem::Version
|
|
80
66
|
version: '0'
|
|
81
67
|
- !ruby/object:Gem::Dependency
|
|
82
|
-
name:
|
|
68
|
+
name: rake
|
|
83
69
|
requirement: !ruby/object:Gem::Requirement
|
|
84
70
|
requirements:
|
|
85
71
|
- - ">="
|
|
@@ -93,7 +79,7 @@ dependencies:
|
|
|
93
79
|
- !ruby/object:Gem::Version
|
|
94
80
|
version: '0'
|
|
95
81
|
- !ruby/object:Gem::Dependency
|
|
96
|
-
name:
|
|
82
|
+
name: rubocop
|
|
97
83
|
requirement: !ruby/object:Gem::Requirement
|
|
98
84
|
requirements:
|
|
99
85
|
- - ">="
|
|
@@ -107,19 +93,19 @@ dependencies:
|
|
|
107
93
|
- !ruby/object:Gem::Version
|
|
108
94
|
version: '0'
|
|
109
95
|
- !ruby/object:Gem::Dependency
|
|
110
|
-
name:
|
|
96
|
+
name: sqlite3
|
|
111
97
|
requirement: !ruby/object:Gem::Requirement
|
|
112
98
|
requirements:
|
|
113
|
-
- - "
|
|
99
|
+
- - ">"
|
|
114
100
|
- !ruby/object:Gem::Version
|
|
115
|
-
version:
|
|
101
|
+
version: '1.4'
|
|
116
102
|
type: :development
|
|
117
103
|
prerelease: false
|
|
118
104
|
version_requirements: !ruby/object:Gem::Requirement
|
|
119
105
|
requirements:
|
|
120
|
-
- - "
|
|
106
|
+
- - ">"
|
|
121
107
|
- !ruby/object:Gem::Version
|
|
122
|
-
version:
|
|
108
|
+
version: '1.4'
|
|
123
109
|
description: Write Through and Read Through caching library inspired by CacheMoney
|
|
124
110
|
and cache_fu, support ActiveRecord 4.
|
|
125
111
|
email:
|
|
@@ -142,7 +128,9 @@ files:
|
|
|
142
128
|
- lib/second_level_cache/active_record/has_one_association.rb
|
|
143
129
|
- lib/second_level_cache/active_record/persistence.rb
|
|
144
130
|
- lib/second_level_cache/active_record/preloader.rb
|
|
131
|
+
- lib/second_level_cache/adapter/paranoia.rb
|
|
145
132
|
- lib/second_level_cache/config.rb
|
|
133
|
+
- lib/second_level_cache/log_subscriber.rb
|
|
146
134
|
- lib/second_level_cache/mixin.rb
|
|
147
135
|
- lib/second_level_cache/record_marshal.rb
|
|
148
136
|
- lib/second_level_cache/record_relation.rb
|
|
@@ -157,17 +145,23 @@ files:
|
|
|
157
145
|
- test/has_one_association_test.rb
|
|
158
146
|
- test/model/account.rb
|
|
159
147
|
- test/model/animal.rb
|
|
148
|
+
- test/model/application_record.rb
|
|
160
149
|
- test/model/book.rb
|
|
150
|
+
- test/model/contribution.rb
|
|
161
151
|
- test/model/image.rb
|
|
162
152
|
- test/model/order.rb
|
|
163
153
|
- test/model/order_item.rb
|
|
154
|
+
- test/model/paranoid.rb
|
|
164
155
|
- test/model/post.rb
|
|
165
156
|
- test/model/topic.rb
|
|
166
157
|
- test/model/user.rb
|
|
158
|
+
- test/paranoid_test.rb
|
|
167
159
|
- test/persistence_test.rb
|
|
168
160
|
- test/polymorphic_association_test.rb
|
|
161
|
+
- test/preloader_belongs_to_test.rb
|
|
162
|
+
- test/preloader_has_many_test.rb
|
|
163
|
+
- test/preloader_has_one_test.rb
|
|
169
164
|
- test/preloader_non_integer_test.rb
|
|
170
|
-
- test/preloader_test.rb
|
|
171
165
|
- test/record_marshal_test.rb
|
|
172
166
|
- test/require_test.rb
|
|
173
167
|
- test/second_level_cache_test.rb
|
|
@@ -201,24 +195,30 @@ summary: 'SecondLevelCache is a write-through and read-through caching library i
|
|
|
201
195
|
is a cache miss, it will populate the cache. Write-Through: As objects are created,
|
|
202
196
|
updated, and deleted, all of the caches are automatically kept up-to-date and coherent.'
|
|
203
197
|
test_files:
|
|
198
|
+
- test/preloader_belongs_to_test.rb
|
|
204
199
|
- test/polymorphic_association_test.rb
|
|
205
200
|
- test/require_test.rb
|
|
206
|
-
- test/
|
|
201
|
+
- test/paranoid_test.rb
|
|
207
202
|
- test/finder_methods_test.rb
|
|
203
|
+
- test/preloader_has_one_test.rb
|
|
208
204
|
- test/preloader_non_integer_test.rb
|
|
209
205
|
- test/belongs_to_association_test.rb
|
|
210
206
|
- test/second_level_cache_test.rb
|
|
211
207
|
- test/enum_attr_test.rb
|
|
212
208
|
- test/record_marshal_test.rb
|
|
209
|
+
- test/preloader_has_many_test.rb
|
|
213
210
|
- test/persistence_test.rb
|
|
214
211
|
- test/single_table_inheritance_test.rb
|
|
215
212
|
- test/model/image.rb
|
|
216
213
|
- test/model/account.rb
|
|
217
214
|
- test/model/order_item.rb
|
|
215
|
+
- test/model/contribution.rb
|
|
218
216
|
- test/model/book.rb
|
|
219
217
|
- test/model/topic.rb
|
|
220
218
|
- test/model/animal.rb
|
|
221
219
|
- test/model/order.rb
|
|
220
|
+
- test/model/paranoid.rb
|
|
221
|
+
- test/model/application_record.rb
|
|
222
222
|
- test/model/post.rb
|
|
223
223
|
- test/model/user.rb
|
|
224
224
|
- test/fetch_by_uniq_key_test.rb
|