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

Unexpected 'Fragment cannot be spread' error #493

Closed
AlistairB opened this issue Jul 30, 2020 · 16 comments
Closed

Unexpected 'Fragment cannot be spread' error #493

AlistairB opened this issue Jul 30, 2020 · 16 comments

Comments

@AlistairB
Copy link
Contributor

Hi,

I am trying to use interfaces in my query using morpheus client. My gql file looks something like (excluded some excessive detail. Let me know if you want my full file):

"""
An object with an ID.
"""
interface Node {
  """
  ID of the object.
  """
  id: ID!
}

"""
Represents a Git object.
"""
interface GitObject {
  id: ID!
}

"""
Represents a Git reference.
"""
type Ref implements Node {
  id: ID!

  """
  The object the ref points to.
  """
  target: GitObject!
}

type Commit implements GitObject & Node {

  id: ID!

  """
  Authorship details of the commit.
  """
  author: String
}

type Tree implements GitObject & Node {
  """
  A list of tree entries.
  """
  treeName: String

  id: ID!
}

And my query looks something like:

defineByDocumentFile
  "../resource/minimal-github.graphql"
  [gql|
    query FetchRepoHeadCommit ($repoOwner: String!, $repoName: String!) {
      repository(name: $repoName, owner: $repoOwner) {
        defaultBranchRef {
          target {
            ... on Commit {
               author
            }
          }
        }
      }
    }
  |]

This fails with Fragment cannot be spread here as objects of type \"GitObject\" can never be of type \"Commit\. Changing target: GitObject! to target: Commit! makes it work. This confuses me as I have type Commit implements GitObject.

My expectation is that this should work based on 2 from https://github.com/morpheusgraphql/morpheus-graphql#interface . Am I missing something?

@nalchevanidze
Copy link
Member

nalchevanidze commented Jul 30, 2020

Thanks, you are right.

Query validation was written before we supported "interfaces", so i forgot to update it too.

I will fix it

@nalchevanidze
Copy link
Member

nalchevanidze commented Aug 1, 2020

@AlistairB i started it #495

@nalchevanidze
Copy link
Member

nalchevanidze commented Aug 3, 2020

@AlistairB please try it with actual master

@AlistairB
Copy link
Contributor Author

Unfortunately I am still getting the same error building with morpheus based on commit 57de511 (current head on master).

@nalchevanidze
Copy link
Member

ooh. that weird i wrote tests for it. can you share full schema?

@nalchevanidze
Copy link
Member

and query with fragment

@AlistairB
Copy link
Contributor Author

If you clone https://github.com/AlistairB/morpheus-repro and stack build it should reproduce the issue. It will only compile if you change https://github.com/AlistairB/morpheus-repro/blob/master/minimal-github.graphql#L89 to target: Commit!.

@nalchevanidze
Copy link
Member

nalchevanidze commented Aug 3, 2020

so, if we have schema.

interface GitObject {
  id: ID!
}

type Commit implements GitObject & Node {
  id: ID!
  author: String
}

type Query  {
  target: GitObject!
}

your query would look like:

{
   target {
    ... on Commit {
         author
         }
   }
}

and would be invalid. as long target guarantees to provide fields defined by GitObject (not by Commit).

so, if we had schema where target has concrete type Commit.

interface GitObject {
  id: ID!
}

type Commit implements GitObject & Node {
  id: ID!
  author: String
}

type Query  {
  target: Commit!
}

then we could query on it GitObject and Commit.

{
   t1: target {
    ... on Commit {
         author
         }
   }
   t2: target {
    ... on GitObject {
         author
         }
   }
}

@AlistairB
Copy link
Contributor Author

AlistairB commented Aug 3, 2020

Hmm, I'm not sure if I understand. My understanding is that you can use the spread operator to conditionally get data IF the type matches.

For example using https://developer.github.com/v4/explorer/

query { 
  repository(owner: "facebook", name: "react") {
    defaultBranchRef {
      target {
        id
        ... on Commit {
          author {
            name
          }
        }
      }
    }
  }
}

will fetch all this data, as target is in fact a Commit.

On the other hand:

query { 
  repository(owner: "facebook", name: "react") {
    defaultBranchRef {
      target {
        id
        ... on Blob {
          byteSize
        }
      }
    }
  }
}

Will only fetch the id, but will not return an error. This is because target: GitObject and type Blob implements GitObject, so it could be a Blob.

And you can combine them:

query { 
  repository(owner: "facebook", name: "react") {
    defaultBranchRef {
      target {
        id
        ... on Commit {
          author {
            name
          }
        }
        ... on Blob {
          byteSize
        }        
      }
    }
  }
}

In terms of the schema I am using, I have directly copied the bits I need from the official github public schema. See https://docs.github.com/en/graphql/overview/public-schema .

This query with the schema does work on github which makes me think it is valid?

@nalchevanidze
Copy link
Member

nalchevanidze commented Aug 3, 2020

@AlistairB okey. may i got something wrong. what you say looks like type casting.
i will read specifications and fix it.

@nalchevanidze
Copy link
Member

@AlistairB can you check again , i fixed it #498

@nalchevanidze
Copy link
Member

@AlistairB validation workded well bot there is some problem with type Generation that i am fixing in #499

@nalchevanidze
Copy link
Member

@AlistairB now it should finally work

@AlistairB
Copy link
Contributor Author

AlistairB commented Aug 13, 2020

Thanks David! This is now working for most cases that I tested. The below is happy and works.

    query FetchRepoHeadCommit ($repoOwner: String!, $repoName: String!) {
      repository(name: $repoName, owner: $repoOwner) {
        defaultBranchRef {
          target {
            id
            ... on Commit {
              committedDate
            }
          }
        }
      }
    }

However, I get an error if I remove returning the id. eg.

    query FetchRepoHeadCommit ($repoOwner: String!, $repoName: String!) {
      repository(name: $repoName, owner: $repoOwner) {
        defaultBranchRef {
          target {
            ... on Commit {
              committedDate
            }
          }
        }
      }
    }

produces No Empty fields on \"RepositoryDefaultBranchRefTargetGitObject\". It seems that you must fetch something from the interface level otherwise it errors. I have pushed a new commit demonstrating this failure to https://github.com/AlistairB/morpheus-repro

Possibly worth noting that I believe putting interface level fields inside the spread is also valid. eg.

    query FetchRepoHeadCommit ($repoOwner: String!, $repoName: String!) {
      repository(name: $repoName, owner: $repoOwner) {
        defaultBranchRef {
          target {
            ... on Commit {
              id
              committedDate
            }
          }
        }
      }
    }

I think this is working aside from the above error. Although, I don't think supporting this style is super important.

@nalchevanidze
Copy link
Member

thanks @AlistairB.

i fixed it in #500

@AlistairB
Copy link
Contributor Author

Awesome, now working! thanks!

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