Giter VIP home page Giter VIP logo

graphql-ruby-fragment_cache's Introduction

Hi! πŸ‘‹

My name is Dmitry and I'm a backend engineer focusing on Ruby, Rails, PostgreSQL and GraphQL. I prefer working on arhitectural, performance and developer experience (i.e., custom linters, CI actions, etc.) tasks. At my free time I'm playing with Go, Rust and Haskell.

I contribute to various open–source projects (Ruby on Rails, graphql-ruby, GitLab, prism and many more). Also, I maintain my own libraries β€” check them out pinned right below.

Featured articles and conference talks:

You can find me on Twitter and LinkedIn.

graphql-ruby-fragment_cache's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

graphql-ruby-fragment_cache's Issues

GraphQL::FragmentCache.cache_store keys accessor

Hi all. Could somebody implement keys method in MemoryStore instance? It's gonna be helpful to get all exists keys and filter by mask and to delete not relevant by hand. Currently I can use GraphQL::FragmentCache.cache_store.instance_variable_get(:@storage).keys. Thanks.

Allow override context cache key

class QueryType < GraphQL::Schema::Object
  field :post, PostType, null: true do
    argument :id, ID, required: true
  end

  def post(id:)
    cache_fragment(context_cache_key: context[:current_user_id]) { Post.find(id) }
  end
end

Cache connection type using multi

First of all, thank you for your great gem!

I am running into the following issue tho: I have all_pages field:
field :all_pages, PageType.connection_type, null: true

When I resolve and cache it using the gem all the pages get cached - which makes sense of course.

def all_pages
  cache_fragment {
    chain = Page
    chain = scope_status(chain, context[:stage])
    chain = lookahead_for_collection(chain, lookahead)
    chain = search_records(chain, search)
    chain = order_records(chain, order)
    chain.all
  }
end

I am using the api in a Gatsby website. So whenever there is an update in my rails app a webhook gets posted to Gatsby Cloud to rebuild the site. This rebuild will fetch all pages with all available fields which is very heavy. Also because they are a lot.

Is there an option to cache all pages but only invalidate a single one (similar to rails.cache.fetch_multi) so that all pages that did not change get fetched from the cache except the one that changed? This would speed up my app significantly.

Thank you! πŸ’œ

Deprecation warning for tracer

Schema.tracer(GraphQL::FragmentCache::Schema::Tracer)` is deprecated; use module-based `trace_with` instead. See: https://graphql-ruby.org/queries/tracing.html
  /usr/local/bundle/gems/graphql-fragment_cache-1.20.0/lib/graphql/fragment_cache.rb:34:in `use'

graphql-ruby 2.3.0 has deprecated .tracer method.

[Question] Programmatically Clear Entire Cache

Hey --

Wondering if there is a way to for the entire cache to clear for all queries as opposed to by query by query.

Is there a way to clear the cache of all cached fragments? Such as Rails.cache.clear?

Does this gem can work with GraphQL Ruby Multiplex and GraphQL Batch?

Hello,

Using GraphQL Ruby Multiplex with Apollo Batch Http Link, this user type works fine

def user(id:)
  user = User.find(id)

  cache_fragment([user, context[:current_user]]) do
    user
  end
end

but when I try to add GraphQL batch here

def user(id:)
  Loaders::RecordLoader.for(User).load(id).then do |user|
    cache_fragment([user, context[:current_user]]) do
      user
    end
  end
end

I get this error:

undefined method `map' for nil:NilClass
/Users/jpalumickas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/graphql-fragment_cache-1.4.0/lib/graphql/fragment_cache/cache_key_builder.rb:147:in `block in path_cache_key'  
/Users/jpalumickas/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/graphql-fragment_cache-1.4.0/lib/graphql/fragment_cache/cache_key_builder.rb:144:in `fetch'                    

Also, this type with Batch works fine when using without Apollo Batch (calling single query)

graphql-ruby 2.0.18 causing tracer breaking changes

The 2.0.18 update to graphql-ruby adds a breaking change to tracers that affects this gem.

Tracing: "execute_field" events on fields defined on interface types will now receive the interface type as data[:owner] instead of the current object type. To get the old behavior, use data[:object].class instead. #4292

A change would likely need to be made in this file: lib/graphql/fragment_cache/schema/tracer.rb

This is causing the below error when attempting to use the gql schema:

Can't add tracer after configuring a `trace_class`, use GraphQL::Tracing::LegacyTrace to merge legacy tracers into a trace class instead.

I'll attempt to make a PR to fix this but am not very familiar with the internal working of this gem or graphql-ruby.

Upgrade to 1.18.0 version error

Hi, I am trying to upgrade the gem to the latest version (1.8.0) and ran into some problems. We are using ddtracerb and it is expecting to receive a hash instead of an array to write_multi function:

This is the error rescued and then raised by your code:

GraphQL::FragmentCache::WriteMultiError:
  undefined method 'keys' for ["graphql/ids/368d52c087dfcf3113a577315c45e3036b316410", {"data": "test"}]:Array

                    keys: hash.keys,
                              ^^^^^
/home/circleci/.rubygems/gems/graphql-fragment_cache-1.18.0/lib/graphql/fragment_cache/cacher.rb:52:in `rescue in block in batched_persist'

