graphql-cache 0.2.2 → 0.2.3

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: 866eda70401ee7db7847f5b87cf8d0e2a9f26e5d21428c4338ee40ea143e8339
4
- data.tar.gz: ebf01aa744da393e9beb14c0dd6f9da20d34752c515b72b2aba08ae295390a4f
3
+ metadata.gz: 1a17d14d49e48de32188c39c81ce2016de951ea7ba2658dffef14a002b28451c
4
+ data.tar.gz: 4a5919a8c028d47fdd67220079f9cede029762f2907b998c544ab7769513c79d
5
5
  SHA512:
6
- metadata.gz: 02a82cb8c0544cfe51fa6fc6e397b402008b851fa3ef31ab28bdfd7effec996ce350052ceb4dcf1e46f25dbba97988e1e39c3f9327788b7514cdf19dadc88a5a
7
- data.tar.gz: a7dfbad849adb64e6c401634d32902ec3c78443032737c31961fa97508fc285753e264d0a1c4b856dea53c7d8d6cd32f56e8e70cc62be1a81d9e3dc13e490109
6
+ metadata.gz: 3ab0efc3d2420acff9f33a06112ff0d46ce77fd9c1336ebe8ce93ba6419f5b8abece70e94440941347ea8fa5ff370b56f6387426930dc1adde8cb030480e963b
7
+ data.tar.gz: 5ccb7a3be368f870f4773bb28280c32cfb1b308352d58bb4e29efca1c18f9ee35515bb7a10e1e5190f11132b3b989aa282f5e94a6c4a5fa421950a60830da745
data/.gitignore CHANGED
@@ -11,3 +11,5 @@
11
11
  .rspec_status
12
12
 
13
13
  *.gem
14
+
15
+ gemfiles/*.gemfile.lock
@@ -1,3 +1,4 @@
1
1
  AllCops:
2
+ TargetRubyVersion: '2.2.0'
2
3
  Exclude:
3
4
  - 'spec/**/*'
@@ -1,12 +1,17 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.5.0
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 rspec
15
+ script: "bundle exec rake"
11
16
  after_script:
12
17
  - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
@@ -0,0 +1,6 @@
1
+ --no-private
2
+ --markup=markdown
3
+ --readme=README.md
4
+ --title='GraphQL Cache API documentation'
5
+ 'lib/**/*.rb' - '*.md'
6
+
@@ -0,0 +1,3 @@
1
+ appraise "graphql-1.8" do
2
+ gem 'graphql', '~> 1.8'
3
+ end
@@ -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 [![Build Status](https://travis-ci.org/Leanstack/graphql-cache.svg?branch=master)](https://travis-ci.org/Leanstack/graphql-cache) [![Test Coverage](https://api.codeclimate.com/v1/badges/c8560834b10db0618175/test_coverage)](https://codeclimate.com/github/Leanstack/graphql-cache/test_coverage) [![Maintainability](https://api.codeclimate.com/v1/badges/c8560834b10db0618175/maintainability)](https://codeclimate.com/github/Leanstack/graphql-cache/maintainability)
1
+ # GraphQL Cache
2
+ [![Build Status](https://travis-ci.org/Leanstack/graphql-cache.svg?branch=master)](https://travis-ci.org/Leanstack/graphql-cache) [![Test Coverage](https://api.codeclimate.com/v1/badges/c8560834b10db0618175/test_coverage)](https://codeclimate.com/github/Leanstack/graphql-cache/test_coverage) [![Maintainability](https://api.codeclimate.com/v1/badges/c8560834b10db0618175/maintainability)](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
- | Key | Default | Description |
59
- |----------|---------|------------------------------------------------------------|
60
- | `expiry` | 5400 | expiration time for this field's key in seconds |
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
 
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "graphql", "~> 1.8"
6
+
7
+ gemspec path: "../"
@@ -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
@@ -1,4 +1,4 @@
1
- require 'gemer'
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
- include Gemer::Configurable
11
-
12
- setup_config do |c|
13
- c.attr :cache
14
- c.attr :expiry, 5400
15
- c.attr :force, false, in: [true, false]
16
- c.attr :logger
17
- c.attr :namespace, 'GraphQL::Cache'
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
- attr_accessor :raw, :method, :config
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
- case self.class.namify(raw.class.name)
30
- when 'array'
31
- deconstruct_array(raw)
32
- when 'relationconnection'
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::RelationConnection.new(
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 data to/from cache on cache hits/misses
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
@@ -2,12 +2,16 @@
2
2
 
3
3
  module GraphQL
4
4
  module Cache
5
- class Rails < ::Rails::Engine
6
- config.after_initialize do
7
- # default values for cache and logger in Rails if not set in initializer
8
- GraphQL::Cache.cache = ::Rails.cache unless GraphQL::Cache.cache
9
- GraphQL::Cache.logger = ::Rails.logger unless GraphQL::Cache.logger
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 if defined?(::Rails)
15
+ end
12
16
  end
13
17
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GraphQL
2
4
  module Cache
3
- VERSION = '0.2.2'.freeze
5
+ VERSION = '0.2.3'
4
6
  end
5
7
  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.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-05-19 00:00:00.000000000 Z
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