<gh_stars>1-10
# -*- coding: utf-8 -*-

from typing import Optional, Any, List
from datetime import datetime
from overrides import overrides
from recc.chrono.datetime import today
from recc.log.logging import recc_database_logger as logger
from recc.database.struct.layout import Layout
from recc.database.interfaces.db_layout import DbLayout
from recc.database.postgresql.mixin.pg_base import PgBase
from recc.database.postgresql.query.layout import (
    INSERT_LAYOUT,
    UPDATE_LAYOUT_DESCRIPTION_BY_UID,
    UPDATE_LAYOUT_DESCRIPTION_BY_PROJECT_UID_AND_NAME,
    UPDATE_LAYOUT_EXTRA_BY_UID,
    UPDATE_LAYOUT_EXTRA_BY_PROJECT_UID_AND_NAME,
    DELETE_LAYOUT_BY_UID,
    DELETE_LAYOUT_BY_PROJECT_UID_AND_NAME,
    SELECT_LAYOUT_BY_UID,
    SELECT_LAYOUT_BY_PROJECT_ID_AND_NAME,
    SELECT_LAYOUT_BY_PROJECT_ID,
)


class PgLayout(DbLayout, PgBase):
    @overrides
    async def insert_layout(
        self,
        project_uid: int,
        name: str,
        description: Optional[str] = None,
        extra: Optional[Any] = None,
        created_at: Optional[datetime] = None,
    ) -> int:
        query = INSERT_LAYOUT
        created = created_at if created_at else today()
        uid = await self.fetch_val(
            query, project_uid, name, description, extra, created
        )
        params_msg = f"project_uid={project_uid},name={name}"
        logger.info(f"insert_layout({params_msg}) -> {uid}")
        return uid

    @overrides
    async def update_layout_description_by_uid(
        self,
        uid: int,
        description: str,
        updated_at: Optional[datetime] = None,
    ) -> None:
        query = UPDATE_LAYOUT_DESCRIPTION_BY_UID
        updated = updated_at if updated_at else today()
        await self.execute(query, uid, description, updated)
        logger.info(f"update_layout_description_by_uid(uid={uid}) ok.")

    @overrides
    async def update_layout_description_by_name(
        self,
        project_uid: int,
        name: str,
        description: str,
        updated_at: Optional[datetime] = None,
    ) -> None:
        query = UPDATE_LAYOUT_DESCRIPTION_BY_PROJECT_UID_AND_NAME
        updated = updated_at if updated_at else today()
        await self.execute(query, project_uid, name, description, updated)
        params_msg = f"project_uid={project_uid},name={name}"
        logger.info(f"update_layout_description_by_name({params_msg}) ok.")

    @overrides
    async def update_layout_extra_by_uid(
        self,
        uid: int,
        extra: Any,
        updated_at: Optional[datetime] = None,
    ) -> None:
        query = UPDATE_LAYOUT_EXTRA_BY_UID
        updated = updated_at if updated_at else today()
        await self.execute(query, uid, extra, updated)
        logger.info(f"update_layout_extra_by_uid(uid={uid}) ok.")

    @overrides
    async def update_layout_extra_by_name(
        self,
        project_uid: int,
        name: str,
        extra: Any,
        updated_at: Optional[datetime] = None,
    ) -> None:
        query = UPDATE_LAYOUT_EXTRA_BY_PROJECT_UID_AND_NAME
        updated = updated_at if updated_at else today()
        await self.execute(query, project_uid, name, extra, updated)
        params_msg = f"project_uid={project_uid},name={name}"
        logger.info(f"update_layout_extra_by_name({params_msg}) ok.")

    @overrides
    async def delete_layout_by_uid(self, uid: int) -> None:
        query = DELETE_LAYOUT_BY_UID
        await self.execute(query, uid)
        logger.info(f"delete_layout_by_uid(uid={uid}) ok.")

    @overrides
    async def delete_layout_by_name(self, project_uid: int, name: str) -> None:
        query = DELETE_LAYOUT_BY_PROJECT_UID_AND_NAME
        await self.execute(query, project_uid, name)
        params_msg = f"project_uid={project_uid},name={name}"
        logger.info(f"delete_layout_by_name({params_msg}) ok.")

    @overrides
    async def select_layout_by_uid(self, uid: int) -> Layout:
        query = SELECT_LAYOUT_BY_UID
        row = await self.fetch_row(query, uid)
        params_msg = f"uid={uid}"
        if not row:
            raise RuntimeError(f"Not found layout: {params_msg}")
        result = Layout(**dict(row))
        result.uid = uid
        logger.info(f"select_layout_by_uid({params_msg}) ok.")
        return result

    @overrides
    async def select_layout_by_name(self, project_uid: int, name: str) -> Layout:
        query = SELECT_LAYOUT_BY_PROJECT_ID_AND_NAME
        row = await self.fetch_row(query, project_uid, name)
        params_msg = f"project_uid={project_uid},name={name}"
        if not row:
            raise RuntimeError(f"Not found layout: {params_msg}")
        result = Layout(**dict(row))
        result.project_uid = project_uid
        result.name = name
        logger.info(f"select_layout_by_name({params_msg}) ok.")
        return result

    @overrides
    async def select_layout_by_project_uid(self, project_uid: int) -> List[Layout]:
        result: List[Layout] = list()
        async with self.conn() as conn:
            async with conn.transaction():
                query = SELECT_LAYOUT_BY_PROJECT_ID
                async for row in conn.cursor(query, project_uid):
                    item = Layout(**dict(row))
                    item.project_uid = project_uid
                    result.append(item)
        params_msg = f"project_uid={project_uid}"
        result_msg = f"{len(result)} layout"
        logger.info(f"select_layout_by_project_uid({params_msg}) -> {result_msg}")
        return result

