Graphql-code-generator: Multiple inline fragments - & vs |

Created on 14 Nov 2017  路  11Comments  路  Source: dotansimha/graphql-code-generator

On a query like this

      dishes {

        ... on RecipeDish {
          id
          recipeId
        }

        ... on IngredientDish {
          id
          ingredient 
        }
      }

The result is

export type Dishes = RecipeDishInlineFragment & IngredientDishInlineFragment

But it should be

export type Dishes = RecipeDishInlineFragment | IngredientDishInlineFragment

Am I not mistaken?

Thanks

Most helpful comment

@altschuler I wrote the comment above being sure that union is & instead of I %)

apollo-codegen produces a union for instance, however it doesn't generate it in a handy form this library does (with subtypes, instead of one long type), which makes it (apollo-codegen) not that useful

export type MenuDishFragmentFragment = {
  dishes:  Array<( {
      __typename: "RecipeDish",
      id: string,
      recipeId: string,
    } | {
      __typename: "IngredientDish",
      id: string,
      ingredient:  {
        productId: string,
      },
    }
  ) >,
};

All 11 comments

Theoretically it should be the union I guess (|), but if it was, you would have neither ingredient nor recipeId available. It's kind of a trade off, but instead you have both of them.

@altschuler but a union implies that every element of dishes will have all three fields (id, recipeId, ingredient), when it's actually not true. Anyway a typeguard based on __typename should help..

@altschuler I wrote the comment above being sure that union is & instead of I %)

apollo-codegen produces a union for instance, however it doesn't generate it in a handy form this library does (with subtypes, instead of one long type), which makes it (apollo-codegen) not that useful

export type MenuDishFragmentFragment = {
  dishes:  Array<( {
      __typename: "RecipeDish",
      id: string,
      recipeId: string,
    } | {
      __typename: "IngredientDish",
      id: string,
      ingredient:  {
        productId: string,
      },
    }
  ) >,
};

Yep, I think having the correct semantics of a union paired with the notion of __typename could be pretty powerful... does __typename get automatically appended to the response or is it something that has to be specifically selected?

@zephraph in apollo graphql express middleware __typename is appended always by default. I'm not sure for other implementations

I think that's the trick. We'd really need to check the spec just to be sure that's the default intent. I think it is... I'm not 100% sure though.

Here http://graphql.org/learn/queries/#meta-fields it says:
GraphQL allows you to request __typename, a meta field, at any point in a query to get the name of the object type at that point.

So look like it should only return __typename on request

I ran into a case where using & breaks. If the types in a union share a field name, but the type of the content of the field is different, it will throw an error stating that the fields are in conflict.

For example, we have an Activity type using the actor-verb-object structure. Object can be of any type we have in the app, and among the options it can be a Story or an Export. Story has a format which takes the values "Book", "Movie", "TV Show", etc, and Export's format field can be "pdf", "doc", etc. Both field are appropriately named for their usage, but when returning either of them using a union type the app will throw the error:

Fields "format" conflict because they return conflicting types StoryFormat! and ExportFormat!. Use different aliases on the fields to fetch both if this was intentional.

So I guess that it should be COMMON_FIELDS & (FRAGMENT | FRAGMENT | FRAGMENT) ?

What do you think? @iamdanthedev @altschuler @zephraph

ok, so I did some work on it, and the results will be: FIELDS & FRAGMENT_SPREAD & (INLINE_FRAGMENT | INLINE_FRAGMENT | INLINE_FRAGMENT).
Since fragment spread are in use to specify list of fields in a context of a type, and inline fragments are in use to declare different selection set for interface/union.

Fixed in 0.8.17 :)

Was this page helpful?
0 / 5 - 0 ratings