second_level_cache 2.1.9 → 2.1.16

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f6a4e2dad0ed044548798d38f155a9c9f153408e
4
- data.tar.gz: 4ffb77cc2f17e40d53f3943686f87427c60cd626
2
+ SHA256:
3
+ metadata.gz: f6149c9f3aaaa26ad9fc6a0fa5633a5602a08c68451eb04c010973e1305649f0
4
+ data.tar.gz: 1945c39303777ea938b7187a3cad868db17348153fe91bf3844e6d4868201171
5
5
  SHA512:
6
- metadata.gz: 2b60fb3e4e71c77541c568c9b6b29c1840bfe4838b7ef50c7c754b78464ddd41ba2133a80964590d2f259019add8bca1bf5d221d14f6473f3fe69893d27ed92f
7
- data.tar.gz: de72573534de9d3acd65d5716adfce3e8a26885bd9c94e9808bca70bc371efadbe3c9f46d38c2e0aea6e16d5afbcdb6e9fd9852d47b714e983cdbc491fec4361
6
+ metadata.gz: '09e8ac1d40c06ce9642af57ff1d98a3759490196380caf5093fd203484a2b5f8eda94157d59424227824755778ae4cbeeff75399591576b79411abeee48ba99e'
7
+ data.tar.gz: 549350c57237148d9b8bb305c8ad6aa7985459111c133bffa4025de02ff61b6380f762b74d619802ad00d09863af0ef596cfdeb2c67b6466c7c50712d8354774
@@ -1,3 +1,13 @@
1
+ 2.1.15
2
+ * Replace Fixnum class check for Integer class
3
+
4
+ 2.1.14
5
+ * support has_one with scope
6
+
7
+ 2.1.10
8
+ * read multi from cache for find(ids)
9
+
10
+ -----
1
11
  2.0.0.rc1
2
12
  -----
3
13
  * ActiveRecord 4 ready!
data/README.md CHANGED
@@ -141,6 +141,13 @@ post = Post.fetch_by_uniq_keys(user_id: 2, slug: "foo")
141
141
  user = User.fetch_by_uniq_keys!(nick_name: "hooopo") # this will raise `ActiveRecord::RecordNotFound` Exception when nick name not exists.
142
142
  ```
143
143
 
144
+ * multi_read_from_cache
145
+
146
+ ```ruby
147
+ # this will use Rails.cache.multi_read method to fetch record, if miss, then use SQL in query.
148
+ blogs = Blog.multi_read_from_cache([1,2,3])
149
+ ```
150
+
144
151
  * You can use Rails's [Eager Loading](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations) feature as normal. Even better, second_level_cache will transform the `IN` query into a Rails.cache.multi_read operation. For example:
145
152
 
146
153
  ```ruby
@@ -7,6 +7,7 @@ require 'second_level_cache/active_record/persistence'
7
7
  require 'second_level_cache/active_record/belongs_to_association'
8
8
  require 'second_level_cache/active_record/has_one_association'
9
9
  require 'second_level_cache/active_record/preloader'
10
+ require 'second_level_cache/active_record/multi_read_from_cache'
10
11
 
11
12
  if defined? Rails
12
13
  require 'second_level_cache/active_record/railtie'
@@ -14,6 +15,7 @@ else
14
15
  ActiveRecord::Base.send(:include, SecondLevelCache::Mixin)
15
16
  ActiveRecord::Base.send(:include, SecondLevelCache::ActiveRecord::Base)
16
17
  ActiveRecord::Base.send(:extend, SecondLevelCache::ActiveRecord::FetchByUniqKey)
18
+ ActiveRecord::Base.send(:extend, SecondLevelCache::ActiveRecord::MultiReadFromCache)
17
19
 
18
20
  ActiveRecord::Base.send(:include, SecondLevelCache::ActiveRecord::Persistence)
19
21
  ActiveRecord::Associations::BelongsToAssociation.send(:include, SecondLevelCache::ActiveRecord::Associations::BelongsToAssociation)
@@ -13,7 +13,7 @@ module SecondLevelCache
13
13
 
14
14
  module ClassMethods
15
15
  def find_with_cache(*ids)
