second_level_cache 2.5.2 → 2.5.3

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: bb263a78785d298fbaccbcb46bb71250f021e66d69f0cf5c89f9d1cd97651c50
4
- data.tar.gz: f861c5fc32002720f2e83b30444ad3f2ac368427406a1c832ca4ba0f5620da89
3
+ metadata.gz: 57109a059ebed4c9d448fa28e474f19eef4ebf7b67e4ebbd728f2be852b61480
4
+ data.tar.gz: '049303d75a982adf35dfea344af63577dd9df1c09a28613bb4dec4332ef95de4'
5
5
  SHA512:
6
- metadata.gz: 9cacc9218aed1c33fd4470c8fa6a5bf21a7e89c22da09f522594e6ab5fb4830a168a7c930c0e3b4470086ac0193e1a906ca27f6543d0cba44fe1b2e9c6cc02f5
7
- data.tar.gz: df2b8f074ce143b141d8fb34d4f5799da505c1e72fdda03dbeaa7284cfd10d9074ca87b93481ba2cafe9df7d578ef40fb11e4afa2a172d351cfcdabc77e7efc4
6
+ metadata.gz: 553a34ea48e7b3100ae819282c354ee0eb51e2d609b7c090bf477035b975a0e497158ca6f4b282add76c882fa7e94277fb39486aaf4e45c35c9e98088a2bbb34
7
+ data.tar.gz: 28a7f7ea7f32467e92097824559fbaebaf3d9dd0fe49443d7779e666cce3270f3378c8e77dae91bffbc5248c8fadd10f00a08ebbbe390641fa9e42007b917ba5
@@ -1,3 +1,8 @@
1
+ 2.5.3
2
+ -------
3
+
4
+ - Fix `fetch_by_uniq_keys` method that cache incorrect when A record modified uniq key and B reocrd used old uniq key of A record (#96)
5
+
1
6
  2.5.2
2
7
  -------
3
8
 
@@ -6,19 +6,22 @@ module SecondLevelCache
6
6
  def fetch_by_uniq_keys(where_values)
7
7
  cache_key = cache_uniq_key(where_values)
8
8
  obj_id = SecondLevelCache.cache_store.read(cache_key)
9
+
9
10
  if obj_id
10
- begin
11
- return find(obj_id)
12
- rescue StandardError
13
- return nil
14
- end
11
+ record = begin
12
+ find(obj_id)
13
+ rescue StandardError
14
+ nil
15
+ end
15
16
  end
16
-
17
+ return record if compare_record_attributes_with_where_values(record, where_values)
17
18
  record = where(where_values).first
18
- return nil unless record
19
-
20
- record.tap do |r|
21
- SecondLevelCache.cache_store.write(cache_key, r.id)
19
+ if record
20
+ SecondLevelCache.cache_store.write(cache_key, record.id)
21
+ return record
22
+ else
23
+ SecondLevelCache.cache_store.delete(cache_key)
24
+ return nil
22
25
  end
23
26
  end
24
27
 
@@ -42,13 +45,30 @@ module SecondLevelCache
42
45
 
43
46
  def cache_uniq_key(where_values)
44
47
  keys = where_values.collect do |k, v|
45
- v = Digest::MD5.hexdigest(v) if v && v.size >= 32
48
+ v = Digest::MD5.hexdigest(v) if v.respond_to?(:size) && v.size >= 32
46
49
  [k, v].join("_")
47
50
  end
48
51
 
49
52
  ext_key = keys.join(",")
50
53
  "uniq_key_#{name}_#{ext_key}"
51
54
  end
55
+
56
+ def compare_record_attributes_with_where_values(record, where_values)
57
+ return false unless record
58
+ where_values.all? do |k, v|
59
+ attribute_value = record.read_attribute(k)
60
+ attribute_value == case attribute_value
61
+ when String
62
+ v.to_s
63
+ when Numeric
64
+ v.to_f
65
+ when Date
66
+ v.to_date
67
+ else # Maybe NilClass/?
68
+ v
69
+ end
70
+ end
71
+ end
52
72
  end
53
73
  end
54
74
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SecondLevelCache
4
- VERSION = "2.5.2"
4
+ VERSION = "2.5.3"
5
5
  end
@@ -76,6 +76,16 @@ module ActiveRecordTestCaseHelper
76
76
  model.column_names.include?(column_name.to_s)
77
77
  end
78
78
 
79
+ def savepoint
80
+ if ActiveRecord::Base.connection.supports_savepoints?
81
+ ActiveRecord::Base.connection.begin_transaction(joinable: false)
82
+ yield
83
+ ActiveRecord::Base.connection.rollback_transaction
84
+ else
85
+ yield
86
+ end
87
+ end
88
+
79
89
  class SQLCounter
80
90
  class << self
81
91
  attr_accessor :ignored_sql, :log, :log_all
@@ -14,6 +14,18 @@ class FetchByUinqKeyTest < ActiveSupport::TestCase
14
14
  assert_equal User.send(:cache_uniq_key, foo: 1, bar: nil), "uniq_key_User_foo_1,bar_"
15
15
  long_val = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
16
16
  assert_equal User.send(:cache_uniq_key, foo: 1, bar: long_val), "uniq_key_User_foo_1,bar_#{Digest::MD5.hexdigest(long_val)}"
17
+ assert Contribution.send(:cache_uniq_key, user_id: 1, date: Time.current.to_date), "uniq_key_Contribution_user_id_1,date_#{Time.current.to_date}"
18
+ end
19
+
20
+ def test_compare_record_attributes_with_where_values
21
+ book = Book.new(title: "foobar")
22
+ assert Book.send(:compare_record_attributes_with_where_values, book, title: :foobar)
23
+ book.discount_percentage = 60.00
24
+ assert Book.send(:compare_record_attributes_with_where_values, book, discount_percentage: "60")
25
+ book.publish_date = Time.current.to_date
26
+ assert Book.send(:compare_record_attributes_with_where_values, book, publish_date: Time.current.to_date.to_s)
27
+ book.title = nil
28
+ assert Book.send(:compare_record_attributes_with_where_values, book, title: nil)
17
29
  end
18
30
 
19
31
  def test_should_query_from_db_using_primary_key
@@ -51,4 +63,31 @@ class FetchByUinqKeyTest < ActiveSupport::TestCase
51
63
  user = User.fetch_by_uniq_key(@user.name, :name)
52
64
  assert_equal user, @user
53
65
  end
66
+
67
+ def test_should_return_correct_when_destroy_old_record_and_create_same_new_record
68
+ savepoint do
69
+ uniq_key = { email: "#{Time.now.to_i}@foobar.com" }
70
+ old_user = User.create(uniq_key)
71
+ new_user = old_user.deep_dup
72
+ assert_equal old_user, User.fetch_by_uniq_keys(uniq_key)
73
+ old_user.destroy
74
+
75
+ # Dirty id cache should be removed
76
+ assert_queries(2) { assert_nil User.fetch_by_uniq_keys(uniq_key) }
77
+ assert_queries(1) { assert_nil User.fetch_by_uniq_keys(uniq_key) }
78
+
79
+ new_user.save
80
+ assert_equal new_user, User.fetch_by_uniq_keys(uniq_key)
81
+ end
82
+ end
83
+
84
+ def test_should_return_correct_when_old_record_modify_uniq_key_and_new_record_use_same_uniq_key
85
+ savepoint do
86
+ uniq_key = { email: @user.email }
87
+ assert_equal @user, User.fetch_by_uniq_keys(uniq_key)
88
+ @user.update_attribute(:email, "#{Time.now.to_i}@foobar.com")
89
+ new_user = User.create(uniq_key)
90
+ assert_equal new_user, User.fetch_by_uniq_keys(uniq_key)
91
+ end
92
+ end
54
93
  end
@@ -4,7 +4,9 @@ ActiveRecord::Base.connection.create_table(:books, force: true) do |t|
4
4
  t.string :title
5
5
  t.string :body
6
6
  t.integer :user_id
7
+ t.decimal :discount_percentage, precision: 5, scale: 2
7
8
  t.integer :images_count, default: 0
9
+ t.date :publish_date
8
10
  end
9
11
 
10
12
  class Book < ActiveRecord::Base
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveRecord::Base.connection.create_table(:contributions, force: true) do |t|
4
+ t.integer :user_id
5
+ t.text :data
6
+ t.date :date
7
+ end
8
+
9
+ class Contribution < ActiveRecord::Base
10
+ second_level_cache
11
+
12
+ validates_uniqueness_of :user_id, scope: :date, if: -> { user_id_changed? || date_changed? }
13
+ belongs_to :user
14
+ end
@@ -25,6 +25,7 @@ require "model/order"
25
25
  require "model/order_item"
26
26
  require "model/account"
27
27
  require "model/animal"
28
+ require "model/contribution"
28
29
 
29
30
  DatabaseCleaner[:active_record].strategy = :truncation
30
31
 
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.5.2
4
+ version: 2.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hooopo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-02 00:00:00.000000000 Z
11
+ date: 2020-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -144,6 +144,7 @@ files:
144
144
  - test/model/account.rb
145
145
  - test/model/animal.rb
146
146
  - test/model/book.rb
147
+ - test/model/contribution.rb
147
148
  - test/model/image.rb
148
149
  - test/model/order.rb
149
150
  - test/model/order_item.rb
@@ -201,6 +202,7 @@ test_files:
201
202
  - test/model/image.rb
202
203
  - test/model/account.rb
203
204
  - test/model/order_item.rb
205
+ - test/model/contribution.rb
204
206
  - test/model/book.rb
205
207
  - test/model/topic.rb
206
208
  - test/model/animal.rb