active_cached_resource 0.1.6 → 0.1.8

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: a7398b81424e7d34365729859220d5d05265452e4c7d8024f123b5a18f0490f0
4
- data.tar.gz: 0c8b48b2cecec7992a5170b3467839cf7c4e9d13f141d552a9206f9eccc5527d
3
+ metadata.gz: 654dbb9442c84be7f315fcf02c1b18c87bcf350c2bdc3bc2b5f7eafe3bb1d8c6
4
+ data.tar.gz: 52544f3e743ef86f0b254412407f60e1015346697d2e6dd7333ce804a3ea1266
5
5
  SHA512:
6
- metadata.gz: ea69cc9271151a45decccb33a3e52275d05bd0dc0d4244472305e6b050479fb51431f42c13705f19a380bf0cfe1dba1e1242ff6480b4b23992fb850c25df32dd
7
- data.tar.gz: '0807a7648e90ffd1e4a0c5650d52c15f67438a9a84366cf9a2563cd775ecd92a68f9fe0d816a8dac80f09f277623928b717a9f25f33fe1c484cb8617da367bc6'
6
+ metadata.gz: 968ddb5feb0ab1bc0df9146407d2504c26cf5fbe303c6eb261ea6073c5d1ead3a217f690f8e1a47d5dc7415cb3be97b864fb83134d4b7e13c02e2aa76a58a3cc
7
+ data.tar.gz: 99e7af8f3a51f67a3bb11608a8d11bde63369e804c946104148a84654199f1b6d4c82ce2fba461049a6ae87bedc9b90f14a0453bf2128fa0f8f9d388b46b11c1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [0.1.7] - 2024-01-23
2
+ - Improved `clear_cache` method for `active_support_cache` strategy to no longer use `delete_matched`.
3
+ - Introduced `.delete_from_cache` method to delete single cached resources.
4
+
1
5
  ## [0.1.6] - 2024-01-15
2
6
  - Renamed `ActiveResource::Collection#refresh` to `#reload` to match Rails ORM naming convention.
3
7
  - Added a `ActiveResource::Collection.none` class method similar to Rails `ActiveRecord::QueryMethods.none`
@@ -2,9 +2,6 @@ require_relative "collection"
2
2
 
3
3
  module ActiveCachedResource
4
4
  module Caching
5
- GLOBAL_PREFIX = "acr"
6
- RELOAD_PARAM = :_acr_reload
7
-
8
5
  extend ActiveSupport::Concern
9
6
 
10
7
  included do
@@ -128,7 +125,7 @@ module ActiveCachedResource
128
125
  # Hacky but this way ActiveCachedResource::Collection#request_resources! can access it
129
126
  if should_reload && args.first == :all
130
127
  options[:params] = {} if options[:params].blank?
131
- options[:params][RELOAD_PARAM] = should_reload
128
+ options[:params][Constants::RELOAD_PARAM] = should_reload
132
129
  args << options
133
130
  end
134
131
 
@@ -140,13 +137,19 @@ module ActiveCachedResource
140
137
  should_reload ? find_via_reload(*args) : find_via_cache(*args)
141
138
  end
142
139
 
143
- # Clears the cache for the specified pattern.
140
+ # Deletes a resource from the cache.
141
+ #
142
+ # @param id [Object] the identifier of the resource to be deleted from the cache.
143
+ def delete_from_cache(id)
144
+ cached_resource.cache.delete(cache_key(id))
145
+ end
146
+
147
+ # Clears the entire cache for the specified model that matches current prefix.
144
148
  #
145
- # @param pattern [String, nil] The pattern to match cache keys against.
146
- # If nil, all cache keys with this models prefix will be cleared.
147
149
  # @return [void]
148
- def clear_cache(pattern = nil)
149
- cached_resource.cache.clear("#{cache_key_prefix}/#{pattern}")
150
+ def clear_cache
151
+ cached_resource.logger.debug("Clearing cache for #{name} cache with prefix: #{cache_key_prefix}")
152
+ cached_resource.cache.clear(cache_key_prefix)
150
153
  end
151
154
 
152
155
  private
@@ -216,8 +219,7 @@ module ActiveCachedResource
216
219
  end
217
220
 
218
221
  def name_key
219
- # `cache_key_prefix` is separated from key parts with a dash to easily distinguish the prefix
220
- "#{cache_key_prefix}-" + name.parameterize.tr("-", "/")
222
+ "#{cache_key_prefix}#{Constants::PREFIX_SEPARATOR}#{name.parameterize.tr("-", "/")}"
221
223
  end
