Sqlc-hs: Use sqlc with Haskell

I am happy to announce sqlc-hs — a Haskell code generator plugin for sqlc, allowing you to generate Haskell types and functions directly from your SQL queries.

I’d be thrilled to hear your feedback, suggestions, or ideas for improvement. Contributions of any kind — from bug reports to pull requests — are more than welcome. Your input will help shape sqlc-hs into a more robust and useful tool for the Haskell community.

20 Likes

This is the first I’ve heard of sqlc; after looking at it a bit, I’m having a hard time figuring why I may want to use it over esqueleto or another haskell eDSL-style encoding. Excepting, of course, the case that for some reason I do want to write the literal sql queries, and then can get some typesafety with sqlc.

Is there some additional elevator-pitch I’m missing? Thanks! Project looks cool.

Thanks @joelmccracken. I am currently working on multiple sufficiently large projects, one with beam and one with sqlc. Both approaches work fine in practice but I tend to enjoy writing SQL more than writing beam queries. Especially since I have the full power of PostgreSQL at my hands where with beam I am stuck with what it offers mostly – it’s complicated DSL nature making it hard to extend. Sqlc “typechecks” your queries and ensures that referenced columns are present making it a great companion when developing the queries.

So I guess all in all it’s a matter of preference but it’s nice being able to have full control over the queries where needed.

1 Like

esqueleto is barely better than raw SQL for anything complicated. so much toil. even with a bunch of the new stuff (records, automatic :& search, etc. all interestingly born from real world use where esqueleto was a pain).

so if sqlc can let me write raw SQL but get some type safety, that’s a step up.

idk about composability for either though. esqueleto is built on silly abstractions so abstracting over stuff is often confusing or just hard.

it’s basically carried by having a “smooth” funnel from persistent when you immediately hit its ceiling.

1 Like

Having been burned by a number of “simple” SQL DSLs and ORMs, I am more than ever convinced that sometimes you just have to learn two languages and that’s okay. Give me a string interpolator that will marshal interpolated terms to the appropriate parameters to a prepared statement and I’ll happily write the raw SQL. The amount of effort I’ve had to put in to reverse engineer the queries from a DSL is just hard to justify compared to learning the transferable skill of writing SQL.

There are pros and cons to database libraries like beam and opaleye. The main advantage, and why I always use beam when I can, is that you can compose fragments of database statements using a library, in a way that cannot be replicated using string interpolators.

At work, I’d often like to take an existing query, and modify it by joining and filtering, for example. Unless you use an eDSL, you’ll have to write similar a new query from scratch.

1 Like

If only esqueleto was built upon something more than (basically) WroterT String - it’s a string interpolate in eDSL’s clothing!

Yeah, I’ve had a lot of success at like 3 different companies with some variation of this type:

data QB = QB Text [PersistValue]

And the obvious Monoid instance. And some obvious primitives.

I have not yet tested this but I think this approach is great. Everyone needs to know SQL anyway. SQL can do a lot so any approach of creating a DSL for it will naturally lead to a complicated DSL. I’ve been using Beam and I’m impressed by the library, but I will test this approach for my next project.

Thanks for creating this!

2 Likes

Not sure how much safety you’re looking for, but my StringInterpolation proposal would support this easily. You’d just allow SqlQuery to be interpolated verbatim.

1 Like

But could sqlc statically analyze interpolated strings?

Writer actually helped me out a lot with SQL (and may have been the only clear win I’ve had with Writer). I wanted to build some really gnarly CTEs and get some actual reuse out of them without having to chase my tail keeping them in order. Writer (NonEmpty CTE) CTE did some work on my behalf. :grinning_face_with_smiling_eyes:

1 Like

ah sure, you mean, could sqlc statically analyze the SQL fragments that are dynamically combined? Theoretically, sure, if sqlc can parse/generate a WHERE clause on its own it can theoretically check that “where clause on column FOO” fits in a hole inside a query with a FOO column in scope. But yeah, idk if sqlc would support that out of the box