active_cached_resource 0.1.5 → 0.1.7

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 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: []