WARNING: This library is a proof of concept made in a day.
This library provides a Skunk connector for Quill. It allows you to write your queries with the be1autiful Quill DSL and execute them with the brilliant Skunk.
Quill is cool. But then I discovered Skunk by reading its documentation, and I really really liked it (have you seen its error messages?). So Skunk is cool too. But what if we could use the magic of Quill DSL with the power of Skunk? That's what this library is about, about power, magic, hegemony, world domination, and socioeconomics (ok, maybe not the last one). But mostly about power and magic. You get the idea, right? right?! But to be honest, I made this as an exercise and proof of concept in a day (16/07/2023).
Soooo, there is this thing about Skunk and Quill. Skunk does its own type encoding/decoding, and
Quill does its own type encoding/decoding. So, this library kind of avoids the problem by using
List[Any]
as the type for the Decoder of Skunk side, which represent the row of the result set.
This value is then passed to Quill, which will properly decode with its own type decoder. The encoder
is less tricky, as it is just handled by Quill, so when we get the final SQL query, we just pass it
to Skunk as the SQL string (avoiding the need to encode the values). And that's it. It works. I don't
have any but
to add here because its the best way I could find to make it work in a few hours.
But if you have any suggestion, please open an issue or a PR!
You need the following resolvers:
// build.sbt
resolvers += "jitpack" at "https://jitpack.io"
// or build.sc
import coursier.maven.MavenRepository
def repositoriesTask = T.task { super.repositoriesTask() ++ Seq(
MavenRepository("jitpack").at("https://jitpack.io")
)
}
Then add the following dependency (this library is published on Jitpack only for Scala 2.13!):
// build.sbt
libraryDependencies += "com.ivmoreau.skunk-quill" %% "skunk-quill" % "<version>"
// or build.sc
ivy"com.ivmoreau.skunk-quill::skunk-quill:<version>"
See the badge above for the latest version. A commit hash can also be used as a version. Or use a version from Releases.
It mostly works like any other Quill connector, except that you need to provide a Skunk Session
in the SkunkContextIO
constructor. The creation of the Session
is up to you, and you can use
the official Skunk documentation for that purpose
(see here). For Quill, see
here.
import cats.effect.{IO, Resource, IOApp}
import cats.effect.std.Console
import skunk.Session
import com.ivmoreau.skunkquill.SkunkContext
import io.getquill.SnakeCase
import natchez.Trace.Implicits.noop
object Main extends IOApp.Simple {
val sessionResource: Resource[IO, Session[IO]] =
Session.single(
host = "localhost",
port = 5432,
user = "user",
database = "somedb",
password = Some("somepw")
)
val db = sessionResource.map(new SkunkContextIO[SnakeCase](SnakeCase, _))
val run = db.use { ctx =>
import ctx.*
val q = quote {
query[Person].filter(p => p.name == "John")
}
ctx.run(q).flatMap { people =>
Console[IO].println(s"Found ${people.size} people: ${people.mkString(", ")}")
}
}
}
You can use any effect system you want. Any effect system??!
Yes, any effect system
Like EVERY effect system?
Maybe. Even the ones that don't exist yet?
Mmmh, I don't know.
The point is, you can use any effect system that has a cats.effect.Async
instance. For example,
if you want to use ZIO, you can use zio-interop-cats
to get the cats.effect.Async
instance.
Monix could work too, provided that you can make it work with Cats Effect 3.
What about Futures from Scala, Akka, Twitter?
They probably won't work because they don't have
a cats.effect.Async
instance. Futures are not lazy, they cannot have a lawful Async
instance. But you may be able to introduce a lawful subtype of that Future in a way that it can be
used with Async.
For the polymorphic version of SkunkContextIO
, you can use SkunkContext
instead.
If you want to use ZIO with Twitter Futures, you can use the following dependency:
// build.sbt
libraryDependencies += "com.ivmoreau.skunk-quill" %% "bird-io" % "<version>"
libraryDependencies += "com.ivmoreau.skunk-quill" %% "skunk-quill-bird-io" % "<version>"
libraryDependencies += "com.ivmoreau.skunk-quill" %% "skunk-quill-zio" % "<version>"
// or build.sc
ivy"com.ivmoreau.skunk-quill::bird-io:<version>"
ivy"com.ivmoreau.skunk-quill::skunk-quill-bird-io:<version>"
ivy"com.ivmoreau.skunk-quill::skunk-quill-zio:<version>"
They provide the following contexts:
import com.ivmoreau.skunkquill.SkunkContextBirdIO
import com.ivmoreau.skunkquill.SkunkContextZIO
Soooo, I mamaged to implement a IO monad based on Twitter Futures. It does the job, or at least the tests pass. BirdIO doesn't depend on quill or skunk, so it can be used for other purposes.
This project is licensed under the Mozilla Public License 2.0 - see the LICENSE. For Quill derived code, see the Apache License 2.0. All new code is explicitly licensed under the MPL 2.0.
Follow the Scala Code of Conduct, and license your work under the MPL 2.0. Contributions are always welcome, from documentation to testing to code changes. You don't need to open an issue first, but it might be a good idea to discuss your plans in case others (or I) are already working on it.