from abc import ABCMeta, abstractmethod
from contextlib import contextmanager
from sqlalchemy import and_
from sqlalchemy.exc import SQLAlchemyError
from zaifbot.common.database import Session
from zaifbot.models import OrderLogs, OhlcPrices
from zaifbot.common.logger import bot_logger


@contextmanager
def transaction():
    session = Session()
    try:
        yield session
        session.commit()
    except SQLAlchemyError as e:
        bot_logger.exception(e)
        session.rollback()
        raise
    finally:
        session.close()


class DaoBase(metaclass=ABCMeta):
    _CLOSED = 1

    def __init__(self):
        self._Model = self._get_model()

    @classmethod
    def _get_session(cls):
        return Session()

    @abstractmethod
    def _get_model(self):
        raise NotImplementedError()

    def create(self, **kwargs):
        item = self.new(**kwargs)
        self.save(item)

    def new(self, **kwargs):
        return self._Model(kwargs)

    def find(self, id_):
        session = self._get_session()
        return session.query(self._get_model()).filter_by(id=id_).first()

    @classmethod
    def update(cls, id_, **kwargs):
        session = cls._get_session()
        item = cls.find(id_)
        for key, value in kwargs.items():
            setattr(item, key, value)
        session.add(item)
        session.commit()

    def find_all(self):
        session = self._get_session()
        session.query(self._get_model()).all()

    @classmethod
    def save(cls, item):
        session = cls._get_session()
        session.add(item)
        # todo: flushとは何ぞや
        # session.flush()
        session.commit()


class OhlcPricesDao(DaoBase):
    def __init__(self, currency_pair, period):
        super().__init__()
        self._currency_pair = currency_pair
        self._period = period

    def _get_model(self):
        return OhlcPrices

    def get_record(self, select_query):
        return select_query.order_by(self._Model.time).all()

    def create_data(self, ohlc_prices):
        session = self._get_session()
        try:
            for record in ohlc_prices:
                record['currency_pair'] = self._currency_pair
                record['period'] = self._period
                session.merge(OhlcPrices(**record))
            session.commit()
            session.close()
            return True
        except SQLAlchemyError as e:
            bot_logger.exception(e)
            session.rollback()
            session.close()
        return False

    def get_records(self, end_time, start_time, closed):
        session = self._get_session()
        select_query = session.query(self._Model)
        if closed:
            select_query = select_query.filter(and_(self._Model.time <= end_time,
                                                    self._Model.time > start_time,
                                                    self._Model.currency_pair == self._currency_pair,
                                                    self._Model.period == self._period,
                                                    self._Model.closed == self._CLOSED
                                                    ))
        else:
            select_query = select_query.filter(and_(self._Model.time <= end_time,
                                                    self._Model.time >= start_time,
                                                    self._Model.currency_pair == self._currency_pair,
                                                    self._Model.period == self._period
                                                    ))
        result = select_query.order_by(self._Model.time).all()
        session.close()
        return result


class OrderLogsDao(DaoBase):
    def _get_model(self):
        return OrderLogs

    def create_data(self, order_log):
        session = self._get_session()
        session.merge(OrderLogs(**order_log))
        try:
            session.commit()
            session.close()
            return True
        except SQLAlchemyError as e:
            bot_logger.exception(e)
            session.rollback()
            session.close()
        return False

@@ -580,25 +580,8 @@
 a):%0A
-    _CLOSED = 1%0A%0A
     
@@ -1888,16 +1888,17 @@
 cord
+s
 (self, s
 elec
@@ -1897,665 +1897,44 @@
 f, s
-elect_query):%0A        return select_query.order_by(self._Model.time).all()%0A%0A    def create_data(self, ohlc_prices):%0A        session = self._get_session()%0A        try:%0A            for record in ohlc_prices:%0A                record%5B'currency_pair'%5D = self._currency_pair%0A                record%5B'period'%5D = self._period%0A                session.merge(OhlcPrices(**record))%0A            session.commit()%0A            session.close()%0A            return True%0A        except SQLAlchemyError as e:%0A            bot_logger.exception(e)%0A            session.rollback()%0A            session.close()%0A        return False%0A%0A    def get_records(self, end_time, start_time, clo
+tart_time, end_time, *, closed=Fal
 se
-d
 ):%0A 
@@ -1974,36 +1974,30 @@
 n()%0A        
-select_query
+result
  = session.q
@@ -2017,145 +2017,64 @@
 del)
-%0A        if closed:%0A            select_query = select_query.filter(and_(self._Model.time %3C= end_time,%0A                                   
+.filter(%0A            and_(self._Model.time %3C= end_time,%0A
     
@@ -2121,43 +2121,8 @@
 me,%0A
-                                   
     
@@ -2188,43 +2188,8 @@
 ir,%0A
-                                   
     
@@ -2258,1114 +2258,228 @@
     
-                                   self._Model.closed == self._CLOSED%0A                                                    ))%0A        else:%0A            select_query = select_query.filter(and_(self._Model.time %3C= end_time,%0A                                                    self._Model.time %3E= start_time,%0A                                                    self._Model.currency_pair == self._currency_pair,%0A                                                    self._Model.period == self._period%0A                                                    ))%0A        result = select_query.order_by(self._Model.time).all()%0A        session.close()%0A        return result%0A%0A%0Aclass OrderLogsDao(DaoBase):%0A    def _get_model(self):%0A        return OrderLogs%0A%0A    def create_data(self, order_log):%0A        session = self._get_session()%0A        session.merge(OrderLogs(**order_log))%0A        try:%0A            session.commit()%0A            session.close()%0A            return True%0A        except SQLAlchemyError as e:%0A            bot_logger.exception(e)%0A            session.rollback()%0A            session.close()%0A        return False
+self._Model.closed == int(closed)%0A                 )%0A        ).order_by(self._Model.time).all()%0A        session.close()%0A        return result%0A%0A%0Aclass OrderLogsDao(DaoBase):%0A    def _get_model(self):%0A        return OrderLogs
 %0A

delete not using lines