Skip to content

Commit

Permalink
Support decoding sets and lists
Browse files Browse the repository at this point in the history
  • Loading branch information
sksamuel committed Apr 14, 2024
1 parent d91e236 commit c86dd97
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ fun interface Decoder<T> {
Double::class -> DoubleDecoder
Int::class -> IntDecoder
Long::class -> LongDecoder
List::class -> ListDecoder(decoderFor(type.arguments.first().type!!))
Set::class -> SetDecoder(decoderFor(type.arguments.first().type!!))
is KClass<*> -> if (classifier.java.isEnum) EnumDecoder(classifier as KClass<out Enum<*>>) else error("Unsupported type $type")
else -> error("Unsupported type $type")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,15 @@ class ListDecoder<T>(private val decoder: Decoder<T>) : Decoder<List<T>> {
}
}
}

class SetDecoder<T>(private val decoder: Decoder<T>) : Decoder<Set<T>> {
override fun decode(schema: Schema, value: Any?): Set<T> {
require(schema.type == Schema.Type.ARRAY)
return when (value) {
is GenericData.Array<*> -> value.map { decoder.decode(schema.elementType, it) }.toSet()
is List<*> -> value.map { decoder.decode(schema.elementType, it) }.toSet()
is Array<*> -> value.map { decoder.decode(schema.elementType, it) }.toSet()
else -> error("Unsupported list type $value")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ class NullDecoder<T>(private val decoder: Decoder<T>) : Decoder<T?> {
// nullables must be encoded with a union of 2 elements, where null is the first type
require(schema.type == Schema.Type.UNION) { "Nulls can only be encoded with a UNION schema" }
require(schema.types.size == 2) { "Nulls can only be encoded with a 2 element union schema" }
require(schema.types[0].type == Schema.Type.NULL) { "Nullable unions must have NULL as the first element type" }
return if (value == null) null else decoder.decode(schema, value)
return if (value == null) null else decoder.decode(schema.types.first { !it.isNullable }, value)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.sksamuel.centurion.avro.decoders

import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import org.apache.avro.SchemaBuilder

class NullDecoderTest : FunSpec({

test("decode null") {
val schema = SchemaBuilder.nullable().intType()
NullDecoder(IntDecoder).decode(schema, null) shouldBe null
NullDecoder(IntDecoder).decode(schema, 1) shouldBe 1
}

})
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class ReflectionRecordDecoderTest : FunSpec({

test("nulls") {
data class Foo(val a: String?, val b: String)

val schema = SchemaBuilder.record("Foo").fields()
.optionalString("a")
.requiredString("b")
Expand All @@ -49,4 +50,34 @@ class ReflectionRecordDecoderTest : FunSpec({

ReflectionRecordDecoder<Foo>().decode(schema, record) shouldBe Foo(null, "hello")
}

test("sets") {
data class Foo(val set1: Set<Int>, val set2: Set<Long?>)

val schema = SchemaBuilder.record("Foo").fields()
.name("set1").type().array().items().intType().noDefault()
.name("set2").type().array().items().type(SchemaBuilder.nullable().longType()).noDefault()
.endRecord()

val record = GenericData.Record(schema)
record.put("set1", listOf(1, 2))
record.put("set2", listOf(1, null, 2))

ReflectionRecordDecoder<Foo>().decode(schema, record) shouldBe Foo(setOf(1, 2), setOf(1L, null, 2L))
}

test("list") {
data class Foo(val list1: List<Int>, val list2: List<Long?>)

val schema = SchemaBuilder.record("Foo").fields()
.name("list1").type().array().items().intType().noDefault()
.name("list2").type().array().items().type(SchemaBuilder.nullable().longType()).noDefault()
.endRecord()

val record = GenericData.Record(schema)
record.put("list1", listOf(1, 2))
record.put("list2", listOf(1, null, 2))

ReflectionRecordDecoder<Foo>().decode(schema, record) shouldBe Foo(listOf(1, 2), listOf(1L, null, 2L))
}
})

0 comments on commit c86dd97

Please sign in to comment.