@@ -5,20 +5,20 @@ import graphql.language.*
55import graphql.schema.*
66import org.neo4j.cypherdsl.core.Node
77import org.neo4j.cypherdsl.core.Relationship
8+ import org.neo4j.cypherdsl.core.SymbolicName
89import org.neo4j.graphql.DirectiveConstants.Companion.CYPHER
910import org.neo4j.graphql.DirectiveConstants.Companion.CYPHER_STATEMENT
1011import org.neo4j.graphql.DirectiveConstants.Companion.DYNAMIC
1112import org.neo4j.graphql.DirectiveConstants.Companion.DYNAMIC_PREFIX
1213import org.neo4j.graphql.DirectiveConstants.Companion.PROPERTY
1314import org.neo4j.graphql.DirectiveConstants.Companion.PROPERTY_NAME
1415import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_DIRECTION
15- import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_DIRECTION_BOTH
16- import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_DIRECTION_IN
17- import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_DIRECTION_OUT
1816import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_FROM
1917import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_NAME
2018import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_TO
2119import org.neo4j.graphql.handler.projection.ProjectionBase
20+ import java.math.BigDecimal
21+ import java.math.BigInteger
2222
2323fun Type <Type <* >>.name (): String? = if (this .inner() is TypeName ) (this .inner() as TypeName ).name else null
2424fun Type <Type <* >>.inner (): Type <Type <* >> = when (this ) {
@@ -34,7 +34,7 @@ fun GraphQLType.inner(): GraphQLType = when (this) {
3434}
3535
3636fun GraphQLType.name (): String? = (this as ? GraphQLNamedType )?.name
37- fun GraphQLType.requiredName (): String = requireNotNull(name()) { -> " name is required but cannot be determined for " + this .javaClass }
37+ fun GraphQLType.requiredName (): String = requireNotNull(name()) { " name is required but cannot be determined for " + this .javaClass }
3838
3939fun GraphQLType.isList () = this is GraphQLList || (this is GraphQLNonNull && this .wrappedType is GraphQLList )
4040fun GraphQLType.isScalar () = this .inner().let { it is GraphQLScalarType || it.innerName().startsWith(" _Neo4j" ) }
@@ -44,7 +44,6 @@ fun GraphQLFieldDefinition.isNeo4jType(): Boolean = this.type.isNeo4jType()
4444
4545fun GraphQLFieldDefinition.isRelationship () = ! type.isNeo4jType() && this .type.inner().let { it is GraphQLFieldsContainer }
4646
47- fun GraphQLFieldsContainer.hasRelationship (name : String ) = this .getFieldDefinition(name)?.isRelationship() ? : false
4847fun GraphQLDirectiveContainer.isRelationType () = getDirective(DirectiveConstants .RELATION ) != null
4948fun GraphQLFieldsContainer.isRelationType () = (this as ? GraphQLDirectiveContainer )?.getDirective(DirectiveConstants .RELATION ) != null
5049fun GraphQLFieldsContainer.relationshipFor (name : String ): RelationshipInfo ? {
@@ -69,16 +68,16 @@ fun GraphQLFieldsContainer.relationshipFor(name: String): RelationshipInfo? {
6968
7069 val relInfo = relDetails(fieldObjectType, relDirective)
7170
72- return if (inverse) relInfo.copy(out = relInfo.out ?. let { ! it } , startField = relInfo.endField, endField = relInfo.startField) else relInfo
71+ return if (inverse) relInfo.copy(direction = relInfo.direction.invert() , startField = relInfo.endField, endField = relInfo.startField) else relInfo
7372}
7473
7574fun GraphQLFieldsContainer.getValidTypeLabels (schema : GraphQLSchema ): List <String > {
7675 if (this is GraphQLObjectType ) {
77- return listOf (this .quotedLabel ())
76+ return listOf (this .label ())
7877 }
7978 if (this is GraphQLInterfaceType ) {
8079 return schema.getImplementations(this )
81- .mapNotNull { it.quotedLabel () }
80+ .mapNotNull { it.label () }
8281 }
8382 return emptyList()
8483}
@@ -92,14 +91,6 @@ fun GraphQLFieldsContainer.label(): String = when {
9291 else -> name
9392}
9493
95- fun GraphQLFieldsContainer.quotedLabel () = this .label().quote()
96-
97- fun GraphQLFieldsContainer.allLabels () = when {
98- this .isRelationType() -> this .quotedLabel()
99- else -> (listOf (name) + ((this as ? GraphQLObjectType )?.interfaces?.map { it.name } ? : emptyList()))
100- .map { it.quote() }
101- .joinToString(" :" )
102- }
10394
10495fun GraphQLFieldsContainer.relevantFields () = fieldDefinitions
10596 .filter { it.type.isScalar() || it.isNeo4jType() }
@@ -113,7 +104,9 @@ fun GraphQLFieldsContainer.relationship(): RelationshipInfo? {
113104 val relType = directiveResolver(RELATION_NAME , " " )!!
114105 val startField = directiveResolver(RELATION_FROM , null )
115106 val endField = directiveResolver(RELATION_TO , null )
116- return RelationshipInfo (this , relType, null , startField, endField)
107+ val direction = directiveResolver(RELATION_DIRECTION , null )?.let { RelationDirection .valueOf(it) }
108+ ? : RelationDirection .OUT
109+ return RelationshipInfo (this , relType, direction, startField, endField)
117110}
118111
119112fun GraphQLType.ref (): GraphQLType = when (this ) {
@@ -127,23 +120,21 @@ fun GraphQLType.ref(): GraphQLType = when (this) {
127120
128121fun relDetails (type : GraphQLFieldsContainer , relDirective : GraphQLDirective ): RelationshipInfo {
129122 val relType = relDirective.getArgument(RELATION_NAME , " " )!!
130- val outgoing = when (relDirective.getArgument<String >(RELATION_DIRECTION , null )) {
131- RELATION_DIRECTION_IN -> false
132- RELATION_DIRECTION_BOTH -> null
133- RELATION_DIRECTION_OUT -> true
134- else -> throw IllegalStateException (" Unknown direction ${relDirective.getArgument<String >(RELATION_DIRECTION , null )} " )
135- }
123+ val direction = relDirective.getArgument<String >(RELATION_DIRECTION , null )
124+ ?.let { RelationDirection .valueOf(it) }
125+ ? : RelationDirection .OUT
126+
136127 return RelationshipInfo (type,
137128 relType,
138- outgoing ,
129+ direction ,
139130 relDirective.getArgument<String >(RELATION_FROM , null ),
140131 relDirective.getArgument<String >(RELATION_TO , null ))
141132}
142133
143134data class RelationshipInfo (
144135 val type : GraphQLFieldsContainer ,
145136 val relType : String ,
146- val out : Boolean? ,
137+ val direction : RelationDirection ,
147138 val startField : String? = null ,
148139 val endField : String? = null ,
149140 val isRelFromType : Boolean = false
@@ -154,10 +145,10 @@ data class RelationshipInfo(
154145 val declaringType : GraphQLFieldsContainer
155146 )
156147
157- val arrows = when (out ) {
158- false -> " <" to " "
159- true -> " " to " >"
160- null -> " " to " "
148+ val arrows = when (direction ) {
149+ RelationDirection . IN -> " <" to " "
150+ RelationDirection . OUT -> " " to " >"
151+ RelationDirection . BOTH -> " " to " "
161152 }
162153
163154 val typeName: String get() = this .type.name
@@ -173,20 +164,26 @@ data class RelationshipInfo(
173164 val relType = relFieldDefinition.type.inner() as ? GraphQLFieldsContainer
174165 ? : throw IllegalArgumentException (" type ${relFieldDefinition.type.innerName()} not found" )
175166 return relType.fieldDefinitions.filter { it.isID() }
176- .map { RelatedField (" ${relFieldName} _${it.name} " , it, relType) }
167+ .map {
168+ // TODO b/c we need to stay backwards kompatible this is not caml case but with underscore
169+ // val filedName = normalizeName(relFieldName, it.name)
170+ val filedName = " ${relFieldName} _${it.name} "
171+ RelatedField (filedName, it, relType)
172+ }
177173 .firstOrNull()
178174 }
179175
180176 fun createRelation (start : Node , end : Node ): Relationship =
181- when (this .out ) {
182- false -> start.relationshipFrom(end, this .relType)
183- true -> start.relationshipTo(end, this .relType)
184- null -> start.relationshipBetween(end, this .relType)
177+ when (this .direction ) {
178+ RelationDirection . IN -> start.relationshipFrom(end, this .relType)
179+ RelationDirection . OUT -> start.relationshipTo(end, this .relType)
180+ RelationDirection . BOTH -> start.relationshipBetween(end, this .relType)
185181 }
186182}
187183
188- fun Field.aliasOrName () = (this .alias ? : this .name).quote()
189- fun Field.contextualize (variable : String ) = variable + (this .alias ? : this .name).capitalize()
184+ fun Field.aliasOrName (): String = (this .alias ? : this .name)
185+ fun Field.contextualize (variable : String ) = variable + this .aliasOrName().capitalize()
186+ fun Field.contextualize (variable : SymbolicName ) = variable.value + this .aliasOrName().capitalize()
190187
191188fun GraphQLType.innerName (): String = inner().name()
192189 ? : throw IllegalStateException (" inner name cannot be retrieved for " + this .javaClass)
@@ -212,25 +209,6 @@ fun <T> GraphQLDirective.getArgument(argumentName: String, defaultValue: T?): T?
212209fun GraphQLFieldDefinition.cypherDirective (): Cypher ? = getDirectiveArgument<String >(CYPHER , CYPHER_STATEMENT , null )
213210 ?.let { statement -> Cypher (statement) }
214211
215- fun String.quote () = if (isJavaIdentifier()) this else " `$this `"
216-
217- fun String.isJavaIdentifier () =
218- this [0 ].isJavaIdentifierStart() &&
219- this .substring(1 ).all { it.isJavaIdentifierPart() }
220-
221- @Suppress(" SimplifiableCallChain" )
222- fun Value <Value <* >>.toCypherString (): String = when (this ) {
223- is StringValue -> " '" + this .value + " '"
224- is EnumValue -> " '" + this .name + " '"
225- is NullValue -> " null"
226- is BooleanValue -> this .isValue.toString()
227- is FloatValue -> this .value.toString()
228- is IntValue -> this .value.toString()
229- is VariableReference -> " $" + this .name
230- is ArrayValue -> this .values.map { it.toCypherString() }.joinToString(" ," , " [" , " ]" )
231- else -> throw IllegalStateException (" Unhandled value $this " )
232- }
233-
234212fun Any.toJavaValue () = when (this ) {
235213 is Value <* > -> this .toJavaValue()
236214 else -> this
@@ -249,11 +227,6 @@ fun Value<*>.toJavaValue(): Any? = when (this) {
249227 else -> throw IllegalStateException (" Unhandled value $this " )
250228}
251229
252- fun paramName (variable : String , argName : String , value : Any? ): String = when (value) {
253- is VariableReference -> value.name
254- else -> " $variable${argName.capitalize()} "
255- }
256-
257230fun GraphQLFieldDefinition.isID () = this .type.inner() == Scalars .GraphQLID
258231fun GraphQLFieldDefinition.isNativeId () = this .name == ProjectionBase .NATIVE_ID
259232fun GraphQLFieldsContainer.getIdField () = this .fieldDefinitions.find { it.isID() }
@@ -274,3 +247,18 @@ fun GraphQLInputObjectType.Builder.addFilterField(fieldName: String, isList: Boo
274247fun GraphQLSchema.queryTypeName () = this .queryType?.name ? : " Query"
275248fun GraphQLSchema.mutationTypeName () = this .mutationType?.name ? : " Mutation"
276249fun GraphQLSchema.subscriptionTypeName () = this .subscriptionType?.name ? : " Subscription"
250+
251+ fun Any?.asGraphQLValue (): Value <* > = when (this ) {
252+ null -> NullValue .newNullValue().build()
253+ is Value <* > -> this
254+ is Array <* > -> ArrayValue .newArrayValue().values(this .map { it.asGraphQLValue() }).build()
255+ is Iterable <* > -> ArrayValue .newArrayValue().values(this .map { it.asGraphQLValue() }).build()
256+ is Map <* , * > -> ObjectValue .newObjectValue().objectFields(this .map { entry -> ObjectField (entry.key as String , entry.value.asGraphQLValue()) }).build()
257+ is Enum <* > -> EnumValue .newEnumValue().name(this .name).build()
258+ is Int -> IntValue .newIntValue(BigInteger .valueOf(this .toLong())).build()
259+ is Long -> IntValue .newIntValue(BigInteger .valueOf(this )).build()
260+ is Number -> FloatValue .newFloatValue(BigDecimal .valueOf(this as Double )).build()
261+ is Boolean -> BooleanValue .newBooleanValue(this ).build()
262+ is String -> StringValue .newStringValue(this ).build()
263+ else -> throw IllegalStateException (" Cannot convert ${this .javaClass.name} into an graphql type" )
264+ }
0 commit comments