@@ -5,20 +5,20 @@ import graphql.language.*
5
5
import graphql.schema.*
6
6
import org.neo4j.cypherdsl.core.Node
7
7
import org.neo4j.cypherdsl.core.Relationship
8
+ import org.neo4j.cypherdsl.core.SymbolicName
8
9
import org.neo4j.graphql.DirectiveConstants.Companion.CYPHER
9
10
import org.neo4j.graphql.DirectiveConstants.Companion.CYPHER_STATEMENT
10
11
import org.neo4j.graphql.DirectiveConstants.Companion.DYNAMIC
11
12
import org.neo4j.graphql.DirectiveConstants.Companion.DYNAMIC_PREFIX
12
13
import org.neo4j.graphql.DirectiveConstants.Companion.PROPERTY
13
14
import org.neo4j.graphql.DirectiveConstants.Companion.PROPERTY_NAME
14
15
import 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
18
16
import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_FROM
19
17
import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_NAME
20
18
import org.neo4j.graphql.DirectiveConstants.Companion.RELATION_TO
21
19
import org.neo4j.graphql.handler.projection.ProjectionBase
20
+ import java.math.BigDecimal
21
+ import java.math.BigInteger
22
22
23
23
fun Type <Type <* >>.name (): String? = if (this .inner() is TypeName ) (this .inner() as TypeName ).name else null
24
24
fun Type <Type <* >>.inner (): Type <Type <* >> = when (this ) {
@@ -34,7 +34,7 @@ fun GraphQLType.inner(): GraphQLType = when (this) {
34
34
}
35
35
36
36
fun 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 }
38
38
39
39
fun GraphQLType.isList () = this is GraphQLList || (this is GraphQLNonNull && this .wrappedType is GraphQLList )
40
40
fun GraphQLType.isScalar () = this .inner().let { it is GraphQLScalarType || it.innerName().startsWith(" _Neo4j" ) }
@@ -44,7 +44,6 @@ fun GraphQLFieldDefinition.isNeo4jType(): Boolean = this.type.isNeo4jType()
44
44
45
45
fun GraphQLFieldDefinition.isRelationship () = ! type.isNeo4jType() && this .type.inner().let { it is GraphQLFieldsContainer }
46
46
47
- fun GraphQLFieldsContainer.hasRelationship (name : String ) = this .getFieldDefinition(name)?.isRelationship() ? : false
48
47
fun GraphQLDirectiveContainer.isRelationType () = getDirective(DirectiveConstants .RELATION ) != null
49
48
fun GraphQLFieldsContainer.isRelationType () = (this as ? GraphQLDirectiveContainer )?.getDirective(DirectiveConstants .RELATION ) != null
50
49
fun GraphQLFieldsContainer.relationshipFor (name : String ): RelationshipInfo ? {
@@ -69,16 +68,16 @@ fun GraphQLFieldsContainer.relationshipFor(name: String): RelationshipInfo? {
69
68
70
69
val relInfo = relDetails(fieldObjectType, relDirective)
71
70
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
73
72
}
74
73
75
74
fun GraphQLFieldsContainer.getValidTypeLabels (schema : GraphQLSchema ): List <String > {
76
75
if (this is GraphQLObjectType ) {
77
- return listOf (this .quotedLabel ())
76
+ return listOf (this .label ())
78
77
}
79
78
if (this is GraphQLInterfaceType ) {
80
79
return schema.getImplementations(this )
81
- .mapNotNull { it.quotedLabel () }
80
+ .mapNotNull { it.label () }
82
81
}
83
82
return emptyList()
84
83
}
@@ -92,14 +91,6 @@ fun GraphQLFieldsContainer.label(): String = when {
92
91
else -> name
93
92
}
94
93
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
- }
103
94
104
95
fun GraphQLFieldsContainer.relevantFields () = fieldDefinitions
105
96
.filter { it.type.isScalar() || it.isNeo4jType() }
@@ -113,7 +104,9 @@ fun GraphQLFieldsContainer.relationship(): RelationshipInfo? {
113
104
val relType = directiveResolver(RELATION_NAME , " " )!!
114
105
val startField = directiveResolver(RELATION_FROM , null )
115
106
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)
117
110
}
118
111
119
112
fun GraphQLType.ref (): GraphQLType = when (this ) {
@@ -127,23 +120,21 @@ fun GraphQLType.ref(): GraphQLType = when (this) {
127
120
128
121
fun relDetails (type : GraphQLFieldsContainer , relDirective : GraphQLDirective ): RelationshipInfo {
129
122
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
+
136
127
return RelationshipInfo (type,
137
128
relType,
138
- outgoing ,
129
+ direction ,
139
130
relDirective.getArgument<String >(RELATION_FROM , null ),
140
131
relDirective.getArgument<String >(RELATION_TO , null ))
141
132
}
142
133
143
134
data class RelationshipInfo (
144
135
val type : GraphQLFieldsContainer ,
145
136
val relType : String ,
146
- val out : Boolean? ,
137
+ val direction : RelationDirection ,
147
138
val startField : String? = null ,
148
139
val endField : String? = null ,
149
140
val isRelFromType : Boolean = false
@@ -154,10 +145,10 @@ data class RelationshipInfo(
154
145
val declaringType : GraphQLFieldsContainer
155
146
)
156
147
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 " "
161
152
}
162
153
163
154
val typeName: String get() = this .type.name
@@ -173,20 +164,26 @@ data class RelationshipInfo(
173
164
val relType = relFieldDefinition.type.inner() as ? GraphQLFieldsContainer
174
165
? : throw IllegalArgumentException (" type ${relFieldDefinition.type.innerName()} not found" )
175
166
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
+ }
177
173
.firstOrNull()
178
174
}
179
175
180
176
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)
185
181
}
186
182
}
187
183
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()
190
187
191
188
fun GraphQLType.innerName (): String = inner().name()
192
189
? : throw IllegalStateException (" inner name cannot be retrieved for " + this .javaClass)
@@ -212,25 +209,6 @@ fun <T> GraphQLDirective.getArgument(argumentName: String, defaultValue: T?): T?
212
209
fun GraphQLFieldDefinition.cypherDirective (): Cypher ? = getDirectiveArgument<String >(CYPHER , CYPHER_STATEMENT , null )
213
210
?.let { statement -> Cypher (statement) }
214
211
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
-
234
212
fun Any.toJavaValue () = when (this ) {
235
213
is Value <* > -> this .toJavaValue()
236
214
else -> this
@@ -249,11 +227,6 @@ fun Value<*>.toJavaValue(): Any? = when (this) {
249
227
else -> throw IllegalStateException (" Unhandled value $this " )
250
228
}
251
229
252
- fun paramName (variable : String , argName : String , value : Any? ): String = when (value) {
253
- is VariableReference -> value.name
254
- else -> " $variable${argName.capitalize()} "
255
- }
256
-
257
230
fun GraphQLFieldDefinition.isID () = this .type.inner() == Scalars .GraphQLID
258
231
fun GraphQLFieldDefinition.isNativeId () = this .name == ProjectionBase .NATIVE_ID
259
232
fun GraphQLFieldsContainer.getIdField () = this .fieldDefinitions.find { it.isID() }
@@ -274,3 +247,18 @@ fun GraphQLInputObjectType.Builder.addFilterField(fieldName: String, isList: Boo
274
247
fun GraphQLSchema.queryTypeName () = this .queryType?.name ? : " Query"
275
248
fun GraphQLSchema.mutationTypeName () = this .mutationType?.name ? : " Mutation"
276
249
fun 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