222
224
 
223
225
  def cache_key_prefix
@@ -228,9 +230,9 @@ module ActiveCachedResource
228
230
  if !result.is_a?(String) || result.empty?
229
231
  raise ArgumentError, "cache_key_prefix must return a non-empty String"
230
232
  end
231
- "#{GLOBAL_PREFIX}/#{result}"
233
+ "#{Constants::GLOBAL_PREFIX}/#{result}"
232
234
  else
233
- "#{GLOBAL_PREFIX}/#{prefix}"
235
+ "#{Constants::GLOBAL_PREFIX}/#{prefix}"
234
236
  end
235
237
  end
236
238
 
@@ -15,16 +15,35 @@ module ActiveCachedResource
15
15
  end
16
16
 
17
17
  def write_raw(key, compressed_value, options)
18
- @cache_store.write(key, compressed_value, options)
18
+ successful_write = @cache_store.write(key, compressed_value, options)
19
+ update_master_key(key, options) if successful_write
20
+
21
+ successful_write
22
+ end
23
+
24
+ def delete_raw(key)
25
+ @cache_store.delete(key)
19
26
  end
20
27
 
21
- def clear_raw(pattern)
22
- if @cache_store.respond_to?(:delete_matched)
23
- @cache_store.delete_matched("#{pattern}*")
24
- true
25
- else
26
- false
27
- end
28
+ def clear_raw(prefix)
29
+ existing_keys = @cache_store.read(prefix)
30
+ return if existing_keys.nil?
31
+
32
+ existing_keys.add(prefix)
33
+ @cache_store.delete_multi(existing_keys.to_a) # Redis implementation does not work with Sets
34
+ end
35
+
36
+ private
37
+
38
+ # Updates the `master` key, which contains keys for a given prefix.
39
+ def update_master_key(key, options)
40
+ prefix, _ = split_key(key)
41
+
42
+ existing_keys = @cache_store.read(prefix) || Set.new
43
+ existing_keys.add(key)
44
+
45
+ # Maintain the list of keys for twice the expiration time
46
+ @cache_store.write(prefix, existing_keys, expires_in: options[:expires_in])
28
47
  end
29
48
  end
30
49
  end
@@ -1,4 +1,3 @@
1
- require "msgpack"
2
1
  module ActiveCachedResource
3
2
  module CachingStrategies
4
3
  class Base
@@ -29,6 +28,14 @@ module ActiveCachedResource
29
28
  write_raw(hash_key(key), compress(value), options)
30
29
  end
31
30
 
31
+ # Deletes the cached value associated with the given key.
32
+ #
33
+ # @param key [Object] the key whose associated cached value is to be deleted.
34
+ # @return [void]
35
+ def delete(key)
36
+ delete_raw(hash_key(key))
37
+ end
38
+
32
39
  # Clears the cache based on the given pattern.
33
40
  #
34
41
  # @param pattern [String] the pattern to match cache keys that need to be cleared.
@@ -76,6 +83,22 @@ module ActiveCachedResource
76
83
  raise NotImplementedError, "#{self.class} must implement `clear_raw`"
77
84
  end
78
85
 
86
+ protected
87
+
88
+ # Splits the provided key into a prefix and the remaining part
89
+ #
90
+ # @param key [String] the key to be split
91
+ #
92
+ # @example Splitting a key
93
+ # split_key("prefix-key") #=> "acr/prefix/keyvalue"
94
+ #
95
+ # @return [Array<String>] an array containing two elements: the part before the first "-", and the rest of the string
96
+ def split_key(key)
97
+ # Prefix of keys are expected to be the first part of key separated by a dash.
98
+ prefix, k = key.split(ActiveCachedResource::Constants::PREFIX_SEPARATOR, 2)
99
+ [prefix, k]
100
+ end
101
+
79
102
  private
80
103
 
81
104
  # Generates a hashed key for caching purposes.
@@ -88,25 +111,25 @@ module ActiveCachedResource
88
111
  # @example Hashing a key
89
112
  # hash_key("prefix-key") #=> "acr/prefix/Digest::SHA256.hexdigest(key)"
90
113
  #
114
+ # @raise [ArgumentError] If the key does not contain a prefix and a key separated by a dash.
115
+ #
91
116
  # @param key [String] the original key to be hashed. It is expected to have a prefix and the key separated by a dash.
