I'd like to have more Contains macro generators, covering common use cases.
Few come to mind:
1. A sealed family form for GenContains
example:
sealed trait User{
def id: String
}
case class Registered(id: String, name: String, email: String) extends User
case class Anonymous(id: String, ip: String) extends User
Here GenContains[User](_.id) must go through all the direct subtypes of User and verify that GenContains(_.id) resolves to lens. Example of generated tree:
val registeredC = GenContains[Registered](_.id)
val anonymousC = GenContains[Anonymous](_.id)
new Contains[User, String] {
def set(s: User, b: String) = s match {
case r: Registered => registeredC.set(r, b)
case a: Anonymous => anonymousC.set(a, b)
}
def extract(s: User): String = s match {
case r: Registered => registeredC.extract(r)
case a: Anonymous => anonymousC.extract(a)
}
}
The proposed solution should work even for the case when path is longer that one field, or one of the direct subtypes is a sealed family itself
2. Typeclass based sealed Contains derivation
Ability to derive Contains when each alternative has implicit Contains to the given type.
In the best form it should support recursion and GADTs
case class Path(str: String)
sealed trait ValidatedField[A] {
def check[B](f: A => Either[String, B]): ValidatedField[B] = Check(this, f)
}
@ClassyOptics
case class Read(path: Path) extends ValidatedField[String]
@Optics
case class Check[A, B](inner: ValidatedField[A], verify: A => Either[String, B]) extends ValidatedField[B]
implicit def checkPath[A, B]: Contains[Check[A, B], Path] = Check.inner >> validatedPath
implicit def validatedPath[A]: Contains[ValidatedField[A], Path] = DeriveContains[ValidatedField[A], Path]
latter should be expanded to
implicit def validatedPath[A]: Contains[ValidatedField[A], Path] = {
new Contains[ValidatedField[A], Path] {
def set(s: ValidatedField[A], b: Path): ValidatedField[A] = s match {
case r: Read => Contains[Read, Path].set(r, b)
case c: Check[x, A] => Contains[Check[x, A], Path].set(c, b)
}
def extract(s: ValidatedField[A]): Path = s match {
case r: Read => Contains[Read, Path].extract(r)
case c: Check[x, A] => Contains[Check[x, A], Path].extract(c)
}
}
}
3. Typeclass based case class to case class derivation
When two case classes have fields related to each other, sometimes we can derive Contains for them. Such case could be a partial replacement for complex data transformation libraries such as https://github.com/scalalandio/chimney
We will derive Contains[A, B] when :
- Each field in
B has a field with the same name in the A
- For any two fields with the same name of types
AF and BF we have AF =:= BF or Contains[AF, BF]
Latter could be relaxed providing implicit `Contains[A, A] during derivation
case class RichName(name: String, searchId: Long)
object RichName {
implicit val nameString: Contains[RichName, String] = GenContains.apply(_.name)
}
case class UserData(
firstName: String,
lastName: String,
age: Int
)
case class UserInfo(
id: Long,
firstName: RichName,
lastName: RichName,
age: Int,
lastUpdated: Instant,
)
val infoData = DeriveContains[UserInfo, UserData]
last line should be expanded to the following
val infoData = new Contains[UserInfo, UserData] {
implicit def sameConv[A]: A Contains A = Same.id
def set(s: UserInfo, b: UserData): UserInfo =
s.copy(
firstName = Contains[RichName, String].set(s.firstName, b.firstName),
lastName = Contains[RichName, String].set(s.lastName, b.lastName),
age = Contains[Int, Int].set(s.age, b.age),
)
def extract(s: UserInfo): UserData = UserData(
firstName = Contains[RichName, String].extract(s.firstName),
lastName = Contains[RichName, String].extract(s.lastName),
age = Contains[Int, Int].extract(s.age)
)
}
I'd like to have more
Containsmacro generators, covering common use cases.Few come to mind:
1. A sealed family form for
GenContainsexample:
Here
GenContains[User](_.id)must go through all the direct subtypes ofUserand verify thatGenContains(_.id)resolves to lens. Example of generated tree:The proposed solution should work even for the case when path is longer that one field, or one of the direct subtypes is a sealed family itself
2. Typeclass based sealed Contains derivation
Ability to derive Contains when each alternative has implicit
Containsto the given type.In the best form it should support recursion and GADTs
latter should be expanded to
3. Typeclass based case class to case class derivation
When two case classes have fields related to each other, sometimes we can derive
Containsfor them. Such case could be a partial replacement for complex data transformation libraries such as https://github.com/scalalandio/chimneyWe will derive
Contains[A, B]when :Bhas a field with the same name in theAAFandBFwe haveAF =:= BForContains[AF, BF]Latter could be relaxed providing implicit `Contains[A, A] during derivation
last line should be expanded to the following