second_level_cache 2.6.4 → 2.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9401e1e025a3e955471ae743711371608400fe8c7f451f74f8b4f73bbb7c9dd6
4
- data.tar.gz: 47c05c11d57d26dfe5c990bf111a173d0864956d788c5c5ace70ca812ef3d629
3
+ metadata.gz: 9161291526eed87047708e5128c64e2907ddf61f017dbf073831c1281b6b504d
4
+ data.tar.gz: 192fffc74fe056dd8bc2d8e6486f4f5de380698bfc728d65bf02853c110a9d66
5
5
  SHA512:
6
- metadata.gz: 516d74db202dbd5d12f866b36a16b30e763a75fa88001c4ac5ab04ce1c73a2a2e412472ceda957401f9da303094d83c5a944b9c062d69e56116abdae76359256
7
- data.tar.gz: b0f3440ffd9333d49ac957cc1db3c988f41276d57f18f874fa84fc664134a14ba0acfcc8b9f5001bab99243ef51c2492ca2ea8fe2768ac461b398a1b06504e65
6
+ metadata.gz: 84e57628cd9eb58d52d7a4d5c23844d8e470ee599d865845287ac9fee9b0659fe7a0b563ab5f2e6d7fd3c59ffce6de543ec0ae91a36e77fd8d2c628f05cd53a1
7
+ data.tar.gz: 60aa90c2dfa0be0920ee121772a426c3ce209423a4c5a2c28bf61efad3ad5da14738317f40df8704e6628db9fc7a2e439619ca2bdb1d7cb2d22073d1ccded656
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+
2
+ New version releases please visit https://github.com/hooopo/second_level_cache/releases
3
+
1
4
  2.6.4
2
5
  -------
3
6
 
data/Gemfile CHANGED
@@ -3,6 +3,5 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
- gem "paranoia", "~> 2.4.2"
7
6
  gem "pry"
