Skip to content

Commit

Permalink
[avro] Add Either typeclass support
Browse files Browse the repository at this point in the history
Support scala Either as a avro type union
  • Loading branch information
RustedBones committed Jul 22, 2024
1 parent aa00c1f commit 55efaa8
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
27 changes: 26 additions & 1 deletion avro/src/main/scala/magnolify/avro/AvroType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import org.joda.{time => joda}
import java.nio.{ByteBuffer, ByteOrder}
import java.time._
import java.{util => ju}
import scala.annotation.implicitNotFound
import scala.annotation.{implicitNotFound, nowarn}
import scala.collection.concurrent
import scala.collection.compat._
import scala.jdk.CollectionConverters._
Expand Down Expand Up @@ -253,6 +253,31 @@ object AvroField {
}
}

implicit def afEither[A, B](implicit
fa: AvroField[A],
fb: AvroField[B]
): AvroField[Either[A, B]] =
new Aux[Either[A, B], Any, Any] {
override protected def buildSchema(cm: CaseMapper): Schema =
Schema.createUnion(fa.schema(cm), fb.schema(cm))
// `Either[A, B]` is a `UNION` of `[A, B]` and must default to first type `A`
override def makeDefault(d: Either[A, B])(cm: CaseMapper): fa.ToT = {
require(d.isLeft, "Either[A, B] can only default to Left[A]")
fa.to(d.left.get)(cm): @nowarn
}
override def from(v: Any)(cm: CaseMapper): Either[A, B] = {
GenericData.get().resolveUnion(schema(cm), v) match {
case 0 => Left(fa.from(v.asInstanceOf[fa.FromT])(cm))
case 1 => Right(fb.from(v.asInstanceOf[fb.FromT])(cm))
}
}

override def to(v: Either[A, B])(cm: CaseMapper): Any = v match {
case Left(a) => fa.to(a)(cm)

Check warning on line 276 in avro/src/main/scala/magnolify/avro/AvroType.scala

View check run for this annotation

Codecov / codecov/patch

avro/src/main/scala/magnolify/avro/AvroType.scala#L276

Added line #L276 was not covered by tests
case Right(b) => fb.to(b)(cm)
}
}

implicit def afIterable[T, C[_]](implicit
f: AvroField[T],
ti: C[T] => Iterable[T],
Expand Down
7 changes: 7 additions & 0 deletions avro/src/test/scala/magnolify/avro/AvroTypeSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ class AvroTypeSuite extends MagnolifySuite {
val inner = DefaultInner(
2,
Some(2),
Right("2"),
List(2, 2),
Map("b" -> 2),
JavaEnums.Color.GREEN,
Expand All @@ -337,6 +338,7 @@ class AvroTypeSuite extends MagnolifySuite {
val inner = DefaultInner(
3,
Some(3),
Right("3"),
List(3, 3),
Map("c" -> 3),
JavaEnums.Color.BLUE,
Expand All @@ -359,6 +361,7 @@ class AvroTypeSuite extends MagnolifySuite {
}

testFail(AvroType[DefaultSome])("Option[T] can only default to None")
testFail(AvroType[DefaultEither])("Either[A, B] can only default to Left[A]")

{
implicit val at: AvroType[LowerCamel] = AvroType[LowerCamel](CaseMapper(_.toUpperCase))
Expand Down Expand Up @@ -493,6 +496,7 @@ case class DoubleFieldDoc(@doc("doc1") @doc("doc2") i: Int)
case class DefaultInner(
i: Int = 1,
o: Option[Int] = None,
e: Either[Int, String] = Left(1),
l: List[Int] = List(1, 1),
m: Map[String, Int] = Map("a" -> 1),
je: JavaEnums.Color = JavaEnums.Color.RED,
Expand All @@ -508,6 +512,7 @@ case class DefaultOuter(
i: DefaultInner = DefaultInner(
2,
None,
Left(2),
List(2, 2),
Map("b" -> 2),
JavaEnums.Color.GREEN,
Expand All @@ -521,7 +526,9 @@ case class DefaultOuter(
),
o: Option[DefaultInner] = None
)

case class DefaultSome(o: Option[Int] = Some(1))
case class DefaultEither(e: Either[Int, String] = Right("1"))

case class DefaultBytes(
a: Array[Byte] = Array(2, 2)
Expand Down

0 comments on commit 55efaa8

Please sign in to comment.