graphql-fragment_cache 1.6.0 → 1.7.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +96 -5
- data/lib/.rbnext/2.3/graphql/fragment_cache/cache_key_builder.rb +196 -0
- data/lib/.rbnext/2.7/graphql/fragment_cache/cache_key_builder.rb +14 -10
- data/lib/graphql/fragment_cache.rb +5 -0
- data/lib/graphql/fragment_cache/cache_key_builder.rb +14 -10
- data/lib/graphql/fragment_cache/field_extension.rb +7 -1
- data/lib/graphql/fragment_cache/fragment.rb +1 -0
- data/lib/graphql/fragment_cache/object_helpers.rb +7 -0
- data/lib/graphql/fragment_cache/rails/cache_key_builder.rb +1 -0
- data/lib/graphql/fragment_cache/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f193c09fd4f7682db9677d754964852e63b7541f2f2fa6d52ea81c8ee8b894fd
|
4
|
+
data.tar.gz: 328017637ba3c31c9c9af6c6beacdb63e696b13d6065c12d73b02874fb2e29d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9fd90630bd8a8505e2fe1a1277b621d22e2c62a23270a87a5487b56fdde57b980859611f80bfeb956915b581e396ee89a75da11548edebddf321ba45a0640e6c
|
7
|
+
data.tar.gz: 43fa3b1709999e950b8002f7764e0e63bdacd9aa32db644ead959e6cc12c0df8d92c26423300af4aad59139a8a30290a2c82cfe0cc4ff412656c20d4c64919e4
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.7.0 (2021-04-30)
|
6
|
+
|
7
|
+
- [PR#62](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/62) Add a way to force a cache miss ([@jeromedalbert][])
|
8
|
+
- [PR#61](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/61) Add conditional caching ([@jeromedalbert][])
|
9
|
+
- [PR#64](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/64) Add a cache namespace ([@jeromedalbert][])
|
10
|
+
- [PR#63](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/63) Add a configure block notation ([@jeromedalbert][])
|
11
|
+
|
5
12
|
## 1.6.0 (2021-03-13)
|
6
13
|
|
7
14
|
- [PR#54](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/54) Include arguments in selections_cache_key ([@bbugh][])
|
@@ -99,3 +106,4 @@
|
|
99
106
|
[@ssnickolay]: https://github.com/ssnickolay
|
100
107
|
[@reabiliti]: https://github.com/reabiliti
|
101
108
|
[@bbugh]: https://github.com/bbugh
|
109
|
+
[@jeromedalbert]: https://github.com/jeromedalbert
|
data/README.md
CHANGED
@@ -80,11 +80,19 @@ end
|
|
80
80
|
|
81
81
|
## Cache key generation
|
82
82
|
|
83
|
-
Cache keys consist of implicit and explicit
|
83
|
+
Cache keys consist of the following parts: namespace, implicit key, and explicit key.
|
84
|
+
|
85
|
+
### Cache namespace
|
86
|
+
|
87
|
+
You can optionally define a namespace that will be prefixed to every cache key:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
GraphQL::FragmentCache.namespace = "my-prefix"
|
91
|
+
```
|
84
92
|
|
85
93
|
### Implicit cache key
|
86
94
|
|
87
|
-
Implicit part of a cache key
|
95
|
+
Implicit part of a cache key contains the information about the schema and the current query. It includes:
|
88
96
|
|
89
97
|
- Hex gsdigest of the schema definition (to make sure cache is cleared when the schema changes).
|
90
98
|
- The current query fingerprint consisting of a _path_ to the field, arguments information and the selections set.
|
@@ -155,7 +163,7 @@ class QueryType < BaseObject
|
|
155
163
|
end
|
156
164
|
```
|
157
165
|
|
158
|
-
### User-provided cache key
|
166
|
+
### User-provided cache key (custom key)
|
159
167
|
|
160
168
|
In most cases you want your cache key to depend on the resolved object (say, `ActiveRecord` model). You can do that by passing an argument to the `#cache_fragment` method in a similar way to Rails views [`#cache` method](https://guides.rubyonrails.org/caching_with_rails.html#fragment-caching):
|
161
169
|
|
@@ -184,6 +192,36 @@ cache_fragment(post)
|
|
184
192
|
cache_fragment(post) { post }
|
185
193
|
```
|
186
194
|
|
195
|
+
Using literals: Even when using a same string for all queries, the cache changes per argument and per selection set (because of the query_key).
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
def post(id:)
|
199
|
+
cache_fragment("find_post") { Post.find(id) }
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
Combining with options:
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
def post(id:)
|
207
|
+
cache_fragment("find_post", expires_in: 5.minutes) { Post.find(id) }
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
Dynamic cache key:
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
def post(id:)
|
215
|
+
last_updated_at = Post.select(:updated_at).find_by(id: id)&.updated_at
|
216
|
+
cache_fragment(last_updated_at, expires_in: 5.minutes) { Post.find(id) }
|
217
|
+
end
|
218
|
+
```
|
219
|
+
|
220
|
+
Note the usage of `.select(:updated_at)` at the cache key field to make this verifying query as fastest and light as possible.
|
221
|
+
|
222
|
+
You can also add touch options for the belongs_to association e.g author's `belongs_to: :post` to have a `touch: true`.
|
223
|
+
So that it invalidates the Post when the author is updated.
|
224
|
+
|
187
225
|
When using `cache_fragment:` option, it's only possible to use the resolved value as a cache key by setting:
|
188
226
|
|
189
227
|
```ruby
|
@@ -260,12 +298,42 @@ class QueryType < BaseObject
|
|
260
298
|
end
|
261
299
|
```
|
262
300
|
|
301
|
+
## Conditional caching
|
302
|
+
|
303
|
+
Use the `if:` (or `unless:`) option:
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
def post(id:)
|
307
|
+
cache_fragment(if: current_user.nil?) { Post.find(id) }
|
308
|
+
end
|
309
|
+
|
310
|
+
# or
|
311
|
+
|
312
|
+
field :post, PostType, cache_fragment: {if: -> { current_user.nil? }} do
|
313
|
+
argument :id, ID, required: true
|
314
|
+
end
|
315
|
+
```
|
316
|
+
|
317
|
+
## Renewing the cache
|
318
|
+
|
319
|
+
You can force the cache to renew during query execution by adding
|
320
|
+
`renew_cache: true` to the query context:
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
MyAppSchema.execute("query { posts { title } }", context: {renew_cache: true})
|
324
|
+
```
|
325
|
+
|
326
|
+
This will treat any cached value as missing even if it's present, and store
|
327
|
+
fresh new computed values in the cache. This can be useful for cache warmers.
|
328
|
+
|
263
329
|
## Cache storage and options
|
264
330
|
|
265
331
|
It's up to your to decide which caching engine to use, all you need is to configure the cache store:
|
266
332
|
|
267
333
|
```ruby
|
268
|
-
GraphQL::FragmentCache.
|
334
|
+
GraphQL::FragmentCache.configure do |config|
|
335
|
+
config.cache_store = MyCacheStore.new
|
336
|
+
end
|
269
337
|
```
|
270
338
|
|
271
339
|
Or, in Rails:
|
@@ -350,7 +418,30 @@ This can reduce a number of cache calls but _increase_ memory usage, because the
|
|
350
418
|
|
351
419
|
## Limitations
|
352
420
|
|
353
|
-
|
421
|
+
1. `Schema#execute`, [graphql-batch](https://github.com/Shopify/graphql-batch) and _graphql-ruby-fragment_cache_ do not [play well](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/issues/45) together. The problem appears when `cache_fragment` is _inside_ the `.then` block:
|
422
|
+
|
423
|
+
```ruby
|
424
|
+
def cached_author_inside_batch
|
425
|
+
AuthorLoader.load(object).then do |author|
|
426
|
+
cache_fragment(author, context: context)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
```
|
430
|
+
|
431
|
+
The problem is that context is not [properly populated](https://github.com/rmosolgo/graphql-ruby/issues/3397) inside the block (the gem uses `:current_path` to build the cache key). There are two possible workarounds: use [dataloaders](https://graphql-ruby.org/dataloader/overview.html) or manage `:current_path` manually:
|
432
|
+
|
433
|
+
```ruby
|
434
|
+
def cached_author_inside_batch
|
435
|
+
outer_path = context.namespace(:interpreter)[:current_path]
|
436
|
+
|
437
|
+
AuthorLoader.load(object).then do |author|
|
438
|
+
context.namespace(:interpreter)[:current_path] = outer_path
|
439
|
+
cache_fragment(author, context: context)
|
440
|
+
end
|
441
|
+
end
|
442
|
+
```
|
443
|
+
|
444
|
+
2. Caching does not work for Union types, because of the `Lookahead` implementation: it requires the exact type to be passed to the `selection` method (you can find the [discussion](https://github.com/rmosolgo/graphql-ruby/pull/3007) here). This method is used for cache key building, and I haven't found a workaround yet ([PR in progress](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/30)). If you get `Failed to look ahead the field` error — please pass `query_cache_key` explicitly:
|
354
445
|
|
355
446
|
```ruby
|
356
447
|
field :cached_avatar_url, String, null: false
|
@@ -0,0 +1,196 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "digest"
|
5
|
+
|
6
|
+
using RubyNext
|
7
|
+
|
8
|
+
module GraphQL
|
9
|
+
module FragmentCache
|
10
|
+
using Ext
|
11
|
+
|
12
|
+
using(Module.new {
|
13
|
+
refine Array do
|
14
|
+
def traverse_argument(argument)
|
15
|
+
return argument unless argument.is_a?(GraphQL::Schema::InputObject)
|
16
|
+
|
17
|
+
"{#{argument.map { |_1, _2| "#{_1}:#{traverse_argument(_2)}" }.sort.join(",")}}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_selections_key
|
21
|
+
map { |val|
|
22
|
+
children = val.selections.empty? ? "" : "[#{val.selections.to_selections_key}]"
|
23
|
+
|
24
|
+
field_name = val.field.name
|
25
|
+
|
26
|
+
unless val.arguments.empty?
|
27
|
+
args = val.arguments.map { |_1, _2| "#{_1}:#{traverse_argument(_2)}" }.sort.join(",")
|
28
|
+
field_name += "(#{args})"
|
29
|
+
end
|
30
|
+
|
31
|
+
"#{field_name}#{children}"
|
32
|
+
}.join(".")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
refine ::GraphQL::Language::Nodes::AbstractNode do
|
37
|
+
def alias?(_)
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
refine ::GraphQL::Language::Nodes::Field do
|
43
|
+
def alias?(val)
|
44
|
+
self.alias == val
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
refine ::GraphQL::Execution::Lookahead do
|
49
|
+
def selection_with_alias(name, **kwargs)
|
50
|
+
return selection(name, **kwargs) if selects?(name, **kwargs)
|
51
|
+
alias_selection(name, **kwargs)
|
52
|
+
end
|
53
|
+
|
54
|
+
def alias_selection(name, selected_type: @selected_type, arguments: nil)
|
55
|
+
return alias_selections[name] if alias_selections.key?(name)
|
56
|
+
|
57
|
+
alias_node = lookup_alias_node(ast_nodes, name)
|
58
|
+
return ::GraphQL::Execution::Lookahead::NULL_LOOKAHEAD unless alias_node
|
59
|
+
|
60
|
+
next_field_name = alias_node.name
|
61
|
+
|
62
|
+
# From https://github.com/rmosolgo/graphql-ruby/blob/1a9a20f3da629e63ea8e5ee8400be82218f9edc3/lib/graphql/execution/lookahead.rb#L91
|
63
|
+
next_field_defn = get_class_based_field(selected_type, next_field_name)
|
64
|
+
|
65
|
+
alias_selections[name] =
|
66
|
+
if next_field_defn
|
67
|
+
next_nodes = []
|
68
|
+
arguments = @query.arguments_for(alias_node, next_field_defn)
|
69
|
+
arguments = arguments.is_a?(::GraphQL::Execution::Interpreter::Arguments) ? arguments.keyword_arguments : arguments
|
70
|
+
@ast_nodes.each do |ast_node|
|
71
|
+
ast_node.selections.each do |selection|
|
72
|
+
find_selected_nodes(selection, next_field_name, next_field_defn, arguments: arguments, matches: next_nodes)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if next_nodes.any?
|
77
|
+
::GraphQL::Execution::Lookahead.new(query: @query, ast_nodes: next_nodes, field: next_field_defn, owner_type: selected_type)
|
78
|
+
else
|
79
|
+
::GraphQL::Execution::Lookahead::NULL_LOOKAHEAD
|
80
|
+
end
|
81
|
+
else
|
82
|
+
::GraphQL::Execution::Lookahead::NULL_LOOKAHEAD
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def alias_selections
|
87
|
+
return @alias_selections if defined?(@alias_selections)
|
88
|
+
@alias_selections ||= {}
|
89
|
+
end
|
90
|
+
|
91
|
+
def lookup_alias_node(nodes, name)
|
92
|
+
return if nodes.empty?
|
93
|
+
|
94
|
+
nodes.find do |node|
|
95
|
+
if node.is_a?(GraphQL::Language::Nodes::FragmentSpread)
|
96
|
+
node = @query.fragments[node.name]
|
97
|
+
raise("Invariant: Can't look ahead to nonexistent fragment #{node.name} (found: #{@query.fragments.keys})") unless node
|
98
|
+
end
|
99
|
+
|
100
|
+
return node if node.alias?(name)
|
101
|
+
child = lookup_alias_node(node.children, name)
|
102
|
+
return child if child
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
})
|
107
|
+
|
108
|
+
# Builds cache key for fragment
|
109
|
+
class CacheKeyBuilder
|
110
|
+
using RubyNext
|
111
|
+
|
112
|
+
class << self
|
113
|
+
def call(**options)
|
114
|
+
new(**options).build
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
attr_reader :query, :path, :object, :schema
|
119
|
+
|
120
|
+
def initialize(object: nil, query:, path:, **options)
|
121
|
+
@object = object
|
122
|
+
@query = query
|
123
|
+
@schema = query.schema
|
124
|
+
@path = path
|
125
|
+
@options = options
|
126
|
+
end
|
127
|
+
|
128
|
+
def build
|
129
|
+
[
|
130
|
+
GraphQL::FragmentCache.namespace,
|
131
|
+
implicit_cache_key,
|
132
|
+
object_cache_key
|
133
|
+
].compact.join("/")
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def implicit_cache_key
|
139
|
+
Digest::SHA1.hexdigest("#{schema_cache_key}/#{query_cache_key}")
|
140
|
+
end
|
141
|
+
|
142
|
+
def schema_cache_key
|
143
|
+
@options.fetch(:schema_cache_key) { schema.schema_cache_key }
|
144
|
+
end
|
145
|
+
|
146
|
+
def query_cache_key
|
147
|
+
@options.fetch(:query_cache_key) { "#{path_cache_key}[#{selections_cache_key}]" }
|
148
|
+
end
|
149
|
+
|
150
|
+
def selections_cache_key
|
151
|
+
current_root =
|
152
|
+
path.reduce(query.lookahead) { |lkhd, field_name|
|
153
|
+
# Handle cached fields inside collections:
|
154
|
+
next lkhd if field_name.is_a?(Integer)
|
155
|
+
|
156
|
+
lkhd.selection_with_alias(field_name)
|
157
|
+
}
|
158
|
+
|
159
|
+
current_root.selections.to_selections_key
|
160
|
+
end
|
161
|
+
|
162
|
+
def path_cache_key
|
163
|
+
@options.fetch(:path_cache_key) do
|
164
|
+
lookahead = query.lookahead
|
165
|
+
|
166
|
+
path.map { |field_name|
|
167
|
+
# Handle cached fields inside collections:
|
168
|
+
next field_name if field_name.is_a?(Integer)
|
169
|
+
|
170
|
+
lookahead = lookahead.selection_with_alias(field_name)
|
171
|
+
raise "Failed to look ahead the field: #{field_name}" if lookahead.is_a?(::GraphQL::Execution::Lookahead::NullLookahead)
|
172
|
+
|
173
|
+
next lookahead.field.name if lookahead.arguments.empty?
|
174
|
+
|
175
|
+
args = lookahead.arguments.map { |_1, _2| "#{_1}:#{traverse_argument(_2)}" }.sort.join(",")
|
176
|
+
"#{lookahead.field.name}(#{args})"
|
177
|
+
}.join("/")
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def traverse_argument(argument)
|
182
|
+
return argument unless argument.is_a?(GraphQL::Schema::InputObject)
|
183
|
+
|
184
|
+
"{#{argument.map { |_1, _2| "#{_1}:#{traverse_argument(_2)}" }.sort.join(",")}}"
|
185
|
+
end
|
186
|
+
|
187
|
+
def object_cache_key
|
188
|
+
@options[:object_cache_key] || object_key(object)
|
189
|
+
end
|
190
|
+
|
191
|
+
def object_key(obj)
|
192
|
+
((!obj.nil?) || nil) && obj._graphql_cache_key
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -126,19 +126,19 @@ module GraphQL
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def build
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
else
|
135
|
-
base_key
|
136
|
-
end
|
137
|
-
end
|
129
|
+
[
|
130
|
+
GraphQL::FragmentCache.namespace,
|
131
|
+
implicit_cache_key,
|
132
|
+
object_cache_key
|
133
|
+
].compact.join("/")
|
138
134
|
end
|
139
135
|
|
140
136
|
private
|
141
137
|
|
138
|
+
def implicit_cache_key
|
139
|
+
Digest::SHA1.hexdigest("#{schema_cache_key}/#{query_cache_key}")
|
140
|
+
end
|
141
|
+
|
142
142
|
def schema_cache_key
|
143
143
|
@options.fetch(:schema_cache_key) { schema.schema_cache_key }
|
144
144
|
end
|
@@ -184,8 +184,12 @@ module GraphQL
|
|
184
184
|
"{#{argument.map { |_1, _2| "#{_1}:#{traverse_argument(_2)}" }.sort.join(",")}}"
|
185
185
|
end
|
186
186
|
|
187
|
+
def object_cache_key
|
188
|
+
@options[:object_cache_key] || object_key(object)
|
189
|
+
end
|
190
|
+
|
187
191
|
def object_key(obj)
|
188
|
-
obj
|
192
|
+
obj&._graphql_cache_key
|
189
193
|
end
|
190
194
|
end
|
191
195
|
end
|
@@ -21,6 +21,7 @@ module GraphQL
|
|
21
21
|
module FragmentCache
|
22
22
|
class << self
|
23
23
|
attr_reader :cache_store
|
24
|
+
attr_accessor :namespace
|
24
25
|
|
25
26
|
def use(schema_defn, options = {})
|
26
27
|
verify_interpreter_and_analysis!(schema_defn)
|
@@ -32,6 +33,10 @@ module GraphQL
|
|
32
33
|
GraphQL::Pagination::Connections.prepend(Connections::Patch)
|
33
34
|
end
|
34
35
|
|
36
|
+
def configure
|
37
|
+
yield self
|
38
|
+
end
|
39
|
+
|
35
40
|
def cache_store=(store)
|
36
41
|
unless store.respond_to?(:read)
|
37
42
|
raise ArgumentError, "Store must implement #read(key) method"
|
@@ -126,19 +126,19 @@ module GraphQL
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def build
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
else
|
135
|
-
base_key
|
136
|
-
end
|
137
|
-
end
|
129
|
+
[
|
130
|
+
GraphQL::FragmentCache.namespace,
|
131
|
+
implicit_cache_key,
|
132
|
+
object_cache_key
|
133
|
+
].compact.join("/")
|
138
134
|
end
|
139
135
|
|
140
136
|
private
|
141
137
|
|
138
|
+
def implicit_cache_key
|
139
|
+
Digest::SHA1.hexdigest("#{schema_cache_key}/#{query_cache_key}")
|
140
|
+
end
|
141
|
+
|
142
142
|
def schema_cache_key
|
143
143
|
@options.fetch(:schema_cache_key) { schema.schema_cache_key }
|
144
144
|
end
|
@@ -184,8 +184,12 @@ module GraphQL
|
|
184
184
|
"{#{argument.map { "#{_1}:#{traverse_argument(_2)}" }.sort.join(",")}}"
|
185
185
|
end
|
186
186
|
|
187
|
+
def object_cache_key
|
188
|
+
@options[:object_cache_key] || object_key(object)
|
189
|
+
end
|
190
|
+
|
187
191
|
def object_key(obj)
|
188
|
-
obj
|
192
|
+
obj&._graphql_cache_key
|
189
193
|
end
|
190
194
|
end
|
191
195
|
end
|
@@ -39,6 +39,13 @@ module GraphQL
|
|
39
39
|
def resolve(object:, arguments:, **_options)
|
40
40
|
resolved_value = NOT_RESOLVED
|
41
41
|
|
42
|
+
if @cache_options[:if].is_a?(Proc)
|
43
|
+
@cache_options[:if] = object.instance_exec(&@cache_options[:if])
|
44
|
+
end
|
45
|
+
if @cache_options[:unless].is_a?(Proc)
|
46
|
+
@cache_options[:unless] = object.instance_exec(&@cache_options[:unless])
|
47
|
+
end
|
48
|
+
|
42
49
|
object_for_key = if @context_key
|
43
50
|
Array(@context_key).map { |key| object.context[key] }
|
44
51
|
elsif @cache_key == :object
|
@@ -46,7 +53,6 @@ module GraphQL
|
|
46
53
|
elsif @cache_key == :value
|
47
54
|
resolved_value = yield(object, arguments)
|
48
55
|
end
|
49
|
-
|
50
56
|
cache_fragment_options = @cache_options.merge(object: object_for_key)
|
51
57
|
|
52
58
|
object.cache_fragment(**cache_fragment_options) do
|
@@ -25,6 +25,13 @@ module GraphQL
|
|
25
25
|
def cache_fragment(object_to_cache = NO_OBJECT, **options, &block)
|
26
26
|
raise ArgumentError, "Block or argument must be provided" unless block_given? || object_to_cache != NO_OBJECT
|
27
27
|
|
28
|
+
if options.key?(:if) || options.key?(:unless)
|
29
|
+
disabled = options.key?(:if) ? !options.delete(:if) : options.delete(:unless)
|
30
|
+
if disabled
|
31
|
+
return block_given? ? block.call : object_to_cache
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
28
35
|
options[:object] = object_to_cache if object_to_cache != NO_OBJECT
|
29
36
|
|
30
37
|
context_to_use = options.delete(:context)
|
@@ -5,6 +5,7 @@ module GraphQL
|
|
5
5
|
# Extends key builder to use .expand_cache_key in Rails
|
6
6
|
class CacheKeyBuilder
|
7
7
|
def object_key(obj)
|
8
|
+
return nil if obj.nil?
|
8
9
|
return obj.graphql_cache_key if obj.respond_to?(:graphql_cache_key)
|
9
10
|
return obj.cache_key_with_version if obj.respond_to?(:cache_key_with_version)
|
10
11
|
return obj.cache_key if obj.respond_to?(:cache_key)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-fragment_cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- DmitryTsepelev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -176,6 +176,7 @@ files:
|
|
176
176
|
- README.md
|
177
177
|
- bin/console
|
178
178
|
- bin/setup
|
179
|
+
- lib/.rbnext/2.3/graphql/fragment_cache/cache_key_builder.rb
|
179
180
|
- lib/.rbnext/2.3/graphql/fragment_cache/memory_store.rb
|
180
181
|
- lib/.rbnext/2.7/graphql/fragment_cache/cache_key_builder.rb
|
181
182
|
- lib/.rbnext/2.7/graphql/fragment_cache/ext/graphql_cache_key.rb
|