8
- gem "rails", "~> 6"
7
+ gem "rails", "~> 7"
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Hackershare
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # SecondLevelCache
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/second_level_cache.svg)](http://badge.fury.io/rb/second_level_cache)
4
- [![Build Status](https://travis-ci.org/hooopo/second_level_cache.svg?branch=master)](https://travis-ci.org/hooopo/second_level_cache)
4
+ [![build](https://github.com/hooopo/second_level_cache/actions/workflows/build.yml/badge.svg)](https://github.com/hooopo/second_level_cache/actions/workflows/build.yml)
5
5
  [![Code Climate](https://codeclimate.com/github/hooopo/second_level_cache.svg)](https://codeclimate.com/github/hooopo/second_level_cache)
6
6
 
7
7
  SecondLevelCache is a write-through and read-through caching library inspired by Cache Money and cache_fu, support ActiveRecord 4, ActiveRecord 5 and ActiveRecord 6.
@@ -10,11 +10,16 @@ Read-Through: Queries by ID, like `current_user.articles.find(params[:id])`, wil
10
10
 
11
11
  Write-Through: As objects are created, updated, and deleted, all of the caches are automatically kept up-to-date and coherent.
12
12
 
13
-
14
13
  ## Install
15
14
 
16
15
  In your gem file:
17
16
 
17
+ ActiveRecord 7
18
+
19
+ ```ruby
20
+ gem 'second_level_cache', '~> 2.7'
21
+ ```
22
+
18
23
  ActiveRecord 5.2 and 6.0:
19
24
 
20
25
  ```ruby
@@ -97,9 +102,9 @@ User.select("id, name").find(1)
97
102
 
98
103
  ## Notice
99
104
 
100
- * SecondLevelCache cache by model name and id, so only find_one query will work.
101
- * Only equal conditions query WILL get cache; and SQL string query like `User.where("name = 'Hooopo'").find(1)` WILL NOT work.
102
- * SecondLevelCache sync cache after transaction commit:
105
+ - SecondLevelCache cache by model name and id, so only find_one query will work.
106
+ - Only equal conditions query WILL get cache; and SQL string query like `User.where("name = 'Hooopo'").find(1)` WILL NOT work.
107
+ - SecondLevelCache sync cache after transaction commit:
103
108
 
104
109
  ```ruby
105
110
  # user and account's write_second_level_cache operation will invoke after the logger.
@@ -117,7 +122,7 @@ end # <- Cache write
117
122
  Rails.logger.info "info"
118
123
  ```
119
124
 
120
- * If you are using SecondLevelCache with database_cleaner, you should set cleaning strategy to `:truncation`:
125
+ - If you are using SecondLevelCache with database_cleaner, you should set cleaning strategy to `:truncation`:
121
126
 
122
127
  ```ruby
123
128
  DatabaseCleaner.strategy = :truncation
@@ -133,15 +138,15 @@ config.cache_store = [:dalli_store, APP_CONFIG["memcached_host"], { namespace: "
133
138
 
134
139
  ## Tips:
135
140
 
136
- * When you want to clear only second level cache apart from other cache for example fragment cache in cache store,
137
- you can only change the `cache_key_prefix` (default: `slc`):
141
+ - When you want to clear only second level cache apart from other cache for example fragment cache in cache store,
142
+ you can only change the `cache_key_prefix` (default: `slc`):
138
143
 
139
144
  ```ruby
140
145
  SecondLevelCache.configure.cache_key_prefix = "slc1"
141
146
  ```
142
147
 
143
- * SecondLevelCache was added model schema digest as cache version, this means when you add/remove/change columns, the caches of this Model will expires.
144
- * When your want change the model cache version by manualy, just add the `version` option like this:
148
+ - SecondLevelCache was added model schema digest as cache version, this means when you add/remove/change columns, the caches of this Model will expires.
149
+ - When your want change the model cache version by manualy, just add the `version` option like this:
145
150
 
146
151
  ```ruby
147
152
  class User < ActiveRecord::Base
@@ -149,7 +154,7 @@ class User < ActiveRecord::Base
149
154
  end
150
155
  ```
151
156
 
152
- * It provides a great feature, not hits db when fetching record via unique key (not primary key).
157
+ - It provides a great feature, not hits db when fetching record via unique key (not primary key).
153
158
 
154
159
  ```ruby
155
160
  # this will fetch from cache
@@ -160,7 +165,7 @@ post = Post.fetch_by_uniq_keys(user_id: 2, slug: "foo")
160
165
  user = User.fetch_by_uniq_keys!(nick_name: "hooopo") # this will raise `ActiveRecord::RecordNotFound` Exception when nick name not exists.
161
166
  ```
162
167
 
163
- * 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:
168
+ - 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:
164
169
 
165
170
  ```ruby
166
171
  Answer.includes(:question).limit(10).order("id DESC").each{|answer| answer.question.title}
@@ -171,8 +176,8 @@ Answer Load (0.2ms) SELECT `answers`.* FROM `answers` ORDER BY id DESC LIMIT 10
171
176
 
172
177
  ## Original design by:
173
178
 
174
- * [chloerei](https://github.com/chloerei)
175
- * [hooopo](https://github.com/hooopo)
179
+ - [chloerei](https://github.com/chloerei)
180
+ - [hooopo](https://github.com/hooopo)
176
181
 
177
182
  ## Contributors
178
183
 
@@ -9,10 +9,10 @@ module SecondLevelCache
9
9
 
10
10
  if obj_id
11
11
  record = begin
12
- find(obj_id)
13
- rescue StandardError
14
- nil
15
- end
12
+ find(obj_id)
13
+ rescue
14
+ nil
15
+ end
16
16
  end
17
17
  return record if record_attributes_equal_where_values?(record, where_values)
18
18
  record = where(where_values).first
@@ -42,20 +42,21 @@ module SecondLevelCache
42
42
  end
43
43
 
44
44
  private
45
- def cache_uniq_key(where_values)
46
- keys = where_values.collect do |k, v|
47
- v = Digest::MD5.hexdigest(v) if v.respond_to?(:size) && v.size >= 32
48
- [k, v].join("_")
49
- end
50
45
 
51
- ext_key = keys.join(",")
52
- "#{SecondLevelCache.configure.cache_key_prefix}/uniq_key_#{name}_#{ext_key}"
46
+ def cache_uniq_key(where_values)
47
+ keys = where_values.collect do |k, v|
48
+ v = Digest::MD5.hexdigest(v) if v.respond_to?(:size) && v.size >= 32
49
+ [k, v].join("_")
53
50
  end
54
51
 
55
- def record_attributes_equal_where_values?(record, where_values)
56
- # https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema/ClassMethods.html#method-i-type_for_attribute
57
- where_values.all? { |k, v| record&.read_attribute(k) == type_for_attribute(k).cast(v) }
58
- end
52
+ ext_key = keys.join(",")
53
+ "#{SecondLevelCache.configure.cache_key_prefix}/uniq_key_#{name}_#{ext_key}"
54
+ end
55
+
56
+ def record_attributes_equal_where_values?(record, where_values)
57
+ # https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema/ClassMethods.html#method-i-type_for_attribute
58
+ where_values.all? { |k, v| record&.read_attribute(k) == type_for_attribute(k).cast(v) }
59
+ end
59
60
  end
60
61
  end
61
62
  end
@@ -11,8 +11,7 @@ module SecondLevelCache
11
11
 
12
12
  through = reflection.options[:through]
13
13
  record = if through
14
- return super if klass.reflections[through.to_s].nil?
15
- return super unless klass.reflections[through.to_s].klass.second_level_cache_enabled?
14
+ return super unless owner.class.reflections[through.to_s].klass.second_level_cache_enabled?
16
15
  begin
17
16
  reflection.klass.find(owner.send(through).read_attribute(reflection.foreign_key))
18
17
  rescue StandardError
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SecondLevelCache
4
+ module ActiveRecord
5
+ module Associations
6
+ module Preloader
7
+ module Association
8
+ # Override load_query method for add Association instance in arguments to LoaderQuery
9
+ # https://github.com/rails/rails/blob/7-0-stable/activerecord/lib/active_record/associations/preloader/association.rb#L148
10
+ def loader_query
11
+ ::ActiveRecord::Associations::Preloader::Association::LoaderQuery.new(self, scope, association_key_name)
12
+ end
13
+
14
+ # Override load_records_for_keys for use SecondLevelCache before preload association
15
+ # https://github.com/rails/rails/blob/8f5b35b6107c28125b571b9842e248b13f804e5c/activerecord/lib/active_record/associations/preloader/association.rb#L7
16
+ module LoaderQuery
17
+ attr_reader :association
18
+
19
+ delegate :klass, to: :association
20
+
21
+ def initialize(association, scope, association_key_name)
22
+ @association = association
23
+ @scope = scope
24
+ @association_key_name = association_key_name
25
+ end
26
+
27
+ def reflection
28
+ association.send(:reflection)
29
+ end
30
+
31
+ def load_records_for_keys(keys, &block)
32
+ ids = keys.to_a
33
+
34
+ return super unless klass.second_level_cache_enabled?
35
+ return super unless reflection.is_a?(::ActiveRecord::Reflection::BelongsToReflection)
36
+ return super if klass.default_scopes.present? || reflection.scope
37
+ return super if association_key_name.to_s != klass.primary_key
38
+
39
+ map_cache_keys = ids.map { |id| klass.second_level_cache_key(id) }
40
+ records_from_cache = ::SecondLevelCache.cache_store.read_multi(*map_cache_keys)
41
+ record_marshals = RecordMarshal.load_multi(records_from_cache.values, &block)
42
+
43
+ # NOTICE
44
+ # Rails.cache.read_multi return hash that has keys only hitted.
45
+ # eg. Rails.cache.read_multi(1,2,3) => {2 => hit_value, 3 => hit_value}
46
+ hitted_ids = record_marshals.map { |record| record.read_attribute(association_key_name).to_s }
47
+ missed_ids = ids.map(&:to_s) - hitted_ids
48
+ ActiveSupport::Notifications.instrument("preload.second_level_cache", key: association_key_name, hit: hitted_ids, miss: missed_ids)
49
+ return SecondLevelCache::RecordRelation.new(record_marshals) if missed_ids.empty?
50
+
51
+ records_from_db = super(missed_ids.to_set, &block)
52
+ records_from_db.map { |r| r.write_second_level_cache }
53
+
54
+ SecondLevelCache::RecordRelation.new(records_from_db + record_marshals)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SecondLevelCache
4
+ module ActiveRecord
5
+ module Associations
6
+ module Preloader
7
+ module Association
8
+ # For < Rails 7
9
+ module Legacy
10
+ RAILS6 = ::ActiveRecord.version >= ::Gem::Version.new("6")
11
+
12
+ def records_for(ids, &block)
13
+ return super unless klass.second_level_cache_enabled?
14
+ return super unless reflection.is_a?(::ActiveRecord::Reflection::BelongsToReflection)
15
+ return super if klass.default_scopes.present? || reflection.scope
16
+ return super if association_key_name.to_s != klass.primary_key
17
+
18
+ map_cache_keys = ids.map { |id| klass.second_level_cache_key(id) }
19
+ records_from_cache = ::SecondLevelCache.cache_store.read_multi(*map_cache_keys)
20
+
21
+ record_marshals = if RAILS6
22
+ RecordMarshal.load_multi(records_from_cache.values) do |record|
23
+ # This block is copy from:
24
+ # https://github.com/rails/rails/blob/6-0-stable/activerecord/lib/active_record/associations/preloader/association.rb#L101
25
+ owner = owners_by_key[convert_key(record[association_key_name])].first
26
+ association = owner.association(reflection.name)
27
+ association.set_inverse_instance(record)
28
+ end
29
+ else
30
+ RecordMarshal.load_multi(records_from_cache.values, &block)
31
+ end
32
+
33
+ # NOTICE
34
+ # Rails.cache.read_multi return hash that has keys only hitted.
35
+ # eg. Rails.cache.read_multi(1,2,3) => {2 => hit_value, 3 => hit_value}
36
+ hitted_ids = record_marshals.map { |record| record.read_attribute(association_key_name).to_s }
37
+ missed_ids = ids.map(&:to_s) - hitted_ids
38
+ ActiveSupport::Notifications.instrument("preload.second_level_cache", key: association_key_name, hit: hitted_ids, miss: missed_ids)
39
+ return SecondLevelCache::RecordRelation.new(record_marshals) if missed_ids.empty?
40
+
41
+ records_from_db = super(missed_ids, &block)
42
+ records_from_db.map { |r| write_cache(r) }
43
+
44
+ SecondLevelCache::RecordRelation.new(records_from_db + record_marshals)
45
+ end
46
+
47
+ private
48
+
49
+ def write_cache(record)
50
+ record.write_second_level_cache
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -8,7 +8,8 @@ require "second_level_cache/active_record/finder_methods"
8
8
  require "second_level_cache/active_record/persistence"
9
9
  require "second_level_cache/active_record/belongs_to_association"
10
10
  require "second_level_cache/active_record/has_one_association"
11
- require "second_level_cache/active_record/preloader"
11
+ require "second_level_cache/active_record/preloader/association"
12
+ require "second_level_cache/active_record/preloader/legacy"
12
13
 
13
14
  # http://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html
14
15
  # ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
@@ -27,7 +28,15 @@ ActiveSupport.on_load(:active_record, run_once: true) do
27
28
  ActiveRecord::Associations::BelongsToAssociation.send(:prepend, SecondLevelCache::ActiveRecord::Associations::BelongsToAssociation)
28
29
  ActiveRecord::Associations::HasOneAssociation.send(:prepend, SecondLevelCache::ActiveRecord::Associations::HasOneAssociation)
29
30
  ActiveRecord::Relation.send(:prepend, SecondLevelCache::ActiveRecord::FinderMethods)
30
- # Rails 5.2 has removed ActiveRecord::Associations::Preloader::BelongsTo
31
- # https://github.com/rails/rails/pull/31079
32
- ActiveRecord::Associations::Preloader::Association.send(:prepend, SecondLevelCache::ActiveRecord::Associations::Preloader)
31
+
32
+ # https://github.com/rails/rails/blob/6-0-stable/activerecord/lib/active_record/associations/preloader/association.rb#L117
33
+ if ::ActiveRecord.version < ::Gem::Version.new("7")
34
+ ActiveRecord::Associations::Preloader::Association.send(:prepend, SecondLevelCache::ActiveRecord::Associations::Preloader::Association::Legacy)
35
+ end
36
+
37
+ if ::ActiveRecord.version >= ::Gem::Version.new("7")
38
+ # https://github.com/rails/rails/blob/7-0-stable/activerecord/lib/active_record/associations/preloader/association.rb#L25
39
+ ActiveRecord::Associations::Preloader::Association.send(:prepend, SecondLevelCache::ActiveRecord::Associations::Preloader::Association)
40
+ ActiveRecord::Associations::Preloader::Association::LoaderQuery.send(:prepend, SecondLevelCache::ActiveRecord::Associations::Preloader::Association::LoaderQuery)
41
+ end
33
42
  end
@@ -17,7 +17,8 @@ module SecondLevelCache
17
17
  return if respond_to?(:deleted?) && send(:deleted?)
18
18
  super
19
19
  end
20
- alias update_second_level_cache write_second_level_cache
20
+
21
+ alias_method :update_second_level_cache, :write_second_level_cache
21
22
  end
22
23
  end
23
24
  end
@@ -76,6 +76,7 @@ module SecondLevelCache
76
76
  expires_in = klass.second_level_cache_options[:expires_in]
77
77
  SecondLevelCache.cache_store.write(second_level_cache_key, marshal, expires_in: expires_in)
78
78
  end
79
- alias update_second_level_cache write_second_level_cache
79
+
80
+ alias_method :update_second_level_cache, :write_second_level_cache
80
81
  end
81
82
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SecondLevelCache
4
- VERSION = "2.6.4"
4
+ VERSION = "2.7.0"
5
5
  end
@@ -5,10 +5,10 @@ lib = File.expand_path("../lib", __FILE__)
5
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
6
 
7
7
  Gem::Specification.new do |gem|
8
- gem.authors = ["Hooopo"]
9
- gem.email = ["hoooopo@gmail.com"]
10
- gem.description = "Write Through and Read Through caching library inspired by CacheMoney and cache_fu, support ActiveRecord 4."
11
- gem.summary = <<-SUMMARY
8
+ gem.authors = ["Hooopo"]
9
+ gem.email = ["hoooopo@gmail.com"]
10
+ gem.description = "Write Through and Read Through caching library inspired by CacheMoney and cache_fu, support ActiveRecord 4."
11
+ gem.summary = <<-SUMMARY
12
12
  SecondLevelCache is a write-through and read-through caching library inspired by Cache Money and cache_fu, support only Rails3 and ActiveRecord.
13
13
 
14
14
  Read-Through: Queries by ID, like current_user.articles.find(params[:id]), will first look in cache store and then look in the database for the results of that query. If there is a cache miss, it will populate the cache.
@@ -16,23 +16,24 @@ Gem::Specification.new do |gem|
16
16
  Write-Through: As objects are created, updated, and deleted, all of the caches are automatically kept up-to-date and coherent.
17
17
  SUMMARY
18
18
 
19
- gem.homepage = "https://github.com/hooopo/second_level_cache"
19
+ gem.homepage = "https://github.com/hooopo/second_level_cache"
20
20
 
21
- gem.files = Dir.glob("lib/**/*.rb") + [
21
+ gem.files = Dir.glob("lib/**/*.rb") + [
22
22
  "README.md",
23
+ "LICENSE",
23
24
  "Rakefile",
24
25
  "Gemfile",
25
26
  "CHANGELOG.md",
26
27
  "second_level_cache.gemspec"
27
28
  ]
28
- gem.test_files = Dir.glob("test/**/*.rb")
29
- gem.executables = gem.files.grep(%r{^bin/})
30
- gem.name = "second_level_cache"
29
+ gem.test_files = Dir.glob("test/**/*.rb")
30
+ gem.executables = gem.files.grep(%r{^bin/})
31
+ gem.name = "second_level_cache"
31
32
  gem.require_paths = ["lib"]
32
- gem.version = SecondLevelCache::VERSION
33
+ gem.version = SecondLevelCache::VERSION
33
34
 
34
- gem.add_runtime_dependency "activerecord", [">= 5.2", "< 7"]
35
- gem.add_runtime_dependency "activesupport", [">= 5.2", "< 7"]
35
+ gem.add_runtime_dependency "activerecord", ">= 6.0"
36
+ gem.add_runtime_dependency "activesupport", ">= 6.0"
36
37
 
37
38
  gem.add_development_dependency "database_cleaner"
38
39
  gem.add_development_dependency "rake"
@@ -11,7 +11,7 @@ class BelongsToAssociationTest < ActiveSupport::TestCase
11
11
  book = @user.books.create
12
12
 
13
13
  @user.write_second_level_cache
14
- book.send(:clear_association_cache)
14
+
15
15
  assert_no_queries do
16
16
  assert_equal @user, book.user
17
17
  end
data/test/test_helper.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "bundler/setup"
4
4
  require "minitest/autorun"
5
- require "active_support/test_case"
5
+ require "active_support/all"
6
6
  require "active_record_test_case_helper"
7
7
  require "database_cleaner"
8
8
  require "active_record"
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.6.4
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hooopo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-10 00:00:00.000000000 Z
11
+ date: 2021-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,40 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.2'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '7'
19
+ version: '6.0'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - ">="
28
25
  - !ruby/object:Gem::Version
29
- version: '5.2'
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '7'
26
+ version: '6.0'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: activesupport
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
31
  - - ">="
38
32
  - !ruby/object:Gem::Version
39
- version: '5.2'
40
- - - "<"
41
- - !ruby/object:Gem::Version
42
- version: '7'
33
+ version: '6.0'
43
34
  type: :runtime
44
35
  prerelease: false
45
36
  version_requirements: !ruby/object:Gem::Requirement
46
37
  requirements:
47
38
  - - ">="
48
39
  - !ruby/object:Gem::Version
49
- version: '5.2'
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: '7'
40
+ version: '6.0'
53
41
  - !ruby/object:Gem::Dependency
54
42
  name: database_cleaner
55
43
  requirement: !ruby/object:Gem::Requirement
@@ -116,6 +104,7 @@ extra_rdoc_files: []
116
104
  files:
117
105
  - CHANGELOG.md
118
106
  - Gemfile
107
+ - LICENSE
119
108
  - README.md
120
109
  - Rakefile
121
110
  - lib/second_level_cache.rb
@@ -127,7 +116,8 @@ files:
127
116
  - lib/second_level_cache/active_record/finder_methods.rb
128
117
  - lib/second_level_cache/active_record/has_one_association.rb
129
118
  - lib/second_level_cache/active_record/persistence.rb
130
- - lib/second_level_cache/active_record/preloader.rb
119
+ - lib/second_level_cache/active_record/preloader/association.rb
120
+ - lib/second_level_cache/active_record/preloader/legacy.rb
131
121
  - lib/second_level_cache/adapter/paranoia.rb
132
122
  - lib/second_level_cache/config.rb
133
123
  - lib/second_level_cache/log_subscriber.rb
@@ -185,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
175
  - !ruby/object:Gem::Version
186
176
  version: '0'
187
177
  requirements: []
188
- rubygems_version: 3.1.2
178
+ rubygems_version: 3.2.3
189
179
  signing_key:
190
180
  specification_version: 4
191
181
  summary: 'SecondLevelCache is a write-through and read-through caching library inspired
@@ -195,34 +185,34 @@ summary: 'SecondLevelCache is a write-through and read-through caching library i
195
185
  is a cache miss, it will populate the cache. Write-Through: As objects are created,
196
186
  updated, and deleted, all of the caches are automatically kept up-to-date and coherent.'
197
187
  test_files:
198
- - test/preloader_belongs_to_test.rb
199
- - test/polymorphic_association_test.rb
200
- - test/require_test.rb
201
- - test/paranoid_test.rb
202
- - test/finder_methods_test.rb
203
- - test/preloader_has_one_test.rb
204
- - test/preloader_non_integer_test.rb
188
+ - test/active_record_test_case_helper.rb
189
+ - test/base_test.rb
205
190
  - test/belongs_to_association_test.rb
206
- - test/second_level_cache_test.rb
207
191
  - test/enum_attr_test.rb
208
- - test/record_marshal_test.rb
209
- - test/preloader_has_many_test.rb
210
- - test/persistence_test.rb
211
- - test/single_table_inheritance_test.rb
212
- - test/model/image.rb
192
+ - test/fetch_by_uniq_key_test.rb
193
+ - test/finder_methods_test.rb
194
+ - test/has_one_association_test.rb
213
195
  - test/model/account.rb
214
- - test/model/order_item.rb
215
- - test/model/contribution.rb
216
- - test/model/book.rb
217
- - test/model/topic.rb
218
196
  - test/model/animal.rb
197
+ - test/model/application_record.rb
198
+ - test/model/book.rb
199
+ - test/model/contribution.rb
200
+ - test/model/image.rb
219
201
  - test/model/order.rb
202
+ - test/model/order_item.rb
220
203
  - test/model/paranoid.rb
221
- - test/model/application_record.rb
222
204
  - test/model/post.rb
205
+ - test/model/topic.rb
223
206
  - test/model/user.rb
224
- - test/fetch_by_uniq_key_test.rb
207
+ - test/paranoid_test.rb
208
+ - test/persistence_test.rb
209
+ - test/polymorphic_association_test.rb
210
+ - test/preloader_belongs_to_test.rb
211
+ - test/preloader_has_many_test.rb
212
+ - test/preloader_has_one_test.rb
213
+ - test/preloader_non_integer_test.rb
214
+ - test/record_marshal_test.rb
215
+ - test/require_test.rb
216
+ - test/second_level_cache_test.rb
217
+ - test/single_table_inheritance_test.rb
225
218
  - test/test_helper.rb
226
- - test/has_one_association_test.rb
227
- - test/base_test.rb
228
- - test/active_record_test_case_helper.rb
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SecondLevelCache
4
- module ActiveRecord
5
- module Associations
6
- module Preloader
7
- RAILS6 = ::ActiveRecord.version >= ::Gem::Version.new("6")
8
-
9
- def records_for(ids, &block)
10
- return super unless klass.second_level_cache_enabled?
11
- return super unless reflection.is_a?(::ActiveRecord::Reflection::BelongsToReflection)
12
- return super if klass.default_scopes.present? || reflection.scope
13
- return super if association_key_name.to_s != klass.primary_key
14
-
15
- map_cache_keys = ids.map { |id| klass.second_level_cache_key(id) }
16
- records_from_cache = ::SecondLevelCache.cache_store.read_multi(*map_cache_keys)
17
-
18
- record_marshals = if RAILS6
19
- RecordMarshal.load_multi(records_from_cache.values) do |record|
20
- # This block is copy from:
21
- # https://github.com/rails/rails/blob/6-0-stable/activerecord/lib/active_record/associations/preloader/association.rb#L101
22
- owner = owners_by_key[convert_key(record[association_key_name])].first
23
- association = owner.association(reflection.name)
24
- association.set_inverse_instance(record)
25
- end
26
- else
27
- RecordMarshal.load_multi(records_from_cache.values, &block)
28
- end
29
-
30
- # NOTICE
31
- # Rails.cache.read_multi return hash that has keys only hitted.
32
- # eg. Rails.cache.read_multi(1,2,3) => {2 => hit_value, 3 => hit_value}
33
- hitted_ids = record_marshals.map { |record| record.read_attribute(association_key_name).to_s }
34
- missed_ids = ids.map(&:to_s) - hitted_ids
35
- ActiveSupport::Notifications.instrument("preload.second_level_cache", key: association_key_name, hit: hitted_ids, miss: missed_ids)
36
- return SecondLevelCache::RecordRelation.new(record_marshals) if missed_ids.empty?
37
-
38
- records_from_db = super(missed_ids, &block)
39
- records_from_db.map { |r| write_cache(r) }
40
-
41
- SecondLevelCache::RecordRelation.new(records_from_db + record_marshals)
42
- end
43
-
44
- private
45
- def write_cache(record)
46
- record.write_second_level_cache
47
- end
48
- end
49
- end
50
- end
51
- end