Skip to content

Commit e801a8e

Browse files
committed
Add support for custom scalars (resolves #9)
1 parent 4792d3f commit e801a8e

File tree

6 files changed

+244
-4
lines changed

6 files changed

+244
-4
lines changed

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@
118118
<artifactId>neo4j-opencypher-dsl</artifactId>
119119
<version>1.1.0</version>
120120
</dependency>
121+
<dependency>
122+
<groupId>ch.qos.logback</groupId>
123+
<artifactId>logback-classic</artifactId>
124+
<version>1.2.3</version>
125+
<scope>test</scope>
126+
</dependency>
121127
</dependencies>
122128

123129
<build>

readme.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ You find more usage examples in the:
8383
* link:src/test/resources/translator-tests1.adoc[Translator 1 TCK]
8484
* link:src/test/resources/translator-tests2.adoc[Translator 2 TCK]
8585
* link:src/test/resources/translator-tests3.adoc[Translator 3 TCK]
86+
* link:src/test/resources/translator-tests-custom-scalars.adoc[Translator custom scalars TCK]
8687
* link:src/test/resources/optimized-query-for-filter.adoc[Alternative Filter TCK]
8788

8889
== Demo
@@ -246,14 +247,14 @@ This example doesn't handle introspection queries, but the one in the test direc
246247
* date(time)
247248
* interfaces
248249
* complex filter parameters, with optional query optimization strategy
250+
* scalars
249251

250252
=== Next
251253

252254
* skip limit params
253255
* sorting (nested)
254256
* input types
255257
* unions
256-
* scalars
257258
* spatial
258259

259260
== Documentation
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.neo4j.graphql
2+
3+
import graphql.schema.Coercing
4+
5+
object NoOpCoercing : Coercing<Any, Any> {
6+
override fun parseLiteral(input: Any?) = input
7+
8+
override fun serialize(dataFetcherResult: Any?) = dataFetcherResult
9+
10+
override fun parseValue(input: Any?) = input
11+
}

src/main/kotlin/org/neo4j/graphql/SchemaBuilder.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import graphql.Scalars
44
import graphql.language.*
55
import graphql.schema.*
66
import graphql.schema.idl.RuntimeWiring
7+
import graphql.schema.idl.ScalarInfo.STANDARD_SCALAR_DEFINITIONS
78
import graphql.schema.idl.SchemaGenerator
89
import graphql.schema.idl.SchemaParser
910
import graphql.schema.idl.TypeDefinitionRegistry
@@ -40,7 +41,23 @@ object SchemaBuilder {
4041
enhancedRegistry.add(ObjectTypeDefinition.newObjectTypeDefinition().name(QUERY).build())
4142
}
4243

43-
val builder = RuntimeWiring.newRuntimeWiring().scalar(DynamicProperties.INSTANCE)
44+
val builder = RuntimeWiring.newRuntimeWiring()
45+
typeDefinitionRegistry.scalars()
46+
.filterNot { entry -> STANDARD_SCALAR_DEFINITIONS.containsKey(entry.key) }
47+
.forEach { (name, definition) ->
48+
val scalar = when (name) {
49+
"DynamicProperties" -> DynamicProperties.INSTANCE
50+
else -> GraphQLScalarType.newScalar()
51+
.name(name)
52+
.description(definition.description?.getContent() ?: "Scalar $name")
53+
.withDirectives(*definition.directives.filterIsInstance<GraphQLDirective>().toTypedArray())
54+
.definition(definition)
55+
.coercing(NoOpCoercing)
56+
.build()
57+
}
58+
builder.scalar(scalar)
59+
}
60+
4461

4562
enhancedRegistry
4663
.getTypes(InterfaceTypeDefinition::class.java)
@@ -205,4 +222,4 @@ object SchemaBuilder {
205222
typeDefinitionRegistry.add(inputType)
206223
return inputName
207224
}
208-
}
225+
}

