Skip to content

Commit 36323d1

Browse files
author
Roman Janusz
committed
MongoPolyDataCompanion
1 parent 3346cd1 commit 36323d1

File tree

4 files changed

+67
-2
lines changed

4 files changed

+67
-2
lines changed

commons-macros/src/main/scala/com/avsystem/commons/macros/serialization/MongoMacros.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class MongoMacros(ctx: blackbox.Context) extends CodecMacroCommons(ctx) {
1414
lazy val MapApplySym: Symbol = typeOf[scala.collection.Map[Any, Any]].member(TermName("apply"))
1515
lazy val TypedMapApplySym: Symbol = getType(tq"$MiscPkg.TypedMap[$ScalaPkg.Any]").member(TermName("apply"))
1616
lazy val AdtAsSym: Symbol = getType(tq"$MongoTypedPkg.AbstractMongoDataCompanion[Any, Any]#macroDslExtensions").member(TermName("as"))
17+
lazy val PolyAdtAsSym: Symbol = getType(tq"$MongoTypedPkg.AbstractMongoPolyDataCompanion[Any, Any]#macroDslExtensions").member(TermName("as"))
1718

1819
// check if some symbol is an abstract method of a sealed trait/class implemented in every case class
1920
// by a field with exactly the same type
@@ -52,7 +53,8 @@ class MongoMacros(ctx: blackbox.Context) extends CodecMacroCommons(ctx) {
5253
case body: Ident if body.symbol == param.symbol =>
5354
c.prefix.tree
5455

55-
case TypeApply(Select(Apply(_, List(prefix)), TermName("as")), List(subtpe)) if body.symbol == AdtAsSym =>
56+
case TypeApply(Select(Apply(_, List(prefix)), TermName("as")), List(subtpe))
57+
if body.symbol == AdtAsSym || body.symbol == PolyAdtAsSym =>
5658
q"${extractRefStep(prefix)}.as[$subtpe]"
5759

5860
case Select(prefix, name: TermName) =>

commons-mongo/jvm/src/main/scala/com/avsystem/commons/mongo/typed/MongoEntityCompanion.scala

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package mongo.typed
44
import com.avsystem.commons.annotation.explicitGenerics
55
import com.avsystem.commons.meta.MacroInstances
66
import com.avsystem.commons.mongo.BsonGenCodecs
7-
import com.avsystem.commons.serialization.GenObjectCodec
7+
import com.avsystem.commons.serialization.{GenCodec, GenObjectCodec}
88

99
import scala.annotation.{compileTimeOnly, implicitNotFound}
1010

@@ -13,6 +13,14 @@ trait MongoAdtInstances[T] {
1313
def format: MongoAdtFormat[T]
1414
}
1515

16+
trait MongoPolyAdtInstances[D[_]] {
17+
// needed by MongoAdtFormat.materialize for generic type
18+
protected final implicit def codecFromFormat[T: MongoFormat]: GenCodec[T] = MongoFormat[T].codec
19+
20+
def codec[T: GenCodec]: GenObjectCodec[D[T]]
21+
def format[T: MongoFormat]: MongoAdtFormat[D[T]]
22+
}
23+
1624
trait MongoEntityInstances[E <: BaseMongoEntity] extends MongoAdtInstances[E] {
1725
def meta: MongoEntityMeta[E]
1826
}
@@ -47,6 +55,25 @@ abstract class AbstractMongoDataCompanion[Implicits, E](implicits: Implicits)(
4755
implicit val format: MongoAdtFormat[E] = instances(implicits, this).format
4856
}
4957

58+
abstract class AbstractMongoPolyDataCompanion[Implicits, D[_]](implicits: Implicits)(
59+
implicit instances: MacroInstances[Implicits, MongoPolyAdtInstances[D]]
60+
) {
61+
implicit def codec[T: GenCodec]: GenObjectCodec[D[T]] = instances(implicits, this).codec[T]
62+
implicit def format[T: MongoFormat]: MongoAdtFormat[D[T]] = instances(implicits, this).format[T]
63+
64+
implicit def isMongoAdtOrSubtype[C <: D[_]]: IsMongoAdtOrSubtype[C] = null
65+
66+
implicit class macroDslExtensions[T](value: D[T]) {
67+
@explicitGenerics
68+
@compileTimeOnly("the .as[Subtype] construct can only be used inside lambda passed to .ref(...) macro")
69+
def as[C <: D[T]]: C = sys.error("stub")
70+
}
71+
72+
def apply[T: MongoFormat]: DataTypeDsl[D[T]] = new DataTypeDsl[D[T]] {
73+
def SelfRef: MongoRef[D[T], D[T]] = MongoRef.RootRef(format[T])
74+
}
75+
}
76+
5077
abstract class AbstractMongoEntityCompanion[Implicits, E <: BaseMongoEntity](implicits: Implicits)(
5178
implicit instances: MacroInstances[Implicits, MongoEntityInstances[E]]
5279
) extends BaseMongoCompanion[E] {
@@ -79,3 +106,19 @@ abstract class MongoDataCompanion[E](
79106
abstract class MongoEntityCompanion[E <: BaseMongoEntity](
80107
implicit instances: MacroInstances[BsonGenCodecs.type, MongoEntityInstances[E]]
81108
) extends AbstractMongoEntityCompanion[BsonGenCodecs.type, E](BsonGenCodecs)
109+
110+
/**
111+
* Like [[MongoDataCompanion]] buf for generic types (with exactly one unbounded type parameter).
112+
*
113+
* @example
114+
* {{{
115+
* case class Point[+T](x: T, y: T)
116+
* object Point extends MongoPolyDataCompanion[Point] {
117+
* def XRef[T: MongoFormat]: MongoPropertyRef[Point[T], T] =
118+
* Point[T].ref(_.x)
119+
* }
120+
* }}}
121+
*/
122+
abstract class MongoPolyDataCompanion[D[_]](
123+
implicit instances: MacroInstances[BsonGenCodecs.type, MongoPolyAdtInstances[D]]
124+
) extends AbstractMongoPolyDataCompanion[BsonGenCodecs.type, D](BsonGenCodecs)

commons-mongo/jvm/src/test/scala/com/avsystem/commons/mongo/typed/MongoRefTest.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class MongoRefTest extends AnyFunSuite {
77
final val Rte = RecordTestEntity
88
final val Ute = UnionTestEntity
99
final val Ir = InnerRecord
10+
final val Pmr = PolyMongoRecord
11+
final val Pmu = PolyMongoUnion
1012

1113
test("filterPath") {
1214
assert(Rte.IdRef.rawPath == "_id")
@@ -30,11 +32,19 @@ class MongoRefTest extends AnyFunSuite {
3032
assert(Rte.ref(_.union.as[CaseOne].data).rawPath == "union.data")
3133
assert(Rte.ref(_.union.as[HasInner].inner).rawPath == "union.inner")
3234
assert(Rte.ref(_.union).as[HasInner].ref(_.inner).rawPath == "union.inner")
35+
assert(Pmr[Int].ref(_.value).rawPath == "value")
3336
assert(Ute.ref(_.as[HasInner].inner).rawPath == "inner")
3437
assert(Ute.as[HasInner].ref(_.inner).rawPath == "inner")
3538
assert(Ute.ref(_.as[HasInner].inner.union.as[HasInner].inner).rawPath == "inner.union.inner")
3639
assert((Ute.ref(_.as[HasInner].inner) andThen Rte.ref(_.union.as[HasInner].inner)).rawPath == "inner.union.inner")
3740
assert((Rte.ref(_.union.as[HasInner].inner) compose Ute.ref(_.as[HasInner].inner)).rawPath == "inner.union.inner")
41+
assert(Pmu[Int].ref(_.as[PolyMongoUnion.CaseOne[Int]].value).rawPath == "value")
42+
assert(Pmu[Int].as[PolyMongoUnion.CaseOne[Int]].ref(_.value).rawPath == "value")
43+
assert(Pmu[Int].ref(_.as[PolyMongoUnion.CaseOne[Int]].str).rawPath == "str")
44+
assert(Pmu[PolyMongoUnion[Int]].ref(x =>
45+
x.as[PolyMongoUnion.CaseOne[PolyMongoUnion[Int]]].value
46+
.as[PolyMongoUnion.CaseOne[Int]].str
47+
).rawPath == "value.str")
3848
}
3949

4050
test("projectionPath") {

commons-mongo/jvm/src/test/scala/com/avsystem/commons/mongo/typed/testEntities.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ case class CaseTwo(id: String, str: String, data: Int, inner: RecordTestEntity)
7070
case class CaseThree(id: String, str: String, data: String, inner: RecordTestEntity) extends HasInner
7171
object UnionTestEntity extends MongoEntityCompanion[UnionTestEntity]
7272

73+
@flatten sealed trait PolyMongoUnion[+T]
74+
object PolyMongoUnion extends MongoPolyDataCompanion[PolyMongoUnion] {
75+
case class CaseOne[+T](value: T, str: String) extends PolyMongoUnion[T]
76+
case class CaseTwo[+T](foo: T, int: Int) extends PolyMongoUnion[T]
77+
case object CaseThree extends PolyMongoUnion[Nothing]
78+
}
79+
80+
case class PolyMongoRecord[+T](value: T, meta: String)
81+
object PolyMongoRecord extends MongoPolyDataCompanion[PolyMongoRecord]
82+
7383
case class TestAutoId(id: ObjectId) extends AnyVal
7484
object TestAutoId extends ObjectIdWrapperCompanion[TestAutoId]
7585

0 commit comments

Comments
 (0)