92
117
  # @return [String] the generated hashed key with the global prefix and the prefix from the original key.
93
118
  def hash_key(key)
94
- # Prefix of keys are expected to be the first part of key separated by a dash.
95
- prefix, k = key.split("-", 2)
119
+ prefix, k = split_key(key)
96
120
  if prefix.nil? || k.nil?
97
121
  raise ArgumentError, "Key must have a prefix and a key separated by a dash"
98
122
  end
99
-
100
- "#{prefix}/" + Digest::SHA256.hexdigest(k)
123
+ "#{prefix}#{ActiveCachedResource::Constants::PREFIX_SEPARATOR}#{Digest::SHA256.hexdigest(k)}"
101
124
  end
102
125
 
103
126
  def compress(value)
104
- MessagePack.pack(value)
127
+ value.to_json
105
128
  end
106
129
 
107
130
  def decompress(value)
108
- MessagePack.unpack(value)
109
- rescue MessagePack::UnpackError
131
+ JSON.parse(value)
132
+ rescue JSON::ParserError
110
133
  nil
111
134
  end
112
135
  end
@@ -11,6 +11,10 @@ module ActiveCachedResource
11
11
 
12
12
  protected
13
13
 
14
+ def delete_raw(key)
15
+ @model.where(key: key).delete_all
16
+ end
17
+
14
18
  def read_raw(key)
15
19
  record = @model.where(key: key).where(@model.arel_table[:expires_at].gt(Time.current)).first
16
20
  record&.value
@@ -7,7 +7,7 @@ module ActiveCachedResource
7
7
 
8
8
  # Delete the reload param from query params.
9
9
  # This is drilled down via `params` option to determine if the collection should be reloaded
10
- should_reload = query_params.delete(ActiveCachedResource::Caching::RELOAD_PARAM)
10
+ should_reload = query_params.delete(Constants::RELOAD_PARAM)
11
11
  if !should_reload
12
12
  from_cache = resource_class.send(:cache_read, from, path_params, query_params, prefix_options)
13
13
  @elements = from_cache
@@ -0,0 +1,7 @@
1
+ module ActiveCachedResource
2
+ module Constants
3
+ GLOBAL_PREFIX = "acr"
4
+ PREFIX_SEPARATOR = ":"
5
+ RELOAD_PARAM = :_acr_reload
6
+ end
7
+ end
@@ -56,7 +56,7 @@ module ActiveCachedResource
56
56
  private
57
57
 
58
58
  def invalidate_cache
59
- self.class.clear_cache(id.to_s)
59
+ self.class.delete_from_cache(id.to_s)
60
60
  end
61
61
 
62
62
  def save_to_cache
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveCachedResource
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.8"
5
5
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "activeresource/lib/activeresource"
4
4
 
5
+ require_relative "active_cached_resource/constants"
5
6
  require_relative "active_cached_resource/model"
6
7
  require_relative "active_cached_resource/version"
7
8
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_cached_resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Luis Urena
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-15 00:00:00.000000000 Z
10
+ date: 2025-01-24 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activemodel-serializers-xml
@@ -51,26 +51,6 @@ dependencies:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: '6.0'
54
- - !ruby/object:Gem::Dependency
55
- name: msgpack
56
- requirement: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '1.7'
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: 1.7.5
64
- type: :runtime
65
- prerelease: false
66
- version_requirements: !ruby/object:Gem::Requirement
67
- requirements:
68
- - - "~>"
69
- - !ruby/object:Gem::Version
70
- version: '1.7'
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: 1.7.5
74
54
  - !ruby/object:Gem::Dependency
75
55
  name: ostruct
76
56
  requirement: !ruby/object:Gem::Requirement
@@ -101,6 +81,7 @@ files:
101
81
  - lib/active_cached_resource/caching_strategies/sql_cache.rb
102
82
  - lib/active_cached_resource/collection.rb
103
83
  - lib/active_cached_resource/configuration.rb
84
+ - lib/active_cached_resource/constants.rb
104
85
  - lib/active_cached_resource/logger.rb
105
86
  - lib/active_cached_resource/model.rb
106
87
  - lib/active_cached_resource/version.rb
@@ -155,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
136
  - !ruby/object:Gem::Version
156
137
  version: '0'
157
138
  requirements: []
158
- rubygems_version: 3.6.2
139
+ rubygems_version: 3.6.3
159
140
  specification_version: 4
160
141
  summary: ActiveResource, but with a caching layer.
161
142
  test_files: []