@@ -3,9 +3,13 @@ package com.auritylab.graphql.kotlin.toolkit.codegen.generator
3
3
import com.auritylab.graphql.kotlin.toolkit.codegen.CodegenOptions
4
4
import com.auritylab.graphql.kotlin.toolkit.codegen.mapper.GeneratedMapper
5
5
import com.auritylab.graphql.kotlin.toolkit.codegen.mapper.KotlinTypeMapper
6
+ import com.auritylab.graphql.kotlin.toolkit.common.directive.DirectiveFacade
6
7
import com.squareup.kotlinpoet.ClassName
8
+ import com.squareup.kotlinpoet.CodeBlock
7
9
import com.squareup.kotlinpoet.FileSpec
8
10
import com.squareup.kotlinpoet.FunSpec
11
+ import com.squareup.kotlinpoet.KModifier
12
+ import com.squareup.kotlinpoet.MemberName
9
13
import com.squareup.kotlinpoet.PropertySpec
10
14
import com.squareup.kotlinpoet.TypeSpec
11
15
import graphql.schema.GraphQLEnumType
@@ -40,16 +44,105 @@ internal class EnumGenerator(
40
44
.initializer(" stringValue" )
41
45
.build()
42
46
)
43
- .also {
47
+ .also { builder ->
44
48
// Go through all enum values and create enum constants within this enum.
45
49
enum.values.forEach { enum ->
46
- it .addEnumConstant(
50
+ builder .addEnumConstant(
47
51
enum.name, TypeSpec .anonymousClassBuilder()
48
52
.addSuperclassConstructorParameter(" %S" , enum.name)
49
53
.build()
50
54
)
51
55
}
56
+
57
+ // If the "kRepresentation" directive is set on the enum, we have to add a parser/converter function
58
+ DirectiveFacade .representation.getArguments(enum)?.className
59
+ ?.let {
60
+ // Add the output property/function.
61
+ builder.addProperty(buildParserProperty(it))
62
+ builder.addFunction(buildPropertyOperatorFunction())
63
+
64
+ // Add the input functions within a companion, as they are static.
65
+ builder.addType(
66
+ TypeSpec .companionObjectBuilder()
67
+ .addFunction(buildInputParser(it))
68
+ .addFunction(buildInputParserOperatorFunction(it))
69
+ .build()
70
+ )
71
+ }
52
72
}
53
73
.build()
54
74
}
75
+
76
+ /* *
77
+ * Will build a parser property which is capable of converting the enum constant into the given
78
+ * [representationClass]. The function utilizes the `.valueOf(...)` method on the enum constant.
79
+ */
80
+ private fun buildParserProperty (representationClass : String ): PropertySpec {
81
+ // Resolve the class name and the valueOf function of the class.
82
+ val parsedClass = ClassName .bestGuess(representationClass)
83
+
84
+ // Build the converter code.
85
+ val code = CodeBlock .builder()
86
+ .beginControlFlow(" return try" )
87
+ .addStatement(" %L(name)" , MemberName (parsedClass, " valueOf" ).canonicalName)
88
+ .endControlFlow()
89
+ .beginControlFlow(" catch(ex: IllegalArgumentException)" )
90
+ .addStatement(
91
+ " throw NoSuchElementException(%P)" ,
92
+ " Enum value '\$ name' could not be found on enum '${parsedClass.canonicalName} '"
93
+ )
94
+ .endControlFlow()
95
+ .build()
96
+
97
+ return PropertySpec .builder(" representation" , parsedClass)
98
+ .getter(FunSpec .getterBuilder().addCode(code).build())
99
+ .build()
100
+ }
101
+
102
+ /* *
103
+ * Will build a function which overrides the invoke operator and delegates to the "representation" property
104
+ * to resolve the representation.
105
+ */
106
+ private fun buildPropertyOperatorFunction (): FunSpec {
107
+ return FunSpec .builder(" invoke" )
108
+ .addModifiers(KModifier .OPERATOR )
109
+ .addCode(" return representation" )
110
+ .build()
111
+ }
112
+
113
+ /* *
114
+ * Will build a function which accepts the representation enum as input and returns the matching generated
115
+ * enum constant. This also utilizes the #valueOf(...) method of the enum.
116
+ */
117
+ private fun buildInputParser (representationClass : String ): FunSpec {
118
+ val code = CodeBlock .builder()
119
+ .beginControlFlow(" return try" )
120
+ .addStatement(" valueOf(input.name)" )
121
+ .endControlFlow()
122
+ .beginControlFlow(" catch(ex: IllegalArgumentException)" )
123
+ .addStatement(
124
+ " throw NoSuchElementException(%P)" ,
125
+ " Enum value '\$ {input.name}' could not be found on enum '\$ {this::class.java.canonicalName}'"
126
+ )
127
+ .endControlFlow()
128
+ .build()
129
+
130
+ // Build the function with the input and the generated code.
131
+ return FunSpec .builder(" of" )
132
+ .addParameter(" input" , ClassName .bestGuess(representationClass))
133
+ .addCode(code)
134
+ .build()
135
+ }
136
+
137
+ /* *
138
+ * Will build a invoke function override, which delegates to the #of(...) function to convert the
139
+ * representation enum to the generated enum constant.
140
+ */
141
+ private fun buildInputParserOperatorFunction (representationClass : String ): FunSpec {
142
+ return FunSpec .builder(" invoke" )
143
+ .addModifiers(KModifier .OPERATOR )
144
+ .addParameter(" input" , ClassName .bestGuess(representationClass))
145
+ .addCode(" return of(input)" )
146
+ .build()
147
+ }
55
148
}
0 commit comments