迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):neo4j-graphql/neo4j-graphql-java开源软件地址(OpenSource Url):https://github.com/neo4j-graphql/neo4j-graphql-java开源编程语言(OpenSource Language):Kotlin 98.3%开源软件介绍(OpenSource Introduction):JVM Library to translate GraphQL queries and mutations to Neo4j’s CypherQuick Links
How does it workThis library
Those Cypher queries can then be executed, e.g. via the Neo4j-Java-Driver (or other JVM drivers) against the graph database and the results can be returned directly to the caller. The request, result and error handling is not part of this library, but we provide demo programs on how to use it in different languages.
ExamplesFor complex examples take a look at our example projects API compatibility to @neo4j/graphqlSince the javascript pendant of this library (neo4j-graphql-js) has majored into a neo4j product, we want to migrate our augmented schema, to match as much as possible to the one of the We will try to make the migration as smooth as possible. For this purpose we will support the old, and the new way of schema augmentation until the next major release.
To already test the new features, you can enable them via some setting in the FAQHow does this relate to the other neo4j graphql libraries?The GRANDstack is a full-stack package that integrates React frontends via GraphQL through Similar to We plan to replace the code in the current Neo4j server plugin How does this related to graphql-javaThis library uses If you wanted, you could combine Thanks a lot to the maintainers of
UsageYou can use the library as dependency: The basic usage should be: val schema =
"""
type Person {
name: ID!
age: Int
}
# Optional if you use generated queries
type Query {
person : [Person]
personByName(name:ID) : Person
}"""
val query = """ { p:personByName(name:"Joe") { age } } """
val schema = SchemaBuilder.buildSchema(idl)
val ctx = QueryContext()
val (cypher, params) = Translator(schema).translate(query, params, ctx)
// generated Cypher
cypher == "MATCH (p:Person) WHERE p.name = $pName RETURN p {.age} as p" You find more usage examples in the: DemoHere is a minimalistic example in Groovy using the Neo4j-Java driver and Spark-Java as webserver.
It is running against a Neo4j instance at (You can also use a Kotlin based server example.) In case you wand to bind the neo4j driver directly to the graphql schema you can use the DataFetchingInterceptor to intercept the cypher queries. // Simplistic GraphQL Server using SparkJava
@Grapes([
@Grab('com.sparkjava:spark-core:2.7.2'),
@Grab('org.neo4j.driver:neo4j-java-driver:1.7.2'),
@Grab('com.google.code.gson:gson:2.8.5'),
@Grab('org.neo4j:neo4j-graphql-java:1.5.0')
])
import spark.*
import static spark.Spark.*
import com.google.gson.Gson
import org.neo4j.graphql.*
import org.neo4j.driver.v1.*
schema = """
type Person {
name: ID!
born: Int
actedIn: [Movie] @relation(name:"ACTED_IN")
}
type Movie {
title: ID!
released: Int
tagline: String
}
type Query {
person : [Person]
}
"""
gson = new Gson()
render = (ResponseTransformer)gson.&toJson
def query(value) { gson.fromJson(value,Map.class)["query"] }
graphql = new Translator(SchemaBuilder.buildSchema(schema))
def translate(query) { graphql.translate(query) }
driver = GraphDatabase.driver("bolt://localhost",AuthTokens.basic("neo4j","s3cr3t"))
def run(cypher) { driver.session().withCloseable {
it.run(cypher.query, Values.value(cypher.params)).list{ it.asMap() }}}
post("/graphql","application/json", { req, res -> run(translate(query(req.body())).first()) }, render); Run the example with: groovy docs/Server.groovy and use http://localhost:4567/graphql as your GraphQL URL. It uses a schema of: type Person {
name: ID!
born: Int
actedIn: [Movie] @relation(name:"ACTED_IN")
}
type Movie {
title: ID!
released: Int
tagline: String
}
type Query {
person : [Person]
} And can run queries like: {
person(first:3) {
name
born
actedIn(first:2) {
title
}
}
} You can also test it with curl -XPOST http://localhost:4567/graphql -d'{"query":"{person {name}}"}' This example doesn’t handle introspection queries, but the one in the test directory does. Advanced QueriesFilter, Sorting, Paging support
{ person(filter: {name_starts_with: "L"}, orderBy: "born_asc", first: 5, offset: 2) { name born actedIn(first: 1) { title } } } { person(filter: {name_starts_with: "J", born_gte: 1970}, first:2) { name born actedIn(first:1) { title released } } } FeaturesCurrent
Next
DocumentationParse SDL schema
Resolve query Fields via Result TypesFor query fields that result in object types (even if wrapped in list/non-null), the appropriate object type is determined via the schema and used to translate the query. e.g. type Query {
person: [Person]
}
# query "person" is resolved to and via "Person"
type Person {
name : String
} Handle Arguments as Equality Comparisons for Top Level and Nested FieldsIf you add a simple argument to your top-level query or nested related fields, those will be translated to direct equality comparisons. person(name:"Joe", age:42) {
name
} to an equivalent of
The literal values are turned into Cypher query parameters. Handle Relationships via @relation Directive on Schema FieldsIf you want to represent a relationship from the graph in GraphQL you have to add a type Person {
name : String
actedIn: [Movie] @relation(name:"ACTED_IN", direction:OUT)
} person(name:"Keanu Reeves") {
name
actedIn {
title
}
}
Handle first, offset ArgumentsTo support pagination person(offset: 5, first:10) {
name
}
Argument Types: string, int, float, arrayThe default Neo4j Cypher types are handled both as argument types as well as field types.
Usage of IDEach type is expected to have exactly one filed of type So there are 3 cases: Case 1: Only the ID field exists
type User {
email: ID!
name: String!
} Case 2: Only the ID field exists interpreted as internal ID
type User {
_id: ID!
email: String!
name: String!
} Case 3: An ID field exists but the internal ID is propagated as well
type User {
_id: Int!
email: ID!
name: String!
}
Parameter SupportGraphQL parameter’s are passed onto Cypher, these are resolved correctly when used within the GraphQL query. ParametrizationFor query injection prevention and caching purposes, literal values are translated into parameters. person(name:"Joe", age:42, first:10) {
name
} to
Those parameters are returned as part of the AliasesWe support query aliases, they are used as Cypher aliases too, so you get them back as keys in your result records. For example: query {
jane: person(name:"Jane") { name, age }
joe: person(name:"Joe") { name, age }
} Inline and Named FragmentsThis is more of a technical feature, both types of fragments are resolved internally. Sorting (top-level)We support sorting via an query {
person(orderBy:[name_asc, age_desc]) {
name
age
}
}
Handle Rich Relationships via @relation Directive on Schema TypesTo represent rich relationship types with properties, a In our example it would be the type Role @relation(name:"ACTED_IN", from:"actor", to:"movie") {
actor: Person
movie: Movie
roles: [String]
}
type Person {
name: String
born: Int
roles: [Role]
}
type Movie {
title: String
released: Int
characters: [Role]
} person(name:"Keanu Reeves") {
roles {
roles
movie {
title
}
}
} FiltersFilters are a powerful way of selecting a subset of data. Inspired by the graph.cool/Prisma filter approach, our filters work the same way. These filters are documented in detail in the https://grandstack.io/docs/graphql-filtering [GRANDstack docs^]. We use nested input types for arbitrary filtering on query types and fields. { Company(filter: { AND: { name_contains: "Ne", country_in ["SE"]}}) { name } } You can also apply nested filter on relations, which use suffixes like { Company(filter: {
employees_none { name_contains: "Jan"},
employees_some: { gender_in : [female]},
company_not: null })
{
name
}
} Optimized FiltersIf you encounter performance problems with the cypher queries generated for the filter, you can activate an alternative algorithm using: var query
try {
val ctx = QueryContext(optimizedQuery = setOf(QueryContext.OptimizationStrategy.FILTER_AS_MATCH))
query = translator.translate(query, params, ctx)
} catch (e: OptimizedQueryException) {
query = translator.translate(query, params)
} If no query can be generated by the alternative algorithm, an Examples of the alternative algorithm can be seen in the tests. Inline and Named FragmentsWe support inline and named fragments according to the GraphQL spec. Most of this is resolved on the parser/query side. Named Fragment
fragment details on Person { name, email, dob }
query {
person {
...details
}
} Inline Fragment
query {
person {
... on Person { name, email, dob }
}
} @cypher DirectivesWith It allows you, without code to compute field values using complex queries. Yo |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论