diff --git a/README.md b/README.md index 09ccd32..55aeac7 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,17 @@ You can also add tags asociated to the Event: ```scala val eventAdapter = EventAdapterFactory.adapt[Type4](withManifest = "SomeEvent", Set("Tag_1", "Tag_2")) ``` +Traits famlily (`sealed trait`), aka: sum types, are mapped automatically: +```scala +sealed trait InvoceLineType +case object ProductLine extends InvoiceLineType +... +case class InvoiceLine(lineType: InvoceLineType, ...) +case class InvoiceLineAdded(line: InvoiceLine) +... +implicit val conf = MacroConfiguration(discriminator = "_type", typeNaming = TypeNaming.SimpleName) +val eventAdapter = EventAdapterFactory.adapt[InvoceLineAdded](withManifest = "InvoiceLineAdded") +``` ## Persistence Id By default the persistence id has the following form: `-`, and the aggregate will be the name of the journal collection. diff --git a/build.sbt b/build.sbt index 25b3f34..307b7fd 100644 --- a/build.sbt +++ b/build.sbt @@ -7,7 +7,7 @@ lazy val rxmongoVersion = "0.20.3" lazy val commonSettings = Seq( name := "akka-reactivemongo-plugin", organization := "null-vector", - version := "1.3.6", + version := "1.3.7", scalaVersion := scala213, crossScalaVersions := supportedScalaVersions, scalacOptions := Seq( diff --git a/core/src/test/scala/org/nullvector/EventAdapterFactorySpec.scala b/core/src/test/scala/org/nullvector/EventAdapterFactorySpec.scala index 1cbc82e..4c13703 100644 --- a/core/src/test/scala/org/nullvector/EventAdapterFactorySpec.scala +++ b/core/src/test/scala/org/nullvector/EventAdapterFactorySpec.scala @@ -1,9 +1,11 @@ package org.nullvector import akka.actor.ActorSystem +import org.nullvector.domin._ import org.scalatest.Matchers._ import org.scalatest._ -import reactivemongo.api.bson.{BSONDocument, BSONDocumentHandler, BSONDocumentReader, BSONDocumentWriter, BSONReader, BSONString, BSONValue, BSONWriter, Macros} +import reactivemongo.api.bson.MacroConfiguration.Aux +import reactivemongo.api.bson.{BSON, BSONDocument, BSONDocumentHandler, BSONDocumentReader, BSONDocumentWriter, BSONReader, BSONString, BSONValue, BSONWriter, FieldNaming, MacroConfiguration, MacroOptions, Macros, TypeNaming} import scala.util.{Success, Try} @@ -59,8 +61,8 @@ class EventAdapterFactorySpec extends FlatSpec { val eventAdapter = EventAdatpterFactory.adapt[I]("Ied", justForTestTags) - eventAdapter.tags("A") should contain ("TagA") - eventAdapter.tags("x") should contain ("TagN") + eventAdapter.tags("A") should contain("TagA") + eventAdapter.tags("x") should contain("TagN") val anInstance = I(K("k")) eventAdapter.payloadToBson(anInstance) .getAsOpt[BSONDocument]("k").get @@ -88,39 +90,17 @@ class EventAdapterFactorySpec extends FlatSpec { payload.m.head._2 shouldBe "Value_A" } -} - -case class A(b: B, c: C, d: D, js: Seq[J]) - -case class B(f: Set[F], g: G) - -case class C(s: String, m: Map[String, Seq[J]]) - -case class D(i: Int, m: Map[String, H] = Map.empty) - -case class F(maybeC: Option[C]) - -case class G(ds: List[D]) + it should "mapping sealed trit familly" in { + val distanceFromEarthAndMars = PlanetDistanceBetweenEarth(and = Mars, kilometers = 209050000.0) -case class H(d: BigDecimal) + implicit val conf: Aux[MacroOptions] = MacroConfiguration(discriminator = "_type", typeNaming = TypeNaming.SimpleName) + val eventAdapter = EventAdatpterFactory.adapt[PlanetDistanceBetweenEarth]("x") -case class J(s: String) - -case class I(k: K) - -case class K(s: String) - -case class L(m: Map[Day, String], day: Day) - -sealed trait Day - -object Day { - def apply(name: String): Day = name match { - case "Monday" => Monday - case "Sunday" => Sunday + val document = eventAdapter.payloadToBson(distanceFromEarthAndMars) + document.getAsOpt[BSONDocument]("and").get.getAsOpt[String]("_type").get should be ("Mars") + eventAdapter.bsonToPayload(document).and should be (Mars) } + } -case object Monday extends Day -case object Sunday extends Day diff --git a/core/src/test/scala/org/nullvector/domin/package.scala b/core/src/test/scala/org/nullvector/domin/package.scala new file mode 100644 index 0000000..2ea64f6 --- /dev/null +++ b/core/src/test/scala/org/nullvector/domin/package.scala @@ -0,0 +1,61 @@ +package org.nullvector + +package object domin { + + case class A(b: B, c: C, d: D, js: Seq[J]) + + case class B(f: Set[F], g: G) + + case class C(s: String, m: Map[String, Seq[J]]) + + case class D(i: Int, m: Map[String, H] = Map.empty) + + case class F(maybeC: Option[C]) + + case class G(ds: List[D]) + + case class H(d: BigDecimal) + + case class J(s: String) + + case class I(k: K) + + case class K(s: String) + + case class L(m: Map[Day, String], day: Day) + + sealed trait Day + + object Day { + def apply(name: String): Day = name match { + case "Monday" => Monday + case "Sunday" => Sunday + } + } + + + case object Monday extends Day + + case object Sunday extends Day + + case class PlanetDistanceBetweenEarth(and: SolarPlanet, kilometers: Double) + + sealed trait SolarPlanet + + case object Mercury extends SolarPlanet + + case object Venus extends SolarPlanet + + case object Earth extends SolarPlanet + + case object Mars extends SolarPlanet + + case object Jupiter extends SolarPlanet + + case object Saturn extends SolarPlanet + + case object Uranus extends SolarPlanet + + case object Neptune extends SolarPlanet + +} diff --git a/macros/src/main/scala/org/nullvector/EventAdapterMacroFactory.scala b/macros/src/main/scala/org/nullvector/EventAdapterMacroFactory.scala index 3039278..37f0c76 100644 --- a/macros/src/main/scala/org/nullvector/EventAdapterMacroFactory.scala +++ b/macros/src/main/scala/org/nullvector/EventAdapterMacroFactory.scala @@ -83,6 +83,8 @@ private object EventAdapterMacroFactory { (caseType: context.universe.Type): org.nullvector.Tree[context.universe.Type] = { import context.universe._ + def isSupprtedTrait(aTypeClass: ClassSymbol) = aTypeClass.isTrait && aTypeClass.isSealed && !aTypeClass.fullName.startsWith("scala") + def extaracCaseClassesFromSupportedTypeClasses(classType: Type): List[Type] = { if (supportedClassTypes.contains(classType.typeSymbol.fullName)) classType.typeArgs.collect { case argType if argType.typeSymbol.asClass.isCaseClass => List(classType, argType) @@ -95,11 +97,14 @@ private object EventAdapterMacroFactory { caseType.decls.toList .collect { case method: MethodSymbol if method.isCaseAccessor => method.returnType } .collect { - case aType if aType.typeSymbol.asClass.isCaseClass => List(extractCaseTypes(context)(aType)) + case aType if aType.typeSymbol.asClass.isCaseClass || isSupprtedTrait(aType.typeSymbol.asClass) => List(extractCaseTypes(context)(aType)) case aType => extaracCaseClassesFromSupportedTypeClasses(aType).map(arg => extractCaseTypes(context)(arg)) }.flatten ) } + else if (isSupprtedTrait(caseType.typeSymbol.asClass)) { + Tree(caseType, caseType.typeSymbol.asClass.knownDirectSubclasses.map(aType => extractCaseTypes(context)(aType.asClass.toType)).toList) + } else Tree.empty }