From 189ae44c62e528d031e2a53456b6fded58688ae6 Mon Sep 17 00:00:00 2001 From: Peter Poschmann <1876911+ex-ratt@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:25:05 +0200 Subject: [PATCH] fix record default value cannot be a collection/map of records (#605) --- .../main/scala/vulcan/internal/schema.scala | 7 ++++ .../src/test/scala/vulcan/CodecSpec.scala | 36 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/modules/core/src/main/scala/vulcan/internal/schema.scala b/modules/core/src/main/scala/vulcan/internal/schema.scala index 41b6b078..dfb78230 100644 --- a/modules/core/src/main/scala/vulcan/internal/schema.scala +++ b/modules/core/src/main/scala/vulcan/internal/schema.scala @@ -10,6 +10,8 @@ import java.nio.ByteBuffer import org.apache.avro.generic.{GenericEnumSymbol, GenericFixed, IndexedRecord} import vulcan.internal.converters.collection._ +import java.{util => ju} + private[vulcan] object schema { final def adaptForSchema(encoded: Any): Any = encoded match { @@ -26,6 +28,11 @@ private[vulcan] object schema { map.updated(field.name, adaptForSchema(record.get(index))) } .asJava + case array: ju.Collection[?] => + array.asScala.map(adaptForSchema).asJava + case map: ju.Map[?, ?] => + // Avro only supports maps with String key, so we only have to adapt the values + map.asScala.map { case (key, value) => key -> adaptForSchema(value) }.asJava case _ => encoded } diff --git a/modules/core/src/test/scala/vulcan/CodecSpec.scala b/modules/core/src/test/scala/vulcan/CodecSpec.scala index 8884b022..1863c222 100644 --- a/modules/core/src/test/scala/vulcan/CodecSpec.scala +++ b/modules/core/src/test/scala/vulcan/CodecSpec.scala @@ -2050,6 +2050,24 @@ final class CodecSpec extends BaseSpec with CodecSpecHelpers { } } + it("should support record array default value") { + case class Test(value: List[Element]) + case class Element(value: Int) + + implicit val elementCodec: Codec[Element] = + Codec.record("Element", "") { field => + field("value", _.value).map(Element(_)) + } + implicit val testCodec: Codec[Test] = + Codec.record("Test", "") { field => + field("value", _.value, default = Some(List(Element(123), Element(456)))).map(Test(_)) + } + + assertSchemaIs[Test] { + """{"type":"record","name":"Test","fields":[{"name":"value","type":{"type":"array","items":{"type":"record","name":"Element","fields":[{"name":"value","type":"int"}]}},"default":[{"value":123},{"value":456}]}]}""" + } + } + it("should support map default value") { case class Test(value: Map[String, Int]) @@ -2063,6 +2081,24 @@ final class CodecSpec extends BaseSpec with CodecSpecHelpers { } } + it("should support record map default value") { + case class Test(value: Map[String, Value]) + case class Value(value: Int) + + implicit val valueCodec: Codec[Value] = + Codec.record("Value", "") { field => + field("value", _.value).map(Value(_)) + } + implicit val testCodec: Codec[Test] = + Codec.record("Test", "") { field => + field("value", _.value, default = Some(Map("key" -> Value(0)))).map(Test(_)) + } + + assertSchemaIs[Test] { + """{"type":"record","name":"Test","fields":[{"name":"value","type":{"type":"map","values":{"type":"record","name":"Value","fields":[{"name":"value","type":"int"}]}},"default":{"key":{"value":0}}}]}""" + } + } + it("should support fixed default value") { case class Inner(value: Array[Byte])