Javascript GraphQL 代码中的循环依赖

Javascript circular dependency in GraphQL code

我是 Javascript 的新手,不知道如何解决这个问题。我正在创建一个 GraphQL 服务来提供对数据库的查询,我想定义三种类型:Person、Company 和 Relationship

type Relation: {
  person: Person
  company: Company
}

type Person: {
  relationship: Relation
}

type Company: {
  relationship: Relation
}

如你所见,他们是相互依存的,我会得到 Person 和 Company undefined,有没有办法解决这个问题?

数据库架构:

// -------------------- Object(company) --------------------
objectType = new GraphQLObjectType ({
  name: 'Object',
  description: 'Object could be a Company, FinancialOrg, Person or Product.',
  fields: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
    },
    entity_type: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'could be Company, FinancialOrg, Person or Product.'
    },
    entity_id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    parent_id: {
      type: GraphQLString,
    },
    name: {
      type: new GraphQLNonNull(GraphQLString),
    },
    normalized_name: {
      type: new GraphQLNonNull(GraphQLString),
    },
    permalink: {
      type: new GraphQLNonNull(GraphQLString),
    }
  },
  resolveType: function(object) {
    return dbHandler.findObjectById(object.id);
  }
})

// -------------------- Relationship --------------------
var relationshipType = new GraphQLObjectType({
  name: 'Relationship',
  description: 'Describe the relationship between a person and a object(Corporation, fund)',
  fields: {
    id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    relationship_id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    person_object_id: {
      type: new GraphQLNonNull(GraphQLString),
    },
    relationship_object_id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'A Corporation or a Fund',
    },
  }
});

// -------------------- Person Type --------------------
personType = new GraphQLObjectType ({
  name: 'Person',
  fields: {
    id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    object_id: {
      type: new GraphQLNonNull(GraphQLString),
    },
    first_name: {
      type: new GraphQLNonNull(GraphQLString),
    },
    last_name: {
      type: new GraphQLNonNull(GraphQLString),
    },
    birthplace: {
      type: GraphQLString
    },
    affiliation_name: {
      type: GraphQLString
    },
  },
});

尝试将您的 GraphQL 端点重构为类似这样的东西

type Person: {
  employers: [Company],
  ...personAttributes
}

type Company: {
  employees: [Person],
  ...companyAttributes
}

在数据库模式中(我猜你使用的是关系数据库)你需要 3 个表:

  • 公司
  • 关系

This article explains how to model many-to-many relationships like the one you have.

注意:如果一个人一次只能在一家公司工作,架构就简单多了。

通常您不会定义特殊的关系类型。在 GraphQL 中,类型之间的关系在类型本身中定义。

例如,在您的 personType 中,您可以有一个名为 companies 的字段,它解析为该人所属的公司列表 (companyTypes)。在您的 companyType 中,您可以类似地定义一个字段 people,它将解析为 personType 的列表。

这将在本质上为您提供两种类型之间的多对多关系,这听起来像是在您的数据库中定义的。

这种风格的 personType 可能看起来像:

personType = new GraphQLObjectType ({
  name: 'Person',
  fields: () => ({
    id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    companies: {
      type: new GraphQLList(companyType),
      resolve: person => dbHandler.getAssociatedCompanies(person.id),
      },
    },
  }),
});

至于循环依赖问题,请注意上面的内容,而不是为 fields 使用对象文字,您可以使用 returns 对象的函数,这不会导致任何问题(尽管你的 linter 可能会抱怨)。

我肯定会建议通读 GraphQL Types 并确保您已为您的字段选择了合适的类型。一旦你足够舒服,你肯定会想研究 GraphQLInterfaceType,它允许你定义其他类型可以实现的公共字段。最终,单独定义类型并让它们实现接口而不是使用通用 objectType.

可能是更好的途径

另请注意,resolveType 可能并不像您认为的那样。来自 GraphQL 类型:“[resolveType 是] 一个函数,用于确定解析字段时实际使用的类型。”您会看到在 GraphQL 类型上可以由多种类型组成,例如 GraphQLInterfaceTypeGraphQLUnionType.

Star Wars example 帮助我解决了这些问题。