graphql-python / graphene-mongo

Graphene MongoEngine integration
http://graphene-mongo.readthedocs.io/en/latest/
MIT License
288 stars 113 forks source link

What is intended way to implement Union? #117

Open sVerentsov opened 4 years ago

sVerentsov commented 4 years ago

Here is the schema that i am trying to implement:

type Text {
  id: ID
  content: String
}
type Image {
  id: ID
  image_url: String
  thumb_url: String
}
union Post = Text | Image
type User {
  id: ID
  posts: [Post]
}
type Query {
  users: [User]
}

and execute this query:

    {
        users {
            posts {
                ... on  Image {
                    image_url
                }
                ... on Text {
                    content
                }
            }
        }
    }

What I have tried:

  1. Mongoengine models: make PostModel as separate Document, inherit TextModel and ImageModel from it and reference PostModel from UserModel.
    Graphene objects: make types for Text, Image, User and Post as MongoengineObjectType.
    (full code here) This returns errors Unknown type "Image". and Unknown type "Text". In this case Post type has only fields Cls: String, id: ID.

  2. Mongoengine models: same.
    Graphene objects: inherit Post from graphene.Union and set Image and Text as types of that union. (full code here) This returns Cannot query field "posts" on type "User".. I suppose this happens because now graphene_mongo does not state that User.posts reference Post

So how should such schema be implemented?

abawchen commented 4 years ago

@sVerentsov : I will take a look, thanks.

sVerentsov commented 4 years ago

I managed to solve this by explicitly stating posts field in User:

class User(MongoengineObjectType):
    class Meta:
        model = UserModel
    posts = graphene.Field(graphene.List(lambda: Post))

class Post(graphene.Union):
    class Meta:
        types = (Image, Text)

Full working code here

It is quite suprising that graphene-mongo resolves posts as references of ImageModel and TextModel automatically.

abawchen commented 4 years ago

https://github.com/graphql-python/graphene-mongo/blob/33be6067a2c451428064d9e4338269dd50744715/graphene_mongo/tests/models.py#L61-L74

generic_reference = mongoengine.GenericReferenceField( 
         choices=[Article, Editor, ] 
     ) 

or you can use GenericReferenceField with choices to do it, but I have not verified ListField(mongoengine.GenericReferenceField()) works or not.