Search code examples
pythoninterfacesqlalchemygraphenedb

Python Graphene Interface + InlineFragment seems doesn't resolve ObjectType fields


I try to resolve ObjectType fields with InlineFragment on a ObjectType that inherit from an Interface but it seems doesn't work.

Here is my schema:

@schema.register
class BundleInterface(graphene.Interface):
    id = graphene.ID()
    identifier = graphene.String()
    name = graphene.String()
    publication_date = DateTime()
    articles = graphene.List('Article')

    def resolve_articles(self, args, info):
        info_parser = InfoParser('Article', info)
        return self.articles.options(load_only(*info_parser.root_fields)).all()

    @classmethod
    def _resolve_type(cls, schema, instance, *args):
        if instance.mid is not None:
            return Issue.internal_type(schema)
        return Bundle.internal_type(schema)


@schema.register
class Bundle(BundleInterface):
    pass


@schema.register
class Issue(BundleInterface):
    mid = graphene.String()
    cover = graphene.Field('Image')
    pages = graphene.List('Page')

    def resolve_cover(self, args, info):
        pass

    def resolve_pages(self, args, info):
        return self.pages['pages']

Here is my Query:

class Query(graphene.ObjectType):
    bundle = graphene.Field('BundleInterface', identifier=graphene.String())

    def resolve_bundle(self, args, info):
        info_parser = InfoParser('BundleInterface', info)
        filters = {}
        filters[object_type_to_model['BundleInterface']['fields']['identifier']] = args.get('identifier')
        return info_parser.root_model.query.filter_by(**filters)\
                                           .options(load_only(*info_parser.root_fields))\
                                           .one()

Here is my sqlalchemy model:

class Bundle(Base):
    __tablename__ = 'bundle'

    bundle_id = Column(Integer, primary_key=True)
    identifier = Column(UUID(as_uuid=True))
    name = Column(String)
    publication_date = Column(DateTime)
    mid = Column(UUID(as_uuid=True))
    pages = Column(JSONB)
    source_id = Column(Integer, ForeignKey('source.source_id'))

Here is my query in graphiql:

{
  bundle(identifier: "30752cba-f3a7-49c8-b6c7-afa6a9579a1c") {
    name
    ... on Issue {
      mid
    }
  }
}

And here is my result:

{
  "data": {
    "bundle": {
      "name": "bundle 1"
    }
  }
}

I am sure that _resolve_type method of BundleInterface return an Issue ObjectType (cause i have printed it) but after that i don't know why Issue ObjectType is not resolved.

I also know that data fetched from postgresql with sqlalchemy contains data that Issue ObjectType needs to resolve itself cause i see in flask logs the sql request sent to psotgresql.

Here is the sql request:

[2016-06-16 20:03:14,588: INFO / sqlalchemy.engine.base.Engine] BEGIN (implicit)
[2016-06-16 20:03:14,589: INFO / sqlalchemy.engine.base.Engine] SELECT bundle.bundle_id AS bundle_bundle_id, bundle.name AS bundle_name, bundle.mid AS bundle_mid 
FROM bundle 
WHERE bundle.identifier = %(identifier_1)s
[2016-06-16 20:03:14,589: INFO / sqlalchemy.engine.base.Engine] {'identifier_1': '30752cba-f3a7-49c8-b6c7-afa6a9579a1c'}

We can see that mid attribut's data are fetched from potsgresql so data are available for Issue ObjectType to resolve itself.

But sqlalchemy return a list of Bundle instance and i want to resolve an Issue ObjectType, maybe it don't works cause of that but i am not sure cause Bundle ObjectType succeeds to resolve itself with Bundle sqlalchemy instance.

Plus no errors are displayed in graphiql interface.

I don't know if it is the right way to implement this pattern ?

Do you have any idea to solve my problem ?


Solution

  • I found the issue. I made a pull request on graphql-core: https://github.com/graphql-python/graphql-core/pull/68