"""SQL repositories for entries."""
import logging
import typing
from typing import Dict, List, Optional, Generic, TypeVar

import injector
import regex
import sqlalchemy as sa
from sqlalchemy import func as sa_func
from sqlalchemy import sql
from sqlalchemy.orm import sessionmaker
import ulid

from karp.foundation.value_objects import UniqueId
from karp.foundation.events import EventBus
from karp.lex.domain import errors
from karp.lex.application import repositories

# from karp.domain.errors import NonExistingField, RepositoryError
from karp.lex.domain.entities.entry import (  # EntryRepositorySettings,; EntryRepository,; create_entry_repository,
    Entry,
    EntryOp,
    EntryStatus,
)
from karp.db_infrastructure import db
from karp.lex_infrastructure.sql import sql_models
from karp.db_infrastructure.sql_repository import SqlRepository
from karp.db_infrastructure.sql_unit_of_work import SqlUnitOfWork

logger = logging.getLogger(__name__)

DUPLICATE_PATTERN = r"Duplicate entry '(.+)' for key '(\w+)'"
DUPLICATE_PROG = regex.compile(DUPLICATE_PATTERN)
NO_PROPERTY_PATTERN = regex.compile(r"has no property '(\w+)'")


class SqlEntryRepository(repositories.EntryRepository, SqlRepository):
    def __init__(
        self,
        history_model,
        # runtime_model,
        resource_config: Dict,
        # resource_id: str,
        # mapped_class: Any
        *,
        session: db.Session,
    ):
        if not session:
            raise TypeError("session can't be None")
        repositories.EntryRepository.__init__(self)
        SqlRepository.__init__(self, session=session)
        self.history_model = history_model
        # self.runtime_model = runtime_model
        self.resource_config = resource_config
        # self.mapped_class = mapped_class
        # self.resource_id = resource_id

    @classmethod
    def from_dict(
        cls,
        name: str,
        resource_config: typing.Dict,
        *,
        session: db.Session,
    ):
        if not session:
            raise TypeError("session can't be None")
        # try:
        table_name = name
        # except KeyError:
        #     raise ValueError("Missing 'table_name' in settings.")

        # history_model = db.get_table(table_name)
        # if history_model is None:
        #     history_model = create_history_entry_table(table_name)
        # history_model.create(bind=db.engine, checkfirst=True)

        logger.info({"table_name": table_name})
        history_model = sql_models.get_or_create_entry_history_model(table_name)

        # runtime_table = db.get_table(runtime_table_name)
        # if runtime_table is None:
        #     runtime_table = create_entry_runtime_table(
        #         runtime_table_name, history_model, settings["config"]
        #     )

        if session:
            history_model.__table__.create(  # type:ignore [attr-defined]
                bind=session.bind, checkfirst=True
            )
        # runtime_table.create(bind=db.engine, checkfirst=True)
        # runtime_model = sql_models.get_or_create_entry_runtime_model(
        #     table_name, history_model, resource_config
        # )
        # if session:
        #     runtime_model.__table__.create(  # type:ignore [attr-defined]
        #         bind=session.bind, checkfirst=True
        #     )  # type:ignore [attr-defined]
        #     for child_model in runtime_model.child_tables.values():
        #         child_model.__table__.create(bind=session.bind, checkfirst=True)
        return cls(
            history_model=history_model,
            # runtime_model=runtime_model,
            resource_config=resource_config,
            # resource_id=settings["resource_id"],
            session=session,
        )

    @classmethod
    def _create_repository_settings(
        cls, resource_id: str, resource_config: typing.Dict
    ) -> typing.Dict:
        return {
            "table_name": resource_id,
            "resource_id": resource_id,
        }

    def _save(self, entry: Entry):
        self._check_has_session()

        history_id = self._insert_history(entry)

        # if entry.discarded:
        #     self._session.execute(
        #         sql.delete(self.runtime_model).where(
        #             self.runtime_model.entry_id == entry.entry_id
        #         )
        #     )
        #     return

        # runtime_entry_raw = self._entry_to_runtime_dict(history_id, entry)
        # try:
        #     entry_by_entry_id = (
        #         self._session.query(self.runtime_model)
        #         .filter_by(entry_id=entry.entry_id)
        #         .first()
        #     )
        #     entry_by_entity_id = (
        #         self._session.query(self.runtime_model)
        #         .filter_by(entity_id=entry.entity_id)
        #         .first()
        #     )

        #     logger.error(
        #         {
        #             "entry_by_entry_id": entry_by_entry_id,
        #             "entry_by_entity_id": entry_by_entity_id,
        #             "entry": entry.dict(),
        #         }
        #     )
        #     if not entry_by_entry_id:
        #         if not entry_by_entity_id:
        #             logger.warning("adding")
        #             return self._session.add(self.runtime_model(**runtime_entry_raw))
        #         else:
        #             logger.warning("entity_id but no entry_id")
        #             entry_by_entity_id.discarded = True
        #             return self._session.add(self.runtime_model(**runtime_entry_raw))
        #             return
        #     else:
        #         if not entry_by_entity_id:
        #             logger.warning("entry_id but no entity_id")
        #             for key, value in runtime_entry_raw.items():
        #                 setattr(entry_by_entry_id, key, value)
        #             return
        #         else:
        #             logger.warning("updating")
        #             for key, value in runtime_entry_raw.items():
        #                 setattr(entry_by_entry_id, key, value)
        #             return
        # if not entry_by_entity_id:
        #     # if entry discarded and replaced
        #     logger.error(
        #         {
        #             "entry_by_entry_id": entry_by_entry_id,
        #             "entry_by_entity_id": entry_by_entity_id,
        #         }
        #     )
        #     assert entry_by_entry_id.discarded
        #     raise RuntimeError(f"entry = {entry.dict()}")

        # if entry_by_entry_id.entity_id != entry.entity_id:
        #     logger.warn(
        #         "entity_id changed",
        #         extra={
        #             "entry_by_entry_id": entry_by_entry_id,
        #             "entry": entry.dict(),
        #         },
        #     )
        #     # raise RuntimeError(f'entry = {entry.dict()}')

        # if entry_by_entry_id.entry_id != entry.entry_id:
        #     logger.error(
        #         {
        #             "entry_by_entry_id": entry_by_entry_id,
        #             "entry_by_entity_id": entry_by_entity_id,
        #             "entry": entry.dict(),
        #         }
        #     )
        #     raise RuntimeError(f"entry = {entry.dict()}")
        # if entry_by_entity_id.entry_id != entry.entry_id:
        #     logger.error(
        #         {"entry_by_entry_id": entry_by_entry_id, "entry": entry.dict()}
        #     )
        #     raise RuntimeError(f"entry = {entry.dict()}")

        # for key, value in runtime_entry_raw.items():
        #     setattr(entry_by_entry_id, key, value)
        #            update_result = self._session.query(
        #                self.runtime_model
        #            ).filter_by(
        #                id=entry.id
        #            ).update(
        #                runtime_entry_raw,
        #            )
        #
        #            if update_result != 1:
        #                self._session.add(
        #                    self.runtime_model(
        #                        **runtime_entry_raw
        #                    )
        #                )
        # return self._session.add(runtime_entry)
        # except db.exc.DBAPIError as exc:
        #     logger.exception("db error")
        #     raise errors.RepositoryError("db failure") from exc

    def _update(self, entry: Entry):
        self._check_has_session()
        history_id = self._insert_history(entry)

        # current_db_entry = (
        #     self._session.query(self.runtime_model)
        #     .filter_by(entry_id=entry.entry_id)
        #     .first()
        # )

        # if not current_db_entry:
        #     raise errors.RepositoryError(f"Could not find {entry.entry_id}")

        # runtime_dict = self._entry_to_runtime_dict(history_id, entry)
        # for key, value in runtime_dict.items():
        #     setattr(current_db_entry, key, value)

        # @classmethod
        # def primary_key(cls):
        #     return "entry_id"

        # def move(self, entry: Entry, *, old_entry_id: str):
        #     self._check_has_session()

        #     db_entry = (
        #         self._session.query(self.runtime_model)
        #         .filter_by(entry_id=old_entry_id)
        #         .first()
        #     )
        #     if not db_entry:
        #         raise errors.RepositoryError(f"Could not find {entry.entry_id}")
        #     db_entry.discarded = True

        return self.save(entry)

    # def delete(self, entry: Entry):
    #     self._check_has_session()

    #     self._insert_history(entry)

    #     db_entry = (
    #         self._session.query(self.runtime_model)
    #         .filter_by(entry_id=entry.entry_id)
    #         .first()
    #     )
    #     if not db_entry:
    #         raise errors.RepositoryError(f"Could not find {entry.entry_id}")
    #     db_entry.discarded = True

    def _insert_history(self, entry: Entry):
        self._check_has_session()
        try:
            ins_stmt = db.insert(self.history_model)
            history_dict = self._entry_to_history_dict(entry)
            ins_stmt = ins_stmt.values(**history_dict)
            result = self._session.execute(ins_stmt)
            return result.lastrowid or result.returned_defaults["history_id"]
        except db.exc.DBAPIError as exc:
            raise errors.RepositoryError("db failure") from exc

    # def entry_ids(self) -> List[str]:
    #     self._check_has_session()
    #     query = self._session.query(self.runtime_model).filter_by(discarded=False)
    #     return [row.entry_id for row in query.all()]

    def entity_ids(self) -> List[str]:
        self._check_has_session()
        subq = (
            sql.select(
                self.history_model.entity_id,
                sa.func.max(self.history_model.last_modified).label("maxdate"),
            )
            .group_by(self.history_model.entity_id)
            .subquery("t2")
        )
        print(subq)
        stmt = sql.select(self.history_model).join(
            subq,
            sa.and_(
                self.history_model.entity_id == subq.c.entity_id,
                self.history_model.last_modified == subq.c.maxdate,
                self.history_model.discarded == False,
            ),
        )
        stmt = stmt.order_by(self.history_model.last_modified.desc())
        query = self._session.execute(stmt).scalars()
        # query = self._session.query(self.history_model).filter_by(discarded=False)
        return [row.entity_id for row in query.all()]

    # def _by_entry_id(
    #     self,
    #     entry_id: str,
    # ) -> Optional[Entry]:
    #     self._check_has_session()
    #     subq = (
    #         sql.select(
    #             self.history_model.entity_id,
    #             sa.func.max(self.history_model.last_modified).label("maxdate"),
    #         )
    #         .group_by(self.history_model.entity_id)
    #         .subquery("t2")
    #     )

    #     stmt = sql.select(self.history_model).join(
    #         subq,
    #         sa.and_(
    #             self.history_model.entity_id == subq.c.entity_id,
    #             self.history_model.last_modified == subq.c.maxdate,
    #             self.history_model.entry_id == entry_id,
    #         ),
    #     )
    #     stmt = stmt.order_by(self.history_model.last_modified.desc())
    #     query = self._session.execute(stmt).scalars()
    #     row = query.first()
    #     return self._history_row_to_entry(row) if row else None

    def _by_id(
        self,
        id: str,
        *,
        version: Optional[int] = None,
        after_date: Optional[float] = None,
        before_date: Optional[float] = None,
        oldest_first: bool = False,
    ) -> Optional[Entry]:
        self._check_has_session()
        query = self._session.query(self.history_model)
        query = query.filter_by(entity_id=id)
        if version:
            query = query.filter_by(version=version)
        elif after_date is not None:
            query = query.filter(
                self.history_model.last_modified >= after_date
            ).order_by(self.history_model.last_modified)
        elif before_date:
            query = query.filter(
                self.history_model.last_modified <= before_date
            ).order_by(self.history_model.last_modified.desc())
        elif oldest_first:
            query = query.order_by(self.history_model.last_modified)
        else:
            query = query.order_by(self.history_model.last_modified.desc())
        row = query.first()
        return self._history_row_to_entry(row) if row else None

    # def history_by_entry_id(self, entry_id: str) -> List[Entry]:
    #     self._check_has_session()
    #     query = self._session.query(self.history_model)
    #     # query = query.join(
    #     #     self.runtime_table, self.history_model.c.id == self.runtime_table.c.id
    #     # )
    #     return query.filter_by(entry_id=entry_id).all()

    def teardown(self):
        """Use for testing purpose."""
        logger.info("starting teardown")
        #         for child_model in self.runtime_model.child_tables.values():
        #             print(f"droping child_model {child_model} ...")
        #             child_model.__table__.drop(bind=db.engine)
        #         print("droping runtime_model ...")
        #         self.runtime_model.__table__.drop(bind=db.engine)
        logger.info("droping history_model ...")
        self.history_model.__table__.drop(bind=self._session.bind)
        logger.info("dropped history_model")

        # db.metadata.drop_all(
        #     bind=db.engine, tables=[self.runtime_model, self.history_model]
        # )

    def all_entries(self) -> typing.Iterable[Entry]:
        self._check_has_session()

        subq = (
            sql.select(
                self.history_model.entity_id,
                sa.func.max(self.history_model.last_modified).label("maxdate"),
            )
            .group_by(self.history_model.entity_id)
            .subquery("t2")
        )

        stmt = sql.select(self.history_model).join(
            subq,
            sa.and_(
                self.history_model.entity_id == subq.c.entity_id,
                self.history_model.last_modified == subq.c.maxdate,
                self.history_model.discarded == False,
            ),
        )
        query = self._session.execute(stmt).scalars()
        # query = self._session.query(
        #     self.history_model).filter_by(discarded=False)
        return [self._history_row_to_entry(db_entry) for db_entry in query.all()]

    def get_total_entries(self) -> int:
        self._check_has_session()
        # query = self._session.query(self.runtime_model.discarded).filter_by(
        #     discarded=False
        # )
        # return query.count()
        return self.num_entities()

    def num_entities(self) -> int:
        self._check_has_session()
        # query = self._session.query(self.runtime_model.discarded).filter_by(
        #     discarded=False
        # )
        subq = (
            sql.select(
                self.history_model.entity_id,
                sa.func.max(self.history_model.last_modified).label("maxdate"),
            )
            .group_by(self.history_model.entity_id)
            .subquery("t2")
        )

        stmt = sql.select(sa_func.count(self.history_model.entity_id)).join(
            subq,
            sa.and_(
                self.history_model.entity_id == subq.c.entity_id,
                self.history_model.last_modified == subq.c.maxdate,
                self.history_model.discarded == False,
            ),
        )
        query = self._session.execute(stmt).scalar()
        return query

    def by_referenceable(self, filters: Optional[Dict] = None, **kwargs) -> List[Entry]:
        self._check_has_session()
        # query = self._session.query(self.runtime_model)
        # query = self._session.query(self.runtime_model, self.history_model).filter(
        #     self.runtime_model.history_id == self.history_model.history_id
        # )
        if filters is None:
            if not kwargs:
                raise ValueError("Must give 'filters' or kwargs")
            else:
                filters = kwargs

        subq = (
            sql.select(
                self.history_model.entity_id,
                sa.func.max(self.history_model.last_modified).label("maxdate"),
            )
            .group_by(self.history_model.entity_id)
            .subquery("t2")
        )
        query_and = sa.and_(
            self.history_model.entity_id == subq.c.entity_id,
            self.history_model.last_modified == subq.c.maxdate,
            self.history_model.discarded == False,
        )

        for filter_key, filter_value in filters.items():
            # query = query.filter(
            #     self.history_model.body.op("->")(filter_key) == filter_value
            # )
            query_and = query_and & (
                sa_func.json_extract(self.history_model.body, f"$.{filter_key}")
                == filter_value
            )
        stmt = sql.select(self.history_model).join(
            subq,
            query_and,
        )
        print(stmt)
        result = [
            self._history_row_to_entry(row)
            for row in self._session.execute(stmt).scalars().all()
        ]
        # joined_filters = []
        # simple_filters = {}

        # for filter_key in filters.keys():
        #     # tmp = collections.defaultdict(dict)
        #     if filter_key in self.resource_config[
        #         "referenceable"
        #     ] and self.resource_config["fields"][filter_key].get("collection"):
        #         logger.debug("collection field", extra={"filter_key": filter_key})
        #         # child_cls = self.runtime_model.child_tables[filter_key]
        #         # tmp[child_cls.__tablename__][filter_key] = filters[filter_key]
        #         # print(f"tmp.values() = {tmp.values()}")
        #         joined_filters.append({filter_key: filters[filter_key]})
        #         # query = query.filter(
        #         #     getattr(self.runtime_model, filter_key).any(filters[filter_key])
        #         # )
        #         # query = self._session.query(self.runtime_model.child_tables[filter_key])
        #         # return query.all()
        #     else:
        #         simple_filters[filter_key] = filters[filter_key]
        #     # joined_filters.extend(tmp.values())

        # try:
        #     query = query.filter_by(**simple_filters)
        # except db.exc.InvalidRequestError as exc:
        #     match = NO_PROPERTY_PATTERN.search(str(exc))
        #     if match:
        #         raise errors.NonExistingField(match.group(1)) from exc
        #     else:
        #         raise errors.RepositoryError("Unknown invalid request") from exc

        # for child_filters in joined_filters:
        #     child_table_name = list(child_filters.keys())[0]
        #     logger.debug("child table name", extra={"table_name": child_table_name})
        #     child_cls = self.runtime_model.child_tables[child_table_name]
        #     child_query = self._session.query(child_cls).filter_by(**child_filters)
        #     for child_e in child_query:
        #         logger.debug("child hit", extra={"child_hit": child_e})
        #     query = query.join(child_cls).filter_by(**child_filters)
        # # result = query.filter_by(**kwargs).all()
        # # # query = self._session.query(self.history_model)
        # # # query = query.join(
        # # #     self.runtime_table,
        # # #     self.history_model.c.history_id == self.runtime_table.c.history_id,
        # # # )
        # # # result = query.filter_by(larger_place=7).all()
        # # print(f"result = {result}")
        # # return result
        # # return query.all()
        # return [self._history_row_to_entry(db_entry) for _, db_entry in query.all()]

        return result

    def get_history(
        self,
        user_id: Optional[str] = None,
        entry_id: Optional[str] = None,
        from_date: Optional[float] = None,
        to_date: Optional[float] = None,
        from_version: Optional[int] = None,
        to_version: Optional[int] = None,
        offset: int = 0,
        limit: int = 100,
    ):
        self._check_has_session()
        query = self._session.query(self.history_model)
        if user_id:
            query = query.filter_by(last_modified_by=user_id)
        if entry_id:
            query = query.filter_by(entity_id=entry_id)
        if entry_id and from_version:
            query = query.filter(self.history_model.version >= from_version)
        elif from_date is not None:
            query = query.filter(self.history_model.last_modified >= from_date)
        if entry_id and to_version:
            query = query.filter(self.history_model.version < to_version)
        elif to_date is not None:
            query = query.filter(self.history_model.last_modified <= to_date)

        paged_query = query.limit(limit).offset(offset)
        total = query.count()
        return [self._history_row_to_entry(row) for row in paged_query.all()], total

    # def _entry_to_history_row(
    #     self, entry: Entry
    # ) -> Tuple[None, UUID, str, int, float, str, Dict, EntryStatus, str, EntryOp, bool]:
    #     return (
    #         None,  # history_id
    #         entry.id,  # id
    #         entry.entry_id,  # entry_id
    #         entry.version,  # version
    #         entry.last_modified,  # last_modified
    #         entry.last_modified_by,  # last_modified_by
    #         entry.body,  # body
    #         entry.status,  # version
    #         entry.message,  # message
    #         entry.op,  # op
    #         entry.discarded,
    #     )

    def _entry_to_history_dict(
        self, entry: Entry, history_id: Optional[int] = None
    ) -> Dict:
        return {
            "history_id": history_id,
            "entity_id": entry.entity_id,
            # "entry_id": str(entry.entity_id),
            "version": entry.version,
            "last_modified": entry.last_modified,
            "last_modified_by": entry.last_modified_by,
            "body": entry.body,
            "status": entry.status,
            "message": entry.message,
            "op": entry.op,
            "discarded": entry.discarded,
            "repo_id": entry.repo_id,
        }

    def _history_row_to_entry(self, row) -> Entry:
        print(f"{row.message=}")
        return Entry(
            body=row.body,
            message=row.message,
            status=row.status,
            op=row.op,
            entity_id=row.entity_id,
            last_modified=row.last_modified,
            last_modified_by=row.last_modified_by,
            discarded=row.discarded,
            version=row.version,
            repository_id=row.repo_id,
            # entry_id=row.entry_id,
            # resource_id=self.resource_id,
        )

    def _entry_to_runtime_dict(self, history_id: int, entry: Entry) -> Dict:
        _entry = {
            "entry_id": str(entry.entity_id),
            "history_id": history_id,
            "entity_id": entry.entity_id,
            "discarded": entry.discarded,
        }
        for field_name in self.resource_config.get("referenceable", ()):
            field_val = entry.body.get(field_name)
            if field_val is None:
                continue
            if self.resource_config["fields"][field_name].get("collection"):
                child_table = self.runtime_model.child_tables[field_name]
                for elem in field_val:
                    if field_name not in _entry:
                        _entry[field_name] = []
                    _entry[field_name].append(child_table(**{field_name: elem}))
            else:
                _entry[field_name] = field_val
        return _entry


class SqlEntryUnitOfWork(
    SqlUnitOfWork,
    repositories.EntryUnitOfWork,
):
    repository_type: str = "sql_entries_base"

    def __init__(
        self,
        session_factory: sessionmaker,
        event_bus: EventBus,
        **kwargs,
    ):
        SqlUnitOfWork.__init__(self)
        repositories.EntryUnitOfWork.__init__(self, event_bus=event_bus, **kwargs)
        self.session_factory = session_factory
        self._entries = None
        self._session = None

    def _begin(self):
        if self._session is None:
            self._session = self.session_factory()
        if self._entries is None:
            self._entries = SqlEntryRepository.from_dict(
                name=self.table_name(),
                resource_config=self.config,
                session=self._session,
            )
        return self

    def table_name(self) -> str:
        return self.name

    @property
    def repo(self) -> SqlEntryRepository:
        if self._entries is None:
            raise RuntimeError("No entries")
        return self._entries

    @classmethod
    def from_dict(cls, settings: typing.Dict, resource_config, **kwargs):
        return cls(repo_settings=settings, resource_config=resource_config, **kwargs)

    def collect_new_events(self) -> typing.Iterable:
        if self._entries:
            return super().collect_new_events()
        else:
            return []


class SqlEntryUnitOfWorkV1(SqlEntryUnitOfWork):
    repository_type: str = "sql_entries_v1"


