neo4j-graphql-js
neo4j-graphql-js copied to clipboard
How to write complex cypher queries/mutations?
The API reference has three ways to customize the generated resolvers:
-
neo4jgraphql(object, params, context, resolveInfo, debug)
-
cypherQuery(params, context, resolveInfo)
-
cypherMutation(params, context, resolveInfo)
The first executes cypher while the last two return a cypher query as string. How can I customize the generated cypher query/mutation, e.g. to create relationships along the way?
Use-case: I want to create an authorship relationship for every created post (referential integrity). The author must be the currently authenticated user. Therefore, the user comes from the context
not the resolveInfo
. Here's what I have so far:
CreatePost: async (object, params, ctx, resolveInfo) => {
const result = await neo4jgraphql(object, params, ctx, resolveInfo, false)
const session = ctx.driver.session()
await session.run(
'MATCH (author:User {id: $userId}), (post:Post {id: $postId}) ' +
'MERGE (post)<-[:WROTE]-(author) ' +
'RETURN author', {
userId: ctx.user.id,
postId: result.id
})
session.close()
return result
}
There are a couple of problems with the above code:
- Non-atomic, no database transation
- The author is not in the result set
- The
id
of created post must be inresolveInfo
My idea is to have more control over the generated cypher query. Could you expose and document more methods, probably from this file how I can construct my own complex queries and mutations?
I could workaround the above problems like patching the resolveInfo
object to access the generated id:
// Keeping the graphql resolveInfo untouched ensures that we don't add the
// following attributes to the result set returned to the graphQL client.
// We only want to pass these attributes to our resolver for internal
// purposes.
const copy = cloneDeep(resolveInfo)
copy.fieldNodes[0].selectionSet.selections.unshift({
kind: 'Field',
name: { kind: 'Name', value: 'id' }
})
return resolve(root, args, context, copy)
I'm excited about the new cypherParams
feature in version 2.4.0
but I don't think it would help me for this particular problem as I have the user's id already.
An abstraction layer for Neo4J would be cool, e.g. for Rails there is ActiveRecord and Arel which helps you to compose complex SQL queries.
Thank you for your great work so far
I use the trick of adding a custom Mutation to do what I'm after:
CreateChildObjective(name: String!, parentId: ID!): Objective
@cypher(
statement: """
MATCH (p:Objective { id: $parentId })
MERGE (o:Objective { id: apoc.create.uuid(), name: $name})-[:DESCRIBES]->(p)
RETURN o
"""
)
Here, the lib gives me all the Mutations to "Create an Objective" and "Create the parent/child relationship between Objectives", but by create a custom mutation, I get more control and I can do everything I want all in one step.
https://github.com/neo4j-graphql/neo4j-graphql-js/issues/608