Skip to content
This repository has been archived by the owner on Jul 6, 2020. It is now read-only.

Allow unions of (non-interface) Objects #113

Merged
merged 6 commits into from
Nov 15, 2019

Conversation

StevenLangbroek
Copy link
Contributor

As discussed on spectrum, starting repro here.

@@ -29,4 +29,8 @@ describe('SchemaPredicates', () => {
expect(schemaPredicates.isFieldNullable('Todo', 'complete')).toBeTruthy();
expect(schemaPredicates.isFieldNullable('Todo', 'author')).toBeTruthy();
});

it('should totally do that thing that Steven is struggling with', () => {
expect(true).toBeTruthy();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we are checking here whether we may have a UnionType: https://github.com/FormidableLabs/urql-exchange-graphcache/blob/6e0f016beadf224249cfb5d9362ca979b484fc24/src/ast/schemaPredicates.ts#L98

You can probably add a case here that checks:

schemaPredicates.isInterfaceOfType('Todo', 'NoTodosError');
schemaPredicates.isInterfaceOfType('NoTodosError', 'Todo')

But I expect our bug to be here: https://github.com/FormidableLabs/urql-exchange-graphcache/blob/6e0f016beadf224249cfb5d9362ca979b484fc24/src/ast/schemaPredicates.ts#L47

We're assuming that typeCondition (so ... on NoTodosError) to be an abstract type when the check fails, but for unions it's actually a regular object type, so we'd have to also check whether we just get the same ObjectType, so:

    const abstractType = this.schema.getType(typeCondition);
+    if (abstractType instanceof GraphQLObjectType) {
+      return abstractType === objectType;
+    }
    expectAbstractType(abstractType, typeCondition);
    const objectType = this.schema.getType(typename);
    expectObjectType(objectType, typename);

@StevenLangbroek StevenLangbroek changed the title WIP: Allow union Types Allow unions of (non-interface) Objects Nov 11, 2019

it('should handle unions of objects', () => {
expect(
schemaPredicates.isInterfaceOfType('LatestTodoResult', 'Todo')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, now it makes a little bit more sense to me; this would be the result of

type Todo {

}

type NoTodosError {

}

union LatestTodoResult = Todo | NoTodosError

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we may want to rename this method now to sth like isMatchingCondition

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll refrain from commenting further on what does and doesn't make sense until I've spent some more time on GraphQL primitives. The fact that it was counterintuitive to me probably has more to do with that than the actual API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I can't really reason about how this test actually implies correctness. What's the failure path here?

@StevenLangbroek StevenLangbroek marked this pull request as ready for review November 11, 2019 20:17
@StevenLangbroek
Copy link
Contributor Author

@kitten @JoviDeCroock is there anything left to do on this?

@JoviDeCroock
Copy link

We might have to rebase with master so the CI can run correctly

@StevenLangbroek
Copy link
Contributor Author

Done :)

@StevenLangbroek
Copy link
Contributor Author

image

Lol thanks codecov.

schemaPredicates.isInterfaceOfType('LatestTodoResult', 'Todo')
).toBeTruthy();
expect(
schemaPredicates.isInterfaceOfType('LatestTodoResult', 'NoTodosError')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're missing a test for this:

expect(
  schemaPredicates.isInterfaceOfType('Todo', 'NoTodosError')
).toBeFalsy();

Also is LatestTodoResult compared with NoTodosError / Todo legal? As in are you able to write this in GraphQL? Because I'm not sure

fragment _ on LatestTodoResult {
}

Where LatestTodoResult is obviously a union, hence a fragment shouldn't be able to match at all 🤔

Copy link
Contributor Author

@StevenLangbroek StevenLangbroek Nov 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that should be ok, but should only yield __typename?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that's valid (sorry commented on wrong thread):

image

Copy link

@JoviDeCroock JoviDeCroock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, thank you so much for taking your time to resolve this!

@JoviDeCroock JoviDeCroock merged commit ce27e2b into urql-graphql:master Nov 15, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants