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

Lookahead for fragments #2053

Closed
Matt888 opened this issue Jan 15, 2019 · 7 comments
Closed

Lookahead for fragments #2053

Matt888 opened this issue Jan 15, 2019 · 7 comments
Assignees
Milestone

Comments

@Matt888
Copy link

Matt888 commented Jan 15, 2019

When attempting to transition from using irep_node to get the list of fields for a query, to using lookahead, this error pops up:

RuntimeError: Invariant: no field for InjectedTestFragment

On v1.8.13, query:

<<~QUERY
  query TestQuery {
    node(id: "1") {
      ...InjectedTestFragment
      id
    }
  }
QUERY

I tried returning nil like master does in lookahead.rb, but that results in no selections at all:

lookahead.selections
=> []

In irep_node, it seemed like it correctly resolved fragments, so it was straightforward to get the requested fields.

cc @swalkinshaw @dylanahsmith

@rmosolgo
Copy link
Owner

rmosolgo commented Jan 16, 2019

Uh oh! I think master has some improvements to lookahead, see for example #1933. (It was put on 1.9-dev, which has since been merged into master). Could you try again on master?

I'm hoping to cut a new 1.9-pre version today (waiting for #2054 at least), so if you'd rather wait for a Rubygems version, it shouldn't be long!

@Matt888
Copy link
Author

Matt888 commented Jan 17, 2019

I just used master to test, and I get the same issue where .selections is an empty array for the above query

@rmosolgo
Copy link
Owner

Oh! sorry to hear it. What is InjectedTestFragment in the query above? (I was guessing it was left out of the example since its contents could be assumed, is that right?)

I made a script to replicate it:

# __lookahead_test.rb
$LOAD_PATH << "./lib"
require "graphql"
puts GraphQL::VERSION

class Node < GraphQL::Schema::Object
  field :id, ID, null: false
end

class Query < GraphQL::Schema::Object
  field :node, Node, null: true, extras: [:lookahead] do
    argument :id, ID, required: true
  end

  def node(id:, lookahead:)
    p lookahead.selections.map(&:name)
    nil
  end
end

class Schema < GraphQL::Schema
  query(Query)
end


p Schema.execute <<-GRAPHQL
  query TestQuery {
    node(id: "1") {
      ...InjectedTestFragment
      id
    }
  }

  fragment InjectedTestFragment on Node {
    __typename
  }
GRAPHQL

But when I run it on my local master, it correctly shows both fields:

~/code/graphql-ruby $ ruby __lookahead_test.rb
1.9.0.pre2
[:__typename, :id]
#<GraphQL::Query::Result @query=... @to_h={"data"=>{"node"=>nil}}>

Can you update that example to demonstrate the failure you're observing?

@Matt888
Copy link
Author

Matt888 commented Jan 18, 2019

Sorry for the delay in getting back to you... it turns out the issue is with Interfaces. Here's the modified script:

# __lookahead_test.rb
$LOAD_PATH << "./lib"
require "graphql"
puts GraphQL::VERSION

Widget = Struct.new(:id, :name)
WIDGETS = [Widget.new("1", "foo")]

module Node
  include GraphQL::Schema::Interface

  field :id, ID, null: false

  definition_methods do
    def resolve_type(object, ctx)
      WidgetType
    end
  end
end

class WidgetType < GraphQL::Schema::Object
  implements Node

  field :name, String, null: false
end

class QueryRoot < GraphQL::Schema::Object
  field :widget, WidgetType, null: false
  field :node, Node, null: false, extras: [:lookahead] do
    argument :id, ID, required: true
  end

  def node(id:, lookahead:)
    p lookahead.selections.map(&:name)
    WIDGETS.first
  end

  def widget
    WIDGETS.first
  end
end

class Schema < GraphQL::Schema
  orphan_types WidgetType
  query(QueryRoot)
end

p Schema.execute <<~GRAPHQL
  query {
    node(id: "1") {
      id
      ... on Widget {
        name
      }
    }
  }
GRAPHQL

When this runs, we get:

1.9.0.pre2
[:id]
#<GraphQL::Query::Result @query=... @to_h={"data"=>{"node"=>{"id"=>"1", "name"=>"foo"}}}>

So the selections on the interface itself (:id) is captured, but the selections on the nested fragment are not captured.

@rmosolgo
Copy link
Owner

Ohhhh thanks for figuring that out! I'll take a look early next week and follow up here.

@rmosolgo rmosolgo added this to the 1.9.0 milestone Jan 18, 2019
@rmosolgo rmosolgo self-assigned this Jan 18, 2019
@rmosolgo
Copy link
Owner

Feel free to give it another go on master and let me know what you think 🍻 !

@Matt888
Copy link
Author

Matt888 commented Jan 22, 2019

Awesome!

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