Created
August 15, 2023 23:19
-
-
Save p-pavel/7801c83f5c03b66ec7266f1673b7bb0d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.annotation.targetName | |
import cats.* | |
import cats.implicits.* | |
import cats.data.{StateT, State} | |
trait CRUD: | |
type Obj | |
type Identity | |
type Criteria | |
val All: Criteria | |
type F[_] | |
extension (c: Criteria) def select: F[Seq[Obj]] | |
extension (id: Identity) | |
def delete: F[Unit] | |
def lookup: F[Option[Obj]] | |
extension (o: Obj) | |
def id: Identity | |
def store: F[Unit] | |
@targetName("deleteObject") | |
def delete: F[Unit] = o.id.delete | |
object CRUD: | |
type Aux[G[_], O] = CRUD {type F[A] = G[A]; type Obj = O} | |
trait StateM[S, F[_]]: | |
def get: F[S] | |
def put(s: S): F[Unit] | |
def modify(f: S => S)(using Monad[F]) = get.map(f).flatMap(put) | |
trait Lens[T, A]: | |
def get(t: T): A | |
def update(a: A): T => T | |
given tailLens[A, T <: Tuple, B](using l: Lens[T, B]): Lens[A *: T, B] with | |
type TT = A *: T | |
def get(t: TT): B = l.get(t.tail) | |
def update(a: B) = { case h *: tail => | |
h *: l.update(a)(tail) | |
} | |
given headLens[A, T <: Tuple]: Lens[A *: T, A] with | |
def get(t: A *: T): A = t.head | |
def update(a: A) = l => a *: l.tail | |
given lensStateM[T, A, F[_]: Monad](using | |
st: StateM[T, F], | |
l: Lens[T, A] | |
): StateM[A, F] with | |
def get: F[A] = st.get.map(l.get) | |
def put(a: A): F[Unit] = st.get.map(l.update(a)).flatMap(st.put) | |
given stateMFromStateT[F[_]: Applicative, S]: StateM[S, StateT[F, S, *]] with | |
def get = StateT.get | |
def put(s: S) = StateT.set(s) | |
trait Identified[A]: | |
type Identity | |
extension (a: A) def id: Identity | |
given idenifiedCrud[A](using | |
c: CRUD { type Obj = A } | |
): (Identified[A] { type Identity = c.Identity }) = | |
new Identified[A]: | |
type Identity = c.Identity | |
extension (a: A) def id: Identity = c.id(a) | |
type SimpleCRUD[O, Id] = CRUD { | |
type Obj = O; type Identity = Id; type Criteria = O => Boolean | |
} | |
given crudOnState[G[_]:Monad, S](using | |
ident: Identified[S], | |
st: StateM[Map[ident.Identity, S], G] | |
): (SimpleCRUD[S, ident.Identity] { type F[A] = G[A] }) = | |
new CRUD: | |
type Identity = ident.Identity | |
type Obj = S | |
type Criteria = S => Boolean | |
type F[A] = G[A] | |
val All = _ => true | |
extension (c: Criteria) def select: F[Seq[Obj]] = ??? | |
extension (id: Identity) | |
def delete: F[Unit] = st.modify(_ - id) | |
def lookup: F[Option[Obj]] = st.get.map(_.get(id)) | |
extension (o: Obj) | |
def id: Identity = ident.id(o) | |
def store: F[Unit] = st.modify(_ + (o.id -> o)) | |
end new | |
case class Person(id: Long, name: String, age: Int) | |
given Identified[Person] with | |
type Identity = Long | |
extension (p: Person) def id = p.id | |
def createPerson[F[_]] (using CRUD.Aux[F, Person]) = | |
Person(123, "Sdaf", 12).store | |
@main | |
def prt = println(createPerson[State[(Map[Long, Person], Int),*]].run((Map.empty,0)).value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment