Often I want to create a GraphQL type that represents the results of a Cypher query that spans than one node. I can't return a concrete node from @cypher
in this case, as no such node exists. I tried to return appropriately named fields from a top-level @cypher
query but this approach did not work.
import { makeAugmentedSchema, neo4jgraphql } from 'neo4j-graphql-js';
import { ApolloServer } from 'apollo-server';
import neo4j from 'neo4j-driver';
const typeDefs = `
type Person {
name: String
age: Int
}
type Query {
persons: [Person] @cypher(
statement: """
WITH [["foo", 42], ["bar", 43]] AS x UNWIND x AS y
RETURN y[0] AS name, y[1] AS age
"""
)
}
`;
const driver = neo4j.driver(
'bolt://localhost:7687',
neo4j.auth.basic('neo4j', 'password')
);
const resolvers = {
};
const schema = makeAugmentedSchema({ typeDefs, resolvers });
const server = new ApolloServer(
{
schema,
resolvers,
context: {driver}
}
)
server.listen(4000, '0.0.0.0').then(({ url }) => {
console.log(`GraphQL API ready at ${url}`);
});
Query:
{
persons {
name
age
}
}
Yields the error:
{
"errors": [
{
"message": "String(\"foo\") (of class org.neo4j.values.storable.StringWrappingStringValue)",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"persons"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"code": "Neo.DatabaseError.General.UnknownError",
"name": "Neo4jError",
"stacktrace": [
"Neo4jError: String(\"foo\") (of class org.neo4j.values.storable.StringWrappingStringValue)",
"",
" at captureStacktrace (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/neo4j-driver/lib/result.js:277:15)",
" at new Result (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/neo4j-driver/lib/result.js:68:19)",
" at newCompletedResult (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/neo4j-driver/lib/transaction.js:449:10)",
" at Object.run (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/neo4j-driver/lib/transaction.js:287:14)",
" at Transaction.run (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/neo4j-driver/lib/transaction.js:123:32)",
" at _callee2$ (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/neo4j-graphql-js/dist/index.js:222:35)",
" at tryCatch (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/regenerator-runtime/runtime.js:63:40)",
" at Generator.invoke [as _invoke] (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/regenerator-runtime/runtime.js:293:22)",
" at Generator.next (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/regenerator-runtime/runtime.js:118:21)",
" at asyncGeneratorStep (/home/amoe/dev/neo4j-graphql-js-return-aggregate-type/node_modules/@babel/runtime-corejs2/helpers/asyncToGenerator.js:5:24)"
]
}
}
}
],
"data": {
"persons": null
}
}
I know I can satisfy individual fields with a per-field @cypher
annotation, that's not appropriate for this case. This question is about satisfying a whole result type.
If the answer requires using a custom handler in the resolvers
array, that's also fine, as long as I can gather the data required to satisfy the type within a single query. Or if this is impossible, that would also be useful information.
The problem is that according to the Person
definition, there must be an object at the query output. So try this query
WITH [["foo", 42], ["bar", 43]] AS x UNWIND x AS y
RETURN { name: y[0], age: y[1] } as Person