Refactor Storage to make sense in the context of external querylangs (Quill)
This commit is contained in:
parent
b52159a915
commit
bd78f6eee3
|
@ -18,7 +18,9 @@ val sharedSettings = Seq(
|
||||||
"org.typelevel" %%% "cats-core" % "1.5.0",
|
"org.typelevel" %%% "cats-core" % "1.5.0",
|
||||||
"org.typelevel" %%% "cats-effect" % "1.1.0",
|
"org.typelevel" %%% "cats-effect" % "1.1.0",
|
||||||
"org.scala-graph" %%% "graph-core" % "1.12.5",
|
"org.scala-graph" %%% "graph-core" % "1.12.5",
|
||||||
)
|
),
|
||||||
|
resolvers += Resolver.sonatypeRepo("releases"),
|
||||||
|
addCompilerPlugin("org.spire-math" % "kind-projector" % "0.9.8" cross CrossVersion.binary)
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val cataquack =
|
lazy val cataquack =
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package tf.bug.cataquack
|
||||||
|
|
||||||
|
import cats.Functor
|
||||||
|
import cats.effect.IO
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A case class meant to be used under IORaw (see package.scala) like so:
|
||||||
|
* {{{
|
||||||
|
* type StringIORaw[T] = IORaw[T, String]
|
||||||
|
* }}}
|
||||||
|
* @param s A concrete value that has been retrieved
|
||||||
|
* @tparam T The target type
|
||||||
|
* @tparam S The raw type
|
||||||
|
*/
|
||||||
|
case class Raw[S, T](s: S) {
|
||||||
|
|
||||||
|
def read(implicit readEv: Read[S, T]): T = readEv.apply(s)
|
||||||
|
|
||||||
|
def map[U](f: T => U): Raw[S, U] = Raw[S, U](s)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
trait RawImplicits {
|
||||||
|
|
||||||
|
implicit def rawFunctor[S]: Functor[Raw[S, ?]] = new Functor[Raw[S, ?]] {
|
||||||
|
override def map[A, B](fa: Raw[S, A])(f: A => B): Raw[S, B] = fa.map(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,9 +1,20 @@
|
||||||
package tf.bug.cataquack
|
package tf.bug.cataquack
|
||||||
|
|
||||||
import cats.Functor
|
import cats._
|
||||||
|
import cats.data._
|
||||||
|
import cats.implicits._
|
||||||
|
|
||||||
trait Storage[F[_], T] {
|
trait Storage[F[_], C[_]] {
|
||||||
|
|
||||||
def get(key: String): F[T]
|
def query[T](key: String): F[T]
|
||||||
|
|
||||||
|
def map[A, B](fa: F[A])(f: A => B)(implicit functor: Functor[F]): F[B] = fa.map(f)
|
||||||
|
def flatMap[A, B](fa: F[A])(f: A => F[B])(implicit flatMap: FlatMap[F]): F[B] = fa.flatMap(f)
|
||||||
|
|
||||||
|
def filter[T](ft: F[T])(f: T => Boolean)(implicit filterFunctor: FunctorFilter[F]): F[T] = ft.filter(f)
|
||||||
|
|
||||||
|
/** Type like List, Id, etc */
|
||||||
|
type Output[T]
|
||||||
|
def execute[T: C](f: F[T]): this.Output[T]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
package tf.bug.cataquack
|
package tf.bug.cataquack
|
||||||
|
|
||||||
object implicits extends ReadImplicits
|
object implicits extends ReadImplicits with RawImplicits
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package tf.bug
|
||||||
|
|
||||||
|
import cats.effect.IO
|
||||||
|
|
||||||
|
package object cataquack {
|
||||||
|
|
||||||
|
type IORaw[S, T] = IO[Raw[S, T]]
|
||||||
|
|
||||||
|
}
|
|
@ -1,39 +0,0 @@
|
||||||
package tf.bug.cats
|
|
||||||
|
|
||||||
import cats._
|
|
||||||
import cats.data._
|
|
||||||
import cats.implicits._
|
|
||||||
import scalax.collection.Graph
|
|
||||||
import scalax.collection.GraphPredef._, scalax.collection.GraphEdge._
|
|
||||||
import tf.bug.cataquack.{Read, Storage}
|
|
||||||
|
|
||||||
case class IDCat(id: Int, name: String, friends: Set[Int]) {
|
|
||||||
def asNode: CatNode = CatNode(id, name)
|
|
||||||
}
|
|
||||||
case class CatNode(id: Int, name: String)
|
|
||||||
|
|
||||||
object Cat {
|
|
||||||
|
|
||||||
def getCats[F[_]: Functor, T](s: Storage[F, T])(implicit read: Read[T, Vector[IDCat]]): F[Vector[IDCat]] = {
|
|
||||||
s.get("cats").map(read.apply)
|
|
||||||
}
|
|
||||||
|
|
||||||
def getCatGraphFromVec[F[_]: Functor, T](s: Storage[F, T])(implicit read: Read[T, Vector[IDCat]]): F[Graph[CatNode, UnDiEdge]] = {
|
|
||||||
getCats(s).map(cats => {
|
|
||||||
val emptyGraph = Graph.empty[CatNode, UnDiEdge]
|
|
||||||
cats.foldLeft(emptyGraph)((g, nc) => g ++ nc.friends.map(friendID => {
|
|
||||||
val fc = cats.find(_.id == friendID)
|
|
||||||
fc.map(rdc => {
|
|
||||||
val ncd = nc.asNode
|
|
||||||
val nrd = rdc.asNode
|
|
||||||
ncd ~ nrd
|
|
||||||
})
|
|
||||||
}).filter(_.isDefined).map(_.get))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
def getCatGraph[F[_]: Functor, T](s: Storage[F, T])(implicit read: Read[T, Graph[CatNode, UnDiEdge]]): F[Graph[CatNode, UnDiEdge]] = {
|
|
||||||
s.get("cats").map(read.apply)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -6,41 +6,56 @@ import cats._
|
||||||
import cats.data._
|
import cats.data._
|
||||||
import cats.implicits._
|
import cats.implicits._
|
||||||
import cats.effect.IO
|
import cats.effect.IO
|
||||||
import tf.bug.cataquack.{Read, Storage}
|
import tf.bug.cataquack.{IORaw, Raw, Read, Storage}
|
||||||
import tf.bug.cataquack.implicits._
|
import tf.bug.cataquack.implicits._
|
||||||
|
|
||||||
import scala.io.Source
|
import scala.io.Source
|
||||||
|
|
||||||
object Example {
|
object Example {
|
||||||
|
|
||||||
|
type StringIORaw[T] = IORaw[String, T]
|
||||||
|
type ReadString[T] = Read[String, T]
|
||||||
|
|
||||||
def main(args: Array[String]): Unit = {
|
def main(args: Array[String]): Unit = {
|
||||||
val f: File = new File("counter.txt")
|
val f: File = new File("counter.txt")
|
||||||
val s: Storage[IO, String] = (key: String) => IO {
|
val s: Storage[StringIORaw, ReadString] = new Storage[StringIORaw, ReadString] {
|
||||||
Source.fromFile(f).getLines().find(_.startsWith(key ++ " ")) match {
|
override def query[T](key: String): StringIORaw[T] = IO {
|
||||||
case Some(line) => line.drop(key.length + 1)
|
val s = Source.fromFile(f).getLines()
|
||||||
case None => throw new IllegalArgumentException(s"No such key: $key")
|
s.find(_.startsWith(key ++ " ")) match {
|
||||||
|
case Some(l) => Raw[String, T](l.drop(key.length + 1))
|
||||||
|
case None => throw new IllegalArgumentException(s"No such key: $key")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Type like IO[List], Id, etc */
|
||||||
|
override type Output[T] = IO[T]
|
||||||
|
|
||||||
|
override def execute[T: ReadString](f: StringIORaw[T]): Output[T] = f.map(_.read)
|
||||||
}
|
}
|
||||||
val count = readCount(s)
|
val count = readCount(s)
|
||||||
val desc = readDescription(s)
|
val desc = readDescription(s)
|
||||||
val pr = for {
|
val pr = for {
|
||||||
c <- count
|
c <- count
|
||||||
d <- desc
|
d <- desc
|
||||||
} yield println(s"$d: $c")
|
} yield println(s"${d.read}: ${c.read}")
|
||||||
pr.unsafeRunSync()
|
pr.unsafeRunSync()
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Counter(n: Long)
|
case class Counter(n: Long)
|
||||||
case class Description(n: String)
|
case class Description(n: String)
|
||||||
|
|
||||||
def readCount[F[_]: Functor, T](s: Storage[F, T])(implicit read: Read[T, Long]): F[Long] = {
|
def readCount[F[_]: Functor, C[_]](s: Storage[F, C]): F[Long] = {
|
||||||
s.get("count").map(read.apply)
|
s.query[Long]("count")
|
||||||
}
|
}
|
||||||
|
|
||||||
def readDescription[F[_]: Functor, T](s: Storage[F, T])(implicit read: Read[T, String]): F[String] = {
|
def readDescription[F[_]: Functor, C[_]](s: Storage[F, C]): F[String] = {
|
||||||
s.get("desc").map(read.apply)
|
s.query[String]("desc")
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit def readStringLong: Read[String, Long] = (i: String) => i.toLong
|
implicit def readStringLong: Read[String, Long] = (i: String) => i.toLong
|
||||||
|
|
||||||
|
implicit def stringIORawFunctor: Functor[StringIORaw] = new Functor[StringIORaw] {
|
||||||
|
override def map[A, B](fa: StringIORaw[A])(f: A => B): StringIORaw[B] = fa.map(a => rawFunctor[String].map(a)(f))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue