@@ -17,6 +17,8 @@ import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_FROM
1717import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_NAME
1818import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_TO
1919import org.neo4j.graphql.handler.projection.ProjectionBase
20+ import org.neo4j.opencypherdsl.Node
21+ import org.neo4j.opencypherdsl.Relationship
2022
2123fun Type <Type <* >>.name (): String? = if (this .inner() is TypeName ) (this .inner() as TypeName ).name else null
2224fun Type <Type <* >>.inner (): Type <Type <* >> = when (this ) {
@@ -36,7 +38,7 @@ fun GraphQLType.isScalar() = this.inner().let { it is GraphQLScalarType || it.na
3638fun GraphQLType.isNeo4jType () = this .inner().name?.startsWith(" _Neo4j" ) == true
3739fun GraphQLFieldDefinition.isNeo4jType (): Boolean = this .type.isNeo4jType()
3840
39- fun GraphQLFieldDefinition.isRelationship () = this .type.inner().let { it is GraphQLFieldsContainer }
41+ fun GraphQLFieldDefinition.isRelationship () = ! type.isNeo4jType() && this .type.inner().let { it is GraphQLFieldsContainer }
4042
4143fun GraphQLFieldsContainer.hasRelationship (name : String ) = this .getFieldDefinition(name)?.isRelationship() ? : false
4244fun GraphQLDirectiveContainer.isRelationType () = getDirective(DirectiveConstants .RELATION ) != null
@@ -46,13 +48,18 @@ fun GraphQLFieldsContainer.relationshipFor(name: String): RelationshipInfo? {
4648 ? : throw IllegalArgumentException (" $name is not defined on ${this .name} " )
4749 val fieldObjectType = field.type.inner() as ? GraphQLFieldsContainer ? : return null
4850
49- // TODO direction is depending on source/target type
50-
51- val (relDirective, isRelFromType) = (fieldObjectType as ? GraphQLDirectiveContainer )
52- ?.getDirective(DirectiveConstants .RELATION )?.let { it to true }
53- ? : field.getDirective(DirectiveConstants .RELATION )?.let { it to false }
54- ? : throw IllegalStateException (" Field $field needs an @relation directive" )
51+ val (relDirective, isRelFromType) = if (isRelationType()) {
52+ (this as ? GraphQLDirectiveContainer )
53+ ?.getDirective(DirectiveConstants .RELATION )?.let { it to false }
54+ ? : throw IllegalStateException (" Type ${this .name} needs an @relation directive" )
55+ } else {
56+ (fieldObjectType as ? GraphQLDirectiveContainer )
57+ ?.getDirective(DirectiveConstants .RELATION )?.let { it to true }
58+ ? : field.getDirective(DirectiveConstants .RELATION )?.let { it to false }
59+ ? : throw IllegalStateException (" Field $field needs an @relation directive" )
60+ }
5561
62+ // TODO direction is depending on source/target type
5663
5764 val relInfo = relDetails(fieldObjectType) { argName, defaultValue -> relDirective.getArgument(argName, defaultValue) }
5865
@@ -62,28 +69,31 @@ fun GraphQLFieldsContainer.relationshipFor(name: String): RelationshipInfo? {
6269
6370fun GraphQLFieldsContainer.getValidTypeLabels (schema : GraphQLSchema ): List <String > {
6471 if (this is GraphQLObjectType ) {
65- return listOf (this .label ())
72+ return listOf (this .quotedLabel ())
6673 }
6774 if (this is GraphQLInterfaceType ) {
6875 return schema.getImplementations(this )
69- .mapNotNull { it.label () }
76+ .mapNotNull { it.quotedLabel () }
7077 }
7178 return emptyList()
7279}
7380
74- @Suppress(" SimplifiableCallChain" )
75- fun GraphQLFieldsContainer.label (includeAll : Boolean = false) = when {
81+ fun GraphQLFieldsContainer.label (): String = when {
7682 this .isRelationType() ->
7783 (this as ? GraphQLDirectiveContainer )
7884 ?.getDirective(DirectiveConstants .RELATION )
79- ?.getArgument(RELATION_NAME )?.value?.toJavaValue()?.toString()?.quote()
80- ? : this .name.quote()
81- else -> when {
82- includeAll -> (listOf (name) + ((this as ? GraphQLObjectType )?.interfaces?.map { it.name } ? : emptyList()))
83- .map { it.quote() }
84- .joinToString(" :" )
85- else -> name.quote()
86- }
85+ ?.getArgument(RELATION_NAME )?.value?.toJavaValue()?.toString()
86+ ? : this .name
87+ else -> name
88+ }
89+
90+ fun GraphQLFieldsContainer.quotedLabel () = this .label().quote()
91+
92+ fun GraphQLFieldsContainer.allLabels () = when {
93+ this .isRelationType() -> this .quotedLabel()
94+ else -> (listOf (name) + ((this as ? GraphQLObjectType )?.interfaces?.map { it.name } ? : emptyList()))
95+ .map { it.quote() }
96+ .joinToString(" :" )
8797}
8898
8999fun GraphQLFieldsContainer.relevantFields () = fieldDefinitions
@@ -163,6 +173,13 @@ data class RelationshipInfo(
163173 .map { RelatedField (" ${relFieldName} _${it.name} " , it, relType) }
164174 .firstOrNull()
165175 }
176+
177+ fun createRelation (start : Node , end : Node ): Relationship =
178+ when (this .out ) {
179+ false -> start.relationshipFrom(end, this .relType)
180+ true -> start.relationshipTo(end, this .relType)
181+ null -> start.relationshipBetween(end, this .relType)
182+ }
166183}
167184
168185fun Field.aliasOrName () = (this .alias ? : this .name).quote()
@@ -233,4 +250,16 @@ fun paramName(variable: String, argName: String, value: Any?): String = when (va
233250
234251fun GraphQLFieldDefinition.isID () = this .type.inner() == Scalars .GraphQLID
235252fun GraphQLFieldDefinition.isNativeId () = this .name == ProjectionBase .NATIVE_ID
236- fun GraphQLFieldsContainer.getIdField () = this .fieldDefinitions.find { it.isID() }
253+ fun GraphQLFieldsContainer.getIdField () = this .fieldDefinitions.find { it.isID() }
254+
255+ fun GraphQLInputObjectType.Builder.addFilterField (fieldName : String , isList : Boolean , filterType : String , description : String? = null) {
256+ val wrappedType: GraphQLInputType = when {
257+ isList -> GraphQLList (GraphQLTypeReference (filterType))
258+ else -> GraphQLTypeReference (filterType)
259+ }
260+ val inputField = GraphQLInputObjectField .newInputObjectField()
261+ .name(fieldName)
262+ .description(description)
263+ .type(wrappedType)
264+ this .field(inputField)
265+ }
0 commit comments