The problem of aligning Haskell types with a database schema has been solved from two different ends:
persistent has a quasi-quoter that generate both the schema and the Haskell types for you, including encoders/decoders, from one definition. Since the query interface arising from that is not as easy to work with as it could, persistent has come out of fashion.
pGenie takes an existing database schema as first-class citizen and generates the Haskell types from that.
Your idea of parameterizing the record types is also found in opaleye. They also implicitly use HKD by instantiating all rank-0 parameters with type applications of the form f a uniformly in f but varying in a.
For those who, for some reason, wish to never write any SQL at all, a compatibility shim between persistent’s convenient quasi-quoter (generating monomorphic types) and opaleye’s wonderful parametric record types would be handy.
Thank you, I did look through the docs for opaleye before so I should have referenced it in the doc. I’ll update it to add the links and indicate that I got the ideas from other sources.
For my personal projects I prefer to write SQL directly in the functions that access the database. For bigger projects type safe query DSLs would definitely be a better choice.
(EDIT: I pushed an update to add the links. It’s not that well written but I wanted to get the updates up there.)
True. But why?
I’m not an expert in flavours of SQL databases and the details of their drivers.
Perhaps @nikita-volkov or @tomjaguarpaw can chime in and explain why pGenie and opaleye (currently) do not work for other SQL databases.
At work, we run both Microsoft SQL and Postgres databases. I chose persistent to generate the schemas, and the Haskell ecosystem offers persistent-odbc as interface to the former, which is painfully inefficient on upsert operations and forces us to stick to ancient compiler versions.
Oh, I just never bothered adding a backend for anything else, since I never used anything else. Technically there is/was an opaleye-sqlite backend, but I don’t think it ever got used.
Why I’ve chosen to bet on one specific relational DB? Because maintaining drivers is hard and every RDBMS is full of specifics and every non-trivial real world application reaches for them. The promises of SQL being a shared standard have not survived the real world practice. When you choose an RDBMS it is always a long term architectural commitment.
Why Postgres? It’s free, it’s open source, it’s featureful and it evolves faster than competition. It seems to be a clear winner in that niche. Also unlike commercial products of Oracle and Microsoft it is not prone to sanctions, which has become a real risk these days.
Well said. And that is why depending on abstractions like ODBC cripple your performance, since you can not use the goodies that each advanced RDBMS offers. The persistent-* ecosystem went to great lengths to provide a common abstraction over all the drivers it offers, but in the end you find yourself using the specific functions only persistent-YourCurrentRDBMS offers.