And this is the original error:

--- Caused by: ---
NoMethodError:
  undefined method `keys' for ["graphql/ids/368d52c087dfcf3113a577315c45e3036b316410", {"data":"test"}]:Array
  
                    keys: hash.keys,
                              ^^^^^
  /home/circleci/.rubygems/gems/ddtrace-1.8.0/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb:234:in `write_multi'

This is the code where it comes from: ddtrace code

Also the ruby version used is: 3.1.3

Issue with context

Hello, I have this issue with context. It throws and error of trying to access a method on a hash.

module Types::Object
  class UserType < BaseObject
    field :last_name, String, null: false, cache_fragment: true
  end
end

Inside gem, it calls cache_fragment method which is building an instance of Fragment. And it's failing there:

# lib/graphql/fragment_cache/fragment.rb

def interpreter_context
  context.namespace(:interpreter)
end

But context is a hash here, so I'm getting

[1] pry(#<GraphQL::Execution::Errors>)> err
=> #<NoMethodError: undefined method `namespace' for #<Hash:0x00007f2bc3d9f8c8>>

Basically, it's exactly that context hash that I build in GraphqlController execute method, common setup:

class GraphqlController < ActionController::API
  def execute
    context = {
      current_user: current_user
    }

    render json: AppSchema.execute(
      params[:query],
      variables: variables,
      context: context,
      operation_name: params[:operation_name]
    )
  end
end

Rails 5.2.4
ruby 2.6.5
graphql 1.11.1
graphql-fragment_cache 1.0.1

Clarification on cache_key options

Maybe it's just me, but I find the readme on this really confusing.

[README]
When using cache_fragment: option, it's only possible to use the resolved value as a cache key by setting:

field :post, PostType, null: true, cache_fragment: {cache_key: :object} do
  argument :id, ID, required: true
end

# this is equal to
def post(id:)
  cache_fragment(Post.find(id))
end

Also, you can pass :value to the cache_key: argument to use the returned value to build a key:

field :post, PostType, null: true, cache_fragment: {cache_key: :value} do
  argument :id, ID, required: true
end

# this is equal to
def post(id:)
  post = Post.find(id)
  cache_fragment(post) { post }
end

[/README]

What is the difference between the "resolved value" being used vs. the "returned value"?

Also, it's not immediately clear how

def post(id:)
  post = Post.find(id)
  cache_fragment(post) { post }
end

AND

def post(id:)
  cache_fragment(Post.find(id))
end

Are different.

"Failed to implement Post.id" when returning cached RawValue in resolvers

It seems to work fine when the resolver returns a collection, and when a resolver returns a single object that is not cached. But, when there's a cache-hit, I always get this error:

E GraphqlController --             Failed to implement Post.id, tried:

            - `Types::Post#id`, which did not exist
            - `PostDecorator#id`, which did not exist
            - Looking up hash key `:id` or `"id"` on `#<GraphQL::Execution::Interpreter::RawValue:0x00000001105e7980>`, but it wasn't a Hash

            To implement this field, define one of the methods above (and check for typos)

12:45:58 E GraphqlController -- /Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/field.rb:848:in `block in public_send_field'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/field.rb:911:in `with_extensions'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/field.rb:803:in `public_send_field'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/field.rb:717:in `block in resolve'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema.rb:118:in `after_lazy'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/field.rb:715:in `resolve'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:511:in `block (4 levels) in evaluate_selection_with_args'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:81:in `call_tracers'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:83:in `block in call_tracers'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-fragment_cache-1.11.0/lib/graphql/fragment_cache/schema/tracer.rb:12:in `trace'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:83:in `call_tracers'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:67:in `trace'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:510:in `block (3 levels) in evaluate_selection_with_args'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/query.rb:366:in `block in with_error_handling'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/errors.rb:107:in `with_error_handling'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/query.rb:365:in `with_error_handling'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:509:in `block (2 levels) in evaluate_selection_with_args'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:812:in `call_method_on_directives'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:506:in `block in evaluate_selection_with_args'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:915:in `after_lazy'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:440:in `evaluate_selection_with_args'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:428:in `evaluate_selection'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:359:in `block (2 levels) in evaluate_selections'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/dataloader/null_dataloader.rb:17:in `append_job'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:358:in `block in evaluate_selections'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:357:in `each'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:357:in `evaluate_selections'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:739:in `block (3 levels) in continue_field'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:812:in `call_method_on_directives'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:738:in `block (2 levels) in continue_field'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:190:in `tap_or_each'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:729:in `block in continue_field'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:915:in `after_lazy'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:715:in `continue_field'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:520:in `block (3 levels) in evaluate_selection_with_args'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:915:in `after_lazy'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:517:in `block (2 levels) in evaluate_selection_with_args'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:812:in `call_method_on_directives'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:506:in `block in evaluate_selection_with_args'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:915:in `after_lazy'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:440:in `evaluate_selection_with_args'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:432:in `block in evaluate_selection'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/member/has_arguments.rb:204:in `block (3 levels) in coerce_arguments'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/dataloader/null_dataloader.rb:17:in `append_job'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/member/has_arguments.rb:185:in `block (2 levels) in coerce_arguments'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/member/has_arguments.rb:184:in `each'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/member/has_arguments.rb:184:in `block in coerce_arguments'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema/member/has_arguments.rb:213:in `coerce_arguments'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/arguments_cache.rb:52:in `dataload_for'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:431:in `evaluate_selection'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:359:in `block (2 levels) in evaluate_selections'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/dataloader/null_dataloader.rb:17:in `append_job'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:358:in `block in evaluate_selections'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:357:in `each'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:357:in `evaluate_selections'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:231:in `block (4 levels) in run_eager'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:812:in `call_method_on_directives'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:230:in `block (3 levels) in run_eager'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/dataloader/null_dataloader.rb:17:in `append_job'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:228:in `block (2 levels) in run_eager'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:190:in `tap_or_each'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:219:in `block in run_eager'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:812:in `call_method_on_directives'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter/runtime.rb:210:in `run_eager'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter.rb:73:in `block in evaluate'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:81:in `call_tracers'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:83:in `block in call_tracers'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-fragment_cache-1.11.0/lib/graphql/fragment_cache/schema/tracer.rb:12:in `trace'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:83:in `call_tracers'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:67:in `trace'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter.rb:72:in `evaluate'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/interpreter.rb:48:in `begin_query'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:85:in `begin_query'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:104:in `block (2 levels) in run_as_multiplex'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/dataloader/null_dataloader.rb:17:in `append_job'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:104:in `block in run_as_multiplex'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:103:in `each'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:103:in `each_with_index'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:103:in `run_as_multiplex'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:63:in `block (2 levels) in run_queries'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:211:in `block in instrument_and_analyze'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:29:in `block (2 levels) in apply_instrumenters'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:46:in `block (2 levels) in each_query_call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:46:in `block (2 levels) in each_query_call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:41:in `each_query_call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:45:in `block in each_query_call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:72:in `call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:44:in `each_query_call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:45:in `block in each_query_call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:72:in `call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:44:in `each_query_call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:27:in `block in apply_instrumenters'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:72:in `call_hooks'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/instrumentation.rb:26:in `apply_instrumenters'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:190:in `instrument_and_analyze'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:62:in `block in run_queries'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:81:in `call_tracers'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:83:in `block in call_tracers'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-fragment_cache-1.11.0/lib/graphql/fragment_cache/schema/tracer.rb:12:in `trace'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:83:in `call_tracers'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/tracing.rb:67:in `trace'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:60:in `run_queries'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/execution/multiplex.rb:50:in `run_all'
/Users/victor/.rvm/gems/ruby-2.7.4/gems/graphql-1.13.10/lib/graphql/schema.rb:1767:in `multiplex'
/Users/victor/Development/project/app/controllers/graphql_controller.rb:49:in `create'

I can call .resolve on this and get a Hash, but then some custom relationships that access object.comments would fail as it's now a Hash, which means I probably need to Post.build(cache_fragment { }.resolve) or something, but from what I understand this should not be needed.

For what it's worth, I have a custom field class that looks like:

module Types::Base
  class Field < GraphQL::Schema::Field
    argument_class Types::Base::Argument

    # Pass `field ..., unauthorized: true` to allow public requests
    def initialize(*args, unauthorized: false, **kwargs, &block)
      @unauthorized = unauthorized
      super(*args, **kwargs, &block)
    end

    # Only allow logged in users unless authorized: true
    def authorized?(obj, args, ctx)
      return true if @unauthorized
      return false unless ctx[:current_user].present?
      true
    end
  end
end

I have included it in my schema like so:

class ProjectSchema < GraphQL::Schema
  use GraphQL::FragmentCache
  use GraphQL::Subscriptions::ActionCableSubscriptions, serializer: Subscriptions::Serialize
  mutation(Types::MutationType)
  query(Types::QueryType)
  subscription(Types::SubscriptionType)
  use GraphQL::Decorate

and applied it to my base resolver:

module Resolvers
  class Base < GraphQL::Schema::Resolver
    argument_class Types::Base::Argument
    include GraphQL::FragmentCache::ObjectHelpers
...

and to my base object:

module Types::Base
  class Object < GraphQL::Schema::Object
    include GraphQL::FragmentCache::Object
    include GraphQL::Decorate::ObjectIntegration
    field_class(Types::Base::Field)
    edge_type_class(Types::Base::Edge)
    connection_type_class(Types::Base::Connection)
  end
end

What am I doing wrong here?

What am I doing wrong here?

Federated queries including cached fields raises an error

Hi there,

We use https://github.com/Gusto/apollo-federation-ruby

When making federated queries that include fields that are cached with graphql-ruby-fragment_cache, we get the error:

RuntimeError: Failed to look ahead the field: variations

Happy to look into this more, but not quite sure where to begin. Got any ideas?

Request body:

{
   "query":"query($representations:[_Any!]!){_entities(representations:$representations){...on ProductCatalogProduct{name variations{id name texture{normalMapThumbnail{redirectUrl __typename}__typename}__typename}}}}",
   "variables":{
      "representations":[
         {
            "__typename":"ProductCatalogProduct",
            "id":"0cb9b065-9153-40d0-873c-81da94e93d19"
         }
      ]
   }
}

Error stacktrace:

File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 171 in block (2 levels) in path_cache_key
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 166 in map
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 166 in block in path_cache_key
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 163 in fetch
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 163 in path_cache_key
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 147 in block in query_cache_key
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 147 in fetch
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 147 in query_cache_key
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 129 in build
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/cache_key_builder.rb line 114 in call
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/fragment.rb line 28 in cache_key
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/fragment.rb line 50 in value_from_cache
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/fragment.rb line 24 in read
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/object_helpers.rb line 37 in cache_fragment
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/field_extension.rb line 52 in resolve
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/field.rb line 780 in run_extensions_before_resolve
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/field.rb line 756 in with_extensions
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/field.rb line 696 in public_send_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/field.rb line 609 in block in resolve
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema.rb line 115 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/field.rb line 607 in resolve
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 272 in block (4 levels) in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 81 in call_tracers
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in block in call_tracers
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/schema/tracer.rb line 12 in trace
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in call_tracers
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in block in call_tracers
File /usr/local/bundle/gems/apollo-federation-1.1.5/lib/apollo-federation/tracing/tracer.rb line 114 in execute_field
File /usr/local/bundle/gems/apollo-federation-1.1.5/lib/apollo-federation/tracing/tracer.rb line 50 in trace
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in call_tracers
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 67 in trace
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 271 in block (3 levels) in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/query.rb line 364 in block in with_error_handling
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/errors.rb line 45 in with_error_handling
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/query.rb line 363 in with_error_handling
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 270 in block (2 levels) in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 432 in resolve_with_directives
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 267 in block in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 214 in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 202 in evaluate_selection
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 142 in block (2 levels) in evaluate_selections
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/dataloader/null_dataloader.rb line 16 in append_job
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 141 in block in evaluate_selections
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 140 in each
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 140 in evaluate_selections
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 384 in block in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 378 in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 425 in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 405 in block (2 levels) in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 402 in block in continue_field
File /usr/local/bundle/gems/activerecord-6.1.3.1/lib/active_record/relation/delegation.rb line 88 in each
File /usr/local/bundle/gems/activerecord-6.1.3.1/lib/active_record/relation/delegation.rb line 88 in each
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 395 in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 425 in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 284 in block (3 levels) in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 278 in block (2 levels) in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 432 in resolve_with_directives
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 267 in block in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 214 in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 206 in block in evaluate_selection
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/member/has_arguments.rb line 132 in block (2 levels) in coerce_arguments
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/dataloader/null_dataloader.rb line 16 in append_job
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/member/has_arguments.rb line 111 in block in coerce_arguments
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/member/has_arguments.rb line 110 in each
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/member/has_arguments.rb line 110 in coerce_arguments
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/arguments_cache.rb line 49 in dataload_for
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 205 in evaluate_selection
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 142 in block (2 levels) in evaluate_selections
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/dataloader/null_dataloader.rb line 16 in append_job
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 141 in block in evaluate_selections
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 140 in each
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 140 in evaluate_selections
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 384 in block in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 378 in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 369 in block in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 358 in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 405 in block (2 levels) in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 402 in block in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 395 in each
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 395 in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 425 in continue_field
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 284 in block (3 levels) in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 278 in block (2 levels) in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 432 in resolve_with_directives
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 267 in block in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 516 in after_lazy
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 214 in evaluate_selection_with_args
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 206 in block in evaluate_selection
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/member/has_arguments.rb line 132 in block (2 levels) in coerce_arguments
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/dataloader/null_dataloader.rb line 16 in append_job
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/member/has_arguments.rb line 111 in block in coerce_arguments
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/member/has_arguments.rb line 110 in each
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema/member/has_arguments.rb line 110 in coerce_arguments
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/arguments_cache.rb line 49 in dataload_for
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 205 in evaluate_selection
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 142 in block (2 levels) in evaluate_selections
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/dataloader/null_dataloader.rb line 16 in append_job
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 141 in block in evaluate_selections
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 140 in each
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 140 in evaluate_selections
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 62 in block in run_eager
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/dataloader/null_dataloader.rb line 16 in append_job
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter/runtime.rb line 61 in run_eager
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter.rb line 77 in block in evaluate
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 81 in call_tracers
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in block in call_tracers
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/schema/tracer.rb line 12 in trace
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in call_tracers
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in block in call_tracers
File /usr/local/bundle/gems/apollo-federation-1.1.5/lib/apollo-federation/tracing/tracer.rb line 54 in trace
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in call_tracers
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 67 in trace
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter.rb line 76 in evaluate
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/interpreter.rb line 49 in begin_query
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 85 in begin_query
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 104 in block (2 levels) in run_as_multiplex
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/dataloader/null_dataloader.rb line 16 in append_job
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 104 in block in run_as_multiplex
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 103 in each
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 103 in each_with_index
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 103 in run_as_multiplex
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 63 in block (2 levels) in run_queries
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 208 in block in instrument_and_analyze
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/instrumentation.rb line 29 in block (2 levels) in apply_instrumenters
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/instrumentation.rb line 46 in block (2 levels) in each_query_call_hooks
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/instrumentation.rb line 41 in each_query_call_hooks
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/instrumentation.rb line 45 in block in each_query_call_hooks
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/instrumentation.rb line 72 in call_hooks
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/instrumentation.rb line 44 in each_query_call_hooks
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/instrumentation.rb line 27 in block in apply_instrumenters
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/instrumentation.rb line 72 in call_hooks
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/instrumentation.rb line 26 in apply_instrumenters
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 187 in instrument_and_analyze
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 62 in block in run_queries
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 81 in call_tracers
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in block in call_tracers
File /usr/local/bundle/gems/graphql-fragment_cache-1.6.0/lib/graphql/fragment_cache/schema/tracer.rb line 12 in trace
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in call_tracers
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in block in call_tracers
File /usr/local/bundle/gems/apollo-federation-1.1.5/lib/apollo-federation/tracing/tracer.rb line 63 in execute_multiplex
File /usr/local/bundle/gems/apollo-federation-1.1.5/lib/apollo-federation/tracing/tracer.rb line 46 in trace
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 83 in call_tracers
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/tracing.rb line 67 in trace
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 60 in run_queries
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/execution/multiplex.rb line 50 in run_all
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema.rb line 1691 in multiplex
File /usr/local/bundle/gems/graphql-1.12.6/lib/graphql/schema.rb line 1662 in execute
File /usr/src/app/app/controllers/graphql_controller.rb line 6 in execute

Problem with AR collection

I have problem with AR collections.
When I try to read a collection, I get an error related to the cache key

rails 6.0.3.1
graphql-fragment_cache 0.1.5
graphql 1.10.10
ruby 2.7.1

module Types
  class QueryType < Types::BaseObject
    field :exercise, Types::ExerciseType, resolver: Queries::ExerciseQuery
    field :exercises, [Types::ExerciseType], resolver: Queries::ExercisesQuery, cache_fragment: true
 end
end
module Types
  class ExerciseType < Types::BaseObject
    field :id, ID, null: false
    field :course_id, ID, null: false, cache_fragment: true
  end
end

And resolvers

module Queries
  class ExerciseResolver < Queries::BaseQuery
    argument :id, ID, required: true
    type Types::ExerciseType, null: true

    def resolve(id:)
      Exercise.find(id)
    end
  end
end
module Queries
  class ExercisesResolver < Queries::BaseQuery
    type [Types::ExerciseType], null: true

    def resolve(id:)
      Exercise.all
    end
  end
end

and when I trying to get a collection if any of fields Types::ExerciseType uses caching, then I get an error

rails_1        | [9ecf2522-ed52-4d25-b5b1-62631be97a01] Failed to look ahead the field: 0
rails_1        | [9ecf2522-ed52-4d25-b5b1-62631be97a01] /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/cache_key_builder.rb:137:in `block in path_cache_key'
rails_1        | /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/cache_key_builder.rb:135:in `map'
rails_1        | /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/cache_key_builder.rb:135:in `path_cache_key'
rails_1        | /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/cache_key_builder.rb:122:in `query_cache_key'
rails_1        | /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/cache_key_builder.rb:109:in `build'
rails_1        | /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/cache_key_builder.rb:94:in `call'
rails_1        | /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/fragment.rb:31:in `cache_key'
rails_1        | /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/fragment.rb:20:in `read'
rails_1        | /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/object_helpers.rb:26:in `cache_fragment'
rails_1        | /usr/local/bundle/gems/graphql-fragment_cache-0.1.5/lib/graphql/fragment_cache/field_extension.rb:52:in `resolve'
rails_1        | /usr/local/bundle/gems/graphql-1.10.10/lib/graphql/schema/field.rb:757:in `run_extensions_before_resolve'
rails_1        | /usr/local/bundle/gems/graphql-1.10.10/lib/graphql/schema/field.rb:739:in `with_extensions'
rails_1        | /usr/local/bundle/gems/graphql-1.10.10/lib/graphql/schema/field.rb:561:in `resolve'

Schema.instrument is deprecated

When running this with graphql 2.2.7, it shows a deprecation warning:

Schema.instrument is deprecated, use `trace_with` instead: https://graphql-ruby.org/queries/tracing.html"
  (From `MyAppSchema.instrument(query, GraphQL::FragmentCache::Schema::Instrumentation)` at /Users/myuser/.gem/ruby/3.2.2/gems/graphql-fragment_cache-1.19.0/lib/graphql/fragment_cache.rb:35:in `use')

Package not working with graphql-ruby > 1.12.10

Issue:
Getting an undefined method error for versions of GraphQL Ruby greater than v1.12.10.

undefined method `final_value' for #<GraphQL::Execution::Interpreter::Runtime:0x00007f223dddedf0>
Did you mean?  final_result
/usr/local/bundle/gems/graphql-fragment_cache-0.1.4/lib/graphql/fragment_cache/cacher.rb:13:in `call'
/usr/local/bundle/gems/graphql-fragment_cache-0.1.4/lib/graphql/fragment_cache/instrumentation.rb:17:in `after_query'

I fixed this by downgrading to v1.12.10.
Maybe this method got renamed to final_result in the later versions?
See API docs here:
https://graphql-ruby.org/api-doc/1.12.10/GraphQL/Execution/Interpreter/Runtime.html#final_value-instance_method
vs
https://graphql-ruby.org/api-doc/1.12.14/GraphQL/Execution/Interpreter/Runtime.html#final_result-instance_method

Love the package otherwise. Keep up the great work πŸ™

Fragment cache somtimes returns null despite cached data loading initially

Hi there,

ENV:
We are currently using your gem on our Rails api which passes data through to an Apollo Angular app. We originally had a pure rails solution but got better performance results with your gem.

Issue:
The problem is that sometimes the cache returns null. This doesn't happen locally but happens when we use the cache on Redis for staging and production. The cached data is returned most of the time but sometimes returns null. We have investigated as much as we could: we first thought it might be the front end but we have narrowed it down to the cache returning null.

How to reproduce:
This only works some of the time

  1. load the site the first time to populate the cache (works)
  2. hard refresh and reload the site (network results show that cache is working)
    image
  3. waiting a while (5 - 10 ish minutes) and loading the page again (returns null). The cache set to expire after 2 hours. Checking Redis shows that the key is still present when this failure occurs.
    image

Question:
Do you have any ideas on what might be causing this or what we might be able to do? Thank you in advance.

Per request cache?

Forgive me if this is out of scope, or I am missing something here. The problem I am seeking to solve is let's say you have 50 people in a list, and they all have the same creator. The current Ruby GraphQL gem will call resolve and serialze the response 50 times. I've been playing around with this gem a bit and don't notice any difference at all in the performance of caching the result. But, I am also concerned because I don't really want to cache the result after the current request ends, because the data might change and I don't want to have to deal with cache invalidation. I was hoping this gem would allow me to resolve creator (and serialize it, which is where ruby_graphql seems to spend the most time) once.


people {
   id
   creator {
     id
     email
   }
}

cache slows down for large responses

Hi, Amazing gem, really useful and I love the api :D

I'm working on an api that sometimes returns massive amounts of data up to 27mB and the cached responses are a bit slow.

I'm guessing this has to do with parsing the cached data text to a hash/json. Do you think it's possible to speed this up at all?

the response time seems linearly correlated with response size
image

Thanks for the help!

Rails cache_key_with_version and cache_key not actually called in code

Hi! πŸ‘‹ Thanks for this great library, it's wonderful.

The docs state that the the Rails cache functions cache_key_with_version and cache_key will be called if it exists, but it doesn't actually call them in the Rails cache key builder:

def object_key(obj)
return obj.graphql_cache_key if obj.respond_to?(:graphql_cache_key)
return obj.map { |item| object_key(item) }.join("/") if obj.is_a?(Array)
return object_key(obj.to_a) if obj.respond_to?(:to_a)
ActiveSupport::Cache.expand_cache_key(obj)
end

and cache_key_with_version doesn't actually show up anywhere in the code except the README.

context is a Hash instead of GraphQL::Query::Context, causing runtime errors

Hello,

I'm running into the exact same error that @CestarBe had in #26, namely that when the context object is being referenced by this library, it is just a Hash and not a GraphQL::Query::Context, therefore it does not have a method called namespace.

#<NoMethodError: undefined method `namespace' for #<Hash:0x00007f2bc3d9f8c8>>

I attempted to debug this by printing the class of context inside my QueryType object and it says that even there the context is just a Hash.

My query object looks something like this:

class QueryType < Types::BaseObject
  field get_post, Post
  
  def post
    print(context.class) # <--- THIS IS A HASH
    PostResolver.new.call(object, args, context)
  end
end

Anyone have any ideas how this could be happening? My GraphqlController and Schema setups look just like the examples in the documentation.

Way to conditionally use fragment cache?

Basically topic, but would like a way to only go through the cache under certain conditions (couldn't tell from code or docs if already supported). For example, if a particular query will explode the cardinality but I want the base case to be cached. Contrived example:

field :search_movies, [MovieResultType], null: false do
  argument :query, String, required: false
end
def search_movies(query: nil)
  cache_fragment(disabled: !query.blank?) do
    Movie.do_expensive_search(query) # and expensive resolving
  end
end

Specs fail when testing cached fields

I have a spec that unit tests a cached graphql field using a custom spec helper.

The class to test and the spec look something like this:

# app/graphql/types/objects/post_type.rb
module Types
  module Objects
    class PostType < Base
      field :comments, Types::Objects::CommentType.connection_type, cache_fragment: true

      def comments
        # ...
      end
    end
  end
end

# spec/graphql/types/objects/post_type_spec.rb
module Types
  module Objects
    describe PostType do
      subject(:post) { create(:post) }

      describe '#comments' do
        before { create_list(:comment, 2, post: post) }

        it { expect(resolve(post, :comments).count).to eq 2 }
      end
    end
  end
end

And the file that provides the resolve helper method looks a bit like this:

# spec/support/graphql/helpers.rb
module GraphQL
  module Helpers
    def resolve(object, field, args = {})
      query = GraphQL::Query.new(MyAppSchema, context: context)
      field = subject.fields[field.to_s.camelize(:lower)]
      type_instance = described_class.authorized_new(object, query.context)
      args.transform_keys! { |arg| arg.to_s.underscore.to_sym }

      resolved = field.resolve(type_instance, args, query.context)

      if resolved.is_a?(GraphQL::Pagination::Connection)
        resolved.nodes
      else
        resolved
      end
    end
  end
end

But when I run the spec I get the following error:

 NoMethodError:
   undefined method `count' for #<GraphQL::Execution::Lazy:0x00007f7e583a5010>
 # ./spec/graphql/types/objects/post_type_spec.rb:1287:in `block (4 levels) in <module:Objects>'

The problem is that in my graphql helper, resolved is a GraphQL::Execution::Lazy object, and this object behaves differently than a more traditional GraphQL::Pagination::Connection object.

I am not familiar with graphql-ruby's internals. I tried resolved.value but I get another error

NoMethodError: undefined method `operation_type' for nil:NilClass
from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/graphql-1.12.6/lib/graphql/query.rb:167:in `lookahead'

Maybe I somehow need to provide operation_type in my helper, although I don't know what value I could provide and where. Or maybe I am on the wrong path.

Any idea what I would need to fix this? Like how to get the nodes from a GraphQL::Execution::Lazy?

In the meantime I have disabled caching for the test environment with the following monkey patch. If noone has any idea, maybe converting my monkey patch into a PR could be an acceptable workaround.

Adding an additional cache key

We have a use case in Rails where we need to specify a cache key (from a Rails ActiveRecord::Relation), but it's not the return value - the relation is processed, which takes quite a long time. Unfortunately, specifying query_cache_key removes the path and the selections keys, which we also need. There does not seem to be a way to specify "extra key". Something like this:

cache_fragment(object_cache_key: where_class.cache_key_with_version) { where_class.do_something }

And the resulting cache key would be:

52355f50328bf0e765dd0cfcc89f11a5f503a082/special_models/query-f99c1b73939dae707295bf67deadbeef-1-20210212224532037173

(or it would be hashed)

I'm thinking it would be like this:

    class CacheKeyBuilder
      def object_key(obj)
        @options.fetch(:object_cache_key) { obj._graphql_cache_key }
      end
    end

Do you think this is a reasonable feature?

[Unable to use] graphql-ruby-fragment_cache + action_policy-graphql

I am trying to use both fragment caching + action policy and due to lack of documentation I am unable to make it work if I have a authorized_scope: true if my field

if I have a field like this:
field :collections, [CollectionType], null: false, authorized_scope: true, cache_fragment: { context_key: :current_user } do

I get an error:

Couldn't find policy class for.... "Couldn't find implicit authorization target for Types::QueryType. Please, provide policy class explicitly using `with` option or define the `implicit_authorization_target` method."] (Array)```

If I add a explicit policy:

field :collections, [CollectionType], null: false, authorized_scope: { with: CollectionTypePolicy }, cache_fragment: { context_key: :current_user } do

I get a different error:

Couldn't infer scope type for GraphQL::Execution::Interpreter::RawValue instance

It works flawlessly for fields without authorization scope, so not sure what I need to add/change on my end or what is missing

How do I expire a cached collection when a sub model changes?

Hey there,

Love this gem. The examples show how to set cache keys for a single record. How do I expire cache keys for collections?

For example,

class Post < ApplicationRecord
  has_many :comments
end

class Comment < ApplicationRecord
  belongs_to :post
end

# somewhere in the GraphQL schema
field :posts, [PostType], null: false, cache_fragment: { context_key: [:current_user] }

I'm not sure how to expire the cached "posts" field.

I tried using "touch".

class Comment < ApplicationRecord
  belongs_to :post, touch: true
end

But it's not expiring the posts field.

Make the cache key human-readable

I have the following quick and dirty monkey patch:

# Monkey patch to make the cache key more human-readable for easier debugging
module GraphQL
  module FragmentCache
    class CacheKeyBuilder
      module MonkeyPatch
        def implicit_cache_key
          full_cache_key = query_cache_key
          cache_key_first_part = full_cache_key.split('(').first.split('[').first.tr('/', '-')
          hex_cache_key = Digest::SHA1.hexdigest(full_cache_key)

          "#{cache_key_first_part}/#{hex_cache_key}"
        end

        def object_cache_key
          super&.tr('/', '-')
        end
      end
      prepend MonkeyPatch
    end
  end
end

This makes cache keys look like this:

[41] pry(main)> $redis.keys('graphql*').sort
[
    [ 0] "graphql/post/766b6ccc10ab9495379351ee8beafea5c6007503/1595-mycorp",
    [ 1] "graphql/currentTenant-activities/8fb06e96554aadb59acc95055d94ac32e35ad383/1595-mycorp",
    [ 2] "graphql/currentTenant-posts/f328972b1d41071057c1e9b2ba2942376ead0def/posts-query-5f6b140cd0b110df8830cb806289afae-6-20220927164337385299-mycorp",
    [ 3] "graphql/currentTenant-orgs/8cd8ca77d3d80ce63a3c71f3458e13f871976742/orgs-query-a1cd705421842de6905cfb2f6c372fc8-1-20220908170650370442-mycorp",
    [ 4] "graphql/currentTenant-orgs/9d43405f9a04e5a7007c7a5b23e9a83025195513/orgs-query-a1cd705421842de6905cfb2f6c372fc8-1-20220908170650370442-mycorp",
    [ 5] "graphql/currentUser-companies-0-plans/636959b06ed3087a042294887cf024825324b17d/companies-28712-20221017002729396154-mycorp",
    [ 6] "graphql/currentUser-companies/3ce35c987a1634135bfdde439535f8d0d80c70ab/users-234196-20221017141421202813-mycorp",
    [ 7] "graphql/tool/136783447b0def9ee3eeffdee6e7d0724b25729d",
    [ 8] "graphql/tool/18ab5818aea282fc778f11f263862d7420491eab/tools-989-20221018005011056666-mycorp",
    [ 9] "graphql/tool/476a0e82181713884b6fc38efd8668cb55b35e16/companies-1281-20221018005011252828-mycorp",
    [10] "graphql/tool/59965cf1a9b31ce7dae6722c5a786a66658c865e/tools-989-20221018005011056666-mycorp"
]

What is nice is that I now get a pretty good idea of what the key is about: the query fingerprint is still there in the middle, but it is prefixed with the query path in plain text, and suffixed with the object cache key in plain text.

This has proved very valuable:

  • when debugging what my keys look like in development, to make sure I am caching with the right object key, saving a lot of potential headaches and bug investigations downstream
  • when searching for keys in general ($redis.keys('*activities*')) or for a particular customer ($redis.keys('*activities*mycorp'))
  • when surgically deleting bad keys for a given query or customer in production (Rails.cache.delete_matched('*posts*')) without having to use the nuclear Rails.cache.clear option

On the flip side the keys are longer, but in practice it hasn't been a problem in my app. I should also mention that I am using redis as my cache store, and since the max key size is 512 MB, I probably won't ever have the issue of keys being too long.

I feel like an option to make keys more human-readable (or maybe even by default) would be helpful. But maybe my needs are too specific.

Do you this is somewhat useful? If so we could make a PR.

Cache expiration

class PostType < GraphQL::Schema::Object
  field :id, ID, null: false
  field :title, String, null: false, cache_fragment: { ex: 2.days }
end

class QueryType < GraphQL::Schema::Object
  field :post, PostType, null: true do
    argument :id, ID, required: true
  end

  def post(id:)
    cache_fragment(ex: 2.days) { Post.find(id) }
  end
end

Namespace issue

I understand that you can setup namespace by either

  1. GraphQL::FragmentCache.namespace = "my-prefix"
  2. GraphQL::FragmentCache.configure { |config| config.namespace = "my-prefix" }

It isn't clear to me whether I can set namespace under config.default_options, eg

GraphQL::FragmentCache.configure do |config|
  config.default_options = {
    namespace: "my-prefix"
  }
end

However when I did the above, I got unexpected behaviour where the cache store tries to read the cache key without namespace but write with the namespace as part of the cache key.

Frankly I would expect namespace to be configured as part of the cache store options in which case each individual cache store would handle the namespace

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.