comparison sat/memory/sqla.py @ 3798:b5013bada4b6

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
author Goffi <goffi@goffi.org>
date Fri, 17 Jun 2022 14:15:23 +0200
parents cc653b2685f0
children 1a10b8b4f169
comparison
equal deleted inserted replaced
3797:cc653b2685f0 3798:b5013bada4b6
28 from sqlalchemy.exc import IntegrityError, NoResultFound 28 from sqlalchemy.exc import IntegrityError, NoResultFound
29 from sqlalchemy.orm import ( 29 from sqlalchemy.orm import (
30 sessionmaker, subqueryload, joinedload, selectinload, contains_eager 30 sessionmaker, subqueryload, joinedload, selectinload, contains_eager
31 ) 31 )
32 from sqlalchemy.orm.decl_api import DeclarativeMeta 32 from sqlalchemy.orm.decl_api import DeclarativeMeta
33 from sqlalchemy.orm.attributes import Mapped
33 from sqlalchemy.future import select 34 from sqlalchemy.future import select
34 from sqlalchemy.engine import Engine, Connection 35 from sqlalchemy.engine import Engine, Connection
35 from sqlalchemy import update, delete, and_, or_, event, func 36 from sqlalchemy import update, delete, and_, or_, event, func
36 from sqlalchemy.sql.functions import coalesce, sum as sum_, now, count 37 from sqlalchemy.sql.functions import coalesce, sum as sum_, now, count
37 from sqlalchemy.dialects.sqlite import insert 38 from sqlalchemy.dialects.sqlite import insert
214 self.initialized.callback(None) 215 self.initialized.callback(None)
215 216
216 ## Generic 217 ## Generic
217 218
218 @aio 219 @aio
220 async def get(
221 self,
222 client: SatXMPPEntity,
223 db_cls: DeclarativeMeta,
224 db_id_col: Mapped,
225 id_value: Any,
226 joined_loads=None
227 ) -> Optional[DeclarativeMeta]:
228 stmt = select(db_cls).where(db_id_col==id_value)
229 if client is not None:
230 stmt = stmt.filter_by(profile_id=self.profiles[client.profile])
231 if joined_loads is not None:
232 for joined_load in joined_loads:
233 stmt = stmt.options(joinedload(joined_load))
234 async with self.session() as session:
235 result = await session.execute(stmt)
236 if joined_loads is not None:
237 result = result.unique()
238 return result.scalar_one_or_none()
239
240 @aio
219 async def add(self, db_obj: DeclarativeMeta) -> None: 241 async def add(self, db_obj: DeclarativeMeta) -> None:
220 """Add an object to database""" 242 """Add an object to database"""
221 async with self.session() as session: 243 async with self.session() as session:
222 async with session.begin(): 244 async with session.begin():
223 session.add(db_obj) 245 session.add(db_obj)
224 246
225 @aio 247 @aio
226 async def delete(self, db_obj: DeclarativeMeta) -> None: 248 async def delete(
227 """Delete an object from database""" 249 self,
250 db_obj: Union[DeclarativeMeta, List[DeclarativeMeta]],
251 session_add: Optional[List[DeclarativeMeta]]
252 ) -> None:
253 """Delete an object from database
254
255 @param db_obj: object to delete or list of objects to delete
256 @param session_add: other objects to add to session.
257 This is useful when parents of deleted objects needs to be updated too, or if
258 other objects needs to be updated in the same transaction.
259 """
260 if not db_obj:
261 return
262 if not isinstance(db_obj, list):
263 db_obj = [db_obj]
228 async with self.session() as session: 264 async with self.session() as session:
229 async with session.begin(): 265 async with session.begin():
230 await session.delete(db_obj) 266 if session_add is not None:
267 for obj in session_add:
268 session.add(obj)
269 for obj in db_obj:
270 await session.delete(obj)
231 await session.commit() 271 await session.commit()
232 272
233 ## Profiles 273 ## Profiles
234 274
235 def getProfilesList(self) -> List[str]: 275 def getProfilesList(self) -> List[str]: