graphql-cache 0.2.2 → 0.2.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/.gitignore +2 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +7 -2
- data/.yardopts +6 -0
- data/Appraisals +3 -0
- data/Gemfile.lock +6 -2
- data/README.md +5 -6
- data/gemfiles/graphql_1.8.gemfile +7 -0
- data/graphql-cache.gemspec +1 -1
- data/lib/graphql/cache.rb +45 -9
- data/lib/graphql/cache/builder.rb +47 -10
- data/lib/graphql/cache/marshal.rb +25 -1
- data/lib/graphql/cache/middleware.rb +9 -0
- data/lib/graphql/cache/rails.rb +10 -6
- data/lib/graphql/cache/version.rb +3 -1
- metadata +19 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a17d14d49e48de32188c39c81ce2016de951ea7ba2658dffef14a002b28451c
|
4
|
+
data.tar.gz: 4a5919a8c028d47fdd67220079f9cede029762f2907b998c544ab7769513c79d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ab0efc3d2420acff9f33a06112ff0d46ce77fd9c1336ebe8ce93ba6419f5b8abece70e94440941347ea8fa5ff370b56f6387426930dc1adde8cb030480e963b
|
7
|
+
data.tar.gz: 5ccb7a3be368f870f4773bb28280c32cfb1b308352d58bb4e29efca1c18f9ee35515bb7a10e1e5190f11132b3b989aa282f5e94a6c4a5fa421950a60830da745
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
- 2.5.
|
4
|
+
- 2.5.1
|
5
|
+
- 2.4.4
|
6
|
+
- 2.3.7
|
7
|
+
- 2.2.10
|
8
|
+
gemfile:
|
9
|
+
- gemfiles/graphql_1.8.gemfile
|
5
10
|
before_script:
|
6
11
|
- gem install bundler
|
7
12
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
8
13
|
- chmod +x ./cc-test-reporter
|
9
14
|
- ./cc-test-reporter before-build
|
10
|
-
script: bundle exec
|
15
|
+
script: "bundle exec rake"
|
11
16
|
after_script:
|
12
17
|
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/.yardopts
ADDED
data/Appraisals
ADDED
data/Gemfile.lock
CHANGED
@@ -2,18 +2,20 @@ PATH
|
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
4
|
graphql-cache (0.2.2)
|
5
|
-
gemer (~> 0.1)
|
6
5
|
graphql (~> 1.8.0)
|
7
6
|
|
8
7
|
GEM
|
9
8
|
remote: https://rubygems.org/
|
10
9
|
specs:
|
10
|
+
appraisal (2.2.0)
|
11
|
+
bundler
|
12
|
+
rake
|
13
|
+
thor (>= 0.14.0)
|
11
14
|
codeclimate-test-reporter (0.6.0)
|
12
15
|
simplecov (>= 0.7.1, < 1.0.0)
|
13
16
|
coderay (1.1.2)
|
14
17
|
diff-lcs (1.3)
|
15
18
|
docile (1.3.0)
|
16
|
-
gemer (0.1.2)
|
17
19
|
graphql (1.8.0)
|
18
20
|
json (2.1.0)
|
19
21
|
method_source (0.9.0)
|
@@ -39,11 +41,13 @@ GEM
|
|
39
41
|
json (>= 1.8, < 3)
|
40
42
|
simplecov-html (~> 0.10.0)
|
41
43
|
simplecov-html (0.10.2)
|
44
|
+
thor (0.20.0)
|
42
45
|
|
43
46
|
PLATFORMS
|
44
47
|
ruby
|
45
48
|
|
46
49
|
DEPENDENCIES
|
50
|
+
appraisal
|
47
51
|
bundler (~> 1.16)
|
48
52
|
codeclimate-test-reporter
|
49
53
|
graphql-cache!
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# GraphQL Cache
|
1
|
+
# GraphQL Cache
|
2
|
+
[](https://travis-ci.org/Leanstack/graphql-cache) [](https://codeclimate.com/github/Leanstack/graphql-cache/test_coverage) [](https://codeclimate.com/github/Leanstack/graphql-cache/maintainability)
|
2
3
|
|
3
4
|
GraphQL Cache is a custom middleware for graphql-ruby providing field-level caching. It is currently a work in progress and the API is subject to change prior to the release v1.0.0.
|
4
5
|
|
@@ -55,11 +56,9 @@
|
|
55
56
|
|
56
57
|
When passing a hash in the `cache` parameter the possible options are:
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
| `force` | false | force cache misses on this field |
|
62
|
-
| `prefix` | | cache key prefix (appended after GraphQL::Cache.namespace) |
|
59
|
+
- `expiry`: expiration time for this field's key in seconds (default: 5400)
|
60
|
+
- `force`: for cache misses on this field (default: false)
|
61
|
+
- `prefix`: cache key prefix (appended after GraphQL::Cache.namespace)
|
63
62
|
|
64
63
|
## Development
|
65
64
|
|
data/graphql-cache.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.require_paths = ['lib']
|
22
22
|
s.required_ruby_version = '>= 2.2.0' # bc graphql-ruby requires >= 2.2.0
|
23
23
|
|
24
|
+
s.add_development_dependency 'appraisal'
|
24
25
|
s.add_development_dependency 'bundler', '~> 1.16'
|
25
26
|
s.add_development_dependency 'codeclimate-test-reporter'
|
26
27
|
s.add_development_dependency 'pry'
|
@@ -28,6 +29,5 @@ Gem::Specification.new do |s|
|
|
28
29
|
s.add_development_dependency 'rspec', '~> 3.0'
|
29
30
|
s.add_development_dependency 'simplecov'
|
30
31
|
|
31
|
-
s.add_dependency 'gemer', '~> 0.1'
|
32
32
|
s.add_dependency 'graphql', '~> 1.8.0'
|
33
33
|
end
|
data/lib/graphql/cache.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'graphql/cache/version'
|
4
4
|
require 'graphql/cache/middleware'
|
@@ -7,16 +7,52 @@ require 'graphql/cache/marshal'
|
|
7
7
|
|
8
8
|
module GraphQL
|
9
9
|
module Cache
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
class << self
|
11
|
+
# An object that must conform to the same API as ActiveSupport::Cache::Store
|
12
|
+
# @return [Object] Defaults to `Rails.cache` in a Rails environment
|
13
|
+
attr_accessor :cache
|
14
|
+
|
15
|
+
# Global default cache key expiration time in seconds.
|
16
|
+
# @return [Integer] Default: 5400 (90 minutes)
|
17
|
+
attr_accessor :expiry
|
18
|
+
|
19
|
+
# When truthy, override all caching (force evalutaion of resolvers)
|
20
|
+
# @return [Boolean] Default: false
|
21
|
+
attr_accessor :force
|
22
|
+
|
23
|
+
# Logger instance to use when logging cache hits/misses.
|
24
|
+
# @return [Logger]
|
25
|
+
attr_accessor :logger
|
26
|
+
|
27
|
+
# Global namespace for keys
|
28
|
+
# @return [String] Default: "GraphQL::Cache"
|
29
|
+
attr_accessor :namespace
|
30
|
+
|
31
|
+
# Provides for initializer syntax
|
32
|
+
#
|
33
|
+
# ```
|
34
|
+
# GraphQL::Cache.configure do |c|
|
35
|
+
# c.namespace = 'MyNamespace'
|
36
|
+
# end
|
37
|
+
# ```
|
38
|
+
def configure
|
39
|
+
yield self
|
40
|
+
end
|
18
41
|
end
|
19
42
|
|
43
|
+
# Default configuration
|
44
|
+
@expiry = 5400
|
45
|
+
@force = false
|
46
|
+
@namespace = 'GraphQL::Cache'
|
47
|
+
|
48
|
+
# Fetches/writes a value for `key` from the cache
|
49
|
+
#
|
50
|
+
# Always evaluates the block unless config[:metadata][:cache] is truthy
|
51
|
+
#
|
52
|
+
# @param key [String] the cache key to attempt to fetch
|
53
|
+
# @param config [Hash] a hash of middleware config values used to marshal cache data
|
54
|
+
# @option config [Hash] :metadata The metadata collected from the field definition
|
55
|
+
# @return [Object]
|
20
56
|
def self.fetch(key, config: {}, &block)
|
21
57
|
return block.call unless config[:metadata][:cache]
|
22
58
|
|
@@ -1,13 +1,43 @@
|
|
1
1
|
module GraphQL
|
2
2
|
module Cache
|
3
|
+
# GraphQL objects can't be serialized to cache so we have
|
4
|
+
# to maintain an abstraction between the raw cache value
|
5
|
+
# and the GraphQL expected object. This class exposes methods
|
6
|
+
# for both deconstructing an object to be stored in cache
|
7
|
+
# and re-hydrating a GraphQL object from raw cache values
|
8
|
+
#
|
3
9
|
class Builder
|
4
|
-
|
10
|
+
# The raw value to perform actions on. Could be a raw cached value, or
|
11
|
+
# a raw GraphQL Field.
|
12
|
+
#
|
13
|
+
# @return [Object]
|
14
|
+
attr_accessor :raw
|
5
15
|
|
16
|
+
# A flag indicating the type of object construction to
|
17
|
+
# use when building a new GraphQL object. Can be one of
|
18
|
+
# 'array', 'collectionproxy', 'relation'. These values
|
19
|
+
# have been chosen because it is easy to use the class
|
20
|
+
# names of the possible object types for this purpose.
|
21
|
+
#
|
22
|
+
# @return [String] 'array' or 'collectionproxy' or 'relation'
|
23
|
+
attr_accessor :method
|
24
|
+
|
25
|
+
# The middleware config hash describing a field's resolution
|
26
|
+
#
|
27
|
+
# @see GraphQL::Cache::Middleware#initialize
|
28
|
+
# @return [Hash]
|
29
|
+
attr_accessor :config
|
30
|
+
|
31
|
+
# Initializer helper that generates a valid `method` string based
|
32
|
+
# on `raw.class.name`.
|
33
|
+
#
|
34
|
+
# @return [Object] A newly initialized GraphQL::Cache::Builder instance
|
6
35
|
def self.[](raw)
|
7
36
|
build_method = namify(raw.class.name)
|
8
37
|
new(raw, build_method)
|
9
38
|
end
|
10
39
|
|
40
|
+
# Ruby-only means of "demodularizing" a string
|
11
41
|
def self.namify(str)
|
12
42
|
str.split('::').last.downcase
|
13
43
|
end
|
@@ -17,6 +47,9 @@ module GraphQL
|
|
17
47
|
self.method = method
|
18
48
|
end
|
19
49
|
|
50
|
+
# Builds a compitable GraphQL object based on the resolution config
|
51
|
+
#
|
52
|
+
# @return [Object] An object suitable for returning from a GraphQL middlware call
|
20
53
|
def build(config)
|
21
54
|
self.config = config
|
22
55
|
|
@@ -25,17 +58,17 @@ module GraphQL
|
|
25
58
|
build_object
|
26
59
|
end
|
27
60
|
|
61
|
+
# Deconstructs a GraphQL field into a cachable value
|
62
|
+
#
|
63
|
+
# @return [Object] A value suitable for writing to cache
|
28
64
|
def deconstruct
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
raw.nodes
|
34
|
-
else
|
35
|
-
deconstruct_object(raw)
|
36
|
-
end
|
65
|
+
return deconstruct_arra(raw) if raw.class == Array
|
66
|
+
return raw.nodes if raw.class.ancestors.include? GraphQL::Relay::BaseConnection
|
67
|
+
|
68
|
+
deconstruct_object(raw)
|
37
69
|
end
|
38
70
|
|
71
|
+
# @private
|
39
72
|
def deconstruct_object(raw)
|
40
73
|
if raw.respond_to?(:object)
|
41
74
|
raw.object
|
@@ -44,6 +77,7 @@ module GraphQL
|
|
44
77
|
end
|
45
78
|
end
|
46
79
|
|
80
|
+
# @private
|
47
81
|
def deconstruct_array(raw)
|
48
82
|
return [] if raw.empty?
|
49
83
|
|
@@ -54,8 +88,9 @@ module GraphQL
|
|
54
88
|
end
|
55
89
|
end
|
56
90
|
|
91
|
+
# @private
|
57
92
|
def build_relation
|
58
|
-
GraphQL::Relay::
|
93
|
+
GraphQL::Relay::BaseConnection.connection_for_nodes(raw).new(
|
59
94
|
raw,
|
60
95
|
config[:field_args],
|
61
96
|
field: config[:query_context].field,
|
@@ -64,6 +99,7 @@ module GraphQL
|
|
64
99
|
)
|
65
100
|
end
|
66
101
|
|
102
|
+
# @private
|
67
103
|
def build_array
|
68
104
|
gql_def = config[:field_definition].type.unwrap.graphql_definition
|
69
105
|
|
@@ -79,6 +115,7 @@ module GraphQL
|
|
79
115
|
end
|
80
116
|
end
|
81
117
|
|
118
|
+
# @private
|
82
119
|
def build_object
|
83
120
|
klass = config[:field_definition].type.unwrap.graphql_definition.metadata[:type_class]
|
84
121
|
if klass
|
@@ -4,18 +4,31 @@ require 'graphql/cache/builder'
|
|
4
4
|
|
5
5
|
module GraphQL
|
6
6
|
module Cache
|
7
|
-
# Used to marshal
|
7
|
+
# Used to marshal cache fetches into either writes or reads
|
8
8
|
class Marshal
|
9
|
+
# The cache key to marshal around
|
10
|
+
#
|
11
|
+
# @return [String] The cache key
|
9
12
|
attr_accessor :key
|
10
13
|
|
14
|
+
# Initializer helper to allow syntax like
|
15
|
+
# `Marshal[key].read(config, &block)`
|
16
|
+
#
|
17
|
+
# @return [GraphQL::Cache::Marshal]
|
11
18
|
def self.[](key)
|
12
19
|
new(key)
|
13
20
|
end
|
14
21
|
|
22
|
+
# Initialize a new instance of {GraphQL::Cache::Marshal}
|
15
23
|
def initialize(key)
|
16
24
|
self.key = key.to_s
|
17
25
|
end
|
18
26
|
|
27
|
+
# Read a value from cache if it exists and re-hydrate it or
|
28
|
+
# execute the block and write it's result to cache
|
29
|
+
#
|
30
|
+
# @param config [Hash] The middleware resolution config
|
31
|
+
# @return [Object]
|
19
32
|
def read(config, &block)
|
20
33
|
cached = cache.read(key)
|
21
34
|
|
@@ -28,6 +41,10 @@ module GraphQL
|
|
28
41
|
end
|
29
42
|
end
|
30
43
|
|
44
|
+
# Executes the resolution block and writes the result to cache
|
45
|
+
#
|
46
|
+
# @see GraphQL::Cache::Builder#deconstruct
|
47
|
+
# @param config [Hash] The middleware resolution config hash
|
31
48
|
def write(config)
|
32
49
|
resolved = yield
|
33
50
|
document = Builder[resolved].deconstruct
|
@@ -36,6 +53,7 @@ module GraphQL
|
|
36
53
|
resolved
|
37
54
|
end
|
38
55
|
|
56
|
+
# @private
|
39
57
|
def expiry(config)
|
40
58
|
cache_config = config[:metadata][:cache]
|
41
59
|
|
@@ -46,14 +64,20 @@ module GraphQL
|
|
46
64
|
end
|
47
65
|
end
|
48
66
|
|
67
|
+
# Uses {GraphQL::Cache::Builder} to build a valid GraphQL object
|
68
|
+
# from a cached value
|
69
|
+
#
|
70
|
+
# @return [Object] An object suitable to return from a GraphQL middleware
|
49
71
|
def build(cached, config)
|
50
72
|
Builder[cached].build(config)
|
51
73
|
end
|
52
74
|
|
75
|
+
# @private
|
53
76
|
def cache
|
54
77
|
GraphQL::Cache.cache
|
55
78
|
end
|
56
79
|
|
80
|
+
# @private
|
57
81
|
def logger
|
58
82
|
GraphQL::Cache.logger
|
59
83
|
end
|
@@ -7,6 +7,7 @@ module GraphQL
|
|
7
7
|
attr_accessor :parent_type, :parent_object, :object, :cache,
|
8
8
|
:field_definition, :field_args, :query_context
|
9
9
|
|
10
|
+
# Called by graphql-ruby during middleware processing
|
10
11
|
def self.call(*args, &block)
|
11
12
|
new(*args).call(&block)
|
12
13
|
end
|
@@ -29,6 +30,7 @@ module GraphQL
|
|
29
30
|
self.object = parent_object.object if parent_object.respond_to? :object
|
30
31
|
end
|
31
32
|
|
33
|
+
# @private
|
32
34
|
def cache_config
|
33
35
|
{
|
34
36
|
parent_type: parent_type,
|
@@ -40,6 +42,7 @@ module GraphQL
|
|
40
42
|
}.merge metadata_hash
|
41
43
|
end
|
42
44
|
|
45
|
+
# @private
|
43
46
|
def metadata_hash
|
44
47
|
{
|
45
48
|
metadata: {
|
@@ -48,6 +51,9 @@ module GraphQL
|
|
48
51
|
}
|
49
52
|
end
|
50
53
|
|
54
|
+
# The primary caching entry point
|
55
|
+
#
|
56
|
+
# @return [Object]
|
51
57
|
def call(&block)
|
52
58
|
GraphQL::Cache.fetch(
|
53
59
|
cache_key,
|
@@ -56,6 +62,7 @@ module GraphQL
|
|
56
62
|
)
|
57
63
|
end
|
58
64
|
|
65
|
+
# @private
|
59
66
|
def cache_key
|
60
67
|
@cache_key ||= [
|
61
68
|
GraphQL::Cache.namespace,
|
@@ -65,12 +72,14 @@ module GraphQL
|
|
65
72
|
].flatten
|
66
73
|
end
|
67
74
|
|
75
|
+
# @private
|
68
76
|
def object_key
|
69
77
|
return nil unless object
|
70
78
|
|
71
79
|
"#{object.class.name}:#{id_from_object}"
|
72
80
|
end
|
73
81
|
|
82
|
+
# @private
|
74
83
|
def id_from_object
|
75
84
|
return object.id if object.respond_to? :id
|
76
85
|
return object.fetch(:id, nil) if object.respond_to? :fetch
|
data/lib/graphql/cache/rails.rb
CHANGED
@@ -2,12 +2,16 @@
|
|
2
2
|
|
3
3
|
module GraphQL
|
4
4
|
module Cache
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
if defined?(::Rails)
|
6
|
+
# Railtie integration used to default {GraphQL::Cache.cache}
|
7
|
+
# and {GraphQL::Cache.logger} when in a Rails environment.
|
8
|
+
class Rails < ::Rails::Engine
|
9
|
+
config.after_initialize do
|
10
|
+
# default values for cache and logger in Rails if not set already
|
11
|
+
GraphQL::Cache.cache = ::Rails.cache unless GraphQL::Cache.cache
|
12
|
+
GraphQL::Cache.logger = ::Rails.logger unless GraphQL::Cache.logger
|
13
|
+
end
|
10
14
|
end
|
11
|
-
end
|
15
|
+
end
|
12
16
|
end
|
13
17
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Kelly
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: appraisal
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,20 +108,6 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: gemer
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0.1'
|
104
|
-
type: :runtime
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0.1'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: graphql
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,6 +134,8 @@ files:
|
|
134
134
|
- ".rspec"
|
135
135
|
- ".rubocop.yml"
|
136
136
|
- ".travis.yml"
|
137
|
+
- ".yardopts"
|
138
|
+
- Appraisals
|
137
139
|
- CODE_OF_CONDUCT.md
|
138
140
|
- CONTRIBUTING.md
|
139
141
|
- Gemfile
|
@@ -143,6 +145,7 @@ files:
|
|
143
145
|
- Rakefile
|
144
146
|
- bin/console
|
145
147
|
- bin/setup
|
148
|
+
- gemfiles/graphql_1.8.gemfile
|
146
149
|
- graphql-cache.gemspec
|
147
150
|
- lib/graphql/cache.rb
|
148
151
|
- lib/graphql/cache/builder.rb
|