@@ -104,7 +104,7 @@ class Translator(val schema: GraphQLSchema) {
104104 private fun projectField (variable : String , field : Field , type : GraphQLObjectType , ctx : Context ) : Cypher {
105105 val fieldDefinition = type.getFieldDefinition(field.name)
106106 return if (inner(fieldDefinition.type) is GraphQLObjectType ) {
107- val patternComprehensions = projectRelationship(variable, field, fieldDefinition, ctx)
107+ val patternComprehensions = projectRelationship(variable, field, fieldDefinition, type, ctx)
108108 Cypher (field.aliasOrName() + " :" + patternComprehensions.query, patternComprehensions.params)
109109 } else Cypher (" ." + field.aliasOrName())
110110 }
@@ -129,23 +129,64 @@ class Translator(val schema: GraphQLSchema) {
129129 projectFragment(fragment.typeCondition.name, type, variable, ctx, fragment.selectionSet)
130130
131131
132- private fun projectRelationship (variable : String , field : Field , fieldDefinition : GraphQLFieldDefinition , ctx : Context ): Cypher {
132+ private fun projectRelationship (variable : String , field : Field , fieldDefinition : GraphQLFieldDefinition , parent : GraphQLObjectType , ctx : Context ): Cypher {
133133 val fieldType = fieldDefinition.type
134134 val innerType = inner(fieldType).name
135- val fieldObjectType = schema.getType(innerType)
136- val relDirective = fieldDefinition.definition.getDirective(" relation" )
137- ? : throw IllegalStateException (" Field $field needs an @relation directive" )
138- val relType = relDirective.getArgument(" name" ).value.toJavaValue()
139- val relDirection = relDirective.getArgument(" direction" ).value.toJavaValue()
140- val (inArrow, outArrow) = if (relDirection.toString() == " IN" ) " <" to " " else " " to " >"
141- val childVariable = field.name + fieldObjectType.name
142- val childPattern = " $childVariable :$innerType "
143- val where = where(childVariable,fieldDefinition,propertyArguments(field))
144- val fieldProjection = projectFields(childVariable, field, fieldObjectType, ctx)
145- val comprehension = " [($variable )$inArrow -[:${relType} ]-$outArrow ($childPattern )${where.query} | ${fieldProjection.query} ]"
146- val skipLimit = skipLimit(field.arguments)
147- val slice = slice(skipLimit,fieldType.isList())
148- return Cypher (comprehension + slice, (where.params + fieldProjection.params))
135+ val fieldObjectType = inner(fieldType) as GraphQLObjectType // schema.getType(innerType) as GraphQLObjectType
136+ val parentIsRelationship = parent.definition.directivesByName.containsKey(" relation" )
137+ // todo combine both if rel-entity
138+ if (! parentIsRelationship) {
139+ val (relDirective, relFromType) = fieldObjectType.definition.getDirective(" relation" )?.let { it to true }
140+ ? : fieldDefinition.definition.getDirective(" relation" )?.let { it to false }
141+ ? : throw IllegalStateException (" Field $field needs an @relation directive" )
142+
143+ val (relType, outgoing, endField) = relDetails(relDirective)
144+ val (inArrow, outArrow) = arrows(outgoing)
145+
146+ val childVariable = field.name // + fieldObjectType.name
147+ val endNodePattern = if (relFromType) {
148+ val label = inner(fieldObjectType.getFieldDefinition(endField).type).name
149+ " $childVariable${endField.capitalize()} :$label "
150+ } else " $childVariable :$innerType "
151+ val relPattern = if (relFromType) " $childVariable :${relType} " else " :${relType} "
152+ val where = where(childVariable, fieldDefinition, propertyArguments(field))
153+ val fieldProjection = projectFields(childVariable, field, fieldObjectType, ctx)
154+
155+ val comprehension = " [($variable )$inArrow -[$relPattern ]-$outArrow ($endNodePattern )${where.query} | ${fieldProjection.query} ]"
156+ val skipLimit = skipLimit(field.arguments)
157+ val slice = slice(skipLimit, fieldType.isList())
158+ return Cypher (comprehension + slice, (where.params + fieldProjection.params))
159+ } else {
160+ val relDirective = parent.definition.directivesByName.getValue(" relation" )
161+ val (relType, outgoing, endField) = relDetails(relDirective)
162+
163+ val fieldProjection = projectFields(variable+ endField.capitalize(), field, fieldObjectType, ctx)
164+
165+ return Cypher (fieldProjection.query)
166+ }
167+ }
168+
169+ private fun arrows (outgoing : Boolean? ): Pair <String , String > {
170+ return when (outgoing) {
171+ false -> " <" to " "
172+ true -> " " to " >"
173+ null -> " " to " "
174+ }
175+ }
176+
177+ private fun relDetails (relDirective : Directive ): Triple <String ,Boolean ?,String > {
178+ val arguments = relDirective.argumentsByName
179+ val relType = arguments.getValue(" name" ).value.toJavaValue().toString()
180+ val relDirection = arguments.get(" direction" )?.value?.toJavaValue()
181+ ? : schema.getDirective(" relation" ).getArgument(" direction" ).defaultValue
182+ val outgoing = when (relDirection.toString()) {
183+ " IN" -> false
184+ " BOTH" -> null
185+ " OUT" -> true
186+ else -> throw IllegalStateException (" Unknown direction $relDirection " )
187+ }
188+ val endField = if (outgoing == true ) " end" else " start"
189+ return Triple (relType, outgoing, endField)
149190 }
150191
151192 private fun slice (skipLimit : Pair <Int , Int >, list : Boolean = false) =
@@ -240,7 +281,7 @@ object SchemaBuilder {
240281 .build()
241282
242283 val schemaGenerator = SchemaGenerator ()
243- val directives = setOf (GraphQLDirective .newDirective().name(" relation" ).argument { it.name(" name" ).type(Scalars .GraphQLString ).also { it.name(" direction" ).type(Scalars .GraphQLString ) } }.build())
284+ val directives = setOf (GraphQLDirective .newDirective().name(" relation" ).argument { it.name(" name" ).type(Scalars .GraphQLString ).also { it.name(" direction" ).type(Scalars .GraphQLString ).defaultValue( " OUT " ) } }.build())
244285 return schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring).transform { bc -> bc.additionalDirectives(directives).build() }
245286 }
246287}
0 commit comments