cacheql 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: edd0f07beea907b403ceae1832e967d3f1a01aee
4
+ data.tar.gz: b3cae9fa387ee21cd4ea3349e843bc2eea1a314f
5
+ SHA512:
6
+ metadata.gz: ef17ab966525e39a38e8c4968d99e44541d4e6fd0cea8735f6abf5279b40b7129af6a74c7be510654f1f7c6316684046c81f416a40965c6a95125b02e7a6670b
7
+ data.tar.gz: 3065ca7f8150a353a7895c528494dcee87283a2c3687f4903930e45c10c42d820437b4d6edaa9a0ef3ee86c78f28e34b61316ee64c878bb693e908856e764992
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.2
5
+ before_install: gem install bundler -v 1.16.0.pre.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in cacheql.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,87 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cacheql (0.1.0)
5
+ graphql-batch (~> 0.3.9)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actionpack (5.2.0)
11
+ actionview (= 5.2.0)
12
+ activesupport (= 5.2.0)
13
+ rack (~> 2.0)
14
+ rack-test (>= 0.6.3)
15
+ rails-dom-testing (~> 2.0)
16
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
17
+ actionview (5.2.0)
18
+ activesupport (= 5.2.0)
19
+ builder (~> 3.1)
20
+ erubi (~> 1.4)
21
+ rails-dom-testing (~> 2.0)
22
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
23
+ activemodel (5.2.0)
24
+ activesupport (= 5.2.0)
25
+ activerecord (5.2.0)
26
+ activemodel (= 5.2.0)
27
+ activesupport (= 5.2.0)
28
+ arel (>= 9.0)
29
+ activesupport (5.2.0)
30
+ concurrent-ruby (~> 1.0, >= 1.0.2)
31
+ i18n (>= 0.7, < 2)
32
+ minitest (~> 5.1)
33
+ tzinfo (~> 1.1)
34
+ arel (9.0.0)
35
+ builder (3.2.3)
36
+ concurrent-ruby (1.0.5)
37
+ crass (1.0.4)
38
+ erubi (1.7.1)
39
+ graphql (1.7.14)
40
+ graphql-batch (0.3.9)
41
+ graphql (>= 0.8, < 2)
42
+ promise.rb (~> 0.7.2)
43
+ i18n (1.0.0)
44
+ concurrent-ruby (~> 1.0)
45
+ loofah (2.2.2)
46
+ crass (~> 1.0.2)
47
+ nokogiri (>= 1.5.9)
48
+ method_source (0.9.0)
49
+ mini_portile2 (2.3.0)
50
+ minitest (5.11.3)
51
+ nokogiri (1.8.2)
52
+ mini_portile2 (~> 2.3.0)
53
+ promise.rb (0.7.4)
54
+ rack (2.0.4)
55
+ rack-test (1.0.0)
56
+ rack (>= 1.0, < 3)
57
+ rails-dom-testing (2.0.3)
58
+ activesupport (>= 4.2.0)
59
+ nokogiri (>= 1.6)
60
+ rails-html-sanitizer (1.0.4)
61
+ loofah (~> 2.2, >= 2.2.2)
62
+ railties (5.2.0)
63
+ actionpack (= 5.2.0)
64
+ activesupport (= 5.2.0)
65
+ method_source
66
+ rake (>= 0.8.7)
67
+ thor (>= 0.18.1, < 2.0)
68
+ rake (10.5.0)
69
+ thor (0.20.0)
70
+ thread_safe (0.3.6)
71
+ tzinfo (1.2.5)
72
+ thread_safe (~> 0.1)
73
+
74
+ PLATFORMS
75
+ ruby
76
+
77
+ DEPENDENCIES
78
+ activerecord (~> 5.0)
79
+ activesupport (~> 5.0)
80
+ bundler (~> 1.16.a)
81
+ cacheql!
82
+ minitest (~> 5.0)
83
+ railties (~> 5.0)
84
+ rake (~> 10.0)
85
+
86
+ BUNDLED WITH
87
+ 1.16.0.pre.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Chatterbug, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # CacheQL
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/cacheql`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'cacheql'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install cacheql
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/chatterbugapp/cacheql.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "cacheql"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/cacheql.gemspec ADDED
@@ -0,0 +1,32 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "cacheql/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cacheql"
8
+ spec.version = CacheQL::VERSION
9
+ spec.authors = ["Nick Quaranto"]
10
+ spec.email = ["nick@quaran.to"]
11
+
12
+ spec.summary = %q{Various GraphQL caching / instrumentation tools}
13
+ spec.description = spec.summary
14
+ spec.homepage = "https://github.com/chatterbug/cacheql"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "graphql-batch", "~> 0.3.9"
25
+
26
+ spec.add_development_dependency "activesupport", "~> 5.0"
27
+ spec.add_development_dependency "activerecord", "~> 5.0"
28
+ spec.add_development_dependency "railties", "~> 5.0"
29
+ spec.add_development_dependency "bundler", "~> 1.16.a"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "minitest", "~> 5.0"
32
+ end
data/lib/cacheql.rb ADDED
@@ -0,0 +1,38 @@
1
+ require "digest"
2
+
3
+ require "graphql"
4
+ require "graphql/batch"
5
+
6
+ require "cacheql/version"
7
+ require "cacheql/resolve_wrapper"
8
+ require_relative "./cacheql/railtie" if defined? Rails::Railtie
9
+
10
+ # Wrap a resolve function to store its value in Rails.cache
11
+ # This requires `cache_key` as an instance method on the object (usually on ActiveRecord's or scopes),
12
+ module CacheQL
13
+ # Query-level caching, for any cacheable_fields
14
+ def self.fetch(cacheable_fields, query, variables, &block)
15
+ document = GraphQL.parse(query)
16
+ cacheables = document.definitions.map { |definition| definition.selections.map(&:name) }.flatten & cacheable_fields
17
+
18
+ if cacheables.present?
19
+ cache_key = [
20
+ CacheQL::Railtie.config.global_key,
21
+ 'result',
22
+ Digest::SHA256.hexdigest(document.to_query_string + variables.to_s)
23
+ ]
24
+ CacheQL::Railtie.config.cache.fetch(cache_key, expires_in: CacheQL::Railtie.config.expires_range.sample.minutes) do
25
+ block.call(document)
26
+ end
27
+ else
28
+ block.call(document)
29
+ end
30
+ end
31
+ end
32
+
33
+ # Always a hack, but looks nice
34
+ # Wrap a resolve func with:
35
+ # resolve CacheQL -> { |obj, args, ctx| obj.do_stuff }
36
+ def CacheQL(resolver_func)
37
+ CacheQL::ResolveWrapper.new(resolver_func)
38
+ end
@@ -0,0 +1,51 @@
1
+ # https://github.com/Shopify/graphql-batch/blob/master/examples/association_loader.rb
2
+ module CacheQL
3
+ class AssociationLoader < GraphQL::Batch::Loader
4
+ def self.validate(model, association_name)
5
+ new(model, association_name)
6
+ nil
7
+ end
8
+
9
+ def initialize(model, association_name)
10
+ @model = model
11
+ @association_name = association_name
12
+ validate
13
+ end
14
+
15
+ def load(record)
16
+ raise TypeError, "#{@model} loader can't load association for #{record.class}" unless record.is_a?(@model)
17
+ return Promise.resolve(read_association(record)) if association_loaded?(record)
18
+ super
19
+ end
20
+
21
+ # We want to load the associations on all records, even if they have the same id
22
+ def cache_key(record)
23
+ record.object_id
24
+ end
25
+
26
+ def perform(records)
27
+ preload_association(records)
28
+ records.each { |record| fulfill(record, read_association(record)) }
29
+ end
30
+
31
+ private
32
+
33
+ def validate
34
+ unless @model.reflect_on_association(@association_name)
35
+ raise ArgumentError, "No association #{@association_name} on #{@model}"
36
+ end
37
+ end
38
+
39
+ def preload_association(records)
40
+ ::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
41
+ end
42
+
43
+ def read_association(record)
44
+ record.public_send(@association_name)
45
+ end
46
+
47
+ def association_loaded?(record)
48
+ record.association(@association_name).loaded?
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,61 @@
1
+ # https://github.com/rmosolgo/graphql-ruby/blob/master/lib/graphql/tracing/scout_tracing.rb
2
+ # https://github.com/rmosolgo/graphql-ruby/blob/master/guides/fields/instrumentation.md
3
+ # http://help.apm.scoutapp.com/#ruby-custom-instrumentation
4
+ module CacheQL
5
+ class FieldInstrumentation
6
+ NAME = "graphql.field".freeze
7
+
8
+ # For use in an around_action call to log all fields. For example:
9
+ #
10
+ # around_action :log_field_instrumentation
11
+ #
12
+ # def log_field_instrumentation(&block)
13
+ # CacheQL::FieldInstrumentation.log(&block)
14
+ # end
15
+ def self.log(&block)
16
+ field_instruments = Hash.new(0)
17
+ ActiveSupport::Notifications.subscribe(NAME) do |*args|
18
+ event = ActiveSupport::Notifications::Event.new(*args)
19
+ field_instruments[event.payload[:label]] += event.duration
20
+ end
21
+
22
+ block.call
23
+
24
+ ActiveSupport::Notifications.unsubscribe(NAME)
25
+ field_instruments.sort_by(&:last).reverse.each do |field, ms|
26
+ CacheQL::Railtie.config.logger.info "[CacheQL::Tracing] #{field} took #{ms.round(3)}ms"
27
+ end
28
+ end
29
+
30
+ # instrumenter must respond to #instrument
31
+ # See ScoutApm::Tracer for example
32
+ def initialize(instrumenter)
33
+ @instrumenter = instrumenter
34
+ end
35
+
36
+ # Track timing for all fields
37
+ def instrument(type, field)
38
+ # Ignore internal GraphQL types
39
+ if type.name.starts_with?("__")
40
+ field
41
+ else
42
+ label = "#{type.name}.#{field.name}"
43
+ old_resolve_proc = field.resolve_proc
44
+
45
+ new_resolve_proc = -> (obj, args, ctx) {
46
+ ActiveSupport::Notifications.instrument(NAME, label: label) do
47
+ @instrumenter.instrument("GraphQL", label) do
48
+ resolved = old_resolve_proc.call(obj, args, ctx)
49
+ resolved
50
+ end
51
+ end
52
+ }
53
+
54
+ # Return a copy of `field`, with a new resolve proc
55
+ field.redefine do
56
+ resolve(new_resolve_proc)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,22 @@
1
+ # Based on https://github.com/rmosolgo/graphql-batch-example/blob/master/good_schema/polymorphic_key_loader.rb
2
+ module CacheQL
3
+ class PolymorphicKeyLoader < GraphQL::Batch::Loader
4
+ def initialize(model, polymorphic_key)
5
+ @model = model
6
+ @polymorphic_key = polymorphic_key
7
+ end
8
+
9
+ def perform(polymorphic_value_sets)
10
+ polymorphic_values = polymorphic_value_sets.flatten.uniq
11
+ records = @model.where(@polymorphic_key => polymorphic_values).to_a
12
+
13
+ polymorphic_value_sets.each do |polymorphic_value_set|
14
+ matching_records = records.select do |record|
15
+ polymorphic_value_set.id == record.public_send("#{@polymorphic_key}_id") &&
16
+ polymorphic_value_set.class.name == record.public_send("#{@polymorphic_key}_type")
17
+ end
18
+ fulfill(polymorphic_value_set, matching_records)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ module CacheQL
2
+ class Railtie < Rails::Railtie
3
+ # Bump to bust all GraphQL caches!
4
+ config.global_key = "CacheQL/v1"
5
+
6
+ # Expire caches within this minute range
7
+ config.expires_range = (90..120).to_a.freeze
8
+
9
+ initializer "cacheql.initialize" do
10
+ # Bring over some rails default
11
+ config.cache = Rails.cache
12
+ config.logger = Rails.logger
13
+
14
+ require "cacheql/field_instrumentation"
15
+ require "cacheql/polymorphic_key_loader"
16
+ require "cacheql/record_loader"
17
+ end
18
+
19
+ initializer "cacheql.initialize_ar" do
20
+ ActiveSupport.on_load(:active_record) do
21
+ require "cacheql/association_loader"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ # Via https://github.com/Shopify/graphql-batch/blob/master/examples/record_loader.rb
2
+ # And https://github.com/rmosolgo/graphql-batch-example/blob/master/good_schema/find_loader.rb
3
+ module CacheQL
4
+ class RecordLoader < GraphQL::Batch::Loader
5
+ def initialize(model, column: model.primary_key, where: nil)
6
+ @model = model
7
+ @column = column.to_s
8
+ @column_type = model.type_for_attribute(@column)
9
+ @where = where
10
+ end
11
+
12
+ def load(key)
13
+ super(@column_type.cast(key))
14
+ end
15
+
16
+ def perform(keys)
17
+ query(keys).each { |record| fulfill(record.public_send(@column), record) }
18
+ keys.each { |key| fulfill(key, nil) unless fulfilled?(key) }
19
+ end
20
+
21
+ private
22
+
23
+ def query(keys)
24
+ scope = @model
25
+ scope = scope.where(@where) if @where
26
+ scope.where(@column => keys)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ module CacheQL
2
+ class ResolveWrapper
3
+ def initialize(resolver_func)
4
+ @resolver_func = resolver_func
5
+ end
6
+
7
+ def __getobj__
8
+ @resolver_func
9
+ end
10
+
11
+ # Resolve function level caching!
12
+ def call(obj, args, ctx)
13
+ cache_key = [CacheQL::Railtie.config.global_key, obj.cache_key, ctx.field.name]
14
+ CacheQL::Railtie.config.cache.fetch(cache_key,
15
+ expires_in: CacheQL::Railtie.config.expires_range.sample.minutes) do
16
+ @resolver_func.call(obj, args, ctx)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module CacheQL
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cacheql
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nick Quaranto
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: graphql-batch
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.9
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.9
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activerecord
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: railties
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.16.a
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.16.a
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '5.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '5.0'
111
+ description: Various GraphQL caching / instrumentation tools
112
+ email:
113
+ - nick@quaran.to
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".travis.yml"
120
+ - Gemfile
121
+ - Gemfile.lock
122
+ - LICENSE.txt
123
+ - README.md
124
+ - Rakefile
125
+ - bin/console
126
+ - bin/setup
127
+ - cacheql.gemspec
128
+ - lib/cacheql.rb
129
+ - lib/cacheql/association_loader.rb
130
+ - lib/cacheql/field_instrumentation.rb
131
+ - lib/cacheql/polymorphic_key_loader.rb
132
+ - lib/cacheql/railtie.rb
133
+ - lib/cacheql/record_loader.rb
134
+ - lib/cacheql/resolve_wrapper.rb
135
+ - lib/cacheql/version.rb
136
+ homepage: https://github.com/chatterbug/cacheql
137
+ licenses:
138
+ - MIT
139
+ metadata: {}
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 2.6.13
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: Various GraphQL caching / instrumentation tools
160
+ test_files: []