# HG changeset patch # User Goffi # Date 1655468123 -7200 # Node ID b5013bada4b6b4e7d130dc433712e929fa13293a # Parent cc653b2685f0514b574433a9d999e0083e2af77e core (memory/sqla): generic `get` + `session_add` in `delete`: new generic `get` allow to retrieve an ORM object with given column and value, and optionally join load attributes. In `delete`, it is now possible to specify instances to add to session, this allow, to update them in the same transaction. It is also now possible to specify a list of object to delete them all in the same transaction. rel 367 diff -r cc653b2685f0 -r b5013bada4b6 sat/memory/sqla.py --- a/sat/memory/sqla.py Fri Jun 17 14:15:23 2022 +0200 +++ b/sat/memory/sqla.py Fri Jun 17 14:15:23 2022 +0200 @@ -30,6 +30,7 @@ sessionmaker, subqueryload, joinedload, selectinload, contains_eager ) from sqlalchemy.orm.decl_api import DeclarativeMeta +from sqlalchemy.orm.attributes import Mapped from sqlalchemy.future import select from sqlalchemy.engine import Engine, Connection from sqlalchemy import update, delete, and_, or_, event, func @@ -216,6 +217,27 @@ ## Generic @aio + async def get( + self, + client: SatXMPPEntity, + db_cls: DeclarativeMeta, + db_id_col: Mapped, + id_value: Any, + joined_loads=None + ) -> Optional[DeclarativeMeta]: + stmt = select(db_cls).where(db_id_col==id_value) + if client is not None: + stmt = stmt.filter_by(profile_id=self.profiles[client.profile]) + if joined_loads is not None: + for joined_load in joined_loads: + stmt = stmt.options(joinedload(joined_load)) + async with self.session() as session: + result = await session.execute(stmt) + if joined_loads is not None: + result = result.unique() + return result.scalar_one_or_none() + + @aio async def add(self, db_obj: DeclarativeMeta) -> None: """Add an object to database""" async with self.session() as session: @@ -223,11 +245,29 @@ session.add(db_obj) @aio - async def delete(self, db_obj: DeclarativeMeta) -> None: - """Delete an object from database""" + async def delete( + self, + db_obj: Union[DeclarativeMeta, List[DeclarativeMeta]], + session_add: Optional[List[DeclarativeMeta]] + ) -> None: + """Delete an object from database + + @param db_obj: object to delete or list of objects to delete + @param session_add: other objects to add to session. + This is useful when parents of deleted objects needs to be updated too, or if + other objects needs to be updated in the same transaction. + """ + if not db_obj: + return + if not isinstance(db_obj, list): + db_obj = [db_obj] async with self.session() as session: async with session.begin(): - await session.delete(db_obj) + if session_add is not None: + for obj in session_add: + session.add(obj) + for obj in db_obj: + await session.delete(obj) await session.commit() ## Profiles