from typing import Optional from django.db.models import Max from mypy_extensions import TypedDict from . import logging logger = logging.getLogger(__name__) SchemaVersion = TypedDict("SchemaVersion", {"migration": int, "config": int, "db": str}) class SchemaVersionHandler: """ Handler for the schema version of this running OpenSlides instance. What is a schema version? This is an indictor of the current schema of the data in the database, config variables, and the database itself. E.b. with a migration, new/changed config variables or with a database change, the schema of the data changes. To detect this is needed to reset the cache, so it does not hold any old data. This affects the server cache, but also the client uses this technique to flush the cache. Get the current schema with `get`. The schema version is built just once. After a change in the schema, all workers needs a restart! """ def __init__(self) -> None: self._schema_version: Optional[SchemaVersion] = None def get(self) -> SchemaVersion: if self._schema_version is not None: return self._schema_version from django.db.migrations.recorder import MigrationRecorder migration = MigrationRecorder.Migration.objects.aggregate(Max("id"))["id__max"] from openslides.core.config import ConfigStore try: config = ConfigStore.objects.get(key="config_version").value except ConfigStore.DoesNotExist: config = 0 try: db = ConfigStore.objects.get(key="db_id").value except ConfigStore.DoesNotExist: db = "" self._schema_version = {"migration": migration, "config": config, "db": db} return self._schema_version def compare(self, other: Optional[SchemaVersion]) -> bool: current = self.get() if not other: logger.info("No old schema version") return False equal = True if current["db"] != other["db"]: other_db = other["db"] or "" logger.info(f"DB changed from {other_db} to {current['db']}") equal = False if current["config"] != other["config"]: other_config = other["config"] or "" logger.info(f"Config changed from {other_config} to {current['config']}") equal = False if current["migration"] != other["migration"]: logger.info( f"Migration changed from {other['migration']} to {current['migration']}" ) equal = False return equal def log_current(self) -> None: current = self.get() logger.info( f"""Schema version: DB: {current["db"]} migration: {current["migration"]} config: {current["config"]}""" ) schema_version_handler = SchemaVersionHandler()