teamwalnut / graphql-ppx

GraphQL language primitives for ReScript/ReasonML written in ReasonML
https://graphql-ppx.com
MIT License
258 stars 53 forks source link

Polymorphic Variants capturing a Union with Fragments #215

Closed GTDev87 closed 3 years ago

GTDev87 commented 3 years ago

Hi, I'm using "reason-apollo-client": "1.0.0-beta.0", and "@reasonml-community/graphql-ppx": "1.0.1",

and I'm having trouble interpreting unions into polymorphic variants.

Using a Js.log, I have an object which looks like the following:

{__typename: "MultipleChoiceQuestion", id: "91d7d8ec-a581-56ef-8467-ca4d54da1dd7", questionBaseId: "91d7d8ec-a581-56ef-8467-ca4d54da1dd7", questionBase: {…}, choices: Array(4)}choices: (4) [{…}, {…}, {…}, {…}]

With this graphql fragment:

module Fields = [%graphql
  {|
    fragment TestFields on Test {
      questions {
        __typename
        ...on LongAnswerQuestion {
          ...LongAnswerQuestionFields
        }
        ...on MultipleChoiceQuestion {
          ...MultipleChoiceQuestionFields
        }
        ...on TrueFalseQuestion {
          ...TrueFalseQuestionFields
        }
        ...on FillInTheBlankQuestion {
          ...FillInTheBlankQuestionFields
        }
      }
   |}
 ];

and the polymorphic variant is returning:

{__typename: "MultipleChoiceQuestion", id: "91d7d8ec-a581-56ef-8467-ca4d54da1dd7", questionBaseId: "91d7d8ec-a581-56ef-8467-ca4d54da1dd7", questionBase: {…}, choices: Array(4)}choices: (4) [{…}, {…}, {…}, {…}]
LongAnswerQuestion q
undefined

Capture through here:

  Js.log("Question_Model question");
  Js.log(question);
  switch (question) {
  | `LongAnswerQuestion(q) =>{
    Js.log("LongAnswerQuestion q");
    Js.log(q);
    q
    |> LongAnswerQuestion.Model.objectToId
    |> Schema.LongAnswerQuestion.idToString
    |> q => UnionSchema.Question.LongAnswer(q)
  }
  | `MultipleChoiceQuestion(q) =>{
    Js.log("MultipleChoiceQuestion q");
    Js.log(q);
    q
    |> MultipleChoiceQuestion.Model.objectToId
    |> Schema.MultipleChoiceQuestion.idToString
    |> q => UnionSchema.Question.MultipleChoice(q)
   }
//Where question is of type 
type unionType = [
  | `LongAnswerQuestion(LongAnswerQuestionFields.t)
  | `MultipleChoiceQuestion(MultipleChoiceQuestionFields.t)
  | `TrueFalseQuestion(TrueFalseQuestionFields.t)
  | `FillInTheBlankQuestion(FillInTheBlankQuestionFields.t)
  | `FutureAddedValue(Js.Json.t)
];
   ...

So the polymorphic variant is interpreted as the incorrect type and is returning undefined when passed through the switch statement.

Do i need a __typespec somewhere to inform the union? Is there a working example of unions being evaluated into fragments that i can follow? I believe I had this working in 1.0.0-beta.11.

Thanks

jfrolich commented 3 years ago

Are you sure it's not a nullable field (and the type is not an option?). Otherwise, can you share the schema so we have a reproduction?

GTDev87 commented 3 years ago

It's not nullable or at least is shouldn't be. questions in the fragment above is a non_null list of non_null union question types.

Even if it were null though, i find it curious that the console recognizes it as a MultipleChoiceQuestion type until it captured by the switch statement which then it gives it LongAnswerQuestion type. Also, I do look for FutureAddedValue as a case too.

I've included the file. It's very large.

graphql_schema.txt

GTDev87 commented 3 years ago

Yea sorry if the example is very complex I was upgrading from using https://github.com/reasonml-community/reason-apollo-hooks/pull/117. I'll look into making a minimal example.

After talking to @jeddeloh, I think I'm of the mind this may be because of the fact I'm defining the types in unionType myself rather than letting the ppx interpret them for me. It may be confusing the switch statement so I'm getting undefined. It is hard to unravel this because this is my design in a bigger project where I have each fragment in it's own files and i aggregate them into bigger fragments.

I'll keep digging and I'll update if I have a minimal example or if I figure out something that works.

GTDev87 commented 3 years ago

A little more info

I expanded the query out removing the fragment directly inside the union.

module Fields = [%graphql
  {|
    fragment TestFields on Test {
      id
      questions {
        ...on LongAnswerQuestion {
          id
          questionBaseId
          questionBase {
            ...QuestionBaseFields
          }
        }
        ...on MultipleChoiceQuestion {
          id
          questionBaseId
          questionBase{
            ...QuestionBaseFields
          }
          choices{
            ...QuestionChoiceFields
          }
        }
        ...on TrueFalseQuestion {
          id
          questionBaseId
          questionBase{
            ...QuestionBaseFields
          }
          choices{
            ...QuestionChoiceFields
          }
        }
        ...on FillInTheBlankQuestion {
          id
          questionBaseId
          questionBase {
            ...QuestionBaseFields
          }
        }
      }
    }
  |}
];

I have the same issue, where the fragment are in the incorrect polymorphic variant and I am getting undefined in the object.

GTDev87 commented 3 years ago

Turns out it was something in reason-apollo-client fixed here (https://github.com/reasonml-community/reason-apollo-client/commit/ff6ec5422d440131a20c7c06fbc2831269b0eef1) I'll close.

jfrolich commented 3 years ago

Oh haha oops. Sorry I didn't get around looking into this!