second_level_cache 2.1.9 → 2.1.16

Sign up to get free protection for your applications and to get access to all the features.
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