ent [1] is what I've been happiest with. It uses code generation, and has an extension system so you can generate your own custom code with the models. I've seen a GraphQL extension and a REST extension, but haven't used either enough to comment beyond that they were easy to set up. Took like 20 minutes and now all my models transparently get GraphQL endpoints.
So far I've been happy with it, but we'll see in a couple of years.
One remaining problem is writing dynamic queries without giving up static verification completely.
For example, optional WHERE, ORDER BY, GROUP BY clauses are very common. Currently the solutions are:
* Give up and write a fully dynamic query. * Generate every possible permutation. Combinatorial explosion quickly makes this impractical. * Write a static query without the optional clauses, then add clauses and execute a dynamic query. The best of both worlds but complicated.
However the optional clauses are almost always independent from each other. It should be possible to statically verify each one with `SELECT NULL FROM <full set of JOINs> WHERE/ORDER BY/GROUP BY <optional clause>`.
EDIT: Now that I think about it, you could have a partially dynamic query that's still statically checked: new WHERE conditions don't change the structure of the query, so as long as they're valid (which can be statically checked) they can be added to the query without changing the type. Same for e.g. ORDER BY or LIMIT. That would make the combinatorial explosion much more manageable, and it would actually represent different code paths (requesting a different set of fields).
* Give up and write a fully dynamic query.
* Generate every possible permutation. Combinatorial explosion quickly makes this impractical.
* Write a static query without the optional clauses, then add clauses and execute a dynamic query. The best of both worlds but complicated.
For what it's worth, a very popular Rust framework (also named SQLx lol) is designed around pure SQL tool.
Personally i think both languages have roughly the same split of SQL vs ORM people. However Rust gives devs way more tooling to to invent, to choose runtime cost, etc. So some types of libraries are just easier in a "complex" language imo.