graphql-fragment_cache 0.1.6 → 1.0.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/CHANGELOG.md +21 -0
- data/README.md +1 -1
- data/lib/.rbnext/2.7/graphql/fragment_cache/cache_key_builder.rb +6 -0
- data/lib/graphql/fragment_cache.rb +11 -5
- data/lib/graphql/fragment_cache/cache_key_builder.rb +6 -0
- data/lib/graphql/fragment_cache/cacher.rb +1 -3
- data/lib/graphql/fragment_cache/connections/patch.rb +26 -0
- data/lib/graphql/fragment_cache/fragment.rb +15 -9
- data/lib/graphql/fragment_cache/memory_store.rb +8 -0
- data/lib/graphql/fragment_cache/object_helpers.rb +2 -42
- data/lib/graphql/fragment_cache/schema/instrumentation.rb +23 -0
- data/lib/graphql/fragment_cache/schema/patch.rb +16 -0
- data/lib/graphql/fragment_cache/schema/tracer.rb +35 -0
- data/lib/graphql/fragment_cache/version.rb +1 -1
- metadata +20 -5
- data/lib/.rbnext/2.7/graphql/fragment_cache/cacher.rb +0 -20
- data/lib/graphql/fragment_cache/instrumentation.rb +0 -21
- data/lib/graphql/fragment_cache/schema_patch.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fd575d2efddb52ef6d0f878b40823baae40cedec5aa683ba5f6a1b39b98bffe
|
4
|
+
data.tar.gz: eba1c06d3650d395575bd96927f831fc206f797b47afa9ebfcfff9adbf2ecf1d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fe016ab01f8b8076b1cc6680f8a09ad9bf1ab9d7f5c798a308465fd0d6d80dd6da24ef5855aa35660d9b8cce0529ab59cb6a45b7b971c58d4f8a9e761b80ff9
|
7
|
+
data.tar.gz: 0430b991c22524be88e3741f700d5c02ac65186f4cf40e7f06440b737c345bba8e44748a9e8d6ef1293356e21ee7560595b5e1563c28da7bb5f88008f7174360
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,26 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.0.3 (2020-08-31)
|
6
|
+
|
7
|
+
- [PR#29](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/29) Cache result JSON instead of connection objects ([@DmitryTsepelev][])
|
8
|
+
|
9
|
+
## 1.0.2 (2020-08-19)
|
10
|
+
|
11
|
+
- [PR#28](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/28) Support #keys method for GraphQL::FragmentCache::MemoryStore instance ([@reabiliti][])
|
12
|
+
|
13
|
+
## 1.0.1 (2020-06-17)
|
14
|
+
|
15
|
+
- [PR#25](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/25) Support fragments with aliases for CacheKeyBuilder ([@DmitryTsepelev][])
|
16
|
+
|
17
|
+
## 1.0.0 (2020-06-13)
|
18
|
+
|
19
|
+
- [PR#24](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/24) Add nil caching. **BREAKING CHANGE**: custom cache stores must also implement `#exist?(key)` method ([@DmitryTsepelev][])
|
20
|
+
|
21
|
+
## 0.1.7 (2020-06-02)
|
22
|
+
|
23
|
+
- [PR#23](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/23) Avoid extra queries after restoring connection from cache ([@DmitryTsepelev][])
|
24
|
+
|
5
25
|
## 0.1.6 (2020-05-30)
|
6
26
|
|
7
27
|
- [PR#22](https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/pull/22) Properly cache entites inside collections ([@DmitryTsepelev][])
|
@@ -35,3 +55,4 @@
|
|
35
55
|
[@DmitryTsepelev]: https://github.com/DmitryTsepelev
|
36
56
|
[@palkan]: https://github.com/palkan
|
37
57
|
[@ssnickolay]: https://github.com/ssnickolay
|
58
|
+
[@reabiliti]: https://github.com/reabiliti
|
data/README.md
CHANGED
@@ -252,7 +252,7 @@ Rails.application.configure do |config|
|
|
252
252
|
end
|
253
253
|
```
|
254
254
|
|
255
|
-
⚠️ Cache store must implement `#read(key)
|
255
|
+
⚠️ Cache store must implement `#read(key)`, `#write(key, value, **options)` and `#exist?(key)` methods.
|
256
256
|
|
257
257
|
The gem provides only in-memory store out-of-the-box (`GraphQL::FragmentCache::MemoryStore`). It's used by default.
|
258
258
|
|
@@ -76,7 +76,13 @@ module GraphQL
|
|
76
76
|
|
77
77
|
def lookup_alias_node(nodes, name)
|
78
78
|
return if nodes.empty?
|
79
|
+
|
79
80
|
nodes.find do |node|
|
81
|
+
if node.is_a?(GraphQL::Language::Nodes::FragmentSpread)
|
82
|
+
node = @query.fragments[node.name]
|
83
|
+
raise("Invariant: Can't look ahead to nonexistent fragment #{node.name} (found: #{@query.fragments.keys})") unless node
|
84
|
+
end
|
85
|
+
|
80
86
|
return node if node.alias?(name)
|
81
87
|
child = lookup_alias_node(node.children, name)
|
82
88
|
return child if child
|
@@ -4,10 +4,13 @@ require "graphql"
|
|
4
4
|
|
5
5
|
require "graphql/fragment_cache/ext/context_fragments"
|
6
6
|
require "graphql/fragment_cache/ext/graphql_cache_key"
|
7
|
-
|
8
|
-
require "graphql/fragment_cache/schema_patch"
|
9
7
|
require "graphql/fragment_cache/object"
|
10
|
-
|
8
|
+
|
9
|
+
require "graphql/fragment_cache/connections/patch"
|
10
|
+
|
11
|
+
require "graphql/fragment_cache/schema/patch"
|
12
|
+
require "graphql/fragment_cache/schema/tracer"
|
13
|
+
require "graphql/fragment_cache/schema/instrumentation"
|
11
14
|
|
12
15
|
require "graphql/fragment_cache/memory_store"
|
13
16
|
|
@@ -22,8 +25,11 @@ module GraphQL
|
|
22
25
|
def use(schema_defn, options = {})
|
23
26
|
verify_interpreter!(schema_defn)
|
24
27
|
|
25
|
-
schema_defn.
|
26
|
-
schema_defn.
|
28
|
+
schema_defn.tracer(Schema::Tracer)
|
29
|
+
schema_defn.instrument(:query, Schema::Instrumentation)
|
30
|
+
schema_defn.extend(Schema::Patch)
|
31
|
+
|
32
|
+
GraphQL::Pagination::Connections.prepend(Connections::Patch)
|
27
33
|
end
|
28
34
|
|
29
35
|
def cache_store=(store)
|
@@ -76,7 +76,13 @@ module GraphQL
|
|
76
76
|
|
77
77
|
def lookup_alias_node(nodes, name)
|
78
78
|
return if nodes.empty?
|
79
|
+
|
79
80
|
nodes.find do |node|
|
81
|
+
if node.is_a?(GraphQL::Language::Nodes::FragmentSpread)
|
82
|
+
node = @query.fragments[node.name]
|
83
|
+
raise("Invariant: Can't look ahead to nonexistent fragment #{node.name} (found: #{@query.fragments.keys})") unless node
|
84
|
+
end
|
85
|
+
|
80
86
|
return node if node.alias?(name)
|
81
87
|
child = lookup_alias_node(node.children, name)
|
82
88
|
return child if child
|
@@ -10,9 +10,7 @@ module GraphQL
|
|
10
10
|
def call(query)
|
11
11
|
return unless query.context.fragments?
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
query.context.fragments.each { _1.persist(final_value) }
|
13
|
+
query.context.fragments.each(&:persist)
|
16
14
|
end
|
17
15
|
end
|
18
16
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module FragmentCache
|
5
|
+
module Connections
|
6
|
+
# Patches GraphQL::Pagination::Connections to support raw values
|
7
|
+
module Patch
|
8
|
+
if Gem::Dependency.new("graphql", ">= 1.11.0").match?("graphql", GraphQL::VERSION)
|
9
|
+
def wrap(field, parent, items, arguments, context, *options)
|
10
|
+
raw_value?(items) ? items : super
|
11
|
+
end
|
12
|
+
else
|
13
|
+
def wrap(field, object, arguments, context, *options)
|
14
|
+
raw_value?(object) ? object : super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def raw_value?(value)
|
21
|
+
GraphQL::Execution::Interpreter::RawValue === value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -6,22 +6,24 @@ module GraphQL
|
|
6
6
|
module FragmentCache
|
7
7
|
# Represents a single fragment to cache
|
8
8
|
class Fragment
|
9
|
-
attr_reader :options, :path, :context
|
10
|
-
|
11
|
-
attr_writer :raw_connection
|
9
|
+
attr_reader :options, :path, :context
|
12
10
|
|
13
11
|
def initialize(context, **options)
|
14
12
|
@context = context
|
15
13
|
@options = options
|
16
|
-
@path =
|
14
|
+
@path = interpreter_context[:current_path]
|
17
15
|
end
|
18
16
|
|
17
|
+
NIL_IN_CACHE = Object.new
|
18
|
+
|
19
19
|
def read
|
20
|
-
FragmentCache.cache_store.read(cache_key)
|
20
|
+
FragmentCache.cache_store.read(cache_key).tap do |cached|
|
21
|
+
return NIL_IN_CACHE if cached.nil? && FragmentCache.cache_store.exist?(cache_key)
|
22
|
+
end
|
21
23
|
end
|
22
24
|
|
23
|
-
def persist
|
24
|
-
value =
|
25
|
+
def persist
|
26
|
+
value = final_value.dig(*path)
|
25
27
|
FragmentCache.cache_store.write(cache_key, value, **options)
|
26
28
|
end
|
27
29
|
|
@@ -31,8 +33,12 @@ module GraphQL
|
|
31
33
|
@cache_key ||= CacheKeyBuilder.call(path: path, query: context.query, **options)
|
32
34
|
end
|
33
35
|
|
34
|
-
def
|
35
|
-
|
36
|
+
def interpreter_context
|
37
|
+
context.namespace(:interpreter)
|
38
|
+
end
|
39
|
+
|
40
|
+
def final_value
|
41
|
+
@final_value ||= interpreter_context[:runtime].final_value
|
36
42
|
end
|
37
43
|
end
|
38
44
|
end
|
@@ -6,8 +6,6 @@ module GraphQL
|
|
6
6
|
module FragmentCache
|
7
7
|
using Ext
|
8
8
|
|
9
|
-
RawConnection = Struct.new(:items, :nodes, :paged_nodes_offset, :has_previous_page, :has_next_page)
|
10
|
-
|
11
9
|
# Adds #cache_fragment method
|
12
10
|
module ObjectHelpers
|
13
11
|
extend Forwardable
|
@@ -24,41 +22,16 @@ module GraphQL
|
|
24
22
|
fragment = Fragment.new(context, options)
|
25
23
|
|
26
24
|
if (cached = fragment.read)
|
27
|
-
return
|
25
|
+
return cached == Fragment::NIL_IN_CACHE ? nil : raw_value(cached)
|
28
26
|
end
|
29
27
|
|
30
28
|
(block_given? ? block.call : object_to_cache).tap do |resolved_value|
|
31
|
-
|
29
|
+
context.fragments << fragment
|
32
30
|
end
|
33
31
|
end
|
34
32
|
|
35
33
|
private
|
36
34
|
|
37
|
-
def restore_cached_value(cached)
|
38
|
-
connection? ? restore_cached_connection(cached) : raw_value(cached)
|
39
|
-
end
|
40
|
-
|
41
|
-
def cache_value(resolved_value, fragment)
|
42
|
-
if connection?
|
43
|
-
unless context.schema.new_connections?
|
44
|
-
raise StandardError,
|
45
|
-
"GraphQL::Pagination::Connections should be enabled for connection caching"
|
46
|
-
end
|
47
|
-
|
48
|
-
connection = wrap_connection(resolved_value)
|
49
|
-
|
50
|
-
fragment.raw_connection = RawConnection.new(
|
51
|
-
connection.items,
|
52
|
-
connection.nodes,
|
53
|
-
connection.instance_variable_get(:@paged_nodes_offset),
|
54
|
-
connection.has_previous_page,
|
55
|
-
connection.has_next_page
|
56
|
-
)
|
57
|
-
end
|
58
|
-
|
59
|
-
context.fragments << fragment
|
60
|
-
end
|
61
|
-
|
62
35
|
def field
|
63
36
|
interpreter_context[:current_field]
|
64
37
|
end
|
@@ -66,19 +39,6 @@ module GraphQL
|
|
66
39
|
def interpreter_context
|
67
40
|
@interpreter_context ||= context.namespace(:interpreter)
|
68
41
|
end
|
69
|
-
|
70
|
-
def restore_cached_connection(raw_connection)
|
71
|
-
wrap_connection(raw_connection.items).tap do |connection|
|
72
|
-
connection.instance_variable_set(:@nodes, raw_connection.nodes)
|
73
|
-
connection.instance_variable_set(:@paged_nodes_offset, raw_connection.paged_nodes_offset)
|
74
|
-
connection.instance_variable_set(:@has_previous_page, raw_connection.has_previous_page)
|
75
|
-
connection.instance_variable_set(:@has_next_page, raw_connection.has_next_page)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def wrap_connection(object)
|
80
|
-
context.schema.connections.wrap(field, object, interpreter_context[:current_arguments], context)
|
81
|
-
end
|
82
42
|
end
|
83
43
|
end
|
84
44
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "graphql/fragment_cache/cacher"
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
module FragmentCache
|
7
|
+
module Schema
|
8
|
+
# Adds hook for saving cached values after query is resolved
|
9
|
+
module Instrumentation
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def before_query(query)
|
13
|
+
end
|
14
|
+
|
15
|
+
def after_query(query)
|
16
|
+
return unless query.valid?
|
17
|
+
|
18
|
+
Cacher.call(query)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "digest/sha1"
|
4
|
+
|
5
|
+
module GraphQL
|
6
|
+
module FragmentCache
|
7
|
+
module Schema
|
8
|
+
# Patches GraphQL::Schema to support fragment cache
|
9
|
+
module Patch
|
10
|
+
def schema_cache_key
|
11
|
+
@schema_cache_key ||= Digest::SHA1.hexdigest(to_definition)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
# Plugin definition
|
5
|
+
module FragmentCache
|
6
|
+
module Schema
|
7
|
+
class Tracer
|
8
|
+
using Ext
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def trace(key, data)
|
12
|
+
yield.tap do |resolved_value|
|
13
|
+
next unless connection_field?(key, data)
|
14
|
+
|
15
|
+
verify_connections!(data[:query].context)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def connection_field?(key, data)
|
22
|
+
key == "execute_field" && data[:field].connection?
|
23
|
+
end
|
24
|
+
|
25
|
+
def verify_connections!(context)
|
26
|
+
return if context.schema.new_connections?
|
27
|
+
|
28
|
+
raise StandardError,
|
29
|
+
"GraphQL::Pagination::Connections should be enabled for connection caching"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
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: 0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- DmitryTsepelev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0.6'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: ruby-next-parser
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 2.8.0.7
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 2.8.0.7
|
139
153
|
description: Fragment cache for graphql-ruby
|
140
154
|
email:
|
141
155
|
- dmitry.a.tsepelev@gmail.com
|
@@ -149,23 +163,24 @@ files:
|
|
149
163
|
- bin/console
|
150
164
|
- bin/setup
|
151
165
|
- lib/.rbnext/2.7/graphql/fragment_cache/cache_key_builder.rb
|
152
|
-
- lib/.rbnext/2.7/graphql/fragment_cache/cacher.rb
|
153
166
|
- lib/.rbnext/2.7/graphql/fragment_cache/ext/graphql_cache_key.rb
|
154
167
|
- lib/graphql-fragment_cache.rb
|
155
168
|
- lib/graphql/fragment_cache.rb
|
156
169
|
- lib/graphql/fragment_cache/cache_key_builder.rb
|
157
170
|
- lib/graphql/fragment_cache/cacher.rb
|
171
|
+
- lib/graphql/fragment_cache/connections/patch.rb
|
158
172
|
- lib/graphql/fragment_cache/ext/context_fragments.rb
|
159
173
|
- lib/graphql/fragment_cache/ext/graphql_cache_key.rb
|
160
174
|
- lib/graphql/fragment_cache/field_extension.rb
|
161
175
|
- lib/graphql/fragment_cache/fragment.rb
|
162
|
-
- lib/graphql/fragment_cache/instrumentation.rb
|
163
176
|
- lib/graphql/fragment_cache/memory_store.rb
|
164
177
|
- lib/graphql/fragment_cache/object.rb
|
165
178
|
- lib/graphql/fragment_cache/object_helpers.rb
|
166
179
|
- lib/graphql/fragment_cache/rails/cache_key_builder.rb
|
167
180
|
- lib/graphql/fragment_cache/railtie.rb
|
168
|
-
- lib/graphql/fragment_cache/
|
181
|
+
- lib/graphql/fragment_cache/schema/instrumentation.rb
|
182
|
+
- lib/graphql/fragment_cache/schema/patch.rb
|
183
|
+
- lib/graphql/fragment_cache/schema/tracer.rb
|
169
184
|
- lib/graphql/fragment_cache/version.rb
|
170
185
|
homepage: https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache
|
171
186
|
licenses:
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GraphQL
|
4
|
-
module FragmentCache
|
5
|
-
using Ext
|
6
|
-
|
7
|
-
# Saves resolved fragment values to cache store
|
8
|
-
module Cacher
|
9
|
-
class << self
|
10
|
-
def call(query)
|
11
|
-
return unless query.context.fragments?
|
12
|
-
|
13
|
-
final_value = query.context.namespace(:interpreter)[:runtime].final_value
|
14
|
-
|
15
|
-
query.context.fragments.each { |_1| _1.persist(final_value) }
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "graphql/fragment_cache/cacher"
|
4
|
-
|
5
|
-
module GraphQL
|
6
|
-
module FragmentCache
|
7
|
-
# Adds hook for saving cached values after query is resolved
|
8
|
-
module Instrumentation
|
9
|
-
module_function
|
10
|
-
|
11
|
-
def before_query(query)
|
12
|
-
end
|
13
|
-
|
14
|
-
def after_query(query)
|
15
|
-
return unless query.valid?
|
16
|
-
|
17
|
-
Cacher.call(query)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "digest/sha1"
|
4
|
-
|
5
|
-
module GraphQL
|
6
|
-
module FragmentCache
|
7
|
-
# Patches GraphQL::Schema to support fragment cache
|
8
|
-
module SchemaPatch
|
9
|
-
def schema_cache_key
|
10
|
-
@schema_cache_key ||= Digest::SHA1.hexdigest(to_definition)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|