Skip to content

Instantly share code, notes, and snippets.

@fmonniot
Last active February 7, 2019 22:39
Show Gist options
  • Save fmonniot/8a0c826af8003bbd459e38624029744c to your computer and use it in GitHub Desktop.
Save fmonniot/8a0c826af8003bbd459e38624029744c to your computer and use it in GitHub Desktop.
Failing path dependent types
object test {
trait Entity {
type Id
type Attribute <: EntityAttribute
def attributes: NonEmptyList[Attribute]
}
trait EntityCompanion {
type Ret <: Entity
// Those three should be the type defined in Entity
type Id // previously type Id = Ret#Id
type Attribute <: EntityAttribute // type Attribute = Ret#Attribute
def apply(attributes: NonEmptyList[Attribute]): Ret
implicit val idMeta: doobie.Meta[Id]
implicit val attributeWrite: doobie.Write[Attribute]
}
trait EntityRepository {
def updateEntity[E <: EntityCompanion](e: E)(id: e.Id, entity: e.Ret): doobie.ConnectionIO[Unit] = {
statements.updateAttributes(e).updateMany {
entity.attributes.map { attribute: entity.Attribute =>
// Fail here, as we get an `entity.Attiribute` and we wants an `e.Attribute` for the update
(attribute, id)
}
}.map(_ => ())
}
object statements {
def updateAttributes[E <: EntityCompanion](e: E): doobie.Update[(e.Attribute, e.Id)] = {
import e.idMeta, e.attributeWrite
??? // Write the doobie query, using the implicit above
}
}
}
sealed trait EntityAttribute
// For the sake of simplicity, redefine libraries base construct here
final case class NonEmptyList[+A](head: A, tail: List[A]) {
def map[B](f: A => B): NonEmptyList[B] = NonEmptyList(f(head), tail.map(f))
}
object doobie {
final class Meta[A](val get: Get[A], val put: Put[A])
sealed abstract class Get[A]
sealed abstract class Put[A]
sealed abstract class Read[A]
sealed abstract class Write[A]
trait ConnectionIO[A] {
def map[B](f: A => B): ConnectionIO[B]
}
trait Update[A] {
def updateMany(fa: NonEmptyList[A]): ConnectionIO[Int]
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment