import asyncio import logging from pathlib import Path from typing import Any, Type from src.file_processor.base import BaseAsyncFileProcessor from src.file_processor.reader import BatchCsvDictReader, CsvDictReader, CsvDictReaderT from src.file_processor.writer import StringWriter from src.result import StatusEnum logger = logging.getLogger('users_cleanup') class CreateMigrationMixin: fo: Path result_queue: asyncio.Queue[Any] def __init__(self, *, task_id: str, identifier: str, changeset_suffix: str, **kwargs: Any) -> None: self.task_id = task_id self.identifier = identifier self.changeset_suffix = changeset_suffix super().__init__(**kwargs) @staticmethod def _row_filter(row: CsvDictReaderT) -> bool: return row['status'] == StatusEnum.SUCCESS.value def get_writer(self) -> StringWriter: return StringWriter(path=self.fo, queue=self.result_queue) async def pre_process(self) -> None: self.result_queue.put_nowait('--liquibase formatted cypher\n\n') class CreateMigration(CreateMigrationMixin, BaseAsyncFileProcessor[CsvDictReaderT, str]): def get_reader(self) -> CsvDictReader: return CsvDictReader( path=self.fi, row_filter=self._row_filter, ensure_keys=('identity_id', 'auth0_id', 'status') ) async def process_row(self, index: int, row: CsvDictReaderT) -> str: identity_id = row['identity_id'] auth0_id = row['auth0_id'] if auth0_id.startswith('auth0|'): auth0_id = auth0_id[6:] changeset_id = identity_id.replace('-', '_') changeset_task = self.task_id.replace('-', '_') changeset_name = ( f'{self.identifier}:{changeset_task}_deactivate_{changeset_id}{self.changeset_suffix}:{index + 1}'.lower() ) return f"""--changeset {changeset_name} MATCH (i:Identity {{id: '{identity_id}'}}) SET i.active = 'N', i.auth0UserId = '{identity_id}', i.lastModifiedBy = 'database/{self.task_id}', i.lastModifiedAt = datetime() RETURN i; --rollback MATCH (i:Identity {{id: '{identity_id}'}}) --rollback SET i.active = 'Y', --rollback i.auth0UserId = '{auth0_id}', --rollback i.lastModifiedBy = 'database/{self.task_id}', --rollback i.lastModifiedAt = datetime() --rollback RETURN i; """ class CreateMigrationBatch(CreateMigrationMixin, BaseAsyncFileProcessor[list[CsvDictReaderT], str]): def __init__( self, *, batch_size: int, changeset_suffix: str, task_id: str, identifier: str, fi: Path, fo: Path, concurrency: int, ) -> None: super().__init__( task_id=task_id, changeset_suffix=changeset_suffix, identifier=identifier, fi=fi, fo=fo, concurrency=concurrency, ) self._batch_size = batch_size def get_reader(self) -> BatchCsvDictReader: return BatchCsvDictReader( path=self.fi, row_filter=self._row_filter, ensure_keys=('identity_id', 'auth0_id', 'status'), batch_size=self._batch_size, ) async def process_row(self, index: int, row: list[CsvDictReaderT]) -> str: changeset_task = self.task_id.replace('-', '_') changeset_name = ( f'{self.identifier}:{changeset_task}_deactivate_batch{self.changeset_suffix}:{index + 1}'.lower() ) migration_ids = [] for row_ in row: migration_ids.append(f"'{row_['identity_id']}'") return f"""--changeset {changeset_name} MATCH (i:Identity) WHERE i.id in [ {',\n '.join(migration_ids)} ] SET i.active = 'N', i.auth0UserId = i.id, i.lastModifiedBy = 'database/{self.task_id}', i.lastModifiedAt = datetime() RETURN count(i); """ def get_command_cls(batch_size: int, **_kwargs: Any) -> Type[CreateMigrationBatch] | Type[CreateMigration]: if batch_size > 1: return CreateMigrationBatch else: return CreateMigration