From 48fae5483db1825ae147af58d28a51aaa4c99d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Murta?= Date: Mon, 8 May 2023 19:31:08 +0100 Subject: [PATCH] [Fix] Select statement dangling session The `Client` was never closing the `Session` in `DatabaseSession`, which meant that tests that compared transactions and banks would work since attributes loaded only on select would still work. However, this was not the intended behavior. Calling select from the client with using sessions should detach objects completely from a DB session. Therefore, attributes on Transaction, TransactionCategory and Bank are now loaded on a join (lazy parameter). --- pfbudget/db/client.py | 10 ++++++++-- pfbudget/db/model.py | 10 +++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/pfbudget/db/client.py b/pfbudget/db/client.py index e911e31..86fb88a 100644 --- a/pfbudget/db/client.py +++ b/pfbudget/db/client.py @@ -22,6 +22,9 @@ class DatabaseSession: self.__session.commit() self.__session.close() + def close(self): + self.__session.close() + def insert(self, sequence: Sequence[Any]) -> None: self.__session.add_all(sequence) @@ -33,7 +36,7 @@ class DatabaseSession: else: stmt = select(what) - return self.__session.scalars(stmt).all() + return self.__session.scalars(stmt).unique().all() class Client: @@ -50,7 +53,10 @@ class Client: T = TypeVar("T") def select(self, what: Type[T], exists: Optional[Any] = None) -> Sequence[T]: - return self.session.select(what, exists) + session = self.session + result = session.select(what, exists) + session.close() + return result def update(self, what: Type[Any], values: Sequence[Mapping[str, Any]]) -> None: with self._sessionmaker() as session, session.begin(): diff --git a/pfbudget/db/model.py b/pfbudget/db/model.py index de4cee4..bb955e5 100644 --- a/pfbudget/db/model.py +++ b/pfbudget/db/model.py @@ -65,7 +65,7 @@ class Bank(Base, Export): BIC: Mapped[str] = mapped_column(String(8)) type: Mapped[accounttype] - nordigen: Mapped[Optional[Nordigen]] = relationship(init=False) + nordigen: Mapped[Optional[Nordigen]] = relationship(init=False, lazy="joined") @property def format(self) -> dict[str, Any]: @@ -101,11 +101,11 @@ class Transaction(Base, Export): split: Mapped[bool] = mapped_column(default=False) category: Mapped[Optional[TransactionCategory]] = relationship( - back_populates="transaction", default=None + back_populates="transaction", default=None, lazy="joined" ) - tags: Mapped[set[TransactionTag]] = relationship(default_factory=set) + tags: Mapped[set[TransactionTag]] = relationship(default_factory=set, lazy="joined") note: Mapped[Optional[Note]] = relationship( - cascade="all, delete-orphan", passive_deletes=True, default=None + cascade="all, delete-orphan", passive_deletes=True, default=None, lazy="joined" ) type: Mapped[str] = mapped_column(init=False) @@ -221,7 +221,7 @@ class TransactionCategory(Base, Export): name: Mapped[catfk] selector: Mapped[CategorySelector] = relationship( - cascade="all, delete-orphan", default=Selector_T.unknown + cascade="all, delete-orphan", default=Selector_T.unknown, lazy="joined" ) transaction: Mapped[Transaction] = relationship(