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 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