@dashdsrdash Oh yeah, I'm not a fan of directly emitting SQL (hi, injection vectors!). Totally willing to wrap the creation of the SQL in a language-specific well-typed abstract syntax tree.
What's biting me in the ORM I'm using is that the ORM has a lot of implicit behavior around class construction but that abstraction is leaky. Among the leaks:
alembic auto-builds migration steps based on the shape of a sqlalchemy model. It can build migration scripts that don't run (for example, if you don't name your foreign keys it builds them with None names in the alembic script and aelmbic can't roll back an unnamed key).
we have a binding layer between sqlalchemy and strawberry (GraphQL API generation) that treats fields that are mapped columns and fields that are relationships differently. Knowing which fields are relationships and which are mapped columns is just something you go look up in the model.
At this point, I'd like to throw out about half of this magic and just have alembic migration files and a GraphQL binding layer that just builds SQL queries to populate GraphQL fields.
Part of me also wonders how much of my irritation is ORMs in general and how much is sqlalchemy in particular. The docs for sqlalchemy include examples for making one-to-one, one-to-many, and many-to-many mappings between model ORM constructs. Those three terms aren't keywords in the API, they're patterns you have to hold your mouth a specific way to make them happen in the model bindings. All this magic and they didn't provide a macro for the three most common patterns in relational database association? "But why though?"
#sqlalchemy #alembic #strawberry