Skip to content

Commit 55efaa8

Browse files
author
Michel Davit
committed
[avro] Add Either typeclass support
Support scala Either as a avro type union
1 parent aa00c1f commit 55efaa8

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import org.joda.{time => joda}
2727
import java.nio.{ByteBuffer, ByteOrder}
2828
import java.time._
2929
import java.{util => ju}
30-
import scala.annotation.implicitNotFound
30+
import scala.annotation.{implicitNotFound, nowarn}
3131
import scala.collection.concurrent
3232
import scala.collection.compat._
3333
import scala.jdk.CollectionConverters._
@@ -253,6 +253,31 @@ object AvroField {
253253
}
254254
}
255255

256+
implicit def afEither[A, B](implicit
257+
fa: AvroField[A],
258+
fb: AvroField[B]
259+
): AvroField[Either[A, B]] =
260+
new Aux[Either[A, B], Any, Any] {
261+
override protected def buildSchema(cm: CaseMapper): Schema =
262+
Schema.createUnion(fa.schema(cm), fb.schema(cm))
263+
// `Either[A, B]` is a `UNION` of `[A, B]` and must default to first type `A`
264+
override def makeDefault(d: Either[A, B])(cm: CaseMapper): fa.ToT = {
265+
require(d.isLeft, "Either[A, B] can only default to Left[A]")
266+
fa.to(d.left.get)(cm): @nowarn
267+
}
268+
override def from(v: Any)(cm: CaseMapper): Either[A, B] = {
269+
GenericData.get().resolveUnion(schema(cm), v) match {
270+
case 0 => Left(fa.from(v.asInstanceOf[fa.FromT])(cm))
271+
case 1 => Right(fb.from(v.asInstanceOf[fb.FromT])(cm))
272+
}
273+
}
274+
275+
override def to(v: Either[A, B])(cm: CaseMapper): Any = v match {
276+
case Left(a) => fa.to(a)(cm)
277+
case Right(b) => fb.to(b)(cm)
278+
}
279+
}
280+
256281
implicit def afIterable[T, C[_]](implicit
257282
f: AvroField[T],
258283
ti: C[T] => Iterable[T],

avro/src/test/scala/magnolify/avro/AvroTypeSuite.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ class AvroTypeSuite extends MagnolifySuite {
317317
val inner = DefaultInner(
318318
2,
319319
Some(2),
320+
Right("2"),
320321
List(2, 2),
321322
Map("b" -> 2),
322323
JavaEnums.Color.GREEN,
@@ -337,6 +338,7 @@ class AvroTypeSuite extends MagnolifySuite {
337338
val inner = DefaultInner(
338339
3,
339340
Some(3),
341+
Right("3"),
340342
List(3, 3),
341343
Map("c" -> 3),
342344
JavaEnums.Color.BLUE,
@@ -359,6 +361,7 @@ class AvroTypeSuite extends MagnolifySuite {
359361
}
360362

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

363366
{
364367
implicit val at: AvroType[LowerCamel] = AvroType[LowerCamel](CaseMapper(_.toUpperCase))
@@ -493,6 +496,7 @@ case class DoubleFieldDoc(@doc("doc1") @doc("doc2") i: Int)
493496
case class DefaultInner(
494497
i: Int = 1,
495498
o: Option[Int] = None,
499+
e: Either[Int, String] = Left(1),
496500
l: List[Int] = List(1, 1),
497501
m: Map[String, Int] = Map("a" -> 1),
498502
je: JavaEnums.Color = JavaEnums.Color.RED,
@@ -508,6 +512,7 @@ case class DefaultOuter(
508512
i: DefaultInner = DefaultInner(
509513
2,
510514
None,
515+
Left(2),
511516
List(2, 2),
512517
Map("b" -> 2),
513518
JavaEnums.Color.GREEN,
@@ -521,7 +526,9 @@ case class DefaultOuter(
521526
),
522527
o: Option[DefaultInner] = None
523528
)
529+
524530
case class DefaultSome(o: Option[Int] = Some(1))
531+
case class DefaultEither(e: Either[Int, String] = Right("1"))
525532

526533
case class DefaultBytes(
527534
a: Array[Byte] = Array(2, 2)

0 commit comments

Comments
 (0)