微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在连接上使用石墨烯数据加载器以及如何仅选择必要的字段

如何解决如何在连接上使用石墨烯数据加载器以及如何仅选择必要的字段

我想使用一些带有 python 石墨烯的非标准数据库来创建一个 GraphQL 端点。该数据库没有现有的 sqlAlchemy 方言,Django ORM 等不支持,所以我尝试使用 DataLoader 类来批量提取数据并最大限度地减少对数据库查询次数。 我阅读了https://docs.graphene-python.org/en/latest/execution/dataloader/。为了说明我的问题,我创建了下一个简化的即用型示例:

import graphene

from graphql.execution.executors.asyncio import AsyncioExecutor
from starlette.applications import Starlette

from starlette.routing import Route
from starlette.graphql import GraphQLApp

from graphene.relay import Node,Connection,ConnectionField
from graphene import String,ObjectType,Field,List,NonNull

from promise import Promise
from promise.DataLoader import DataLoader



class User(ObjectType):
    """User information."""

    class Meta:
        interfaces = (Node,)

    user_id = String(description='User id.',name='userID')
    user_name = String(description='User name.')

    @classmethod
    def get_node(cls,info,_id):
        return user_loader.load(_id)


class UserConnection(Connection):
    class Meta:
        node = User


def get_user(_id):
    return User(id=_id,user_id=_id,user_name='Bill Gates',)


user_data = {x.id: x for x in [get_user(f'EEE-{x}') for x in range(8)]}


class UserLoader(DataLoader):

    def batch_load_fn(self,keys):
        return Promise.resolve([user_data.get(key) for key in keys])


user_loader = UserLoader()


class Query(ObjectType):
    user = Field(User,user_id=String(description='User ID',name='userID',required=True),description='User information')
    users = List(User,user_ids=List(NonNull(String),name='userIDs',required=True)
    all_users = ConnectionField(UserConnection)

    node = Node.Field()


    def resolve_user(self,user_id):
        return user_loader.load(user_id)

    def resolve_users(self,user_ids):
        return user_loader.load_many(user_ids)

    def resolve_all_users(self,**args):
        return list(user_data.values())


routes = [
    Route('/',GraphQLApp(schema=graphene.Schema(query=Query),executor_class=AsyncioExecutor)
          ),]


app = Starlette(routes=routes)


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app,host='127.0.0.1',port=8000)

我希望以下 GraphQL 查询能够正常工作:

fragment userFields on User {
  userID
  userName
}


query getUser {
  user(userID: "EEE-3") {
    id
    ...userFields
  }
}


query getUsers {
  users(userIDs: ["EEE-3","EEE-4","EEE-5"]) {
    id
    ...userFields
  }
}


query getNode {
  node(id: "VXNlcjpFRUUtMw==") {
    id
    ... on User {
      ...userFields
    }
  }
}

query getAllUsers {
  allUsers(first: 2) {
    edges {
      node {
        id
        ...userFields
      }
      cursor
    }
    pageInfo{
      hasNextPage
      hasPrevIoUsPage
      startCursor
      endCursor
    }
  }
}

这里我不使用该数据库来使示例保持简单,因为我的问题是关于如何正确使用 DataLoader,或者我还应该做什么才能达到我的目的。我在 user_data 变量中有数据并使用 get_user 函数访问它们,但在实际情况下它会查询我的数据库

这里似乎一切正常,除了两件事:

  1. 函数 resolve_all_users 直接作用于基础数据集或完整查询。虽然我希望它作为一些分页界面,根据 firstafter 等参数仅提取必要的数据。我可以在 resolve_connection 类上显式调用 UserConnection 函数,并且我看到它使用了一些数组切片函数。但是示例中的 DataLoader 使用 User id 而不是索引。此外,创建索引 DataLoader 似乎很昂贵,因为我想获得连续间隔并且不想将所有索引作为列表传递。我应该怎么做才能仅使用一个请求来解析此字段?

  2. 还有 DataLoader 我从数据库提取完整的 User 对象,即使不是所有的字段都是必需的。是否可以优化它以仅提取 GraphQL 查询字段中所需的内容

提前致谢。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。