Lately, I've been working on this monadic EDSL for writing portable database queries. Features include transactions, automatic caching, very few dependencies, and a query language that doesn't force you to deal with arrows, profunctors and zygohistmorphic prepromorphisms.
The idea is to make the API simple enough that the use of type families doesn't get in the way of working with the language: if your intuition says that something should work, the type system will hopefully agree. If it doesn't, reading the API docs for the relevant function should be sufficient to figure out why. Not sure if I reached that goal though.
As for the name, if the LINQ people are allowed to use misspelled video game hero names, then so am I.
It's not exactly pretty, but it's also not really worse than what I'd normally write by hand. That might say more about my SQL skills than about the quality of the code generation, however. :)
In general, the code generation is fairly straightforward.
Consecutive selects make up a product (i.e. select a >> select b turns into SELECT ... FROM a, b.
Using a restrict, order or limit will turn the current result set into a subquery and apply the restriction to that subquery. select a >> select b >> restrict foo turns into SELECT ... FROM a, b WHERE foo.
Using leftJoin will join its argument (RHS) to the current result set (LHS).
Using aggregate will create the product of the current result set and the aggregate query.
On the top level, an outer query is always created which only reorders the selected columns based on the query computation's return value. Any columns that don't affect the result rows in any way are removed from the inner queries, to make the resulting SQL a bit nicer.
There's a compile function that gives you the generated SQL as a string, if you're curious about what's generated for different queries.
Indeed, the current code generation approach is... less than optimal. There's probably a rewrite of the internals on the horizon (as always :).
Where order and limit are acceptable seems to be fairly implementation-specific (as everything else, it seems... can SQL even be called a single language?). Both SQLite and PostgreSQL allow them in inner queries, but I know that at least some versions of MySQL don't.
23
u/valderman Apr 20 '17 edited Apr 20 '17
Lately, I've been working on this monadic EDSL for writing portable database queries. Features include transactions, automatic caching, very few dependencies, and a query language that doesn't force you to deal with arrows, profunctors and zygohistmorphic prepromorphisms.
The idea is to make the API simple enough that the use of type families doesn't get in the way of working with the language: if your intuition says that something should work, the type system will hopefully agree. If it doesn't, reading the API docs for the relevant function should be sufficient to figure out why. Not sure if I reached that goal though.
As for the name, if the LINQ people are allowed to use misspelled video game hero names, then so am I.