class SqlEntryUnitOfWorkV2(SqlEntryUnitOfWork):
    repository_type: str = "sql_entries_v2"

    def table_name(self) -> str:
        u = ulid.from_uuid(self.entity_id)
        random_part = u.randomness().str
        return f"{self.name}_{random_part}"


# ===== Value objects =====
# class SqlEntryRepositorySettings(EntryRepositorySettings):
#     def __init__(self, *, table_name: str, config: Dict):
#         self.table_name = table_name
#         self.config = config


# @create_entry_repository.register(SqlEntryRepositorySettings)
# def _(settings: SqlEntryRepositorySettings) -> SqlEntryRepository:
#     history_model = sql_models.get_or_create_entry_history_model(settings.table_name)

#     runtime_table_name = f"runtime_{settings.table_name}"

#     runtime_model = sql_models.get_or_create_entry_runtime_model(
#         runtime_table_name, history_model, settings.config
#     )
#     return SqlEntryRepository(history_model, runtime_model, settings.config)
SqlEntryUowType = TypeVar("SqlEntryUowType", bound=SqlEntryUnitOfWork)


class SqlEntryUowCreator(Generic[SqlEntryUowType]):
    repository_type: str = "repository_type"

    @injector.inject
    def __init__(
        self,
        session_factory: sessionmaker,
        event_bus: EventBus,
    ):
        self._session_factory = session_factory
        self.event_bus = event_bus
        self.cache = {}

    def _create_uow(self, **kwargs) -> SqlEntryUowType:
        raise NotImplementedError(f"please implement this for {self}")

    def __call__(
        self,
        entity_id: UniqueId,
        name: str,
        config: Dict,
        connection_str: Optional[str],
        user: str,
        message: str,
        timestamp: float,
    ) -> SqlEntryUowType:
        if entity_id not in self.cache:
            self.cache[entity_id] = self._create_uow(
                entity_id=entity_id,
                name=name,
                config=config,
                connection_str=connection_str,
                last_modified_by=user,
                message=message,
                last_modified=timestamp,
                session_factory=self._session_factory,
                event_bus=self.event_bus,
            )
        return self.cache[entity_id]


class SqlEntryUowV1Creator(SqlEntryUowCreator[SqlEntryUnitOfWorkV1]):
    repository_type: str = "sql_entries_v1"

    def _create_uow(self, **kwargs) -> SqlEntryUnitOfWorkV1:
        return SqlEntryUnitOfWorkV1(**kwargs)


class SqlEntryUowV2Creator(SqlEntryUowCreator[SqlEntryUnitOfWorkV2]):
    repository_type: str = "sql_entries_v2"

    def _create_uow(self, **kwargs) -> SqlEntryUnitOfWorkV2:
        return SqlEntryUnitOfWorkV2(**kwargs)
