简体   繁体   English

Apollo GraphQL:如何拥有使用递归的解析器?

[英]Apollo GraphQL: How to have a resolver that uses recursion?

My database is modelled as a "forest," or a group of trees.我的数据库被建模为“森林”或一组树。 There are top level nodes that can link to multiple nodes below it, each potentially linking to nodes below it.有一些顶级节点可以链接到它下面的多个节点,每个节点都可能链接到它下面的节点。

I want to implement a resolver that finds a tree and deletes it.我想实现一个找到树并将其删除的解析器。 This means it has to find a top-level node, search for its children, delete them, and then search for their own children, and so on.这意味着它必须找到一个顶级节点,搜索其子节点,删除它们,然后搜索自己的子节点,等等。 I'm not sure how to implement this recursion with resolvers.我不确定如何使用解析器实现此递归。

A recursive structure for this would look something like一个递归结构看起来像

function deleteNodes(rootID) {
    root = database.find(id: rootID);
    if (!root.childrenIDs) return;
    database.delete(id: rootID);
    root.childrenIDs.map((childId) => deleteNodes(childId));
}

But I'm not sure how this would work in a resolver, where my code structure looks like:但我不确定这将如何在解析器中工作,我的代码结构如下所示:

module.exports {
    Query: {...},
    Mutation: {
        deleteNodes: async (_, args) => {...}
    }
}

How could I design a helper function or recursively call a resolver, or if that's not permitted, how could I execute what I want?我如何设计一个帮助器 function 或递归调用解析器,或者如果不允许这样做,我该如何执行我想要的? Not sure I can call the resolver directly inside the resolver itself.不确定我可以直接在解析器本身内部调用解析器。

The rule that I have that could help you here is that resolvers should have no business logic in them.我在这里可以帮助您的规则是解析器中不应包含业务逻辑。 I use apollo-server and DataSources , but before that I had a similar setup, where the context object has all of my business logic on it.我使用 apollo-server 和DataSources ,但在此之前我有一个类似的设置,其中context object 包含我所有的业务逻辑。 In this way, the resolvers are "just routers", and you can replace GraphQL with REST + Express, or gRPC, or whatever you want.这样,解析器“只是路由器”,您可以将 GraphQL 替换为 REST + Express 或 gRPC 或任何您想要的。

I'm using the DataSources model here, but you could just have a set of "business logic helpers. I do all of this on context so I can inject them easier for testing.我在这里使用 DataSources model,但您可以只拥有一组“业务逻辑帮助程序。我在context完成所有这些,因此我可以更轻松地注入它们进行测试。

That would mean that in this case, your resolver would look like this:这意味着在这种情况下,您的解析器将如下所示:

module.exports = {
  Query: {...},
  Mutation: {
    deleteNodes: async (_, args, context) => {
      const result = await context.dataSources.nodes.deleteNodes(args.id);
      // something to handle your result
      return whatever;
    }
  }
}

Separately, you would have some nodes dataSource:另外,您将有一些nodes数据源:

const { DataSource } = require('apollo-datasource')

module.exports = class NodesDataSource extends DataSource {
  constructor() {
    this.database = something;
  }

  deleteNodes(rootID) {
    const root = await this.database.find(id: rootID);
    if (!root.childrenIDs) return;
    await this.database.delete(id: rootID);
    await Promise.all(root.childrenIDs.map((childId) => this.deleteNodes(childId)));
  }
}

and in your ApolloServer setup:在您的 ApolloServer 设置中:

const NodesDataSource = require('./datasources/nodes-datasource');

const server = new ApolloServer({
  resolvers,
  typeDefs,
  dataSources: () => {
    return {
      nodes: new NodesDataSource(),
    };
  },
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM