Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarification on cache_key options #98

Closed
gsdean opened this issue Jan 19, 2023 · 6 comments
Closed

Clarification on cache_key options #98

gsdean opened this issue Jan 19, 2023 · 6 comments

Comments

@gsdean
Copy link
Contributor

gsdean commented Jan 19, 2023

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.

@DmitryTsepelev
Copy link
Owner

Hey! The difference is that when you pass only argument (second snippet) it will be used both for building the cache key and as a value for caching, and when you pass an argument and a block — it will build the key using object but return the value.

For instance, imagine that post somehow depends on the user. In this case you might want to cache the post for this particular user, not for everyone:

def post(id:)
  post = Post.find(id)
  cache_fragment([post, current_user]) { post }
end

In case of cache_fragment(Post.find(id)) you do not have this granularity of control: it will grab post, build a key from it and return it back.

@gsdean
Copy link
Contributor Author

gsdean commented Jan 28, 2023

Sorry for being obtuse here, but its still not clear from the documentation what the difference between :value and :object is in terms of cache_key:.

@DmitryTsepelev
Copy link
Owner

@gsdean but the explanation above is more clear, right?

@gsdean
Copy link
Contributor Author

gsdean commented Feb 6, 2023

Sadly no, I think what would be helpful is to clarify the difference in terms of just the attribute without overriding the getter. In other words, what is the difference between:

field :post, PostType, null: true, cache_fragment: {cache_key: :value}

and

field :post, PostType, null: true, cache_fragment: {cache_key: :object}

?

@gsdean
Copy link
Contributor Author

gsdean commented Feb 6, 2023

Also not to hijack the thread, but have you seen this #72 (comment)

There is a pretty serious race condition that we should probably address.

@DmitryTsepelev
Copy link
Owner

When cache_key is equals :value then the value from the resolver method will be used as a key, when you use object — current object will be used as a key.

For instance impagine a post that has the author, and for some reason we want author cache to be refreshed only when post is updated. In this case we can do this:

class Post
  field :cached_author, Types::User, null: true, cache_fragment: {cache_key: :object}

  def cached_author
    object.author
  end
end

class Query < Base
  field :post, Post, null: true do
    argument :id, GraphQL::Types::ID, required: true
  end

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

If you keep this code as is than Post instance will be a key for this cached author, otherwise — author itself.

The same thing but in code https://github.com/DmitryTsepelev/graphql-ruby-fragment_cache/blob/master/spec/graphql/fragment_cache/field_extensions_spec.rb#L171.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants