Source code for cata_log_hub.database.signals

# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Cata-Log - the central hub for digital flyers
# Copyright (C) 2026 David Aderbauer & The Cata-Log Contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.


import logging

from sqlalchemy import Connection, Engine, delete, event, orm
from sqlalchemy.engine.interfaces import DBAPIConnection
from sqlalchemy.pool.base import _ConnectionRecord

from . import models

logger = logging.getLogger(__name__)


[docs] @event.listens_for(Engine, "connect") def set_sqlite_pragma( dbapi_connection: DBAPIConnection, connection_record: _ConnectionRecord, # noqa: ARG001 # required for event decorator ) -> None: """Event setting pragmas on all engines after connecting to db.""" if "sqlite" in dbapi_connection.__class__.__module__: # pragma: no branch cursor = dbapi_connection.cursor() cursor.execute("PRAGMA journal_mode=WAL;") cursor.execute("PRAGMA foreign_keys=ON;") cursor.execute("PRAGMA busy_timeout=5000;") # 5s cursor.execute("PRAGMA synchronous=NORMAL;") cursor.close()
[docs] @event.listens_for(models.PageFile, "after_delete") def after_pagefile_delete( mapper: orm.Mapper, # noqa: ARG001 # required for event decorator connection: Connection, # noqa: ARG001 # required for event decorator target: models.PageFile, ) -> None: """Event cleaning up a page file after deleting the file from db.""" target.path.unlink(missing_ok=True) logger.debug( "Success cleaning up page file of a deleted page.", extra={"pagefile_id": target.id, "pagefile_path": target.path}, )
[docs] @event.listens_for(models.Page, "after_delete") def after_page_delete( mapper: orm.Mapper, # noqa: ARG001 # required for event decorator connection: Connection, target: models.Page, ) -> None: """Event cleaning up an orphaned page file after deleting the page.""" if len(target.file.pages) == 1: connection.execute( delete(models.PageFile).where(models.PageFile.id == target.file_id) )
[docs] @event.listens_for(models.Provider, "after_insert") def after_provider_insert( mapper: orm.Mapper, # noqa: ARG001 # required for event decorator connection: Connection, target: models.Provider, ) -> None: """Event setting up a providers task after its insertion.""" target.add_job() connection.execute( models.Provider.__table__.update() .where(models.Provider.id == target.id) .values(job_id=target.job_id) ) logger.debug( "Success adding task to a newly inserted provider.", extra={"provider_id": target.id, "job_id": target.job_id}, )
[docs] @event.listens_for(models.Provider, "after_delete") def after_provider_delete( mapper: orm.Mapper, # noqa: ARG001 # required for event decorator connection: Connection, # noqa: ARG001 # required for event decorator target: models.Provider, ) -> None: """Event cleaning up a providers task after deleting the provider.""" target.remove_job() logger.debug( "Success cleaning up periodictask of a deleted provider.", extra={"provider_id": target.id, "job_id": target.job_id}, )
__all__ = [ "after_page_delete", "after_pagefile_delete", "after_provider_delete", "after_provider_insert", "set_sqlite_pragma", ]