second_level_cache 2.1.0.rc2 → 2.1.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 +7 -0
- data/Gemfile +2 -2
- data/README.md +1 -1
- data/lib/second_level_cache/active_record.rb +1 -1
- data/lib/second_level_cache/active_record/has_one_association.rb +5 -1
- data/lib/second_level_cache/active_record/persistence.rb +2 -1
- data/lib/second_level_cache/active_record/preloader.rb +5 -7
- data/lib/second_level_cache/version.rb +1 -1
- data/second_level_cache.gemspec +1 -1
- data/test/active_record_test_case_helper.rb +120 -0
- data/test/{active_record/base_test.rb → base_test.rb} +2 -2
- data/test/{active_record/belongs_to_association_test.rb → belongs_to_association_test.rb} +3 -3
- data/test/{active_record/fetch_by_uniq_key_test.rb → fetch_by_uniq_key_test.rb} +9 -9
- data/test/{active_record/finder_methods_test.rb → finder_methods_test.rb} +4 -4
- data/test/{active_record/has_one_association_test.rb → has_one_association_test.rb} +3 -3
- data/test/{active_record/model → model}/account.rb +0 -0
- data/test/{active_record/model → model}/book.rb +0 -0
- data/test/{active_record/model → model}/image.rb +0 -0
- data/test/{active_record/model → model}/post.rb +0 -0
- data/test/{active_record/model → model}/topic.rb +0 -0
- data/test/{active_record/model → model}/user.rb +0 -0
- data/test/{active_record/persistence_test.rb → persistence_test.rb} +7 -2
- data/test/{active_record/polymorphic_association_test.rb → polymorphic_association_test.rb} +3 -4
- data/test/preloader_test.rb +55 -0
- data/test/record_marshal_test.rb +2 -2
- data/test/require_test.rb +2 -2
- data/test/{active_record/second_level_cache_test.rb → second_level_cache_test.rb} +2 -2
- data/test/test_helper.rb +29 -4
- metadata +63 -75
- data/test/active_record/preloader_test.rb +0 -28
- data/test/active_record/test_helper.rb +0 -55
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 06b57d2d883c83e10d5b5b927b1666e92a84c6b1
|
4
|
+
data.tar.gz: 80c99a97b2b2753f98b886a6f4d50de61e6352ba
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: eec1e049ea36e70c0d9c707efdb1aeda373c327b6b2be1082076619373c5d6b9bc782797dedd2cec2d4c52e947363282d4f1d3f3a43d12de7f2e2b96aff418f3
|
7
|
+
data.tar.gz: 9dd02f79e8312da7af052282a89ddca1328209ffe5b6b68f2815fd394bd6cbd9820fc6c4d862d89009324e5ccf2c748bdbc362726cabeb304daa9c0000ccc0ac
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -14,4 +14,4 @@ ActiveRecord::Base.send(:extend, SecondLevelCache::ActiveRecord::FetchByUniqKey)
|
|
14
14
|
ActiveRecord::Base.send(:include, SecondLevelCache::ActiveRecord::Persistence)
|
15
15
|
ActiveRecord::Associations::BelongsToAssociation.send(:include, SecondLevelCache::ActiveRecord::Associations::BelongsToAssociation)
|
16
16
|
ActiveRecord::Associations::HasOneAssociation.send(:include, SecondLevelCache::ActiveRecord::Associations::HasOneAssociation)
|
17
|
-
ActiveRecord::Associations::Preloader::
|
17
|
+
ActiveRecord::Associations::Preloader::BelongsTo.send(:include, SecondLevelCache::ActiveRecord::Associations::Preloader::BelongsTo)
|
@@ -12,7 +12,11 @@ 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
|
-
|
15
|
+
if reflection.options[:as]
|
16
|
+
cache_record = klass.fetch_by_uniq_keys({reflection.foreign_key => owner[reflection.active_record_primary_key], reflection.type => owner.class.base_class.name})
|
17
|
+
else
|
18
|
+
cache_record = klass.fetch_by_uniq_key(owner[reflection.active_record_primary_key], reflection.foreign_key)
|
19
|
+
end
|
16
20
|
return cache_record.tap{|record| set_inverse_instance(record)} if cache_record
|
17
21
|
|
18
22
|
record = find_target_without_second_level_cache
|
@@ -17,7 +17,8 @@ module SecondLevelCache
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def reload_with_second_level_cache(options = nil)
|
20
|
-
|
20
|
+
expire_second_level_cache
|
21
|
+
reload_without_second_level_cache(options)
|
21
22
|
end
|
22
23
|
|
23
24
|
def touch_with_second_level_cache(name = nil)
|
@@ -3,13 +3,11 @@ module SecondLevelCache
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Associations
|
5
5
|
class Preloader
|
6
|
-
module
|
6
|
+
module BelongsTo
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
included do
|
10
|
-
|
11
|
-
alias_method_chain :records_for, :second_level_cache
|
12
|
-
end
|
10
|
+
alias_method_chain :records_for, :second_level_cache
|
13
11
|
end
|
14
12
|
|
15
13
|
def records_for_with_second_level_cache(ids)
|
@@ -17,9 +15,9 @@ module SecondLevelCache
|
|
17
15
|
|
18
16
|
map_cache_keys = ids.map{|id| klass.second_level_cache_key(id)}
|
19
17
|
records_from_cache = ::SecondLevelCache.cache_store.read_multi(*map_cache_keys)
|
20
|
-
# NOTICE
|
18
|
+
# NOTICE
|
21
19
|
# Rails.cache.read_multi return hash that has keys only hitted.
|
22
|
-
# eg. Rails.cache.read_multi(1,2,3) => {2 => hit_value, 3 => hit_value}
|
20
|
+
# eg. Rails.cache.read_multi(1,2,3) => {2 => hit_value, 3 => hit_value}
|
23
21
|
hitted_ids = records_from_cache.map{|key, _| key.split("/")[2].to_i}
|
24
22
|
missed_ids = ids.map{|x| x.to_i} - hitted_ids
|
25
23
|
|
@@ -40,6 +38,6 @@ module SecondLevelCache
|
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
43
|
-
end
|
41
|
+
end
|
44
42
|
end
|
45
43
|
end
|
data/second_level_cache.gemspec
CHANGED
@@ -35,5 +35,5 @@ Gem::Specification.new do |gem|
|
|
35
35
|
gem.add_runtime_dependency "activerecord", ["> 4.0.0", "< 5.0"]
|
36
36
|
gem.add_development_dependency "sqlite3"
|
37
37
|
gem.add_development_dependency "rake"
|
38
|
-
gem.add_development_dependency "database_cleaner", "~> 1.
|
38
|
+
gem.add_development_dependency "database_cleaner", "~> 1.3.0"
|
39
39
|
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'active_support/test_case'
|
2
|
+
|
3
|
+
module ActiveRecordTestCaseHelper
|
4
|
+
def teardown
|
5
|
+
SQLCounter.clear_log
|
6
|
+
end
|
7
|
+
|
8
|
+
def assert_date_from_db(expected, actual, message = nil)
|
9
|
+
assert_equal expected.to_s, actual.to_s, message
|
10
|
+
end
|
11
|
+
|
12
|
+
def capture(stream)
|
13
|
+
stream = stream.to_s
|
14
|
+
captured_stream = Tempfile.new(stream)
|
15
|
+
stream_io = eval("$#{stream}")
|
16
|
+
origin_stream = stream_io.dup
|
17
|
+
stream_io.reopen(captured_stream)
|
18
|
+
|
19
|
+
yield
|
20
|
+
|
21
|
+
stream_io.rewind
|
22
|
+
return captured_stream.read
|
23
|
+
ensure
|
24
|
+
captured_stream.close
|
25
|
+
captured_stream.unlink
|
26
|
+
stream_io.reopen(origin_stream)
|
27
|
+
end
|
28
|
+
|
29
|
+
def capture_sql
|
30
|
+
SQLCounter.clear_log
|
31
|
+
yield
|
32
|
+
SQLCounter.log_all.dup
|
33
|
+
end
|
34
|
+
|
35
|
+
def assert_sql(*patterns_to_match)
|
36
|
+
capture_sql { yield }
|
37
|
+
ensure
|
38
|
+
failed_patterns = []
|
39
|
+
patterns_to_match.each do |pattern|
|
40
|
+
failed_patterns << pattern unless SQLCounter.log_all.any?{ |sql| pattern === sql }
|
41
|
+
end
|
42
|
+
assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{SQLCounter.log.join("\n")}"}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def assert_queries(num = 1, options = {})
|
46
|
+
ignore_none = options.fetch(:ignore_none) { num == :any }
|
47
|
+
SQLCounter.clear_log
|
48
|
+
x = yield
|
49
|
+
the_log = ignore_none ? SQLCounter.log_all : SQLCounter.log
|
50
|
+
if num == :any
|
51
|
+
assert_operator the_log.size, :>=, 1, "1 or more queries expected, but none were executed."
|
52
|
+
else
|
53
|
+
mesg = "#{the_log.size} instead of #{num} queries were executed.#{the_log.size == 0 ? '' : "\nQueries:\n#{the_log.join("\n")}"}"
|
54
|
+
assert_equal num, the_log.size, mesg
|
55
|
+
end
|
56
|
+
x
|
57
|
+
end
|
58
|
+
|
59
|
+
def assert_no_queries(options = {}, &block)
|
60
|
+
options.reverse_merge! ignore_none: true
|
61
|
+
assert_queries(0, options, &block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def assert_column(model, column_name, msg=nil)
|
65
|
+
assert has_column?(model, column_name), msg
|
66
|
+
end
|
67
|
+
|
68
|
+
def assert_no_column(model, column_name, msg=nil)
|
69
|
+
assert_not has_column?(model, column_name), msg
|
70
|
+
end
|
71
|
+
|
72
|
+
def has_column?(model, column_name)
|
73
|
+
model.reset_column_information
|
74
|
+
model.column_names.include?(column_name.to_s)
|
75
|
+
end
|
76
|
+
|
77
|
+
class SQLCounter
|
78
|
+
class << self
|
79
|
+
attr_accessor :ignored_sql, :log, :log_all
|
80
|
+
def clear_log; self.log = []; self.log_all = []; end
|
81
|
+
end
|
82
|
+
|
83
|
+
self.clear_log
|
84
|
+
|
85
|
+
self.ignored_sql = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/, /^COMMIT/]
|
86
|
+
|
87
|
+
# FIXME: this needs to be refactored so specific database can add their own
|
88
|
+
# ignored SQL, or better yet, use a different notification for the queries
|
89
|
+
# instead examining the SQL content.
|
90
|
+
oracle_ignored = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im, /^\s*select .* from all_constraints/im, /^\s*select .* from all_tab_cols/im]
|
91
|
+
mysql_ignored = [/^SHOW TABLES/i, /^SHOW FULL FIELDS/, /^SHOW CREATE TABLE /i, /^SHOW VARIABLES /]
|
92
|
+
postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select tablename\b.*from pg_tables\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im, /^SHOW search_path/i]
|
93
|
+
sqlite3_ignored = [/^\s*SELECT name\b.*\bFROM sqlite_master/im]
|
94
|
+
|
95
|
+
[oracle_ignored, mysql_ignored, postgresql_ignored, sqlite3_ignored].each do |db_ignored_sql|
|
96
|
+
ignored_sql.concat db_ignored_sql
|
97
|
+
end
|
98
|
+
|
99
|
+
attr_reader :ignore
|
100
|
+
|
101
|
+
def initialize(ignore = Regexp.union(self.class.ignored_sql))
|
102
|
+
@ignore = ignore
|
103
|
+
end
|
104
|
+
|
105
|
+
def call(name, start, finish, message_id, values)
|
106
|
+
sql = values[:sql]
|
107
|
+
|
108
|
+
# FIXME: this seems bad. we should probably have a better way to indicate
|
109
|
+
# the query was cached
|
110
|
+
return if 'CACHE' == values[:name]
|
111
|
+
|
112
|
+
self.class.log_all << sql
|
113
|
+
self.class.log << sql unless ignore =~ sql
|
114
|
+
end
|
115
|
+
|
116
|
+
ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
ActiveSupport::TestCase.send(:include, ActiveRecordTestCaseHelper)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class BaseTest < ActiveSupport::TestCase
|
5
5
|
def setup
|
6
6
|
@user = User.create :name => 'csdn', :email => 'test@csdn.com'
|
7
7
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class BelongsToAssociationTest < ActiveSupport::TestCase
|
5
5
|
def setup
|
6
6
|
@user = User.create :name => 'csdn', :email => 'test@csdn.com'
|
7
7
|
end
|
@@ -11,7 +11,7 @@ class ActiveRecord::BelongsToAssociationTest < Minitest::Test
|
|
11
11
|
|
12
12
|
@user.write_second_level_cache
|
13
13
|
book.clear_association_cache
|
14
|
-
|
14
|
+
assert_no_queries do
|
15
15
|
assert_equal @user, book.user
|
16
16
|
end
|
17
17
|
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class FetchByUinqKeyTest < ActiveSupport::TestCase
|
5
5
|
def setup
|
6
|
-
DatabaseCleaner[:active_record].start
|
7
6
|
@user = User.create :name => 'hooopo', :email => 'hoooopo@gmail.com'
|
8
7
|
@post = Post.create :slug => "foobar", :topic_id => 2
|
9
8
|
end
|
@@ -17,15 +16,16 @@ class ActiveRecord::FetchByUinqKeyTest < Minitest::Test
|
|
17
16
|
|
18
17
|
def test_should_query_from_db_using_primary_key
|
19
18
|
Post.fetch_by_uniq_keys(:topic_id => 2, :slug => "foobar")
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
@post.expire_second_level_cache
|
20
|
+
assert_sql 'SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1' do
|
21
|
+
Post.fetch_by_uniq_keys(:topic_id => 2, :slug => "foobar")
|
22
|
+
end
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_should_not_hit_db_using_fetch_by_uniq_key_twice
|
26
26
|
post = Post.fetch_by_uniq_keys(:topic_id => 2, :slug => "foobar")
|
27
27
|
assert_equal post, @post
|
28
|
-
|
28
|
+
assert_no_queries do
|
29
29
|
Post.fetch_by_uniq_keys(:topic_id => 2, :slug => "foobar")
|
30
30
|
end
|
31
31
|
end
|
@@ -34,12 +34,12 @@ class ActiveRecord::FetchByUinqKeyTest < Minitest::Test
|
|
34
34
|
assert_raises(ActiveRecord::RecordNotFound) do
|
35
35
|
Post.fetch_by_uniq_keys!(:topic_id => 2, :slug => "foobar1")
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
assert_raises(ActiveRecord::RecordNotFound) do
|
39
39
|
User.fetch_by_uniq_key!("xxxxx", :name)
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def test_should_work_with_fetch_by_uniq_key
|
44
44
|
user = User.fetch_by_uniq_key(@user.name, :name)
|
45
45
|
assert_equal user, @user
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class FinderMethodsTest < ActiveSupport::TestCase
|
5
5
|
def setup
|
6
6
|
@user = User.create :name => 'csdn', :email => 'test@csdn.com'
|
7
7
|
end
|
@@ -13,14 +13,14 @@ class ActiveRecord::FinderMethodsTest < Minitest::Test
|
|
13
13
|
|
14
14
|
def test_should_find_with_cache
|
15
15
|
@user.write_second_level_cache
|
16
|
-
|
16
|
+
assert_no_queries do
|
17
17
|
assert_equal @user, User.find(@user.id)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_should_find_with_condition
|
22
22
|
@user.write_second_level_cache
|
23
|
-
|
23
|
+
assert_no_queries do
|
24
24
|
assert_equal @user, User.where(:name => @user.name).find(@user.id)
|
25
25
|
end
|
26
26
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class HasOneAssociationTest < ActiveSupport::TestCase
|
5
5
|
def setup
|
6
6
|
@user = User.create :name => 'hooopo', :email => 'hoooopo@gmail.com'
|
7
7
|
@account = @user.create_account
|
@@ -9,7 +9,7 @@ class ActiveRecord::HasOneAssociationTest < Minitest::Test
|
|
9
9
|
|
10
10
|
def test_should_fetch_account_from_cache
|
11
11
|
clean_user = @user.reload
|
12
|
-
|
12
|
+
assert_no_queries do
|
13
13
|
clean_user.account
|
14
14
|
end
|
15
15
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,13 +1,18 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class PersistenceTest < ActiveSupport::TestCase
|
5
5
|
def setup
|
6
6
|
@user = User.create :name => 'csdn', :email => 'test@csdn.com'
|
7
7
|
@topic = Topic.create :title => "csdn"
|
8
8
|
end
|
9
9
|
|
10
10
|
def test_should_reload_object
|
11
|
+
User.where(id: @user.id).update_all(email: 'different@csdn.com')
|
12
|
+
assert_equal 'different@csdn.com', @user.reload.email
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_should_reload_object_associations
|
11
16
|
User.increment_counter :books_count, @user.id
|
12
17
|
assert_equal 0, @user.books_count
|
13
18
|
assert_equal 1, @user.reload.books_count
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class PolymorphicAssociationTest < ActiveSupport::TestCase
|
5
5
|
def setup
|
6
6
|
@user = User.create :name => 'csdn', :email => 'test@csdn.com'
|
7
7
|
end
|
@@ -10,7 +10,7 @@ class ActiveRecord::PolymorphicAssociationTest < Minitest::Test
|
|
10
10
|
image = @user.images.create
|
11
11
|
|
12
12
|
@user.write_second_level_cache
|
13
|
-
|
13
|
+
assert_no_queries do
|
14
14
|
assert_equal @user, image.imagable
|
15
15
|
end
|
16
16
|
end
|
@@ -21,4 +21,3 @@ class ActiveRecord::PolymorphicAssociationTest < Minitest::Test
|
|
21
21
|
assert_equal @user, image.imagable
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class PreloaderTest < ActiveSupport::TestCase
|
5
|
+
def test_belongs_to_preload_caches_includes
|
6
|
+
topics = [
|
7
|
+
Topic.create(title: 'title1', body: 'body1'),
|
8
|
+
Topic.create(title: 'title2', body: 'body2'),
|
9
|
+
Topic.create(title: 'title3', body: 'body3')
|
10
|
+
]
|
11
|
+
topics.each { |topic| topic.posts.create(body: "post#{topic.id}") }
|
12
|
+
|
13
|
+
results = nil
|
14
|
+
assert_queries(1) do
|
15
|
+
results = Post.includes(:topic).order('id ASC').to_a
|
16
|
+
end
|
17
|
+
assert_equal topics, results.map(&:topic)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_belongs_to_when_read_multi_missed_from_cache_AR_will_fetch_missed_records_from_db
|
21
|
+
topics = [
|
22
|
+
Topic.create(title: 'title1', body: 'body1'),
|
23
|
+
Topic.create(title: 'title2', body: 'body2'),
|
24
|
+
Topic.create(title: 'title3', body: 'body3')
|
25
|
+
]
|
26
|
+
topics.each { |topic| topic.posts.create(body: "post#{topic.id}") }
|
27
|
+
expired_topic = topics.first
|
28
|
+
expired_topic.expire_second_level_cache
|
29
|
+
|
30
|
+
results = nil
|
31
|
+
assert_queries(2) do
|
32
|
+
assert_sql(/IN\s+\(#{expired_topic.id}\)/m) do
|
33
|
+
results = Post.includes(:topic).order('id ASC').to_a
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
assert_equal topics, results.map(&:topic)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_has_many_preloader_returns_correct_results
|
41
|
+
topic = Topic.create(id: 1)
|
42
|
+
Post.create(id: 1)
|
43
|
+
post = topic.posts.create
|
44
|
+
|
45
|
+
assert_equal [post], Topic.includes(:posts).find(1).posts
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_has_one_preloader_returns_correct_results
|
49
|
+
user = User.create(id: 1)
|
50
|
+
Account.create(id: 1)
|
51
|
+
account = user.create_account
|
52
|
+
|
53
|
+
assert_equal account, User.includes(:account).find(1).account
|
54
|
+
end
|
55
|
+
end
|
data/test/record_marshal_test.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
class RecordMarshalTest <
|
4
|
+
class RecordMarshalTest < ActiveSupport::TestCase
|
5
5
|
def setup
|
6
6
|
@user = User.create :name => 'csdn', :email => 'test@csdn.com'
|
7
7
|
end
|
data/test/require_test.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
require 'test_helper'
|
3
3
|
require 'active_record'
|
4
4
|
|
5
|
-
class RequireTest <
|
5
|
+
class RequireTest < ActiveSupport::TestCase
|
6
6
|
def setup
|
7
7
|
ActiveRecord::Relation
|
8
|
-
require '
|
8
|
+
require 'test_helper'
|
9
9
|
@user = User.create :name => 'Dingding Ye', :email => 'yedingding@gmail.com'
|
10
10
|
end
|
11
11
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'test_helper'
|
3
3
|
|
4
|
-
class
|
4
|
+
class SecondLevelCacheTest < ActiveSupport::TestCase
|
5
5
|
def setup
|
6
6
|
@user = User.create :name => 'csdn', :email => 'test@csdn.com'
|
7
7
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,14 +1,39 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require 'rubygems'
|
3
2
|
require 'bundler/setup'
|
4
|
-
require 'second_level_cache'
|
5
3
|
require 'minitest/autorun'
|
4
|
+
require 'active_support/test_case'
|
5
|
+
require 'active_record_test_case_helper'
|
6
6
|
require 'database_cleaner'
|
7
7
|
|
8
|
-
|
8
|
+
require 'active_record'
|
9
|
+
require 'second_level_cache'
|
10
|
+
|
11
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
12
|
+
|
13
|
+
require 'model/user'
|
14
|
+
require 'model/book'
|
15
|
+
require 'model/image'
|
16
|
+
require 'model/topic'
|
17
|
+
require 'model/post'
|
18
|
+
require 'model/account'
|
19
|
+
|
20
|
+
DatabaseCleaner[:active_record].strategy = :truncation
|
9
21
|
|
10
22
|
SecondLevelCache.configure do |config|
|
11
23
|
config.cache_store = ActiveSupport::Cache::MemoryStore.new
|
12
24
|
end
|
13
25
|
|
14
|
-
SecondLevelCache.logger.level = Logger::
|
26
|
+
SecondLevelCache.logger.level = Logger::ERROR
|
27
|
+
ActiveSupport::Cache::MemoryStore.logger = SecondLevelCache::Config.logger
|
28
|
+
ActiveRecord::Base.logger = SecondLevelCache::Config.logger
|
29
|
+
|
30
|
+
class ActiveSupport::TestCase
|
31
|
+
setup do
|
32
|
+
SecondLevelCache.cache_store.clear
|
33
|
+
DatabaseCleaner.start
|
34
|
+
end
|
35
|
+
|
36
|
+
teardown do
|
37
|
+
DatabaseCleaner.clean
|
38
|
+
end
|
39
|
+
end
|
metadata
CHANGED
@@ -1,108 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: second_level_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.0
|
5
|
-
prerelease: 6
|
4
|
+
version: 2.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Hooopo
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2014-
|
11
|
+
date: 2014-09-23 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activesupport
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 4.0.0
|
22
|
-
- - <
|
20
|
+
- - "<"
|
23
21
|
- !ruby/object:Gem::Version
|
24
22
|
version: '5.0'
|
25
23
|
type: :runtime
|
26
24
|
prerelease: false
|
27
25
|
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
26
|
requirements:
|
30
|
-
- -
|
27
|
+
- - ">"
|
31
28
|
- !ruby/object:Gem::Version
|
32
29
|
version: 4.0.0
|
33
|
-
- - <
|
30
|
+
- - "<"
|
34
31
|
- !ruby/object:Gem::Version
|
35
32
|
version: '5.0'
|
36
33
|
- !ruby/object:Gem::Dependency
|
37
34
|
name: activerecord
|
38
35
|
requirement: !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
36
|
requirements:
|
41
|
-
- -
|
37
|
+
- - ">"
|
42
38
|
- !ruby/object:Gem::Version
|
43
39
|
version: 4.0.0
|
44
|
-
- - <
|
40
|
+
- - "<"
|
45
41
|
- !ruby/object:Gem::Version
|
46
42
|
version: '5.0'
|
47
43
|
type: :runtime
|
48
44
|
prerelease: false
|
49
45
|
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
46
|
requirements:
|
52
|
-
- -
|
47
|
+
- - ">"
|
53
48
|
- !ruby/object:Gem::Version
|
54
49
|
version: 4.0.0
|
55
|
-
- - <
|
50
|
+
- - "<"
|
56
51
|
- !ruby/object:Gem::Version
|
57
52
|
version: '5.0'
|
58
53
|
- !ruby/object:Gem::Dependency
|
59
54
|
name: sqlite3
|
60
55
|
requirement: !ruby/object:Gem::Requirement
|
61
|
-
none: false
|
62
56
|
requirements:
|
63
|
-
- -
|
57
|
+
- - ">="
|
64
58
|
- !ruby/object:Gem::Version
|
65
59
|
version: '0'
|
66
60
|
type: :development
|
67
61
|
prerelease: false
|
68
62
|
version_requirements: !ruby/object:Gem::Requirement
|
69
|
-
none: false
|
70
63
|
requirements:
|
71
|
-
- -
|
64
|
+
- - ">="
|
72
65
|
- !ruby/object:Gem::Version
|
73
66
|
version: '0'
|
74
67
|
- !ruby/object:Gem::Dependency
|
75
68
|
name: rake
|
76
69
|
requirement: !ruby/object:Gem::Requirement
|
77
|
-
none: false
|
78
70
|
requirements:
|
79
|
-
- -
|
71
|
+
- - ">="
|
80
72
|
- !ruby/object:Gem::Version
|
81
73
|
version: '0'
|
82
74
|
type: :development
|
83
75
|
prerelease: false
|
84
76
|
version_requirements: !ruby/object:Gem::Requirement
|
85
|
-
none: false
|
86
77
|
requirements:
|
87
|
-
- -
|
78
|
+
- - ">="
|
88
79
|
- !ruby/object:Gem::Version
|
89
80
|
version: '0'
|
90
81
|
- !ruby/object:Gem::Dependency
|
91
82
|
name: database_cleaner
|
92
83
|
requirement: !ruby/object:Gem::Requirement
|
93
|
-
none: false
|
94
84
|
requirements:
|
95
|
-
- - ~>
|
85
|
+
- - "~>"
|
96
86
|
- !ruby/object:Gem::Version
|
97
|
-
version: 1.
|
87
|
+
version: 1.3.0
|
98
88
|
type: :development
|
99
89
|
prerelease: false
|
100
90
|
version_requirements: !ruby/object:Gem::Requirement
|
101
|
-
none: false
|
102
91
|
requirements:
|
103
|
-
- - ~>
|
92
|
+
- - "~>"
|
104
93
|
- !ruby/object:Gem::Version
|
105
|
-
version: 1.
|
94
|
+
version: 1.3.0
|
106
95
|
description: Write Through and Read Through caching library inspired by CacheMoney
|
107
96
|
and cache_fu, support ActiveRecord 4.
|
108
97
|
email:
|
@@ -111,6 +100,12 @@ executables: []
|
|
111
100
|
extensions: []
|
112
101
|
extra_rdoc_files: []
|
113
102
|
files:
|
103
|
+
- CHANGELOG.md
|
104
|
+
- Gemfile
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- lib/second_level_cache.rb
|
108
|
+
- lib/second_level_cache/active_record.rb
|
114
109
|
- lib/second_level_cache/active_record/base.rb
|
115
110
|
- lib/second_level_cache/active_record/belongs_to_association.rb
|
116
111
|
- lib/second_level_cache/active_record/fetch_by_uniq_key.rb
|
@@ -118,82 +113,75 @@ files:
|
|
118
113
|
- lib/second_level_cache/active_record/has_one_association.rb
|
119
114
|
- lib/second_level_cache/active_record/persistence.rb
|
120
115
|
- lib/second_level_cache/active_record/preloader.rb
|
121
|
-
- lib/second_level_cache/active_record.rb
|
122
116
|
- lib/second_level_cache/arel/wheres.rb
|
123
117
|
- lib/second_level_cache/config.rb
|
124
118
|
- lib/second_level_cache/record_marshal.rb
|
125
119
|
- lib/second_level_cache/version.rb
|
126
|
-
- lib/second_level_cache.rb
|
127
|
-
- README.md
|
128
|
-
- Rakefile
|
129
|
-
- Gemfile
|
130
|
-
- CHANGELOG.md
|
131
120
|
- second_level_cache.gemspec
|
132
|
-
- test/
|
133
|
-
- test/
|
134
|
-
- test/
|
135
|
-
- test/
|
136
|
-
- test/
|
137
|
-
- test/
|
138
|
-
- test/
|
139
|
-
- test/
|
140
|
-
- test/
|
141
|
-
- test/
|
142
|
-
- test/
|
143
|
-
- test/
|
144
|
-
- test/
|
145
|
-
- test/
|
146
|
-
- test/
|
147
|
-
- test/active_record/test_helper.rb
|
121
|
+
- test/active_record_test_case_helper.rb
|
122
|
+
- test/base_test.rb
|
123
|
+
- test/belongs_to_association_test.rb
|
124
|
+
- test/fetch_by_uniq_key_test.rb
|
125
|
+
- test/finder_methods_test.rb
|
126
|
+
- test/has_one_association_test.rb
|
127
|
+
- test/model/account.rb
|
128
|
+
- test/model/book.rb
|
129
|
+
- test/model/image.rb
|
130
|
+
- test/model/post.rb
|
131
|
+
- test/model/topic.rb
|
132
|
+
- test/model/user.rb
|
133
|
+
- test/persistence_test.rb
|
134
|
+
- test/polymorphic_association_test.rb
|
135
|
+
- test/preloader_test.rb
|
148
136
|
- test/record_marshal_test.rb
|
149
137
|
- test/require_test.rb
|
138
|
+
- test/second_level_cache_test.rb
|
150
139
|
- test/test_helper.rb
|
151
140
|
homepage: https://github.com/csdn-dev/second_level_cache
|
152
141
|
licenses: []
|
142
|
+
metadata: {}
|
153
143
|
post_install_message:
|
154
144
|
rdoc_options: []
|
155
145
|
require_paths:
|
156
146
|
- lib
|
157
147
|
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
-
none: false
|
159
148
|
requirements:
|
160
|
-
- -
|
149
|
+
- - ">="
|
161
150
|
- !ruby/object:Gem::Version
|
162
151
|
version: '0'
|
163
152
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
|
-
none: false
|
165
153
|
requirements:
|
166
|
-
- -
|
154
|
+
- - ">="
|
167
155
|
- !ruby/object:Gem::Version
|
168
|
-
version:
|
156
|
+
version: '0'
|
169
157
|
requirements: []
|
170
158
|
rubyforge_project:
|
171
|
-
rubygems_version:
|
159
|
+
rubygems_version: 2.2.2
|
172
160
|
signing_key:
|
173
|
-
specification_version:
|
174
|
-
summary:
|
161
|
+
specification_version: 4
|
162
|
+
summary: 'SecondLevelCache is a write-through and read-through caching library inspired
|
175
163
|
by Cache Money and cache_fu, support only Rails3 and ActiveRecord. Read-Through:
|
176
164
|
Queries by ID, like current_user.articles.find(params[:id]), will first look in
|
177
165
|
cache store and then look in the database for the results of that query. If there
|
178
166
|
is a cache miss, it will populate the cache. Write-Through: As objects are created,
|
179
167
|
updated, and deleted, all of the caches are automatically kept up-to-date and coherent.'
|
180
168
|
test_files:
|
181
|
-
- test/
|
182
|
-
- test/
|
183
|
-
- test/
|
184
|
-
- test/
|
185
|
-
- test/
|
186
|
-
- test/
|
187
|
-
- test/
|
188
|
-
- test/
|
189
|
-
- test/
|
190
|
-
- test/
|
191
|
-
- test/
|
192
|
-
- test/
|
193
|
-
- test/
|
194
|
-
- test/
|
195
|
-
- test/
|
196
|
-
- test/active_record/test_helper.rb
|
169
|
+
- test/active_record_test_case_helper.rb
|
170
|
+
- test/base_test.rb
|
171
|
+
- test/belongs_to_association_test.rb
|
172
|
+
- test/fetch_by_uniq_key_test.rb
|
173
|
+
- test/finder_methods_test.rb
|
174
|
+
- test/has_one_association_test.rb
|
175
|
+
- test/model/account.rb
|
176
|
+
- test/model/book.rb
|
177
|
+
- test/model/image.rb
|
178
|
+
- test/model/post.rb
|
179
|
+
- test/model/topic.rb
|
180
|
+
- test/model/user.rb
|
181
|
+
- test/persistence_test.rb
|
182
|
+
- test/polymorphic_association_test.rb
|
183
|
+
- test/preloader_test.rb
|
197
184
|
- test/record_marshal_test.rb
|
198
185
|
- test/require_test.rb
|
186
|
+
- test/second_level_cache_test.rb
|
199
187
|
- test/test_helper.rb
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# -*- encoding : utf-8 -*-
|
2
|
-
require 'active_record/test_helper'
|
3
|
-
|
4
|
-
class ActiveRecord::PreloaderTest < Minitest::Test
|
5
|
-
def setup
|
6
|
-
DatabaseCleaner[:active_record].start
|
7
|
-
@topic1 = Topic.create :title => "title1", :body => "body1"
|
8
|
-
@topic2 = Topic.create :title => "title2", :body => "body2"
|
9
|
-
@topic3 = Topic.create :title => "title3", :body => "body3"
|
10
|
-
@post1 = @topic1.posts.create :body => "post1"
|
11
|
-
@post2 = @topic2.posts.create :body => "post2"
|
12
|
-
@post3 = @topic3.posts.create :body => "post3"
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_preload_work_properly
|
16
|
-
results = Post.includes(:topic).order("id ASC").to_a
|
17
|
-
assert_equal results.size, 3
|
18
|
-
assert_equal results.first.topic, @topic1
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_when_read_multi_missed_from_cache_AR_will_fetch_missed_records_from_db
|
22
|
-
@topic1.expire_second_level_cache
|
23
|
-
results = Post.includes(:topic).order("id ASC").to_a
|
24
|
-
assert_equal results.size, 3
|
25
|
-
assert_equal results.first.topic, @topic1
|
26
|
-
assert_match /IN\s+\(#{@topic1.id}\)/m, $sql_logger
|
27
|
-
end
|
28
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# -*- encoding : utf-8 -*-
|
2
|
-
require 'test_helper'
|
3
|
-
require 'active_record'
|
4
|
-
require 'second_level_cache/active_record'
|
5
|
-
|
6
|
-
def open_test_db_connect
|
7
|
-
ActiveRecord::Base.establish_connection(
|
8
|
-
:adapter => 'sqlite3',
|
9
|
-
:database => 'test/test.sqlite3'
|
10
|
-
)
|
11
|
-
end
|
12
|
-
open_test_db_connect
|
13
|
-
|
14
|
-
def close_test_db_connect
|
15
|
-
ActiveRecord::Base.connection.disconnect!
|
16
|
-
end
|
17
|
-
|
18
|
-
class Minitest::Test
|
19
|
-
def no_connection
|
20
|
-
close_test_db_connect
|
21
|
-
assert_nothing_raised { yield }
|
22
|
-
ensure
|
23
|
-
open_test_db_connect
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
def assert_nothing_raised(*)
|
28
|
-
yield
|
29
|
-
end
|
30
|
-
|
31
|
-
def teardown
|
32
|
-
$sql_logger = nil
|
33
|
-
SecondLevelCache.cache_store.clear
|
34
|
-
DatabaseCleaner[:active_record].clean
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
module ActiveRecord
|
39
|
-
module Querying
|
40
|
-
def find_by_sql_with_test(sql, binds = [])
|
41
|
-
$sql_logger ||= ""
|
42
|
-
$sql_logger << sql.to_sql
|
43
|
-
$sql_logger << "\n"
|
44
|
-
find_by_sql_without_test(sql, binds)
|
45
|
-
end
|
46
|
-
alias_method_chain :find_by_sql, :test
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
require 'active_record/model/user'
|
51
|
-
require 'active_record/model/book'
|
52
|
-
require 'active_record/model/image'
|
53
|
-
require 'active_record/model/topic'
|
54
|
-
require 'active_record/model/post'
|
55
|
-
require 'active_record/model/account'
|