Refactor Storage to make sense in the context of external querylangs (Quill)
This commit is contained in:
parent
b52159a915
commit
bd78f6eee3
7 changed files with 81 additions and 54 deletions
|
@ -18,7 +18,9 @@ val sharedSettings = Seq(
|
|||
"org.typelevel" %%% "cats-core" % "1.5.0",
|
||||
"org.typelevel" %%% "cats-effect" % "1.1.0",
|
||||
"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 =
|
||||
|
|
29
cataquack/src/main/scala/tf/bug/cataquack/Raw.scala
Normal file
29
cataquack/src/main/scala/tf/bug/cataquack/Raw.scala
Normal file
|
@ -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
|
||||
|
||||
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
|
||||
|
||||
object implicits extends ReadImplicits
|
||||
object implicits extends ReadImplicits with RawImplicits
|
||||
|
|
9
cataquack/src/main/scala/tf/bug/cataquack/package.scala
Normal file
9
cataquack/src/main/scala/tf/bug/cataquack/package.scala
Normal file
|
@ -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.implicits._
|
||||
import cats.effect.IO
|
||||
import tf.bug.cataquack.{Read, Storage}
|
||||
import tf.bug.cataquack.{IORaw, Raw, Read, Storage}
|
||||
import tf.bug.cataquack.implicits._
|
||||
|
||||
import scala.io.Source
|
||||
|
||||
object Example {
|
||||
|
||||
type StringIORaw[T] = IORaw[String, T]
|
||||
type ReadString[T] = Read[String, T]
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val f: File = new File("counter.txt")
|
||||
val s: Storage[IO, String] = (key: String) => IO {
|
||||
Source.fromFile(f).getLines().find(_.startsWith(key ++ " ")) match {
|
||||
case Some(line) => line.drop(key.length + 1)
|
||||
case None => throw new IllegalArgumentException(s"No such key: $key")
|
||||
val s: Storage[StringIORaw, ReadString] = new Storage[StringIORaw, ReadString] {
|
||||
override def query[T](key: String): StringIORaw[T] = IO {
|
||||
val s = Source.fromFile(f).getLines()
|
||||
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 desc = readDescription(s)
|
||||
val pr = for {
|
||||
c <- count
|
||||
d <- desc
|
||||
} yield println(s"$d: $c")
|
||||
} yield println(s"${d.read}: ${c.read}")
|
||||
pr.unsafeRunSync()
|
||||
}
|
||||
|
||||
case class Counter(n: Long)
|
||||
case class Description(n: String)
|
||||
|
||||
def readCount[F[_]: Functor, T](s: Storage[F, T])(implicit read: Read[T, Long]): F[Long] = {
|
||||
s.get("count").map(read.apply)
|
||||
def readCount[F[_]: Functor, C[_]](s: Storage[F, C]): F[Long] = {
|
||||
s.query[Long]("count")
|
||||
}
|
||||
|
||||
def readDescription[F[_]: Functor, T](s: Storage[F, T])(implicit read: Read[T, String]): F[String] = {
|
||||
s.get("desc").map(read.apply)
|
||||
def readDescription[F[_]: Functor, C[_]](s: Storage[F, C]): F[String] = {
|
||||
s.query[String]("desc")
|
||||
}
|
||||
|
||||
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 a new issue