16
- return all.find(ids.first) if ids.size == 1 && ids.first.is_a?(Fixnum)
16
+ return all.find(ids.first) if ids.size == 1 && ids.first.is_a?(Integer)
17
17
  find_without_cache(*ids)
18
18
  end
19
19
  end
@@ -6,10 +6,9 @@ module SecondLevelCache
6
6
 
7
7
  included do
8
8
  alias_method_chain :find_one, :second_level_cache
9
+ alias_method_chain :find_some, :second_level_cache
9
10
  end
10
11
 
11
- # TODO find_some
12
- # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation/finder_methods.rb#L289-L309
13
12
  #
14
13
  # Cacheable:
15
14
  #
@@ -39,6 +38,35 @@ module SecondLevelCache
39
38
  record
40
39
  end
41
40
 
41
+ def find_some_with_second_level_cache(ids)
42
+ return find_some_without_second_level_cache(ids) unless second_level_cache_enabled?
43
+ return find_some_without_second_level_cache(ids) unless select_all_column?
44
+
45
+ if cachable?
46
+ result = multi_read_from_cache(ids)
47
+ else
48
+ result = where(:id => ids).all
49
+ end
50
+
51
+ expected_size =
52
+ if limit_value && ids.size > limit_value
53
+ limit_value
54
+ else
55
+ ids.size
56
+ end
57
+
58
+ # 11 ids with limit 3, offset 9 should give 2 results.
59
+ if offset_value && (ids.size - offset_value < expected_size)
60
+ expected_size = ids.size - offset_value
61
+ end
62
+
63
+ if result.size == expected_size
64
+ result
65
+ else
66
+ raise_record_not_found_exception!(ids, result.size, expected_size)
67
+ end
68
+ end
69
+
42
70
  private
43
71
 
44
72
  def cachable?
@@ -12,10 +12,13 @@ module SecondLevelCache
12
12
 
13
13
  def find_target_with_second_level_cache
14
14
  return find_target_without_second_level_cache unless klass.second_level_cache_enabled?
15
- return find_target_without_second_level_cache if reflection.options[:through] || reflection.scope
16
- # TODO: implement cache with has_one through, scope
15
+
16
+ return find_target_without_second_level_cache if reflection.options[:through]
17
+ # TODO: implement cache with has_one through
17
18
  if reflection.options[:as]
18
19
  cache_record = klass.fetch_by_uniq_keys({reflection.foreign_key => owner[reflection.active_record_primary_key], reflection.type => owner.class.base_class.name})
20
+ elsif reflection.scope
21
+ cache_record = klass.fetch_by_uniq_keys(create_scope)
19
22
  else
20
23
  cache_record = klass.fetch_by_uniq_key(owner[reflection.active_record_primary_key], reflection.foreign_key)
21
24
  end
@@ -0,0 +1,21 @@
1
+ module SecondLevelCache
2
+ module ActiveRecord
3
+ module MultiReadFromCache
4
+ def multi_read_from_cache(ids)
5
+ map_cache_keys = ids.map{|id| second_level_cache_key(id)}
6
+ records_from_cache = ::SecondLevelCache.cache_store.read_multi(*map_cache_keys)
7
+ hitted_ids = records_from_cache.map{|key, _| key.split("/")[2].to_i}
8
+ missed_ids = ids.map{|x| x.to_i} - hitted_ids
9
+
10
+ ::SecondLevelCache::Config.logger.info "missed ids -> #{missed_ids.inspect} | hitted ids -> #{hitted_ids.inspect}"
11
+
12
+ if missed_ids.empty?
13
+ RecordMarshal.load_multi(records_from_cache.values)
14
+ else
15
+ records_from_db = where(:id => missed_ids)
16
+ records_from_db.map{|record| record.write_second_level_cache ; record} + RecordMarshal.load_multi(records_from_cache.values)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -3,6 +3,7 @@ class SecondLevelCache::ActiveRecord::Railtie < Rails::Railtie
3
3
  ActiveRecord::Base.send(:include, SecondLevelCache::Mixin)
4
4
  ActiveRecord::Base.send(:include, SecondLevelCache::ActiveRecord::Base)
5
5
  ActiveRecord::Base.send(:extend, SecondLevelCache::ActiveRecord::FetchByUniqKey)
6
+ ActiveRecord::Base.send(:extend, SecondLevelCache::ActiveRecord::MultiReadFromCache)
6
7
 
7
8
  ActiveRecord::Base.send(:include, SecondLevelCache::ActiveRecord::Persistence)
8
9
  ActiveRecord::Associations::BelongsToAssociation.send(:include, SecondLevelCache::ActiveRecord::Associations::BelongsToAssociation)
@@ -1,4 +1,4 @@
1
1
  # -*- encoding : utf-8 -*-
2
- module SecondLevelCache
3
- VERSION = "2.1.9"
2
+ module SecondLevelCache
3
+ VERSION = "2.1.16"
4
4
  end
@@ -33,7 +33,7 @@ Gem::Specification.new do |gem|
33
33
  gem.add_runtime_dependency "activesupport", ["> 4.0.0", "< 5.0"]
34
34
 
35
35
  gem.add_runtime_dependency "activerecord", ["> 4.0.0", "< 5.0"]
36
- gem.add_development_dependency "sqlite3"
36
+ gem.add_development_dependency "sqlite3", "~> 1.3.6"
37
37
  gem.add_development_dependency "rake"
38
38
  gem.add_development_dependency 'pry'
39
39
  gem.add_development_dependency "database_cleaner", "~> 1.3.0"
@@ -4,6 +4,7 @@ require 'test_helper'
4
4
  class FinderMethodsTest < ActiveSupport::TestCase
5
5
  def setup
6
6
  @user = User.create :name => 'csdn', :email => 'test@csdn.com'
7
+ @other_user = User.create :name => 'shopper+', :email => 'test@shopperplus.com'
7
8
  end
8
9
 
9
10
  def test_should_find_without_cache
@@ -41,4 +42,41 @@ class FinderMethodsTest < ActiveSupport::TestCase
41
42
  end
42
43
  refute_equal @user.name, @from_db.name
43
44
  end
45
+
46
+ def test_find_some_record
47
+ @users = User.find(@user.id, @other_user.id)
48
+ assert_equal 2, @users.size
49
+ end
50
+
51
+ def test_find_some_record_without_second_level_cache
52
+ User.without_second_level_cache do
53
+ @users = User.find(@user.id, @other_user.id)
54
+ end
55
+ assert_equal 2, @users.size
56
+ end
57
+
58
+ def test_missing_id_will_raise_for_find_some
59
+ assert_raises(ActiveRecord::RecordNotFound) do
60
+ @users = User.find(@user.id, User.last.id + 10000)
61
+ end
62
+ end
63
+
64
+ def test_filter_works_fine_for_find_some
65
+ assert_raises(ActiveRecord::RecordNotFound) do
66
+ @users = User.where("name is null").find(@user.id, @other_user.id)
67
+ end
68
+ end
69
+
70
+ def test_half_in_cache_for_find_some
71
+ @user.expire_second_level_cache
72
+ @users = User.find(@user.id, @other_user.id)
73
+ assert_equal 2, @users.size
74
+ end
75
+
76
+ def test_no_record_in_cache_for_find_some
77
+ @user.expire_second_level_cache
78
+ @other_user.expire_second_level_cache
79
+ @users = User.find(@user.id, @other_user.id)
80
+ assert_equal 2, @users.size
81
+ end
44
82
  end
@@ -31,7 +31,11 @@ class HasOneAssociationTest < ActiveSupport::TestCase
31
31
  user.create_namespace(name: 'hooopo')
32
32
  group_namespace2 = Namespace.create(user_id: user.id, name: 'rails', kind: 'group')
33
33
  assert_not_equal user.namespace, nil
34
- clear_user = User.find(user.id)
34
+ assert_equal user.reload.namespace.name, 'hooopo'
35
+ clear_user = user.reload
36
+ assert_no_queries do
37
+ clear_user.namespace
38
+ end
35
39
  assert_equal clear_user.namespace.name, 'hooopo'
36
40
  end
37
41
  end
@@ -0,0 +1,19 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'test_helper'
3
+
4
+ class MultiReadFromCacheTest < ActiveSupport::TestCase
5
+ def setup
6
+ @user = User.create :name => 'hooopo', :email => 'hoooopo@gmail.com'
7
+ @other_user = User.create :name => 'hoooopo', :email => "hooooopo@gmail.com"
8
+ end
9
+
10
+ def test_multi_read_from_cache
11
+ result = User.multi_read_from_cache([@user.id, @other_user.id])
12
+ assert_equal 2, result.size
13
+ end
14
+
15
+ def test_multi_read_not_exist_id_from_cache
16
+ result = User.multi_read_from_cache([@user.id, @other_user.id + 100])
17
+ assert_equal 1, result.size
18
+ end
19
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: second_level_cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.9
4
+ version: 2.1.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hooopo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-16 00:00:00.000000000 Z
11
+ date: 2020-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -54,16 +54,16 @@ dependencies:
54
54
  name: sqlite3
55
55
  requirement: !ruby/object:Gem::Requirement
56
56
  requirements:
57
- - - ">="
57
+ - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '0'
59
+ version: 1.3.6
60
60
  type: :development
61
61
  prerelease: false
62
62
  version_requirements: !ruby/object:Gem::Requirement
63
63
  requirements:
64
- - - ">="
64
+ - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '0'
66
+ version: 1.3.6
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: rake
69
69
  requirement: !ruby/object:Gem::Requirement
@@ -126,6 +126,7 @@ files:
126
126
  - lib/second_level_cache/active_record/fetch_by_uniq_key.rb
127
127
  - lib/second_level_cache/active_record/finder_methods.rb
128
128
  - lib/second_level_cache/active_record/has_one_association.rb
129
+ - lib/second_level_cache/active_record/multi_read_from_cache.rb
129
130
  - lib/second_level_cache/active_record/persistence.rb
130
131
  - lib/second_level_cache/active_record/preloader.rb
131
132
  - lib/second_level_cache/active_record/railtie.rb
@@ -143,6 +144,7 @@ files:
143
144
  - test/model/animal.rb
144
145
  - test/model/book.rb
145
146
  - test/model/image.rb
147
+ - test/model/multi_read_from_cache_test.rb
146
148
  - test/model/post.rb
147
149
  - test/model/topic.rb
148
150
  - test/model/user.rb
@@ -172,8 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
174
  - !ruby/object:Gem::Version
173
175
  version: '0'
174
176
  requirements: []
175
- rubyforge_project:
176
- rubygems_version: 2.2.2
177
+ rubygems_version: 3.0.3
177
178
  signing_key:
178
179
  specification_version: 4
179
180
  summary: 'SecondLevelCache is a write-through and read-through caching library inspired
@@ -183,24 +184,25 @@ summary: 'SecondLevelCache is a write-through and read-through caching library i
183
184
  is a cache miss, it will populate the cache. Write-Through: As objects are created,
184
185
  updated, and deleted, all of the caches are automatically kept up-to-date and coherent.'
185
186
  test_files:
186
- - test/active_record_test_case_helper.rb
187
- - test/base_test.rb
188
- - test/belongs_to_association_test.rb
189
- - test/fetch_by_uniq_key_test.rb
187
+ - test/polymorphic_association_test.rb
188
+ - test/require_test.rb
189
+ - test/preloader_test.rb
190
190
  - test/finder_methods_test.rb
191
- - test/has_one_association_test.rb
191
+ - test/belongs_to_association_test.rb
192
+ - test/second_level_cache_test.rb
193
+ - test/record_marshal_test.rb
194
+ - test/persistence_test.rb
195
+ - test/single_table_inheritance_test.rb
196
+ - test/model/image.rb
192
197
  - test/model/account.rb
193
- - test/model/animal.rb
194
198
  - test/model/book.rb
195
- - test/model/image.rb
196
- - test/model/post.rb
197
199
  - test/model/topic.rb
200
+ - test/model/animal.rb
201
+ - test/model/multi_read_from_cache_test.rb
202
+ - test/model/post.rb
198
203
  - test/model/user.rb
199
- - test/persistence_test.rb
200
- - test/polymorphic_association_test.rb
201
- - test/preloader_test.rb
202
- - test/record_marshal_test.rb
203
- - test/require_test.rb
204
- - test/second_level_cache_test.rb
205
- - test/single_table_inheritance_test.rb
204
+ - test/fetch_by_uniq_key_test.rb
206
205
  - test/test_helper.rb
206
+ - test/has_one_association_test.rb
207
+ - test/base_test.rb
208
+ - test/active_record_test_case_helper.rb