second_level_cache 2.6.4 → 2.7.0

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
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