# -*- coding: utf-8 -*-

from typing import Optional, Any, List
from datetime import datetime
from overrides import overrides
from recc.chrono.datetime import today
from recc.log.logging import recc_database_logger as logger
from recc.database.struct.layout import Layout
from recc.database.interfaces.db_layout import DbLayout
from recc.database.postgresql.mixin.pg_base import PgBase
from recc.database.postgresql.query.layout import (
    INSERT_LAYOUT,
    UPDATE_LAYOUT_DESCRIPTION_BY_UID,
    UPDATE_LAYOUT_DESCRIPTION_BY_PROJECT_UID_AND_NAME,
    UPDATE_LAYOUT_EXTRA_BY_UID,
    UPDATE_LAYOUT_EXTRA_BY_PROJECT_UID_AND_NAME,
    DELETE_LAYOUT_BY_UID,
    DELETE_LAYOUT_BY_PROJECT_UID_AND_NAME,
    SELECT_LAYOUT_BY_UID,
    SELECT_LAYOUT_BY_PROJECT_ID_AND_NAME,
    SELECT_LAYOUT_BY_PROJECT_ID,
)


class PgLayout(DbLayout, PgBase):
    @overrides
    async def insert_layout(
        self,
        project_uid: int,
        name: str,
        description: Optional[str] = None,
        extra: Optional[Any] = None,
        created_at: Optional[datetime] = None,
    ) -> int:
        query = INSERT_LAYOUT
        created = created_at if created_at else today()
        uid = await self.fetch_val(
            query, project_uid, name, description, extra, created
        )
        params_msg = f"project_uid={project_uid},name={name}"
        logger.info(f"insert_layout({params_msg}) -> {uid}")
        return uid

    @overrides
    async def update_layout_description_by_uid(
        self,
        uid: int,
        description: str,
        updated_at: Optional[datetime] = None,
    ) -> None:
        query = UPDATE_LAYOUT_DESCRIPTION_BY_UID
        updated = updated_at if updated_at else today()
        await self.execute(query, uid, description, updated)
        logger.info(f"update_layout_description_by_uid(uid={uid}) ok.")

    @overrides
    async def update_layout_description_by_name(
        self,
        project_uid: int,
        name: str,
        description: str,
        updated_at: Optional[datetime] = None,
    ) -> None:
        query = UPDATE_LAYOUT_DESCRIPTION_BY_PROJECT_UID_AND_NAME
        updated = updated_at if updated_at else today()
        await self.execute(query, project_uid, name, description, updated)
        params_msg = f"project_uid={project_uid},name={name}"
        logger.info(f"update_layout_description_by_name({params_msg}) ok.")

    @overrides
    async def update_layout_extra_by_uid(
        self,
        uid: int,
        extra: Any,
        updated_at: Optional[datetime] = None,
    ) -> None:
        query = UPDATE_LAYOUT_EXTRA_BY_UID
        updated = updated_at if updated_at else today()
        await self.execute(query, uid, extra, updated)
        logger.info(f"update_layout_extra_by_uid(uid={uid}) ok.")

    @overrides
    async def update_layout_extra_by_name(
        self,
        project_uid: int,
        name: str,
        extra: Any,
        updated_at: Optional[datetime] = None,
    ) -> None:
        query = UPDATE_LAYOUT_EXTRA_BY_PROJECT_UID_AND_NAME
        updated = updated_at if updated_at else today()
        await self.execute(query, project_uid, name, extra, updated)
        params_msg = f"project_uid={project_uid},name={name}"
        logger.info(f"update_layout_extra_by_name({params_msg}) ok.")

    @overrides
    async def delete_layout_by_uid(self, uid: int) -> None:
        query = DELETE_LAYOUT_BY_UID
        await self.execute(query, uid)
        logger.info(f"delete_layout_by_uid(uid={uid}) ok.")

    @overrides
    async def delete_layout_by_name(self, project_uid: int, name: str) -> None:
        query = DELETE_LAYOUT_BY_PROJECT_UID_AND_NAME
        await self.execute(query, project_uid, name)
        params_msg = f"project_uid={project_uid},name={name}"
        logger.info(f"delete_layout_by_name({params_msg}) ok.")

    @overrides
    async def select_layout_by_uid(self, uid: int) -> Layout:
        query = SELECT_LAYOUT_BY_UID
        row = await self.fetch_row(query, uid)
        params_msg = f"uid={uid}"
        if not row:
            raise RuntimeError(f"Not found layout: {params_msg}")
        result = Layout(**dict(row))
        result.uid = uid
        logger.info(f"select_layout_by_uid({params_msg}) ok.")
        return result

    @overrides
    async def select_layout_by_name(self, project_uid: int, name: str) -> Layout:
        query = SELECT_LAYOUT_BY_PROJECT_ID_AND_NAME
        row = await self.fetch_row(query, project_uid, name)
        params_msg = f"project_uid={project_uid},name={name}"
        if not row:
            raise RuntimeError(f"Not found layout: {params_msg}")
        result = Layout(**dict(row))
        result.project_uid = project_uid
        result.name = name
        logger.info(f"select_layout_by_name({params_msg}) ok.")
        return result

    @overrides
    async def select_layout_by_project_uid(self, project_uid: int) -> List[Layout]:
        result: List[Layout] = list()
        async with self.conn() as conn:
            async with conn.transaction():
                query = SELECT_LAYOUT_BY_PROJECT_ID
                async for row in conn.cursor(query, project_uid):
                    item = Layout(**dict(row))
                    item.project_uid = project_uid
                    result.append(item)
        params_msg = f"project_uid={project_uid}"
        result_msg = f"{len(result)} layout"
        logger.info(f"select_layout_by_project_uid({params_msg}) -> {result_msg}")
        return result
# -*- coding: utf-8 -*-