GraphQL级联删除

时间:2017-09-11 16:09:49

标签: graphql

我正在使用GraphQL,并希望从数据库和其他按实体分配给第一个实体的实体中删除实体。

假设我在GraphQL Schema中有三种类型

  1. 用户
  2. 分配
  3. 任务
  4. 逻辑如下:User以某种方式与Task相关。该关系由“中间”对象Assignment表示。 (在Assignment中,我可以设置User是任务或工作者的主管,或者实际上是什么,这不是重点。)

    现在,我想要删除User并且相关AssignmentTask不应删除)。

    我想知道我是否可以通过只执行一个只有一个参数的突变查询来做到这一点:用户ID?

    我想的是:

    mutation deleteUser($userId: ID!){
      deleteUser(id: $userId){
        id
        assignment {
          id # use that id somehow below
        }
      } {
        deleteAssignment(id: id_from_above) {
        }
      }
    }
    

    这样的事情是否可能?

2 个答案:

答案 0 :(得分:1)

我认为您将从阅读Mutation section of the GraphQL spec中受益。

  

如果操作是突变,则操作的结果是在突变根对象类型上执行突变的顶级选择集的结果。该选择集应该连续执行。

这里的关键点是突变:

  • 被认为是一种查询,除了它们有副作用
  • 他们不是以方便或甚至同时的顺序完成的 - 比如查询 - 但按顺序完成

要具体说明您的问题:如果删除用户需要在概念上也删除该用户的分配,并删除分配删除所有任务,那么暴露的变异(即"查询")可能只是:

mutation deleteUser($userId: ID!) {
  deleteUser(id: $userId)
}

并且相关的删除恰好发生,并且不需要返回任何内容。如果 想要返回内容,您可以添加可供查看的内容:

mutation deleteUser($userId: ID!) {
  deleteUser(id: $userId) {
    assignment {
      task
    }
  }
}

或者,如果您希望删除由客户端控制的分配和任务,那么"查看"子删除(触发这种实际删除:

mutation deleteUser($userId: ID!) {
  deleteUser(id: $userId) {
    deleteAssignment {
      deleteTask
    }
  }
}

当然假设你恰当地定义Mutation类型以使这些字段可用,并且底层软件会相应地采取上述行为。

答案 1 :(得分:0)

如果仅希望级联删除操作,则客户端无需执行任何操作-无需特殊查询。只需在您的突变解析器中执行适当的逻辑即可。

例如如果您有一种服务方法可以删除变异解析程序最终会调用的用户(该示例使用Java,但是使用的是任何语言(您未提及),则逻辑相同):

boolean deleteUser(String id) {
   // either do the assignment deletion yourself here (not good)
   // or set your database to cascade the deletions (preferable)
   dataBase.execute("DELETE FROM User WHERE id = :id");
   return true; //have to return *something*
}

客户端不需要关心这个,他们只是告诉您的系统删除用户:

mutation deleteUser($userId: ID!){
  deleteUser(id: $userId)
}

如果您希望客户端能够获得比布尔成功标志更好的东西,请返回该东西(这当然意味着相应地更改架构):

String deleteUser(String id) {       
   dataBase.execute("DELETE FROM User WHERE id = :id");
   //return the e.g. the ID
   return id;
}

String deleteUser(String id) { 
   User user = dataBase.execute("SELECT FROM User WHERE id = :id");   
   dataBase.execute("DELETE FROM User WHERE id = :id");
   //return the whole deleted user
   return user;
}

后者使客户端能够查询结果(这些是子查询,而不是子突变,不存在子突变之类的东西):

mutation deleteUser($userId: ID!){
  deleteUser(id: $userId) {
    id
    assignments {
      id
    }
  }
}

要注意的是,与查询不同,变异不能嵌套,但是可以,您可以发送多个顶级变异(如您的示例)。不幸的是,没有办法将第一个的结果用作第二个的输入。有人要求将此内容引入GraphQL规范,但这可能会或可能不会发生。

表示您的示例:

mutation deleteUser($userId: ID!) {
  deleteUser(id: $userId) {
    id
    assignment {
      id # use that id somehow below
    }
  } {

  deleteAssignment(id: id_from_above) {
    id
  }
}
不幸的是,

是不可能的。

您必须要么作为两个单独的请求来执行此操作,要么想出一种更精细的方法。如果需要允许客户进行更深层次的控制,该怎么办就是接受更复杂的输入,而不仅仅是ID,例如:

input DeleteUserInput {
  id: ID!
  deleteOwnAssignments: Boolean
  deleteManagedAssignments: Boolean
}

mutation deleteUser($input: DeleteUserInput!) {
  deleteUser(input: $input)
}

boolean deleteUser(String id, boolean deleteOwnAssignments, boolean deleteManagedAssignments) {
   if (deleteOwnAssignments) {
       dataBase.execute("DELETE FROM Assignment WHERE assigned_to = :id");
   }
   if (deleteManagedAssignments) {
       dataBase.execute("DELETE FROM Assignment WHERE manager_id = :id");
   }
   dataBase.execute("DELETE FROM User WHERE id = :id");
   return true; //or return whatever is appropriate
}