identity_cache 1.2.0 → 1.6.3
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 +4 -4
- data/.github/workflows/ci.yml +8 -7
- data/.gitignore +1 -1
- data/.rubocop.yml +0 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +84 -2
- data/Gemfile +4 -4
- data/Gemfile.lock +118 -0
- data/README.md +28 -5
- data/Rakefile +98 -6
- data/dev.yml +17 -17
- data/gemfiles/Gemfile.latest-release +1 -0
- data/gemfiles/Gemfile.min-supported +5 -5
- data/gemfiles/Gemfile.rails-edge +1 -0
- data/identity_cache.gemspec +3 -3
- data/lib/identity_cache/belongs_to_caching.rb +1 -1
- data/lib/identity_cache/cache_fetcher.rb +12 -3
- data/lib/identity_cache/cache_key_loader.rb +1 -1
- data/lib/identity_cache/cached/attribute.rb +66 -3
- data/lib/identity_cache/cached/attribute_by_multi.rb +94 -9
- data/lib/identity_cache/cached/attribute_by_one.rb +4 -40
- data/lib/identity_cache/cached/belongs_to.rb +14 -10
- data/lib/identity_cache/cached/primary_index.rb +10 -2
- data/lib/identity_cache/cached/recursive/association.rb +1 -1
- data/lib/identity_cache/cached/reference/has_many.rb +1 -1
- data/lib/identity_cache/configuration_dsl.rb +1 -1
- data/lib/identity_cache/encoder.rb +1 -0
- data/lib/identity_cache/fallback_fetcher.rb +5 -1
- data/lib/identity_cache/memoized_cache_proxy.rb +10 -0
- data/lib/identity_cache/parent_model_expiration.rb +8 -3
- data/lib/identity_cache/query_api.rb +12 -6
- data/lib/identity_cache/should_use_cache.rb +10 -0
- data/lib/identity_cache/version.rb +1 -1
- data/lib/identity_cache/with_primary_index.rb +27 -14
- data/lib/identity_cache.rb +131 -21
- data/shipit.rubygems.yml +4 -1
- metadata +13 -12
- data/isogun.yml +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0daa9d36baa2b4c2e08dc8c29ab55274a1dbfab1d0146010720a68bfe9eff20e
|
4
|
+
data.tar.gz: '08708fb388587b7def00967250321904ffbfa9c071aca71f6b360ea22ec0ab8f'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61e4c7010330259878bb07f61a806b2b8d21d3cfbc67d07074cd9dddafd69471c6aa50ebdf880e39b9a0dba7203d0215f1336829842457ea877e3f065ce8e98e
|
7
|
+
data.tar.gz: e1d0f10f2a4a3ff678b4b89b60547c342ab6a0ce8f5d1623ebcdb29c227e08ee7da8234c32ed3388b745aa11f4be1989d5a554a521152bdd72ebaa9c92cc9747
|
data/.github/workflows/ci.yml
CHANGED
@@ -16,14 +16,14 @@ jobs:
|
|
16
16
|
matrix:
|
17
17
|
entry:
|
18
18
|
- name: 'Minimum supported'
|
19
|
-
ruby: '
|
19
|
+
ruby: '3.0'
|
20
20
|
gemfile: "Gemfile.min-supported"
|
21
21
|
- name: 'Latest released & run rubocop'
|
22
|
-
ruby: '3.
|
22
|
+
ruby: '3.3'
|
23
23
|
gemfile: "Gemfile.latest-release"
|
24
24
|
rubocop: true
|
25
25
|
- name: 'Rails edge'
|
26
|
-
ruby: '3.
|
26
|
+
ruby: '3.3'
|
27
27
|
gemfile: "Gemfile.rails-edge"
|
28
28
|
edge: true
|
29
29
|
|
@@ -69,25 +69,26 @@ jobs:
|
|
69
69
|
run: |
|
70
70
|
sudo apt-get update
|
71
71
|
sudo apt-get -y install libmemcached-dev libmysqlclient-dev libpq-dev libsasl2-dev
|
72
|
+
|
72
73
|
- uses: actions/checkout@v2
|
73
74
|
- name: Set up Ruby
|
74
75
|
uses: ruby/setup-ruby@v1
|
75
76
|
with:
|
76
77
|
ruby-version: ${{ matrix.entry.ruby }}
|
77
|
-
|
78
|
-
|
79
|
-
gem install bundler
|
80
|
-
bundle install --jobs 4 --retry 3
|
78
|
+
bundler-cache: true
|
79
|
+
|
81
80
|
- name: Test with mysql
|
82
81
|
env:
|
83
82
|
DB: mysql2
|
84
83
|
run: bundle exec rake test
|
84
|
+
|
85
85
|
- name: Test with postgres and memcached_store
|
86
86
|
env:
|
87
87
|
DB: postgresql
|
88
88
|
POSTGRES_PASSWORD: postgres
|
89
89
|
ADAPTER: memcached
|
90
90
|
run: bundle exec rake test
|
91
|
+
|
91
92
|
- name: Run rubocop
|
92
93
|
if: matrix.entry.rubocop
|
93
94
|
run: bundle exec rubocop
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.3.4
|
data/CHANGELOG.md
CHANGED
@@ -1,18 +1,99 @@
|
|
1
1
|
# Identity Cache Changelog
|
2
2
|
|
3
|
+
## Unreleased
|
4
|
+
|
5
|
+
## 1.6.3
|
6
|
+
|
7
|
+
- Split the `with_deferred_parent_expiration` and `with_deferred_parent_expiration`. (#578)
|
8
|
+
|
9
|
+
## 1.6.2
|
10
|
+
|
11
|
+
- Support deferred expiry of associations and attributes. Add a rake task to create test database. (#577)
|
12
|
+
|
13
|
+
## 1.6.1
|
14
|
+
|
15
|
+
- Fix deprecation warnings on Active Record 7.2. (#575)
|
16
|
+
|
17
|
+
## 1.6.0
|
18
|
+
|
19
|
+
- Introduce `.with_deferred_parent_expiration`, which takes a block and avoids duplicate parent cache expiry. (#569)
|
20
|
+
|
21
|
+
## 1.5.6
|
22
|
+
|
23
|
+
- Minor performance improvements on association read
|
24
|
+
|
25
|
+
## 1.5.5
|
26
|
+
|
27
|
+
- Minor performance improvements on association read
|
28
|
+
|
29
|
+
|
30
|
+
## 1.5.4
|
31
|
+
|
32
|
+
- Make `prefetch_associations` work as expected on associations that have been partially prefetched
|
33
|
+
|
34
|
+
## 1.5.3
|
35
|
+
|
36
|
+
- No longer call `should_use_cache?` on embedded/prefetched associations when reading values
|
37
|
+
|
38
|
+
## 1.5.2
|
39
|
+
|
40
|
+
- Add missing `should_use_cache?` to `fetch_multi` methods.
|
41
|
+
|
42
|
+
## 1.5.1
|
43
|
+
|
44
|
+
- Fix parent cache invalidation for custom foreign key associations
|
45
|
+
|
46
|
+
## 1.5.0
|
47
|
+
|
48
|
+
- Require Active Record 7+
|
49
|
+
- Require Ruby 3+
|
50
|
+
- Improve compatibility with Active Record 7.1.
|
51
|
+
|
52
|
+
## 1.4.1
|
53
|
+
|
54
|
+
### Fixes
|
55
|
+
|
56
|
+
- Fix `fetch_multi_by` bug for queries having a single field with distinct values. (#536)
|
57
|
+
|
58
|
+
## 1.4.0
|
59
|
+
|
60
|
+
### Features
|
61
|
+
|
62
|
+
- Add `fetch_multi_by` support for composite-key indexes. (#534)
|
63
|
+
|
64
|
+
## 1.3.1
|
65
|
+
|
66
|
+
### Fixes
|
67
|
+
|
68
|
+
- Remove N+1 queries from embedded associations when using `fetch` while `should_use_cache` is false. (#531)
|
69
|
+
|
70
|
+
## 1.3.0
|
71
|
+
|
72
|
+
### Features
|
73
|
+
|
74
|
+
- Return meaningful value from `expire_cache` indicating whenever it succeeded or failed in the process. (#523)
|
75
|
+
|
76
|
+
### Fixes
|
77
|
+
|
78
|
+
- Expire parents cache when when calling `expire_cache`. (#523)
|
79
|
+
- Avoid creating too many shapes on Ruby 3.2+. (#526)
|
80
|
+
|
3
81
|
## 1.2.0
|
4
82
|
|
5
83
|
### Fixes
|
84
|
+
|
6
85
|
- Fix mem_cache_store adapter with pool_size (#489)
|
7
86
|
- Fix dalli deprecation warning about requiring 'dalli/cas/client' (#511)
|
8
87
|
- Make transitionary method IdentityCache.with_fetch_read_only_records thread-safe (#503)
|
9
88
|
|
10
89
|
### Features
|
90
|
+
|
11
91
|
- Add support for fill lock with lock wait to avoid thundering herd problem (#373)
|
12
92
|
|
13
93
|
## 1.1.0
|
14
94
|
|
15
95
|
### Fixes
|
96
|
+
|
16
97
|
- Fix double debug logging of cache hits and misses (#474)
|
17
98
|
- Fix a Rails 6.1 deprecation warning for Rails 7.0 compatibility (#482)
|
18
99
|
- Recursively install parent expiry hooks when expiring parent caches (#476)
|
@@ -24,10 +105,12 @@
|
|
24
105
|
- Fix fetch `has_many` embedded association on record after adding to it (#449)
|
25
106
|
|
26
107
|
### Features
|
108
|
+
|
27
109
|
- Support multiple databases and transactional tests in `IdentityCache.should_use_cache?` (#293)
|
28
110
|
- Add support for the default `MemCacheStore` from `ActiveSupport` (#465)
|
29
111
|
|
30
112
|
### Breaking Changes
|
113
|
+
|
31
114
|
- Drop ruby 2.4 support, since it is no longer supported upstream (#468)
|
32
115
|
|
33
116
|
## 1.0.1
|
@@ -99,7 +182,7 @@
|
|
99
182
|
- Remove support for 3.2
|
100
183
|
- Fix N+1 from fetching embedded ids on a cache miss
|
101
184
|
- Raise when trying to cache a through association. Previously it wouldn't be invalidated properly.
|
102
|
-
- Raise if a class method is called on a scope.
|
185
|
+
- Raise if a class method is called on a scope. Previously the scope was ignored.
|
103
186
|
- Raise if a class method is called on a subclass of one that included IdentityCache. This never worked properly.
|
104
187
|
- Fix cache_belongs_to on polymorphic assocations.
|
105
188
|
- Fetching a cache_belongs_to association no longer loads the belongs_to association
|
@@ -160,7 +243,6 @@
|
|
160
243
|
|
161
244
|
## 0.0.5
|
162
245
|
|
163
|
-
|
164
246
|
## 0.0.4
|
165
247
|
|
166
248
|
- Fix: only marshal attributes, embedded associations and normalized association IDs
|
data/Gemfile
CHANGED
@@ -3,15 +3,15 @@
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem "rubocop", "~> 1.
|
6
|
+
gem "rubocop", "~> 1.61.0"
|
7
7
|
|
8
8
|
gem "rubocop-shopify", "~> 2.9.0", require: false
|
9
9
|
|
10
10
|
gem "mysql2", "~> 0.5.3", platform: :mri
|
11
11
|
gem "pg", ">= 0.18", "< 2.0", platform: :mri
|
12
|
-
gem "memcached", "
|
13
|
-
gem "memcached_store", "~>
|
14
|
-
gem "dalli", "~> 2.
|
12
|
+
gem "memcached", github: "Shopify/memcached", branch: "1-0-stable-shopify", platform: :mri
|
13
|
+
gem "memcached_store", "~> 2.3.2", platform: :mri
|
14
|
+
gem "dalli", "~> 3.2.3"
|
15
15
|
gem "cityhash", "~> 0.6.0", platform: :mri
|
16
16
|
|
17
17
|
gem "byebug", platform: :mri
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/Shopify/memcached.git
|
3
|
+
revision: 54a89bae698896a00fd2ceeb142dada6285f73ed
|
4
|
+
branch: 1-0-stable-shopify
|
5
|
+
specs:
|
6
|
+
memcached (1.9.0)
|
7
|
+
|
8
|
+
PATH
|
9
|
+
remote: .
|
10
|
+
specs:
|
11
|
+
identity_cache (1.6.3)
|
12
|
+
activerecord (>= 7.0)
|
13
|
+
ar_transaction_changes (~> 1.1)
|
14
|
+
|
15
|
+
GEM
|
16
|
+
remote: https://rubygems.org/
|
17
|
+
specs:
|
18
|
+
activemodel (7.2.0)
|
19
|
+
activesupport (= 7.2.0)
|
20
|
+
activerecord (7.2.0)
|
21
|
+
activemodel (= 7.2.0)
|
22
|
+
activesupport (= 7.2.0)
|
23
|
+
timeout (>= 0.4.0)
|
24
|
+
activesupport (7.2.0)
|
25
|
+
base64
|
26
|
+
bigdecimal
|
27
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
28
|
+
connection_pool (>= 2.2.5)
|
29
|
+
drb
|
30
|
+
i18n (>= 1.6, < 2)
|
31
|
+
logger (>= 1.4.2)
|
32
|
+
minitest (>= 5.1)
|
33
|
+
securerandom (>= 0.3)
|
34
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
35
|
+
ar_transaction_changes (1.1.9)
|
36
|
+
activerecord (>= 5.2.0)
|
37
|
+
ast (2.4.2)
|
38
|
+
base64 (0.2.0)
|
39
|
+
bigdecimal (3.1.8)
|
40
|
+
byebug (11.1.3)
|
41
|
+
cityhash (0.6.0)
|
42
|
+
concurrent-ruby (1.3.4)
|
43
|
+
connection_pool (2.4.1)
|
44
|
+
dalli (3.2.3)
|
45
|
+
drb (2.2.1)
|
46
|
+
i18n (1.14.5)
|
47
|
+
concurrent-ruby (~> 1.0)
|
48
|
+
json (2.7.1)
|
49
|
+
language_server-protocol (3.17.0.3)
|
50
|
+
logger (1.6.0)
|
51
|
+
memcached_store (2.3.4)
|
52
|
+
activesupport (>= 6)
|
53
|
+
memcached (~> 1.8)
|
54
|
+
minitest (5.25.1)
|
55
|
+
mocha (2.1.0)
|
56
|
+
ruby2_keywords (>= 0.0.5)
|
57
|
+
mysql2 (0.5.6)
|
58
|
+
parallel (1.24.0)
|
59
|
+
parser (3.3.0.5)
|
60
|
+
ast (~> 2.4.1)
|
61
|
+
racc
|
62
|
+
pg (1.5.6)
|
63
|
+
racc (1.7.3)
|
64
|
+
rainbow (3.1.1)
|
65
|
+
rake (13.1.0)
|
66
|
+
regexp_parser (2.9.0)
|
67
|
+
rexml (3.3.6)
|
68
|
+
strscan
|
69
|
+
rubocop (1.61.0)
|
70
|
+
json (~> 2.3)
|
71
|
+
language_server-protocol (>= 3.17.0)
|
72
|
+
parallel (~> 1.10)
|
73
|
+
parser (>= 3.3.0.2)
|
74
|
+
rainbow (>= 2.2.2, < 4.0)
|
75
|
+
regexp_parser (>= 1.8, < 3.0)
|
76
|
+
rexml (>= 3.2.5, < 4.0)
|
77
|
+
rubocop-ast (>= 1.30.0, < 2.0)
|
78
|
+
ruby-progressbar (~> 1.7)
|
79
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
80
|
+
rubocop-ast (1.31.2)
|
81
|
+
parser (>= 3.3.0.4)
|
82
|
+
rubocop-shopify (2.9.0)
|
83
|
+
rubocop (~> 1.33)
|
84
|
+
ruby-progressbar (1.13.0)
|
85
|
+
ruby2_keywords (0.0.5)
|
86
|
+
securerandom (0.3.1)
|
87
|
+
spy (1.0.5)
|
88
|
+
stackprof (0.2.26)
|
89
|
+
strscan (3.1.0)
|
90
|
+
timeout (0.4.1)
|
91
|
+
tzinfo (2.0.6)
|
92
|
+
concurrent-ruby (~> 1.0)
|
93
|
+
unicode-display_width (2.5.0)
|
94
|
+
|
95
|
+
PLATFORMS
|
96
|
+
arm64-darwin-22
|
97
|
+
arm64-darwin-23
|
98
|
+
x86_64-linux
|
99
|
+
|
100
|
+
DEPENDENCIES
|
101
|
+
byebug
|
102
|
+
cityhash (~> 0.6.0)
|
103
|
+
dalli (~> 3.2.3)
|
104
|
+
identity_cache!
|
105
|
+
memcached!
|
106
|
+
memcached_store (~> 2.3.2)
|
107
|
+
minitest (~> 5.14)
|
108
|
+
mocha (~> 2.0)
|
109
|
+
mysql2 (~> 0.5.3)
|
110
|
+
pg (>= 0.18, < 2.0)
|
111
|
+
rake (~> 13.0)
|
112
|
+
rubocop (~> 1.61.0)
|
113
|
+
rubocop-shopify (~> 2.9.0)
|
114
|
+
spy (~> 1.0)
|
115
|
+
stackprof
|
116
|
+
|
117
|
+
BUNDLED WITH
|
118
|
+
2.4.22
|
data/README.md
CHANGED
@@ -101,7 +101,15 @@ product = Product.fetch_by_handle(handle)
|
|
101
101
|
# Fetch multiple products by providing an array of index values.
|
102
102
|
products = Product.fetch_multi_by_handle(handles)
|
103
103
|
|
104
|
+
# Fetch a single product by providing composite attributes.
|
104
105
|
products = Product.fetch_by_vendor_and_product_type(vendor, product_type)
|
106
|
+
|
107
|
+
# Fetch multiple products by providing an array of composite attributes.
|
108
|
+
products = Product.fetch_multi_by_vendor_and_product_type([
|
109
|
+
[vendor_1, product_type_1],
|
110
|
+
[vendor_2, product_type_2],
|
111
|
+
# ...
|
112
|
+
])
|
105
113
|
```
|
106
114
|
|
107
115
|
This gives you a lot of freedom to use your objects the way you want to, and doesn't get in your way. This does keep an independent cache copy in Memcached so you might want to watch the number of different caches that are being added.
|
@@ -254,11 +262,26 @@ Cache keys include a version number by default, specified in `IdentityCache::CAC
|
|
254
262
|
|
255
263
|
## Caveats
|
256
264
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
265
|
+
IdentityCache is never going to be 100% consistent, since cache invalidations can be lost. As such, it was intentionally designed to be _opt-in_, so it is only used where cache inconsistency is tolerated. This means IdentityCache does not mess with the way normal Rails associations work, and including it in a model won't change any clients of that model until you switch them to use `fetch` instead of `find`. This means that you need to think carefully about when you use `fetch` and when you use `find`.
|
266
|
+
|
267
|
+
Expected sources of lost cache invalidations include:
|
268
|
+
* Database write performed that doesn't trigger an after_commit callback
|
269
|
+
* Process/system getting killed or crashing between the database commit and cache invalidation
|
270
|
+
* Network unavailability, including transient failures, preventing the delivery of the cache invalidation
|
271
|
+
* Memcached unavailability or failure preventing the processing of the cache invalidation request
|
272
|
+
* Memcached flush / restart could remove a cache invalidation that would normally interrupt a cache fill that started when the cache key was absent. E.g.
|
273
|
+
1. cache key absent (not just invalidated)
|
274
|
+
2. process 1 reads cache key
|
275
|
+
3. process 1 starts reading from the database
|
276
|
+
4. process 2 writes to the database
|
277
|
+
5. process 2 writes a cache invalidation marker to cache key
|
278
|
+
6. memcached flush
|
279
|
+
7. process 1 uses an `ADD` operation, which succeeds in filling the cache with the now stale data
|
280
|
+
* Rollout of cache namespace changes (e.g. from upgrading IdentityCache, adding columns, cached associations or from application changes to IdentityCache.cache_namespace) can result in cache fills to the new namespace that aren't invalidated by cache invalidations from a process still using the old namespace
|
281
|
+
|
282
|
+
Cache expiration is meant to be used to help the system recover, but it only works if the application avoids using the cache data as a transaction to write data. IdentityCache avoids loading cached data from its methods during an open transaction, but can't prevent cache data that was loaded before the transaction was opened from being used in a transaction. IdentityCache won't help with scaling write traffic, it was intended for scaling database queries from read-only requests.
|
283
|
+
|
284
|
+
IdentityCache also caches the absence of database values (e.g. to avoid performance problems when it is destroyed), so lost cache invalidations can also result in that value continuing to remain absent. As such, avoid sending the id of an uncommitted database record to another process (e.g. queuing it to a background job), since that could result in an attempt to read the record by its id before it has been created. A cache invalidation will still be attempted when the record is created, but that could be lost.
|
262
285
|
|
263
286
|
## Notes
|
264
287
|
|
data/Rakefile
CHANGED
@@ -9,14 +9,82 @@ require "rdoc/task"
|
|
9
9
|
desc("Default: run tests and style checks.")
|
10
10
|
task(default: [:test, :rubocop])
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
namespace :test do
|
13
|
+
desc "Test the identity_cache plugin with default Gemfile"
|
14
|
+
Rake::TestTask.new(:default) do |t|
|
15
|
+
t.libs << "lib"
|
16
|
+
t.libs << "test"
|
17
|
+
t.pattern = "test/**/*_test.rb"
|
18
|
+
t.verbose = true
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Test the identity_cache plugin with minimum supported dependencies"
|
22
|
+
task :min_supported do
|
23
|
+
gemfile = File.expand_path("gemfiles/Gemfile.min-supported", __dir__)
|
24
|
+
ENV["BUNDLE_GEMFILE"] = gemfile
|
25
|
+
|
26
|
+
puts "\nInstalling dependencies for #{gemfile}..."
|
27
|
+
Bundler.with_unbundled_env do
|
28
|
+
system("bundle install --gemfile #{gemfile}") || abort("Bundle install failed")
|
29
|
+
end
|
30
|
+
|
31
|
+
puts "Running tests with #{gemfile}..."
|
32
|
+
Rake::TestTask.new(:run_min_supported) do |t|
|
33
|
+
t.libs << "lib"
|
34
|
+
t.libs << "test"
|
35
|
+
t.pattern = "test/**/*_test.rb"
|
36
|
+
t.verbose = true
|
37
|
+
end
|
38
|
+
Rake::Task["run_min_supported"].invoke
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Test the identity_cache plugin with latest released dependencies"
|
42
|
+
task :latest_release do
|
43
|
+
gemfile = File.expand_path("gemfiles/Gemfile.latest-release", __dir__)
|
44
|
+
ENV["BUNDLE_GEMFILE"] = gemfile
|
45
|
+
|
46
|
+
puts "\nInstalling dependencies for #{gemfile}..."
|
47
|
+
Bundler.with_unbundled_env do
|
48
|
+
system("bundle install --gemfile #{gemfile}") || abort("Bundle install failed")
|
49
|
+
end
|
50
|
+
|
51
|
+
puts "Running tests with #{gemfile}..."
|
52
|
+
Rake::TestTask.new(:run_latest_release) do |t|
|
53
|
+
t.libs << "lib"
|
54
|
+
t.libs << "test"
|
55
|
+
t.pattern = "test/**/*_test.rb"
|
56
|
+
t.verbose = true
|
57
|
+
end
|
58
|
+
Rake::Task["run_latest_release"].invoke
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "Test the identity_cache plugin with rails edge dependencies"
|
62
|
+
task :rails_edge do
|
63
|
+
gemfile = File.expand_path("gemfiles/Gemfile.rails-edge", __dir__)
|
64
|
+
ENV["BUNDLE_GEMFILE"] = gemfile
|
65
|
+
|
66
|
+
puts "\nInstalling dependencies for #{gemfile}..."
|
67
|
+
Bundler.with_unbundled_env do
|
68
|
+
system("bundle install --gemfile #{gemfile}") || abort("Bundle install failed")
|
69
|
+
end
|
70
|
+
|
71
|
+
puts "Running tests with #{gemfile}..."
|
72
|
+
Rake::TestTask.new(:run_rails_edge) do |t|
|
73
|
+
t.libs << "lib"
|
74
|
+
t.libs << "test"
|
75
|
+
t.pattern = "test/**/*_test.rb"
|
76
|
+
t.verbose = true
|
77
|
+
end
|
78
|
+
Rake::Task["run_rails_edge"].invoke
|
79
|
+
end
|
18
80
|
end
|
19
81
|
|
82
|
+
desc "Run default tests"
|
83
|
+
task test: ["test:default"]
|
84
|
+
|
85
|
+
desc "Run all tests (default, min_supported, latest_release, rails_edge)"
|
86
|
+
task test_all: ["test:default", "test:min_supported", "test:latest_release", "test:rails_edge"]
|
87
|
+
|
20
88
|
task :rubocop do
|
21
89
|
require "rubocop/rake_task"
|
22
90
|
RuboCop::RakeTask.new
|
@@ -47,3 +115,27 @@ namespace :profile do
|
|
47
115
|
ruby "./performance/profile.rb"
|
48
116
|
end
|
49
117
|
end
|
118
|
+
|
119
|
+
namespace :db do
|
120
|
+
desc "Create the identity_cache_test database"
|
121
|
+
task :create do
|
122
|
+
require "mysql2"
|
123
|
+
|
124
|
+
config = {
|
125
|
+
host: ENV.fetch("MYSQL_HOST") || "localhost",
|
126
|
+
port: ENV.fetch("MYSQL_PORT") || 1037,
|
127
|
+
username: ENV.fetch("MYSQL_USER") || "root",
|
128
|
+
password: ENV.fetch("MYSQL_PASSWORD") || "",
|
129
|
+
}
|
130
|
+
|
131
|
+
begin
|
132
|
+
client = Mysql2::Client.new(config)
|
133
|
+
client.query("CREATE DATABASE IF NOT EXISTS identity_cache_test")
|
134
|
+
puts "Database 'identity_cache_test' created successfully. host: #{config[:host]}, port: #{config[:port]}"
|
135
|
+
rescue Mysql2::Error => e
|
136
|
+
puts "Error creating database: #{e.message}"
|
137
|
+
ensure
|
138
|
+
client&.close
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/dev.yml
CHANGED
@@ -1,18 +1,14 @@
|
|
1
1
|
name: identity-cache
|
2
2
|
|
3
3
|
up:
|
4
|
-
-
|
5
|
-
- mysql-client@5.7:
|
6
|
-
or: [mysql@5.7]
|
7
|
-
conflicts: [mysql-connector-c, mysql, mysql-client]
|
8
|
-
- ruby: 2.7.2
|
9
|
-
- isogun
|
4
|
+
- ruby
|
10
5
|
- bundler
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
- memcached
|
7
|
+
- mysql
|
8
|
+
- custom:
|
9
|
+
name: create database identity_cache_test
|
10
|
+
met?: mysql -u root -h 127.0.0.1 -P 1037 -e "SHOW DATABASES;" | grep identity_cache_test
|
11
|
+
meet: bundle exec rake db:create
|
16
12
|
|
17
13
|
commands:
|
18
14
|
test:
|
@@ -20,7 +16,7 @@ commands:
|
|
20
16
|
optional:
|
21
17
|
argument: file
|
22
18
|
optional: args...
|
23
|
-
desc:
|
19
|
+
desc: "Run tests"
|
24
20
|
run: |
|
25
21
|
if [[ $# -eq 0 ]]; then
|
26
22
|
bundle exec rake test
|
@@ -28,22 +24,26 @@ commands:
|
|
28
24
|
bundle exec ruby -I test "$@"
|
29
25
|
fi
|
30
26
|
|
27
|
+
test-all:
|
28
|
+
desc: "Run tests for all gemfiles (default, min_supported, latest_release, rails_edge)"
|
29
|
+
run: bundle exec rake test_all
|
30
|
+
|
31
31
|
style:
|
32
|
-
desc:
|
32
|
+
desc: "Run rubocop checks"
|
33
33
|
run: bundle exec rubocop "$@"
|
34
34
|
|
35
35
|
check:
|
36
|
-
desc:
|
36
|
+
desc: "Run tests and style checks"
|
37
37
|
run: bundle exec rake test && bundle exec rubocop
|
38
38
|
|
39
39
|
benchmark-cpu:
|
40
|
-
desc:
|
40
|
+
desc: "Run the identity cache CPU benchmark"
|
41
41
|
run: bundle exec rake benchmark:cpu
|
42
42
|
|
43
43
|
profile:
|
44
|
-
desc:
|
44
|
+
desc: "Profile IDC code"
|
45
45
|
run: bundle exec rake profile:run
|
46
46
|
|
47
47
|
update-serialization-format:
|
48
|
-
desc:
|
48
|
+
desc: "Update serialization format test fixture"
|
49
49
|
run: bundle exec rake update_serialization_format
|
@@ -3,10 +3,10 @@ gemspec path: ".."
|
|
3
3
|
|
4
4
|
gem "ar_transaction_changes", "~> 1.1.0"
|
5
5
|
|
6
|
-
gem "activerecord", "~>
|
7
|
-
gem "mysql2", "~> 0.
|
8
|
-
gem "pg", "~>
|
9
|
-
gem "memcached", "
|
10
|
-
gem "memcached_store", "~>
|
6
|
+
gem "activerecord", "~> 7.0.0"
|
7
|
+
gem "mysql2", "~> 0.5"
|
8
|
+
gem "pg", "~> 1.1"
|
9
|
+
gem "memcached", github: "Shopify/memcached", branch: "1-0-stable-shopify"
|
10
|
+
gem "memcached_store", "~> 2.3.2"
|
11
11
|
gem "dalli", "~> 2.7.11"
|
12
12
|
gem "cityhash", "~> 0.6.0"
|
data/gemfiles/Gemfile.rails-edge
CHANGED
@@ -5,6 +5,7 @@ gem "activerecord", github: "rails/rails", branch: "main"
|
|
5
5
|
gem "activesupport", github: "rails/rails", branch: "main"
|
6
6
|
gem "mysql2", "~> 0.5"
|
7
7
|
gem "pg", "~> 1.1"
|
8
|
+
gem "memcached", github: "Shopify/memcached", branch: "1-0-stable-shopify"
|
8
9
|
gem "memcached_store"
|
9
10
|
gem "dalli"
|
10
11
|
gem "cityhash"
|
data/identity_cache.gemspec
CHANGED
@@ -31,15 +31,15 @@ Gem::Specification.new do |gem|
|
|
31
31
|
gem.require_paths = ["lib"]
|
32
32
|
gem.version = IdentityCache::VERSION
|
33
33
|
|
34
|
-
gem.required_ruby_version = ">=
|
34
|
+
gem.required_ruby_version = ">= 3.0.0"
|
35
35
|
|
36
36
|
gem.metadata["allowed_push_host"] = "https://rubygems.org"
|
37
37
|
|
38
|
-
gem.add_dependency("activerecord", ">=
|
38
|
+
gem.add_dependency("activerecord", ">= 7.0")
|
39
39
|
gem.add_dependency("ar_transaction_changes", "~> 1.1")
|
40
40
|
|
41
41
|
gem.add_development_dependency("minitest", "~> 5.14")
|
42
|
-
gem.add_development_dependency("mocha", "~>
|
42
|
+
gem.add_development_dependency("mocha", "~> 2.0")
|
43
43
|
gem.add_development_dependency("rake", "~> 13.0")
|
44
44
|
gem.add_development_dependency("spy", "~> 1.0")
|
45
45
|
end
|
@@ -14,7 +14,7 @@ module IdentityCache
|
|
14
14
|
ensure_base_model
|
15
15
|
|
16
16
|
unless (reflection = reflect_on_association(association))
|
17
|
-
raise AssociationError, "Association named '#{association}' was not found on #{self
|
17
|
+
raise AssociationError, "Association named '#{association}' was not found on #{self}"
|
18
18
|
end
|
19
19
|
|
20
20
|
if reflection.scope
|