Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
♻️ REFACTOR: Fully abstract QueryBuilder (#5093)
There are four primary modules involved in the QueryBuilder abstraction: - `aiida/orm/implementation/django/querybuilder.py::DjagoQueryBuilder` - `aiida/orm/implementation/sqlalchemy/querybuilder.py::SqlaQueryBuilder` - `aiida/orm/implementation/querybuilder.py::BackendQueryBuilder` - `aiida/orm/querybuilder.py::QueryBuilder` Previously, all of these modules imported objects from SQLAlchemy, i.e. there was actually no abstraction, since everything was tightly coupled to SQLAlchemy. As well as this lack of abstraction, the spread of logic and state across these modules made it very difficult to decipher the workings of the code. This commit fully abstracts the QueryBuilder; moving all SQLAlchemy code to `SqlaQueryBuilder`, making the `BackendQueryBuilder` a proper abstract class, and reducing `QueryBuilder` backend interaction to the 6 abstract methods: `count`, `iterall`, `iterdict`, `as_sql`, `analyze_query`. These methods all pass the (JSONable) query dict to the backend, which it uses to build the query. As was previously the case on the frontend, `SqlaQueryBuilder` hashes this dict, to ensure the query is only rebuilt on changes. Some other changes of note: - `aiida/orm/implementation/sqlalchemy/querybuilder.py` is split into a few modules, to improve modularity - The `QueryBuilder.get_query` and `QueryBuilder.inject_query` method have been removed, since naturally these break abstraction (relying on an `sqlalchemy.Query` object) - The `QueryBuilder.distinct` method now savez its state to the query dict, rather than directly calling the `sqlachemy.Query.distinct`. - Correctly reset `limit` after calling `QueryBuilder.one()` - Improve validation of `joining_keyword`; before it would only validate against all possible keywords, now it validates against only the keywords for the entity type. - Improve the defaults for joinin_keywords, i.e. rather than always setting `with_incoming` for all entities, set `with_node` for non-node entities. - `sqlalchemy_utils` is now only used in `tests/backends/aiida_sqlalchemy/test_utils.py`, so I have moved it to the `tests` extras, rather than `install_requires` - lots of typing!
- Loading branch information