自定义逻辑
@cypher
@cypher
指令将 GraphQL 字段绑定到 Cypher 查询的结果。此指令可用于类型中的属性或作为顶级查询。
全局变量
全局变量可在 Cypher 语句中使用,并可应用于 @cypher
指令。
变量 | 描述 | 示例 |
---|---|---|
|
引用当前解析的节点,可用于遍历图。 |
|
|
此值由以下 TypeScript 接口定义表示
|
您可以使用请求中的 JWT 返回当前登录用户的 value。
|
|
用于从 GraphQL 上下文函数将值注入到 Cypher 查询中。 |
注入到上下文中
在 Cypher 查询中使用
|
返回值
Cypher 语句的返回值必须始终与应用指令的类型相同。
变量还必须使用与传递给 columnName
的名称相同的名称进行别名化。这可以是节点、关系查询或 Cypher 语句 RETURN
语句中的别名。
标量值
Cypher 语句必须返回与应用指令的标量类型匹配的值。例如
type Query {
randomNumber: Int @cypher(statement: "RETURN rand() as result", columnName: "result")
}
对象类型
返回对象类型时,该类型的全部字段必须在 Cypher 返回值中可用。这可以通过从 Cypher 查询返回整个对象或返回对象类型所需字段的映射来实现。此处演示了两种方法
type User {
id
}
type Query {
users: [User]
@cypher(
statement: """
MATCH (u:User)
RETURN u
""",
columnName: "u"
)
}
type User {
id
}
type Query {
users: [User] @cypher(statement: """
MATCH (u:User)
RETURN {
id: u.id
} as result
""", columnName: "result")
}
后一种方法的缺点是,您需要在更改对象类型定义时调整返回对象。
输入参数
@cypher
语句可以通过在参数名称前添加 $
来访问查询参数。例如
type Query {
name(value: String): String @cypher(statement: "RETURN $value AS res", columnName: "res")
}
以下 GraphQL 查询返回参数 value
query {
name(value: "Jane Smith")
}
使用示例
@cypher
指令可在不同的上下文中使用,例如本节中描述的上下文。
在对象类型字段上
在以下示例中,字段 similarMovies
绑定到 Movie
类型,用于查找具有演员重叠的其他电影
type Actor {
actorId: ID!
name: String
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}
type Movie {
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 子句中包装在 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 库生成查询和变异解析器,因此您无需自己实现它们。但是,如果您除了自动生成的 CRUD 操作之外还需要其他行为,则可以为这些场景指定自定义解析器。
要向对象类型添加一个从类型中现有值解析的字段,而不是存储新值,您应该使用 @customResolver
指令对其进行标记,并为其定义自定义解析器。
例如,此模式
const typeDefs = `
type User {
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
参数
requires
参数可以用于
-
选择集字符串。
-
任何字段中,只要它不是另一个
@customResolver
字段。 -
如果自定义解析器依赖于任何字段。这确保了在 Cypher 生成过程中,这些属性会从数据库中选择。
使用选择集字符串可以从相关类型中选择字段,如下例所示
const typeDefs = `
type Address {
houseNumber: Int!
street: String!
city: String!
}
type User {
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 {
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 {
title: String!
publicationYear: Int!
author: [Author!]! @relationship(type: "WROTE", direction: IN)
}
type Journal implements Publication {
subject: String!
publicationYear: Int!
author: [Author!]! @relationship(type: "WROTE", direction: IN)
}
但是,**不能**要求库生成的额外字段,例如聚合和连接。例如,以下类型定义将抛出错误,因为它们尝试要求 publicationsAggregate
interface Publication {
publicationYear: Int!
}
type Author {
name: String!
publications: [Publication!]! @relationship(type: "WROTE", direction: OUT)
publicationsWithAuthor: [String!]!
@customResolver(
requires: "name publicationsAggregate { count }"
)
}
type Book implements Publication {
title: String!
publicationYear: Int!
author: [Author!]! @relationship(type: "WROTE", direction: IN)
}
type Journal implements Publication {
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 {
name: String!
slug: String! @populatedBy(callback: "slug", operations: [CREATE, UPDATE])
}
模式构建(请注意,回调是异步的)
const slugCallback = async (root) => {
return `${root.name}_slug`
}
new Neo4jGraphQL({
typeDefs,
driver,
features: {
populatedBy: {
callbacks: {
slug: slugCallback
}
}
}
})
上下文值
请求的 GraphQL 上下文作为回调中的第三个参数可用。这映射到 GraphQL 解析器的参数模式。
例如,如果您想要一个字段 modifiedBy
type Record {
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>
,因此它始终为空对象。