Sqlite-easy: A primitive yet easy to use sqlite library

I’ve published a new package named sqlite-easy. It’s not much of an original content as much as it’s a basic wrapper around some functionality of direct-sqlite, migrant-core, and resource-pool.

The basic idea is making it low-effort to embed a simple database or persist some state for simple applications with just a bit of writing and not a lot of reading.

It includes support for connecting to a sqlite database, running queries, migrations, and simple transactions.

The package is experimental and is not recommended for use in serious projects or production setting, but if you have a toy project that could benefit from it, consider trying it!

You can quickly try it out in ghci if you’d like:

➜  cabal repl --build-depends sqlite-easy
λ> :set -XOverloadedStrings
λ> import Database.Sqlite.Easy
λ> withDb ":memory:" $ run "select 1 + 1"
[[SQLInteger 2]]
λ> pool <- createSqlitePool "/tmp/mysqliteasydb.bin"
λ> withPool pool $ run "create table t (x text)"
λ> :{
λ| withPool pool $
λ|   transaction $ do
λ|     run "insert into t values ('a'),('b'),('c')"
λ|     run "insert into t values ('b'),('a'),('b')"
λ| :}
λ> withPool pool $ runWith "select x, count(x) from t where x <> ? group by x" [SQLText "c"]
[[SQLText "a",SQLInteger 2],[SQLText "b",SQLInteger 3]]

How does it compare to sqlite-simlpe, which has been around for quite a while now? One difference I see that this one depends also resource-pool and has some helpers to use it.

Good question. Thanks!

sqlite-simple has more capabilities (for example streaming results) than sqlite-easy and is much more battle-tested, but is a bit more complicated to work with and imo a bit less ergonomic. Specifically:

  • sqlite-easy does not use typeclasses. No ToRow or FromField or other. It uses SQLData instead to encode possible database values and leaves the encoding/decoding to the user. I find this to be easier to work with and it does not require type annotations.
  • sqlite-easy uses the SQLite type instead of Connection -> IO. This means that we don’t need to thread through the Connection, and it makes working with transactions a bit easier I think.
  • As you mentioned, sqlite-easy comes with simple resource-pool out of the box, so if you’re not sure what you’re doing or need something quick, this is pretty handy.
  • sqlite-easy comes with migrations support (via migrant) out of the box. If you know what you’re doing you will find migrant-sqlite-simple or other solutions, and you’ll figure out how to use it yourself. sqlite-easy caters to people that want a documented solution out of the box.
  • sqlite-easy’s dependency footprint is a bit smaller than sqlite-simple’s, but not by much.

All in all, if you are a Haskell veteran that knows how to figure stuff out yourself, and you want a more featureful, battle-tested library, you might want to use sqlite-simple. If you don’t have as much experience and want to just follow a manual to get your toy project working, and you are fine with using a more restricted, experimental library, starting with sqlite-easy might be easier.