I use sqlalchemy daily, it's an amazing library, but I wanted something more lightweight and straightforward for this project. I find the unit of work pattern cumbersome
it's called "sqlalchemy core"
Although nobody seems to use the term ORM correctly any more so it's entirely possible that neither is peewee or sqlorm.
The story behind why ORM is nowadays no longer used correctly is kind of funny:
1. Query generator sounds primitive, like cavemen banging rocks together. Software engineers are scared of primitive technologies because it makes their CVs look bad.
2. Actual ORMs attempt to present a relational database as if it was a graph or document database. This fundamentally requires a translation which cannot be made performant automatically and often requires very careful work to make performant (which is a massive source of abstraction leaks in real ORMs). People don't realise the performance hit until they've written a chunk of their application and start getting users.
3. Once enough people encountered this problem, they decided to "improve" ORMs by writing new "ORMs" which "avoid" this problem by just not actually doing any of the heavy mapping. i.e. They're the re-invention of a query generator.
It is still basically a query generator, just with the helpful step of converting selected tuples into objects, and tracking changes to those objects. This means that it is often possible to solve ORM-related performance issues without too much work.
It’s been a long time since I worked with SQLAlchemy though (or even touched Python), so my memory or knowledge of the current ecosystem might be off.
I’ve written a few ORMs and you have the same performance executing a select and getting rows back and translating them into objects than you do my ORMs. It’s literally the same. Are you going to return back a Row* from your function? No. You’re going to return an object or an array. Building that from an array of rows is no different than an ORM mapping those rows for you using instructions on what field goes where.
Just like you do in your function to build an object. “Oh but it’s at compile time!” You’ll shout. So are mine. CodeGen exists. The real issue you experience is that a certain style of ORMs confuse you. Unit of work or ActiceRecord pattern style ORMs can literally be codegen’ed into your binary to make mapping as fast as new() {}.
ORMs provide you with objects and relationships. Some of them even do validation should you choose. It’s about correctness and not going Wild West on your database with no regard to schema or normalization. If you’re properly normalized, you’ll be thankful for ORMs saving you from the JOIN hell you so desperately hang on to.