自定义逻辑
这是 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
Neo4j GraphQL Library 会生成查询和变更解析器,因此您无需自行实现它们。但是,如果您需要除了自动生成的 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
此指令用于指定一个回调函数,该函数在 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>
,因此它将始终是一个空对象。