自定义逻辑
|
这是 GraphQL Library 7 版本的文档。对于长期支持 (LTS) 版本 5,请参考 GraphQL Library 5 LTS 版本。 |
@cypher
@cypher 指令将 GraphQL 字段绑定到 Cypher 查询的结果上。该指令既可用于类型中的属性,也可用于顶级查询。
定义
全局变量
全局变量可在 Cypher 语句中使用,并可应用于 @cypher 指令。
| 变量 | 描述 | 示例 |
|---|---|---|
|
指代当前解析的节点,可用于遍历图数据库。 |
|
|
该值由以下 TypeScript 接口定义表示
|
你可以使用请求中的 JWT 来返回当前登录用户的值
|
|
使用它从 GraphQL 上下文函数向 Cypher 查询注入值。 |
注入到上下文中
在 Cypher 查询中使用
|
返回值
Cypher 语句的返回值必须始终与应用该指令的类型保持一致。
变量还必须使用与传递给 columnName 相同的名称进行别名化。这可以是节点名称、关系查询,或者是 Cypher 语句 RETURN 子句中的别名。
标量值
Cypher 语句必须返回与应用该指令的标量类型相匹配的值。例如
type Query {
randomNumber: Int @cypher(statement: "RETURN rand() as result", columnName: "result")
}
对象类型
当返回对象类型时,该类型的所有字段都必须在 Cypher 返回值中可用。这可以通过从 Cypher 查询中返回整个对象,或者返回对象类型所需字段的映射来实现。此处演示了这两种方法
type User @node {
id
}
type Query {
users: [User]
@cypher(
statement: """
MATCH (u:User)
RETURN u
""",
columnName: "u"
)
}
type User @node {
id
}
type Query {
users: [User] @cypher(statement: """
MATCH (u:User)
RETURN {
id: u.id
} as result
""", columnName: "result")
}
后一种方法的缺点是,当你更改对象类型定义时,需要相应地调整返回对象。
使用
@cypher 指令可用于本节所述的不同上下文中。
在对象类型字段上
在以下示例中,字段 similarMovies 被绑定到 Movie 类型,用于查找具有重叠演员的其他电影
type Actor @node {
actorId: ID!
name: String
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}
type Movie @node {
movieId: ID!
title: String
description: String
year: Int
actors(limit: Int = 10): [Actor!]!
@relationship(type: "ACTED_IN", direction: IN)
similarMovies(limit: Int = 10): [Movie]
@cypher(
statement: """
MATCH (this)<-[:ACTED_IN]-(:Actor)-[:ACTED_IN]->(rec:Movie)
WITH rec, COUNT(*) AS score ORDER BY score DESC
RETURN rec LIMIT $limit
""",
columnName: "rec"
)
}
@coalesce
在从 GraphQL 转换为 Cypher 时,应用此指令的任何字段实例都将被包裹在 WHERE 和 RETURN 子句的 coalesce() 函数中。有关更多信息,请参阅 理解不存在的属性并处理空值。
此指令有助于针对数据库中不存在的属性进行查询。但是,如果这是常态,建议用有意义的值填充这些属性。@coalesce 指令是该函数的一个原始实现,它仅接受静态默认值,而不使用节点中的另一个属性或 Cypher 表达式。
定义
"""Int | Float | String | Boolean | ID | DateTime | Enum"""
scalar ScalarOrEnum
"""Instructs @neo4j/graphql to wrap the property in a coalesce() function during queries, using the single value specified."""
directive @coalesce(
"""The value to use in the coalesce() function. Must be a scalar type and must match the type of the field with which this directive decorates."""
value: Scalar!,
) on FIELD_DEFINITION
@limit
@customResolver
|
在 Aura Console 中创建的数据 API 当前不支持自定义解析器。 |
Neo4j GraphQL 库会自动生成查询和变更解析器,因此你无需自行实现它们。但是,如果你除了自动生成的 CRUD 操作外还需要其他行为,可以为这些场景指定自定义解析器。
若要向对象类型添加一个从类型中的现有值解析得出(而不是存储新值)的字段,你应该用 @customResolver 指令标记它,并为其定义一个自定义解析器。
以这个 schema 为例
const typeDefs = `
type User @node {
firstName: String!
lastName: String!
fullName: String! @customResolver(requires: "firstName lastName")
}
`;
const resolvers = {
User: {
fullName(source) {
return `${source.firstName} ${source.lastName}`;
},
},
};
const neoSchema = new Neo4jGraphQL({
typeDefs,
resolvers,
});
此处 fullName 是从 firstName 和 lastName 字段解析得出的值。在字段定义上指定 @customResolver 指令可防止 fullName 被包含在任何查询或变更字段中,从而使其不会成为数据库中 :User 节点的属性。
在 requires 参数中包含 firstName 和 lastName 字段意味着,在解析器的定义中,属性 firstName 和 lastName 将始终在 source 对象上定义。如果未指定这些字段,则无法保证这一点。
定义
"""Informs @neo4j/graphql that a field will be resolved by a custom resolver, and allows specification of any field dependencies."""
directive @customResolver(
"""Selection set of the fields that the custom resolver will depend on. These fields are passed as an object to the first argument of the custom resolver."""
requires: SelectionSet
) on FIELD_DEFINITION
用法
requires 参数可用于
-
选择集字符串。
-
任何字段(只要它不是另一个
@customResolver字段)。 -
如果自定义解析器依赖于任何字段。这确保了在 Cypher 生成过程中,这些属性会从数据库中被选中。
使用选择集字符串可以从相关类型中选择字段,如下例所示
const typeDefs = `
type Address @node {
houseNumber: Int!
street: String!
city: String!
}
type User @node {
id: ID!
firstName: String!
lastName: String!
address: Address! @relationship(type: "LIVES_AT", direction: OUT)
fullName: String
@customResolver(requires: "firstName lastName address { city street }")
}
`;
const resolvers = {
User: {
fullName({ firstName, lastName, address }) {
return `${firstName} ${lastName} from ${address.street} in ${address.city}`;
},
},
};
const neoSchema = new Neo4jGraphQL({
typeDefs,
resolvers,
});
在这里,如果选择了 fullName 字段,则 firstName、lastName、address.street 和 address.city 字段将始终从数据库中被选中,并可用于自定义解析器。
也可以使用内联片段来有条件地选择接口/联合类型中的字段
interface Publication {
publicationYear: Int!
}
type Author @node {
name: String!
publications: [Publication!]! @relationship(type: "WROTE", direction: OUT)
publicationsWithAuthor: [String!]!
@customResolver(
requires: "name publications { publicationYear ...on Book { title } ... on Journal { subject } }"
)
}
type Book implements Publication @node {
title: String!
publicationYear: Int!
author: [Author!]! @relationship(type: "WROTE", direction: IN)
}
type Journal implements Publication @node {
subject: String!
publicationYear: Int!
author: [Author!]! @relationship(type: "WROTE", direction: IN)
}
但是,**不能**要求库生成的额外字段(如聚合和连接)。例如,以下类型定义将抛出错误,因为它们试图要求 publicationsAggregate
interface Publication {
publicationYear: Int!
}
type Author @node {
name: String!
publications: [Publication!]! @relationship(type: "WROTE", direction: OUT)
publicationsWithAuthor: [String!]!
@customResolver(
requires: "name publicationsAggregate { count }"
)
}
type Book implements Publication @node {
title: String!
publicationYear: Int!
author: [Author!]! @relationship(type: "WROTE", direction: IN)
}
type Journal implements Publication @node {
subject: String!
publicationYear: Int!
author: [Author!]! @relationship(type: "WROTE", direction: IN)
}
@populatedBy
|
在 Aura Console 中创建的数据 API 当前不支持 |
此指令用于指定一个回调函数,该函数在 GraphQL 查询解析期间执行,用于填充输入中未提供的字段。
对于非必需值,回调可以返回 undefined(意味着不会更改或向属性添加任何内容)或 null(意味着该属性将被删除)。
@populatedBy 指令只能用于标量字段。
定义
enum PopulatedByOperation {
CREATE
UPDATE
}
"""Instructs @neo4j/graphql to invoke the specified callback function to populate the field when updating or creating the properties on a node or relationship."""
directive @populatedBy(
"""The name of the callback function."""
callback: String!
"""Which events to invoke the callback on."""
operations: [PopulatedByOperation!]! = [CREATE, UPDATE]
) on FIELD_DEFINITION
用法
类型定义
type Product @node {
name: String!
slug: String! @populatedBy(callback: "slug", operations: [CREATE, UPDATE])
}
Schema 构建(注意回调是异步的)
const slugCallback = async (root) => {
return `${root.name}_slug`
}
new Neo4jGraphQL({
typeDefs,
driver,
features: {
populatedBy: {
callbacks: {
slug: slugCallback
}
}
}
})
上下文值
请求的 GraphQL 上下文作为回调的第三个参数提供。这映射到 GraphQL 解析器的参数模式。
例如,如果你想要一个 modifiedBy 字段
type Record @node {
content: String!
modifiedBy: @populatedBy(callback: "modifiedBy", operations: [CREATE, UPDATE])
}
如果用户名位于 context.username 中,你可以定义如下回调
const modifiedByCallback = async (_parent, _args, context) => {
return context.username;
}
new Neo4jGraphQL({
typeDefs,
driver,
features: {
populatedBy: {
callbacks: {
modifiedBy: modifiedByCallback
}
}
}
})
注意,第二个位置参数(在此例中为 _args)的类型为 Record<string, never>,因此它始终是一个空对象。这是为了保持与 GraphQL 解析器兼容的签名。
populatedByOperation
context 参数包含 populatedByOperation 字段。此字段是触发回调的变更类型(CREATE 或 UPDATE)。populatedByOperation 允许根据操作类型执行不同的逻辑。例如
const modifiedByCallback = async (_parent, _args, context) => {
if(context.populatedByOperation === "UPDATE"){
return context.username;
} else {
return "";
}
}