# This file was generated by mettle.genes.db.GenPy3 [ver 2.1] on Mon Feb 15 23:21:02 2021
#  Target Database = postgresql
#
import asyncio
import copy
import datetime
import uuid
import time
import mettle.lib
import mettle.io
import mettle.db

from bs_loco.db.tables.msg_req_res import tMsgReqRes
from bs_loco.db.tables.msg_req_res_key import tMsgReqResKey

from .msg_req_res_lock_one import dMsgReqResLockOne
from .msg_req_res_select_one import dMsgReqResSelectOne
from .msg_req_res_update import dMsgReqResUpdate
from .msg_req_res_insert import dMsgReqResInsert
from .msg_req_res_delete_one import dMsgReqResDeleteOne

class dMsgReqRes:

    def __init__(self, dbcon: mettle.db.IAConnect):
        """
        Constructor.

        :param dbcon: Mettle database connection object.
        """
        self.rec    = tMsgReqRes()
        self._dbcon = dbcon

    def __enter__(self):
        """
        DAO enter.
        """
        return self

    def __exit__(self, type, value, traceback):
        """
        DAO exit.
        """
        pass

    async def lock_one(self, _lock4update: mettle.db.DBLock, _expected: bool = True) -> bool:
        """
        Lock and select the record.

        :param _lock4update: The db lock object to use.
        :param _expected: If set to false, will not raise if record is not found.
        :return: True if selected, False if not found and _expected is set to False
        """
        _key = tMsgReqResKey()

        self.rec._write_key(_key)

        return await self.lock_one_by_key(_key, _lock4update, _expected)

    async def lock_one_with(self, _rec: tMsgReqRes, _lock4update: mettle.db.DBLock, _expected: bool = True) -> bool:
        """
        Lock and select the record using a record.

        :param _rec: The table rec to select with and into.
        :param _lock4update: The db lock object to use.
        :param _expected: If set to false, will not raise if record is not found.
        :return: True if selected, False if not found and _expected is set to False
        """
        _key = tMsgReqResKey()
        _rec._write_key(_key)

        await self.lock_one_by_key(_key, _lock4update, _expected)
        _rec._copy_from(self.rec)
        return True

    async def lock_one_deft(self,
                            id: int,
                            _lock4update: mettle.db.DBLock,
                            _expected: bool = True) -> bool:
        """
        Attempt to lock and select the record by it's primary key columns.

        :param id: int
        :param _lock4update:  The db lock object to use. 
        :param _expected: bool
        """
        _key = tMsgReqResKey()

        _key.id = id

        return await self.lock_one_by_key(_key, _lock4update, _expected)

    async def lock_one_by_key(self, _key: tMsgReqResKey, _lock4update: mettle.db.DBLock, _expected: bool = True) -> bool:
        """
        Attempt to lock and select the record with it's primary key.

        :param _key: Primary key of the table record.
        :param _lock4update: The db lock object to use.
        :param _expected: If set to false, will not raise if record is not found.
        :return: True if selected, False if not found and _expected is set to False
        """
        with dMsgReqResLockOne(self._dbcon) as _qry:
            _dex = _lock4update.retrys - 1 if _lock4update.retrys > 0 else 0

            while _dex >= 0:
                try:
                    await _qry.exec(_key)
                    if not await _qry.fetch():
                        if not _expected:
                            return False

                        raise mettle.lib.xMettle("LockOne failed to return a record (dMsgReqRes)")

                    break
                except mettle.lib.xMettle as _x:
                    if _x.get_error_code() != mettle.lib.xMettle.eCode.DBLockNoWaitFailed:
                        raise _x

                    if _dex == 0:
                        raise mettle.lib.xMettle("Could not lock MsgReqRes record after %d attempt(s) at %d mili second intervals!" % (
_lock4update.retrys, _lock4update.mili_seconds), errCode = mettle.lib.xMettle.eCode.DBLockNoWaitFailed)

                    if _lock4update.mili_seconds > 0:
                        await asyncio.sleep(_lock4update.mili_seconds * 0.001)
                _dex -= 1

            self.rec = _qry.orec

            return True

    async def try_select_one(self) -> bool:
        """
        Attempt to select the record.

        :return: True if the record was found.
        """
        _key = tMsgReqResKey()

        self.rec._write_key(_key)

        return await self.try_select_one_by_key(_key)

    async def try_select_one_with(self, _rec: tMsgReqRes) -> bool:
        """
        Attempt to select the record using a table rec.

        :param _rec: The table rec to select with and into.
        :return: True if the row as selectd.
        """
        _key = tMsgReqResKey()
        _rec._write_key(_key)

        if not await self.try_select_one_by_key(_key):
            return False

        _rec._copy_from(self.rec)

        return True

    async def try_select_one_deft(self,
                                  id: int) -> bool:
        """
        Attempt to select the record by it's primary key columns.

        :param id: int
        :return: True if the row as selectd.
        """
        _key = tMsgReqResKey()

        _key.id = id

        return await self.try_select_one_by_key(_key)

    async def try_select_one_by_key(self, _key: tMsgReqResKey) -> bool:
        """
        Attempt to select the record with it's primary key.

        :param _key: Primary key of the table record.
        :returns: True if row was selected.
        """
        with dMsgReqResSelectOne(self._dbcon) as _qry:
            await _qry.exec(_key)
            if not await _qry.fetch():
                return False

            self.rec = _qry.orec

        return True

    async def select_one(self) -> "dMsgReqRes":
        """
        Selects the record, raises and error if it does not exist.

        :return: Self for convenience.
        """
        if not await self.try_select_one():
            raise mettle.lib.xMettle("SelectOne failed to return a record (dMsgReqRes)")

        return self

    async def select_one_with(self, _rec: tMsgReqRes) -> "dMsgReqRes":
        """
        Attempt to select the record with the table record.

        :param _rec: Table record.
        :returns: Self for convenience.
        """
        if not await self.try_select_one_with(_rec):
            raise mettle.lib.xMettle("SelectOne failed to return a record (dMsgReqRes)")

        return self

    async def select_one_deft(self,
                              id: int) -> "dMsgReqRes":
        """
        Selects the record by its primary key columns, raises and error if it does not exist.

        :param id: int
        """
        _key = tMsgReqResKey()

        _key.id = id

        if not await self.try_select_one_by_key(_key):
            raise mettle.lib.xMettle("SelectOne failed to return a record (dMsgReqRes)")

        return self

    async def select_one_by_key(self, _key: tMsgReqResKey) -> "dMsgReqRes":
        """
        Attempt to select the record with it's primary key.

        :param _key: Primary key of the table record.
        :return: Self for convenience.
        """
        if not await self.try_select_one_by_key(_key):
            raise mettle.lib.xMettle("SelectOne failed to return a record (dMsgReqRes)")

        return self

    async def update_deft(self,
                          id: int,
                          msgreq_id: int,
                          corr_id_list: dict,
                          filename: str,
                          mimetype: str,
                          content: bytearray,
                          modified_by: str):
        """
        Update the record by setting all column values.

        :param id: int
        :param msgreq_id: int
        :param corr_id_list: dict
        :param filename: str
        :param mimetype: str
        :param content: bytearray
        :param modified_by: str
        :param tm_stamp: datetime.datetime
        """
        self.rec.id = id
        self.rec.msgreq_id = msgreq_id
        self.rec.corr_id_list = corr_id_list
        self.rec.filename = filename
        self.rec.mimetype = mimetype
        self.rec.content = content
        self.rec.modified_by = modified_by

        await self.update()

    async def update(self, irec: tMsgReqRes = None):
        """
        Update the record in the database with the record or irec if it is not None.

        :param irec: If not None use this record to update the database.
        """
        if irec:
            self.rec._copy_from(irec)

        with dMsgReqResUpdate(self._dbcon) as _qry:
            await _qry.exec(self.rec)

        if irec:
            irec._copy_from(self.rec)

    async def insert_deft(self,
                          msgreq_id: int,
                          corr_id_list: dict,
                          filename: str,
                          mimetype: str,
                          content: bytearray,
                          modified_by: str):
        """
        Insert the record setting all column values.

        :param id: int
        :param msgreq_id: int
        :param corr_id_list: dict
        :param filename: str
        :param mimetype: str
        :param content: bytearray
        :param modified_by: str
        :param tm_stamp: datetime.datetime
        """
        self.rec.msgreq_id = msgreq_id
        self.rec.corr_id_list = corr_id_list
        self.rec.filename = filename
        self.rec.mimetype = mimetype
        self.rec.content = content
        self.rec.modified_by = modified_by

        await self.insert()

    async def insert(self, irec: tMsgReqRes = None):
        """
        Insert the record in the database with the record or irec if it is not None.

        :param irec: If not None use this record to insert into the database.
        """
        if irec:
            self.rec._copy_from(irec)

        with dMsgReqResInsert(self._dbcon) as _qry:
            await _qry.exec(self.rec)

        if irec:
            irec._copy_from(self.rec)

    async def delete_one_deft(self,
                              id: int):
        """
        Delete one record by it's primary key columns.

        :param id: int
        """
        _key = tMsgReqResKey()

        _key.id = id

        self.delete_one(_key)

    async def delete_one(self, irec: tMsgReqResKey = None):
        """
        Delete the record by its primary key or irec if it is not None.

        :param irec: If not None use this record to delete record.
        """
        _key = tMsgReqResKey()

        if irec:
            _key._copy_from(irec)
        else:
            self.rec._write_key(_key)

        with dMsgReqResDeleteOne(self._dbcon) as _qry:
            await _qry.exec(_key)