src/test/kotlin/org/neo4j/graphql/CypherTests.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ class CypherTests {
2929
@TestFactory
3030
fun `translator-tests3`() = CypherTestSuite("translator-tests3.adoc").run()
3131

32+
@TestFactory
33+
fun `translator-tests-custom-scalars`() = CypherTestSuite("translator-tests-custom-scalars.adoc").run()
34+
3235
@TestFactory
3336
fun `optimized-query-for-filter`() = CypherTestSuite("optimized-query-for-filter.adoc").run()
34-
}
37+
}
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
:toc:
2+
3+
= Translator Tests
4+
5+
== Schema
6+
7+
[source,graphql,schema=true]
8+
----
9+
scalar Date
10+
type Movie {
11+
_id: ID!
12+
title: String!
13+
released: Date
14+
}
15+
----
16+
17+
== Tests
18+
19+
=== Create
20+
21+
.GraphQL-Query
22+
[source,graphql]
23+
----
24+
mutation {
25+
createMovie(title:"Forrest Gump", released: 1994) {
26+
title
27+
released
28+
}
29+
}
30+
----
31+
32+
.Cypher params
33+
[source,json]
34+
----
35+
{
36+
"createMovieTitle": "Forrest Gump",
37+
"createMovieReleased": 1994
38+
}
39+
----
40+
41+
.Cypher
42+
[source,cypher]
43+
----
44+
CREATE (createMovie:Movie { title: $createMovieTitle, released: $createMovieReleased })
45+
WITH createMovie
46+
RETURN createMovie { .title, .released } AS createMovie
47+
----
48+
49+
=== Update
50+
51+
.GraphQL-Query
52+
[source,graphql]
53+
----
54+
mutation {
55+
updateMovie(_id: 1, released: 1995) {
56+
title
57+
released
58+
}
59+
}
60+
----
61+
62+
.Cypher params
63+
[source,json]
64+
----
65+
{
66+
"updateMovie_id": 1,
67+
"updateMovieReleased": 1995
68+
}
69+
----
70+
71+
.Cypher
72+
[source,cypher]
73+
----
74+
MATCH (updateMovie: Movie)
75+
WHERE ID(updateMovie) = toInteger($updateMovie_id)
76+
SET updateMovie = { released: $updateMovieReleased }
77+
WITH updateMovie
78+
RETURN updateMovie { .title, .released } AS updateMovie
79+
----
80+
81+
=== Merge
82+
83+
.GraphQL-Query
84+
[source,graphql]
85+
----
86+
mutation {
87+
mergeMovie(_id: 1, released: 1995) {
88+
title
89+
released
90+
}
91+
}
92+
----
93+
94+
.Cypher params
95+
[source,json]
96+
----
97+
{
98+
"mergeMovie_id": 1,
99+
"mergeMovieReleased": 1995
100+
}
101+
----
102+
103+
.Cypher
104+
[source,cypher]
105+
----
106+
MATCH (mergeMovie: Movie)
107+
WHERE ID(mergeMovie) = toInteger($mergeMovie_id)
108+
SET mergeMovie += { released: $mergeMovieReleased }
109+
WITH mergeMovie
110+
RETURN mergeMovie { .title, .released } AS mergeMovie
111+
----
112+
113+
=== Merge null
114+
115+
.GraphQL-Query
116+
[source,graphql]
117+
----
118+
mutation {
119+
updateMovie(_id: 1, released: null) {
120+
title
121+
released
122+
}
123+
}
124+
----
125+
126+
.Cypher params
127+
[source,json]
128+
----
129+
{
130+
"updateMovie_id": 1,
131+
"updateMovieReleased": null
132+
}
133+
----
134+
135+
.Cypher
136+
[source,cypher]
137+
----
138+
MATCH (updateMovie: Movie)
139+
WHERE ID(updateMovie) = toInteger($updateMovie_id)
140+
SET updateMovie = { released: $updateMovieReleased }
141+
WITH updateMovie
142+
RETURN updateMovie { .title, .released } AS updateMovie
143+
----
144+
145+
=== Find
146+
147+
.GraphQL-Query
148+
[source,graphql]
149+
----
150+
{
151+
movie(released: 1994) {
152+
title
153+
released
154+
}
155+
}
156+
----
157+
158+
.Cypher params
159+
[source,json]
160+
----
161+
{
162+
"movieReleased": 1994
163+
}
164+
----
165+
166+
.Cypher
167+
[source,cypher]
168+
----
169+
MATCH (movie: Movie)
170+
WHERE movie.released = $movieReleased
171+
RETURN movie { .title, .released } AS movie
172+
----
173+
174+
=== Filter
175+
176+
.GraphQL-Query
177+
[source,graphql]
178+
----
179+
{
180+
movie(filter:{released_gte: 1994}) {
181+
title
182+
released
183+
}
184+
}
185+
----
186+
187+
.Cypher params
188+
[source,json]
189+
----
190+
{
191+
"filterMovieReleased_GTE": 1994
192+
}
193+
----
194+
195+
.Cypher
196+
[source,cypher]
197+
----
198+
MATCH (movie: Movie)
199+
WHERE movie.released >= $filterMovieReleased_GTE
200+
RETURN movie { .title, .released } AS movie
201+
----
202+

0 commit comments

Comments
 (0)