Skip to content

Commit 9efc0a5

Browse files
authored
feat: support primitive arrays (#543)
Adds support for `IntArray`, `LongArray`, `ShortArray`, `FloatArray`, `DoubleArray`, `CharArray`, and `BooleanArray`.
1 parent 8c9c671 commit 9efc0a5

File tree

3 files changed

+79
-3
lines changed

3 files changed

+79
-3
lines changed

kgraphql/src/main/kotlin/com/apurebase/kgraphql/Extensions.kt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import kotlinx.coroutines.coroutineScope
88
import kotlinx.coroutines.withContext
99
import kotlin.reflect.KClass
1010
import kotlin.reflect.KType
11+
import kotlin.reflect.full.createType
1112
import kotlin.reflect.full.isSubclassOf
1213
import kotlin.reflect.jvm.jvmErasure
1314

@@ -21,13 +22,23 @@ internal fun String.dropQuotes(): String = if (isLiteral()) {
2122

2223
internal fun String.isLiteral(): Boolean = startsWith('\"') && endsWith('\"')
2324

24-
internal fun KClass<*>.isIterable() = isSubclassOf(Iterable::class)
25+
internal fun KClass<*>.isIterable() = isSubclassOf(Iterable::class) || this in typeByPrimitiveArrayClass.keys
2526

2627
internal fun KType.isIterable() = jvmErasure.isIterable() || toString().startsWith("kotlin.Array")
2728

29+
internal val typeByPrimitiveArrayClass = mapOf(
30+
IntArray::class to Int::class.createType(),
31+
LongArray::class to Long::class.createType(),
32+
ShortArray::class to Short::class.createType(),
33+
FloatArray::class to Float::class.createType(),
34+
DoubleArray::class to Double::class.createType(),
35+
CharArray::class to Char::class.createType(),
36+
BooleanArray::class to Boolean::class.createType()
37+
)
38+
2839
internal fun KType.getIterableElementType(): KType {
2940
require(isIterable()) { "KType $this is not collection type" }
30-
return arguments.firstOrNull()?.type ?: throw NoSuchElementException("KType $this has no type arguments")
41+
return typeByPrimitiveArrayClass[jvmErasure] ?: arguments.firstOrNull()?.type ?: throw NoSuchElementException("KType $this has no type arguments")
3142
}
3243

3344
internal suspend fun <T, R> Iterable<T>.mapIndexedParallel(

kgraphql/src/main/kotlin/com/apurebase/kgraphql/schema/execution/ParallelRequestExecutor.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.apurebase.kgraphql.schema.scalar.serializeScalar
1414
import com.apurebase.kgraphql.schema.structure.Field
1515
import com.apurebase.kgraphql.schema.structure.InputValue
1616
import com.apurebase.kgraphql.schema.structure.Type
17+
import com.apurebase.kgraphql.typeByPrimitiveArrayClass
1718
import com.fasterxml.jackson.databind.JsonNode
1819
import com.fasterxml.jackson.databind.node.ArrayNode
1920
import com.fasterxml.jackson.databind.node.NullNode
@@ -180,10 +181,17 @@ class ParallelRequestExecutor(val schema: DefaultSchema) : RequestExecutor {
180181

181182
return when {
182183
// Check value, not returnType, because this method can be invoked with element value
183-
value is Collection<*> || value is Array<*> || value is ArrayNode -> ctx.scope.async {
184+
value is Collection<*> || value is Array<*> || value is ArrayNode || value::class in typeByPrimitiveArrayClass.keys -> ctx.scope.async {
184185
val values: Collection<*> = when (value) {
185186
is Array<*> -> value.toList()
186187
is ArrayNode -> value.toList()
188+
is IntArray -> value.toList()
189+
is ShortArray -> value.toList()
190+
is LongArray -> value.toList()
191+
is FloatArray -> value.toList()
192+
is DoubleArray -> value.toList()
193+
is CharArray -> value.toList()
194+
is BooleanArray -> value.toList()
187195
else -> value as Collection<*>
188196
}
189197
if (returnType.isList()) {

kgraphql/src/test/kotlin/com/apurebase/kgraphql/specification/typesystem/ListsSpecificationTest.kt

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,4 +249,61 @@ class ListsSpecificationTest {
249249
response.extract<List<*>>("data/createNestedLists/nested2") shouldBe listOf(listOf(listOf(listOf(listOf("foobar")))))
250250
response.extract<List<*>>("data/createNestedLists/nested3") shouldBe null
251251
}
252+
253+
@Test
254+
fun `primitive arrays can be used`() {
255+
class Model(
256+
val intArray: IntArray,
257+
val shortArray: ShortArray,
258+
val longArray: LongArray,
259+
val floatArray: FloatArray,
260+
val doubleArray: DoubleArray,
261+
val charArray: CharArray,
262+
val booleanArray: BooleanArray
263+
)
264+
265+
val schema = KGraphQL.schema {
266+
extendedScalars()
267+
query("model") {
268+
resolver { ->
269+
Model(
270+
intArrayOf(1, 2, 3),
271+
shortArrayOf(5, 6),
272+
longArrayOf(7, 8),
273+
floatArrayOf(0.0f, 1.0f),
274+
doubleArrayOf(2.0, 3.0),
275+
charArrayOf('a', 'b'),
276+
booleanArrayOf(true, false)
277+
)
278+
}
279+
}
280+
}
281+
282+
schema.printSchema() shouldBe """
283+
scalar Char
284+
285+
scalar Long
286+
287+
scalar Short
288+
289+
type Model {
290+
booleanArray: [Boolean!]!
291+
charArray: [Char!]!
292+
doubleArray: [Float!]!
293+
floatArray: [Float!]!
294+
intArray: [Int!]!
295+
longArray: [Long!]!
296+
shortArray: [Short!]!
297+
}
298+
299+
type Query {
300+
model: Model!
301+
}
302+
303+
""".trimIndent()
304+
305+
schema.executeBlocking("{ model { intArray shortArray longArray floatArray doubleArray charArray booleanArray } }") shouldBe """
306+
{"data":{"model":{"intArray":[1,2,3],"shortArray":[5,6],"longArray":[7,8],"floatArray":[0.0,1.0],"doubleArray":[2.0,3.0],"charArray":["a","b"],"booleanArray":[true,false]}}}
307+
""".trimIndent()
308+
}
252309
}

0 commit comments

Comments
 (0)