Update model to new sqlalchemy version

This commit is contained in:
Matthias
2024-02-07 07:21:16 +01:00
parent 4700782f60
commit 8f9f4b40cd
4 changed files with 28 additions and 22 deletions

View File

@@ -1,14 +1,15 @@
from datetime import datetime from datetime import datetime
from typing import Optional from typing import ClassVar, Optional
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, Text, UniqueConstraint from sqlalchemy import DateTime, ForeignKey, Integer, String, Text, UniqueConstraint, select
from sqlalchemy.orm import Query, relationship from sqlalchemy.orm import Mapped, Query, mapped_column, relationship
from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.constants import DATETIME_PRINT_FORMAT
from freqtrade.persistence.base import _DECL_BASE from freqtrade.persistence.base import ModelBase, SessionType
from freqtrade.util import dt_now
class CustomData(_DECL_BASE): class CustomData(ModelBase):
""" """
CustomData database model CustomData database model
Keeps records of metadata as key/value store Keeps records of metadata as key/value store
@@ -18,20 +19,22 @@ class CustomData(_DECL_BASE):
- One metadata entry can only be associated with one Trade - One metadata entry can only be associated with one Trade
""" """
__tablename__ = 'trade_custom_data' __tablename__ = 'trade_custom_data'
session: ClassVar[SessionType]
# Uniqueness should be ensured over pair, order_id # Uniqueness should be ensured over pair, order_id
# its likely that order_id is unique per Pair on some exchanges. # its likely that order_id is unique per Pair on some exchanges.
__table_args__ = (UniqueConstraint('ft_trade_id', 'cd_key', name="_trade_id_cd_key"),) __table_args__ = (UniqueConstraint('ft_trade_id', 'cd_key', name="_trade_id_cd_key"),)
id = Column(Integer, primary_key=True) id = mapped_column(Integer, primary_key=True)
ft_trade_id = Column(Integer, ForeignKey('trades.id'), index=True, default=0) ft_trade_id = mapped_column(Integer, ForeignKey('trades.id'), index=True, default=0)
trade = relationship("Trade", back_populates="custom_data") trade = relationship("Trade", back_populates="custom_data")
cd_key = Column(String(255), nullable=False) cd_key: Mapped[str] = mapped_column(String(255), nullable=False)
cd_type = Column(String(25), nullable=False) cd_type: Mapped[str] = mapped_column(String(25), nullable=False)
cd_value = Column(Text, nullable=False) cd_value: Mapped[str] = mapped_column(Text, nullable=False)
created_at = Column(DateTime, nullable=False, default=datetime.utcnow) created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=dt_now)
updated_at = Column(DateTime, nullable=True) updated_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
def __repr__(self): def __repr__(self):
create_time = (self.created_at.strftime(DATETIME_PRINT_FORMAT) create_time = (self.created_at.strftime(DATETIME_PRINT_FORMAT)
@@ -54,4 +57,4 @@ class CustomData(_DECL_BASE):
if key is not None: if key is not None:
filters.append(CustomData.cd_key.ilike(key)) filters.append(CustomData.cd_key.ilike(key))
return CustomData.query.filter(*filters) return CustomData.session.scalars(select(CustomData))

View File

@@ -3,6 +3,8 @@ import logging
from datetime import datetime from datetime import datetime
from typing import Any, List, Optional from typing import Any, List, Optional
from sqlalchemy import select
from freqtrade.persistence.custom_data import CustomData from freqtrade.persistence.custom_data import CustomData
@@ -86,8 +88,8 @@ class CustomDataWrapper:
if CustomDataWrapper.use_db and value_db is not None: if CustomDataWrapper.use_db and value_db is not None:
data_entry.cd_value = value_db data_entry.cd_value = value_db
CustomData.query.session.add(data_entry) CustomData.session.add(data_entry)
CustomData.query.session.commit() CustomData.session.commit()
elif not CustomDataWrapper.use_db: elif not CustomDataWrapper.use_db:
cd_index = -1 cd_index = -1
for index, data_entry in enumerate(CustomDataWrapper.custom_data): for index, data_entry in enumerate(CustomDataWrapper.custom_data):
@@ -97,7 +99,7 @@ class CustomDataWrapper:
if cd_index >= 0: if cd_index >= 0:
data_entry.cd_type = value_type data_entry.cd_type = value_type
data_entry.value = value data_entry.cd_value = value
data_entry.updated_at = datetime.utcnow() data_entry.updated_at = datetime.utcnow()
CustomDataWrapper.custom_data[cd_index] = data_entry CustomDataWrapper.custom_data[cd_index] = data_entry
@@ -108,6 +110,6 @@ class CustomDataWrapper:
def get_all_custom_data() -> List[CustomData]: def get_all_custom_data() -> List[CustomData]:
if CustomDataWrapper.use_db: if CustomDataWrapper.use_db:
return CustomData.query.all() return CustomData.session.scalars(select(CustomData)).all()
else: else:
return CustomDataWrapper.custom_data return CustomDataWrapper.custom_data

View File

@@ -1467,7 +1467,8 @@ class Trade(ModelBase, LocalTrade):
orders: Mapped[List[Order]] = relationship( orders: Mapped[List[Order]] = relationship(
"Order", order_by="Order.id", cascade="all, delete-orphan", lazy="selectin", "Order", order_by="Order.id", cascade="all, delete-orphan", lazy="selectin",
innerjoin=True) # type: ignore innerjoin=True) # type: ignore
custom_data = relationship("CustomData", order_by="CustomData.id", cascade="all, delete-orphan") custom_data: Mapped[List[CustomData]] = relationship(
"CustomData", order_by="CustomData.id", cascade="all, delete-orphan") # type: ignore
exchange: Mapped[str] = mapped_column(String(25), nullable=False) # type: ignore exchange: Mapped[str] = mapped_column(String(25), nullable=False) # type: ignore
pair: Mapped[str] = mapped_column(String(25), nullable=False, index=True) # type: ignore pair: Mapped[str] = mapped_column(String(25), nullable=False, index=True) # type: ignore

View File

@@ -1770,7 +1770,7 @@ class Telegram(RPCHandler):
) )
@authorized_only @authorized_only
def _list_custom_data(self, update: Update, context: CallbackContext) -> None: async def _list_custom_data(self, update: Update, context: CallbackContext) -> None:
""" """
Handler for /list_custom_data <id> <key>. Handler for /list_custom_data <id> <key>.
List custom_data for specified trade (and key if supplied). List custom_data for specified trade (and key if supplied).
@@ -1807,14 +1807,14 @@ class Telegram(RPCHandler):
msg = "Message dropped because length exceeds " msg = "Message dropped because length exceeds "
msg += f"maximum allowed characters: {MAX_MESSAGE_LENGTH}" msg += f"maximum allowed characters: {MAX_MESSAGE_LENGTH}"
logger.warning(msg) logger.warning(msg)
self._send_msg(msg) await self._send_msg(msg)
else: else:
message = f"Didn't find any custom-data entries for Trade ID: `{trade_id}`" message = f"Didn't find any custom-data entries for Trade ID: `{trade_id}`"
message += f" and Key: `{key}`." if key is not None else "" message += f" and Key: `{key}`." if key is not None else ""
self._send_msg(message) await self._send_msg(message)
except RPCException as e: except RPCException as e:
self._send_msg(str(e)) await self._send_msg(str(e))
async def _update_msg(self, query: CallbackQuery, msg: str, callback_path: str = "", async def _update_msg(self, query: CallbackQuery, msg: str, callback_path: str = "",
reload_able: bool = False, parse_mode: str = ParseMode.MARKDOWN) -> None: reload_able: bool = False, parse_mode: str = ParseMode.MARKDOWN) -> None: