You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: readme.adoc
+230-5Lines changed: 230 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,23 @@
2
2
3
3
This is an early stage alpha implementation written in Kotlin.
4
4
5
+
== How does it work
6
+
7
+
This library
8
+
9
+
1. parses a GraphQL schema and
10
+
2. uses the information of the annotated schema to translate _GraphQL_ queries and parameters into _Cypher_ queries and parameters.
11
+
12
+
Those Cypher queries can then 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.
13
+
14
+
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.
15
+
16
+
NOTE: All the supported features are listed below, detailed docs will be added.
17
+
18
+
== Usage
19
+
20
+
You can use the library as dependency: `org.neo4j:neo4j-graphql-java:1.0.0-M01` in any JVM program.
21
+
5
22
The basic usage should be:
6
23
7
24
[source,kotlin]
@@ -22,11 +39,67 @@ val query = """ { p:personByName(name:"Joe") { age } } """
22
39
val schema = SchemaBuilder.buildSchema(idl)
23
40
val (cypher, params) = Translator(schema).translate(query, params)
24
41
25
-
cypher == "MATCH (p:Person) WHERE p.name = 'Joe' RETURN p {.age}"
42
+
cypher == "MATCH (p:Person) WHERE p.name = $pName RETURN p {.age} as p"
43
+
----
44
+
45
+
== Demo
46
+
47
+
Here is a minimalistic example in Groovy using the Neo4j-Java driver and Spark-Java as webserver.
48
+
It is running against a Neo4j instance at `bolt://localhost` (username: `neo4j`, password: `password`) containing the `:play movies` graph.
49
+
50
+
[source,groovy]
51
+
----
52
+
include::docs/Server.groovy[]
26
53
----
27
54
55
+
Run the example with:
56
+
57
+
----
58
+
groovy docs/Server.groovy
59
+
----
60
+
61
+
and use http://localhost:4567/graphql as your GraphQL URL.
62
+
63
+
It uses a schema of:
64
+
65
+
[source,graphql]
66
+
----
67
+
type Person {
68
+
name: String
69
+
born: Int
70
+
actedIn: [Movie] @relation(name:"ACTED_IN")
71
+
}
72
+
type Movie {
73
+
title: String
74
+
released: Int
75
+
tagline: String
76
+
}
77
+
type Query {
78
+
person : [Person]
79
+
}
80
+
----
81
+
82
+
And can run queries like:
83
+
84
+
[source,graphql]
85
+
----
86
+
{
87
+
person(first:3) {
88
+
name
89
+
born
90
+
actedIn(first:2) {
91
+
title
92
+
}
93
+
}
94
+
}
95
+
----
96
+
97
+
image::docs/graphiql.jpg[]
98
+
28
99
== Features
29
100
101
+
=== Current
102
+
30
103
* parse SDL schema
31
104
* resolve query fields via result types
32
105
* handle arguments as equality comparisons for top level and nested fields
@@ -37,11 +110,8 @@ cypher == "MATCH (p:Person) WHERE p.name = 'Joe' RETURN p {.age}"
37
110
* parametrization
38
111
* aliases
39
112
* inline and named fragments
40
-
* sorting (top-level)
41
-
* @relationship types
42
-
* filters
43
113
44
-
== Next
114
+
=== Next
45
115
46
116
* sorting (nested)
47
117
* interfaces
@@ -50,3 +120,158 @@ cypher == "MATCH (p:Person) WHERE p.name = 'Joe' RETURN p {.age}"
50
120
* auto-generate queries
51
121
* auto-generate mutations
52
122
* unions
123
+
* scalars
124
+
* date(time), spatial
125
+
126
+
== Documentation
127
+
128
+
=== Parse SDL schema
129
+
130
+
Currently schemas with object types, enums and Query types are parsed and handled.
131
+
It supports the built-in scalars for GraphQL.
132
+
133
+
=== Resolve query Fields via Result Types
134
+
135
+
For _query fields_ that result in object types (even if wrapped in list/non-null), the appropriate object type is found in the schema and used to translate the query.
136
+
137
+
e.g.
138
+
139
+
[source,graphql]
140
+
----
141
+
type Query {
142
+
person: [Person]
143
+
}
144
+
# query "person" is resolved to and via "Person"
145
+
146
+
type Person {
147
+
name : String
148
+
}
149
+
----
150
+
151
+
=== Handle Arguments as Equality Comparisons for Top Level and Nested Fields
152
+
153
+
If you add a simple argument to your top-level query or nested related fields, those will be translated to direct equality comparisons.
154
+
155
+
[source,graphql]
156
+
----
157
+
person(name:"Joe", age:42) {
158
+
name
159
+
}
160
+
----
161
+
162
+
to
163
+
164
+
[source,cypher]
165
+
----
166
+
MATCH (person:Person) WHERE person.name = 'Joe' AND person.age = 42 RETURN person { .name } AS person
167
+
----
168
+
169
+
Only that the literal values are turned into parameters.
170
+
171
+
=== Handle Relationships via @relation Directive on Schema Fields
172
+
173
+
If you want to represent a relationship from the graph in GraphQL you have to add an `@relation` directive that contains the relationship-type and the direction.
174
+
Default relationship-type is 'OUT'.
175
+
So you can use different domain names in your GraphQL fields that are independent of your graph model.
176
+
177
+
[source,graphql]
178
+
----
179
+
type Person {
180
+
name : String
181
+
actedIn: [Movie]
182
+
}
183
+
----
184
+
185
+
----
186
+
person(name:"Keanu Reeves") {
187
+
name
188
+
actedIn {
189
+
title
190
+
}
191
+
}
192
+
----
193
+
194
+
195
+
=== Handle first, offset Arguments
196
+
197
+
To support pagination `first` is translated to `LIMIT` in Cypher and `offset` into `SKIP`
198
+
For nested queries these are converted into slices for arrays.
199
+
200
+
=== Argument Types: string, int, float, array
201
+
202
+
The default Neo4j types are handled both as argument types as well as field types.
203
+
204
+
NOTE: Datetime and spatial not yet.
205
+
206
+
=== Parameter Support
207
+
208
+
We handle passed in GraphQL parameters, these are resolved correctly when used within the GraphQL query.
209
+
210
+
211
+
=== Parametrization
212
+
213
+
As we don't want to have literal values in our Cypher queries, all of them are translated into parameters.
214
+
215
+
[source,graphql]
216
+
----
217
+
person(name:"Joe", age:42, first:10) {
218
+
name
219
+
}
220
+
----
221
+
222
+
to
223
+
224
+
[source,cypher]
225
+
----
226
+
MATCH (person:Person) WHERE person.name = $personName AND person.age = $personAge RETURN person { .name } AS person LIMIT $first
227
+
----
228
+
229
+
Those parameters are returned as part of the `Cypher` type that's returned from the `translate()` method.
230
+
231
+
=== Aliases
232
+
233
+
We support query aliases, they are used as Cypher aliases too, so you get them back as keys in your result records.
234
+
235
+
=== Inline and Named Fragments
236
+
237
+
This is more of a technical feature, both types of fragments are resolved internally.
238
+
239
+
=== Sorting (top-level)
240
+
241
+
We support sorting via an `orderBy` argument, which takes an Enum or String value of `fieldName_asc` or `fieldName_desc`.
242
+
243
+
NOTE: Those enums are not yet automatically generated.
244
+
245
+
=== @relationship on Types
246
+
247
+
To represent rich relationship types with properties, a @relation directive is supported on an object Type
248
+
249
+
250
+
=== Filters
251
+
252
+
Filters are a powerful way of selecting a subset of data.
253
+
Inspired by the https://www.graph.cool/docs/reference/graphql-api/query-api-nia9nushae[graph.cool/Prisma filter approach], our filters work the same way.
254
+
255
+
NOTE: we'll create more detailed docs, for now the prisma docs on that topic are pretty good.
256
+
257
+
258
+
We use nested input types for arbitrary filtering on query types and fields
0 commit comments