active_cached_resource 0.1.5 → 0.1.7

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: febe875b913adcca00b5ca5eab9c43b23691912ba4465ce34c3f842ba2c0652c
4
- data.tar.gz: 39d644336fd27dc4404c8c2d6f130b74e64686c8d923ee6c3b0257fcd1890576
3
+ metadata.gz: 45d04dcc0d591d945fbee26f110200f54a889a55516b2340e16f5a53e571d07d
4
+ data.tar.gz: 9ccf72f8ff91404b52650d199c2ea0569e93b1cc62e830ec2f8551cae8537d23
5
5
  SHA512:
6
- metadata.gz: 78ac473ce4a0710031fd09b9f88f713e90838b287e8361b22ef1c534f8cb9d13369ea2ab1eb78a96e47ea7cfa04bed8014157891098f92743bf4f54113292596
7
- data.tar.gz: dc3d33e8c76855b9e58eab1d258aa335f3d939688e2be0ee853a0614d901f61339204c358d866e8ec379318c0fd604e3eee2d4a3318a7d6a28cf9662bf6b2e9b
6
+ metadata.gz: 4a3f42bfc71f0f3abba12204f1bb27ce08389ec6a28d79ca527b95b9bc010eee02bb9f3bc238bbd9a481a3d4f3454b1f05baba48b8885474f92d0778db189975
7
+ data.tar.gz: 8cda34284a02b73a3c4c3f5a29eb00543c82636340371997af90219d556e80c62056e3d4d50bf7f795680dfd02805c637a4f89c4611a056cffac48c1754e0e81
data/CHANGELOG.md CHANGED
@@ -1,9 +1,20 @@
1
- ## [0.1.5] - 2024-01-30
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
+
5
+ ## [0.1.6] - 2024-01-15
6
+ - Renamed `ActiveResource::Collection#refresh` to `#reload` to match Rails ORM naming convention.
7
+ - Added a `ActiveResource::Collection.none` class method similar to Rails `ActiveRecord::QueryMethods.none`
8
+ - Enhanced `ActiveResource::Collection#where` so that it returns `ActiveResource::Collection.none` if `resource_class` is missing.
9
+ - This is useful for when `where` clauses are chained on an empty `ActiveResource::Collection`
10
+
11
+ ## [0.1.5] - 2024-01-09
2
12
  - Added callbacks to cache:
3
13
  - Create/POST, refresh cache after successful POST request
4
14
  - Update/PUT, refresh cache after successful PUT request
5
15
  - Destroy/DELETE, invalidate cache after successful DELETE request
6
16
  - Fixed issue with generator for SQLCache strategy tables
17
+
7
18
  ## [0.1.4] - 2024-12-20
8
19
  - CI Improvements
9
20
  - Added annotations
@@ -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)
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.5"
4
+ VERSION = "0.1.7"
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
 
@@ -21,6 +21,23 @@ module ActiveResource # :nodoc:
21
21
  attr_writer :prefix_options
22
22
  attr_reader :from
23
23
 
24
+ # Returns a frozen empty collection.
25
+ #
26
+ # @return [ActiveResource::Collection] an empty collection
27
+ def self.none
28
+ new([]).tap do |collection|
29
+ collection.instance_variable_set(:@requested, true)
30
+ end
31
+ end
32
+
33
+ # Creates a new ActiveResource::Collection instance.
34
+ #
35
+ # ==== Arguments
36
+ #
37
+ # +elements+ (Array<Object>) - An optional array of resources to be set as the collection elements.
38
+ # Defaults to an empty array.
39
+ # +from+ (String, Symbol) - The path to the collection resource or the symbol for the collection resource.
40
+
24
41
  # ActiveResource::Collection is a wrapper to handle parsing index responses that
25
42
  # do not directly map to Rails conventions.
26
43
  #
@@ -98,12 +115,12 @@ module ActiveResource # :nodoc:
98
115
  @prefix_options || {}
99
116
  end
100
117
 
101
- # Refreshes the collection by re-fetching the resources from the API.
118
+ # Reload the collection by re-fetching the resources from the API.
102
119
  #
103
120
  # ==== Returns
104
121
  #
105
122
  # [Array<Object>] The collection of resources retrieved from the API.
106
- def refresh
123
+ def reload
107
124
  @requested = false
108
125
  request_resources!
109
126
  end
@@ -182,6 +199,7 @@ module ActiveResource # :nodoc:
182
199
  # # => PostCollection:xxx (filtered collection)
183
200
  def where(clauses = {})
184
201
  raise ArgumentError, "expected a clauses Hash, got #{clauses.inspect}" unless clauses.is_a? Hash
202
+ return self.class.none if resource_class.nil?
185
203
  new_clauses = query_params.merge(clauses)
186
204
  resource_class.where(new_clauses)
187
205
  end
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.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Luis Urena
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-09 00:00:00.000000000 Z
10
+ date: 2025-01-23 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activemodel-serializers-xml
@@ -52,25 +52,19 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: '6.0'
54
54
  - !ruby/object:Gem::Dependency
55
- name: msgpack
55
+ name: ostruct
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '1.7'
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: 1.7.5
60
+ version: 0.6.1
64
61
  type: :runtime
65
62
  prerelease: false
66
63
  version_requirements: !ruby/object:Gem::Requirement
67
64
  requirements:
68
65
  - - "~>"
69
66
  - !ruby/object:Gem::Version
70
- version: '1.7'
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: 1.7.5
67
+ version: 0.6.1
74
68
  email:
75
69
  - eljean@live.com
76
70
  executables: []
@@ -87,6 +81,7 @@ files:
87
81
  - lib/active_cached_resource/caching_strategies/sql_cache.rb
88
82
  - lib/active_cached_resource/collection.rb
89
83
  - lib/active_cached_resource/configuration.rb
84
+ - lib/active_cached_resource/constants.rb
90
85
  - lib/active_cached_resource/logger.rb
91
86
  - lib/active_cached_resource/model.rb
92
87
  - lib/active_cached_resource/version.rb
@@ -141,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
136
  - !ruby/object:Gem::Version
142
137
  version: '0'
143
138
  requirements: []
144
- rubygems_version: 3.6.2
139
+ rubygems_version: 3.6.3
145
140
  specification_version: 4
146
141
  summary: ActiveResource, but with a caching layer.
147
142
  test_files: []