incrdecr_cached_counts 0.0.6 → 0.4.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 +5 -5
- data/.circleci/config.yml +47 -0
- data/README.rdoc +2 -0
- data/incrdecr_cached_counts.gemspec +1 -3
- data/lib/cached_counts.rb +17 -8
- data/lib/cached_counts/query_context.rb +21 -0
- data/lib/cached_counts/version.rb +1 -1
- data/spec/spec_helper.rb +0 -7
- metadata +8 -49
- data/.circleci-matrix.yml +0 -8
- data/.travis.yml +0 -15
- data/circle.yml +0 -10
- data/lib/cached_counts/connection_for.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b1abd3ec58583d46e713effab128bece6d90b4799261cb5714981e8e545a293b
|
4
|
+
data.tar.gz: 435c1c883ba00f766473e563732602245e5a1680f92bbc852251ce48497bab53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 870a0f140a0d815f1e2e824ae5c9cd802cfcab3be446f376ad2f08f80ff2eadd560d899a7f85cfd099d08a2ffbc517beeb5926575cae557e5a68c2d3d9bb79e8
|
7
|
+
data.tar.gz: 6f6058c68108b32c94e3d6c4be7d785974371f21b7fd828f4df9a5b33d108912537ed102685bb2601aac5e3267a32ea27d4a65508721c0ca5cb5566e44aac1f5
|
@@ -0,0 +1,47 @@
|
|
1
|
+
version: 2.1
|
2
|
+
|
3
|
+
jobs:
|
4
|
+
build:
|
5
|
+
docker:
|
6
|
+
- image: cimg/ruby:2.7-node # use a tailored CircleCI docker image.
|
7
|
+
steps:
|
8
|
+
- checkout
|
9
|
+
|
10
|
+
- run: bundle config set path 'vendor/bundle'
|
11
|
+
- run: sudo apt-get update
|
12
|
+
- run: sudo apt install libsqlite3-dev
|
13
|
+
|
14
|
+
# There's probably a better way of doing this that avoids the repetition and manual
|
15
|
+
# deletion of Gemfile.lock.
|
16
|
+
- restore_cache:
|
17
|
+
key: rails-5.2.4.4-{{ checksum "Gemfile" }}
|
18
|
+
- run:
|
19
|
+
name: bundle install
|
20
|
+
command: bundle install
|
21
|
+
environment:
|
22
|
+
ACTIVERECORD_VERSION: 5.2.4.4
|
23
|
+
- save_cache:
|
24
|
+
key: rails-5.2.4.4-{{ checksum "Gemfile" }}
|
25
|
+
paths:
|
26
|
+
- vendor/bundle
|
27
|
+
- run:
|
28
|
+
name: Test with Rails 5.2
|
29
|
+
command: bundle exec rspec
|
30
|
+
|
31
|
+
- run: rm Gemfile.lock
|
32
|
+
- restore_cache:
|
33
|
+
key: rails-6.0.3.4-{{ checksum "Gemfile" }}
|
34
|
+
- run:
|
35
|
+
name: bundle install
|
36
|
+
command: bundle install --path vendor/bundle
|
37
|
+
environment:
|
38
|
+
ACTIVERECORD_VERSION: 6.0.3.4
|
39
|
+
- save_cache:
|
40
|
+
key: rails-6.0.3.4-{{ checksum "Gemfile" }}
|
41
|
+
paths:
|
42
|
+
- vendor/bundle
|
43
|
+
- restore_cache:
|
44
|
+
key: rails-6.0.3.4-{{ checksum "Gemfile" }}
|
45
|
+
- run:
|
46
|
+
name: Test with Rails 6.0
|
47
|
+
command: bundle exec rspec
|
data/README.rdoc
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
= CachedCounts
|
2
2
|
|
3
|
+
{<img src="http://circleci.com/gh/academia-edu/cached_counts.svg?style=svg" />}[https://circleci.com/gh/academia-edu/cached_counts]
|
4
|
+
|
3
5
|
A replacement for Rails' counter caches, using memcached.
|
4
6
|
|
5
7
|
Caches counts of models in a scope or association in memcached, and keeps the
|
@@ -19,13 +19,11 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
s.add_dependency "rails", ">=
|
22
|
+
s.add_dependency "rails", ">= 5.2"
|
23
23
|
s.add_dependency "dalli"
|
24
24
|
|
25
25
|
s.add_development_dependency "sqlite3"
|
26
26
|
s.add_development_dependency "rspec"
|
27
27
|
s.add_development_dependency "database_cleaner"
|
28
|
-
s.add_development_dependency "test_after_commit"
|
29
|
-
s.add_development_dependency "after_commit_exception_notification"
|
30
28
|
s.add_development_dependency "rake"
|
31
29
|
end
|
data/lib/cached_counts.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'cached_counts/logger'
|
2
2
|
require 'cached_counts/dalli_check'
|
3
|
-
require 'cached_counts/
|
3
|
+
require 'cached_counts/query_context'
|
4
4
|
|
5
5
|
module CachedCounts
|
6
6
|
extend ActiveSupport::Concern
|
@@ -185,6 +185,18 @@ module CachedCounts
|
|
185
185
|
association_count_key(id, attribute_name, version)
|
186
186
|
end
|
187
187
|
|
188
|
+
# Try to fetch values for ids from the cache. If it's a miss return the default value
|
189
|
+
define_singleton_method "try_#{attr_name}_counts_for" do |ids, default=nil|
|
190
|
+
raw_result = Rails.cache.read_multi(*ids.map{|id| association_count_key(id, attribute_name, version)})
|
191
|
+
|
192
|
+
result = {}
|
193
|
+
ids.each do |id|
|
194
|
+
result[id] = raw_result[association_count_key(id, attribute_name, version)]&.to_i || default
|
195
|
+
end
|
196
|
+
|
197
|
+
result
|
198
|
+
end
|
199
|
+
|
188
200
|
define_singleton_method "#{attr_name}_count_for" do |id|
|
189
201
|
new({id: id}, without_protection: true).send("#{attr_name}_count")
|
190
202
|
end
|
@@ -255,11 +267,8 @@ module CachedCounts
|
|
255
267
|
relation = relation.reorder('')
|
256
268
|
relation.select_values = ['count(*)']
|
257
269
|
|
258
|
-
|
259
|
-
|
260
|
-
conn.select_value(relation.to_sql, nil, relation.values[:bind] || []).to_i
|
261
|
-
else
|
262
|
-
conn.select_value(relation.to_sql).to_i
|
270
|
+
CachedCounts.query_context.call(counted_class) do
|
271
|
+
counted_class.connection.select_value(relation.to_sql).to_i
|
263
272
|
end
|
264
273
|
end
|
265
274
|
|
@@ -285,7 +294,7 @@ module CachedCounts
|
|
285
294
|
end
|
286
295
|
|
287
296
|
def add_counting_hooks(attribute_name, key_getter, counted_class, options)
|
288
|
-
increment_hook = "increment_#{attribute_name}_count"
|
297
|
+
increment_hook = "increment_#{attribute_name}_count".to_sym
|
289
298
|
counted_class.send :define_method, increment_hook do
|
290
299
|
if (key = instance_exec &key_getter)
|
291
300
|
Rails.cache.increment(
|
@@ -296,7 +305,7 @@ module CachedCounts
|
|
296
305
|
end
|
297
306
|
end
|
298
307
|
|
299
|
-
decrement_hook = "decrement_#{attribute_name}_count"
|
308
|
+
decrement_hook = "decrement_#{attribute_name}_count".to_sym
|
300
309
|
counted_class.send :define_method, decrement_hook do
|
301
310
|
if (key = instance_exec &key_getter)
|
302
311
|
Rails.cache.decrement(
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CachedCounts
|
2
|
+
class << self
|
3
|
+
# Optional configuration: Set a proc which takes as arguments (1) the class
|
4
|
+
# we are counting and (2) the block that runs the count query. The
|
5
|
+
# `query_context` block must call the block that's passed as an argument.
|
6
|
+
#
|
7
|
+
# This is useful for replication, e.g.,
|
8
|
+
#
|
9
|
+
# CachedCounts.query_context = proc do |klass, &run_query|
|
10
|
+
# role = klass == User ? :reading : :writing
|
11
|
+
# ActiveRecord::Base.connected_to(role: role) do
|
12
|
+
# run_query.call
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
attr_writer :query_context
|
16
|
+
|
17
|
+
def query_context
|
18
|
+
@query_context ||= proc { |_klass, &block| block.call }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -25,13 +25,6 @@ end
|
|
25
25
|
require_relative './fixtures.rb'
|
26
26
|
require 'database_cleaner'
|
27
27
|
|
28
|
-
if Rails.version.to_f < 5.0
|
29
|
-
require 'test_after_commit'
|
30
|
-
end
|
31
|
-
if Rails.version.to_f < 4.2
|
32
|
-
require 'after_commit_exception_notification'
|
33
|
-
end
|
34
|
-
|
35
28
|
RSpec.configure do |config|
|
36
29
|
config.before(:suite) do
|
37
30
|
DatabaseCleaner.strategy = :transaction
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: incrdecr_cached_counts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Judd
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '5.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: dalli
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,34 +80,6 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: test_after_commit
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: after_commit_exception_notification
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
83
|
- !ruby/object:Gem::Dependency
|
112
84
|
name: rake
|
113
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,20 +102,18 @@ executables: []
|
|
130
102
|
extensions: []
|
131
103
|
extra_rdoc_files: []
|
132
104
|
files:
|
133
|
-
- ".circleci
|
105
|
+
- ".circleci/config.yml"
|
134
106
|
- ".gitignore"
|
135
|
-
- ".travis.yml"
|
136
107
|
- ".yardopts"
|
137
108
|
- Gemfile
|
138
109
|
- MIT-LICENSE
|
139
110
|
- README.rdoc
|
140
111
|
- Rakefile
|
141
|
-
- circle.yml
|
142
112
|
- incrdecr_cached_counts.gemspec
|
143
113
|
- lib/cached_counts.rb
|
144
|
-
- lib/cached_counts/connection_for.rb
|
145
114
|
- lib/cached_counts/dalli_check.rb
|
146
115
|
- lib/cached_counts/logger.rb
|
116
|
+
- lib/cached_counts/query_context.rb
|
147
117
|
- lib/cached_counts/railtie.rb
|
148
118
|
- lib/cached_counts/version.rb
|
149
119
|
- spec/caches_count_of_spec.rb
|
@@ -174,19 +144,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
174
144
|
- !ruby/object:Gem::Version
|
175
145
|
version: '0'
|
176
146
|
requirements: []
|
177
|
-
|
178
|
-
rubygems_version: 2.4.5.1
|
147
|
+
rubygems_version: 3.1.4
|
179
148
|
signing_key:
|
180
149
|
specification_version: 4
|
181
150
|
summary: A replacement for Rails' counter caches using memcached (via Dalli)
|
182
|
-
test_files:
|
183
|
-
- spec/caches_count_of_spec.rb
|
184
|
-
- spec/caches_count_where_spec.rb
|
185
|
-
- spec/database.yml
|
186
|
-
- spec/fixtures.rb
|
187
|
-
- spec/fixtures/department.rb
|
188
|
-
- spec/fixtures/following.rb
|
189
|
-
- spec/fixtures/university.rb
|
190
|
-
- spec/fixtures/user.rb
|
191
|
-
- spec/spec_helper.rb
|
192
|
-
has_rdoc:
|
151
|
+
test_files: []
|
data/.circleci-matrix.yml
DELETED
data/.travis.yml
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
sudo: false # use newer travis infrastructure
|
2
|
-
language: ruby
|
3
|
-
rvm:
|
4
|
-
- "2.1.8"
|
5
|
-
- "2.2.4"
|
6
|
-
- "2.3.0"
|
7
|
-
env:
|
8
|
-
- "ACTIVERECORD_VERSION=4.2.6"
|
9
|
-
- "ACTIVERECORD_VERSION=4.1.15"
|
10
|
-
- "ACTIVERECORD_VERSION=4.0.13"
|
11
|
-
- "ACTIVERECORD_VERSION=master"
|
12
|
-
matrix:
|
13
|
-
allow_failures:
|
14
|
-
# Master may or may not pass
|
15
|
-
- env: "ACTIVERECORD_VERSION=master"
|
data/circle.yml
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
module CachedCounts
|
2
|
-
class << self
|
3
|
-
# Optional configuration: set a proc which takes the class we are counting
|
4
|
-
# and returns a connection. Useful with replication, e.g. with Octopus:
|
5
|
-
#
|
6
|
-
# `CachedCounts.connection_for = proc { |klass| klass.using(:read_slave).connection }`
|
7
|
-
attr_writer :connection_for
|
8
|
-
|
9
|
-
def connection_for(counted_class)
|
10
|
-
@connection_for ||= proc { |klass| klass.connection }
|
11
|
-
@connection_for[counted_class]
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|