Coverage for art_studio_tz/db_sql.py: 76%
50 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-28 09:38 +0200
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-28 09:38 +0200
1"""db_sql.py - SQLAlchemy based DB module"""
2from sqlalchemy import create_engine, Column, Integer, String, DateTime, func, desc
3from sqlalchemy.orm import sessionmaker, declarative_base
4from sqlalchemy.exc import SQLAlchemyError
5from typing import Any, Dict, List, Optional, Callable, cast
7Base = declarative_base()
10class QuoteModel(Base):
11 """SQLAlchemy model for the quotes table."""
12 __tablename__ = "quotes"
14 id = Column(Integer, primary_key=True, autoincrement=True)
15 text = Column(String(1024), nullable=False)
16 author = Column(String(255), nullable=True)
17 timestep = Column(DateTime(timezone=True), server_default=func.now()) # время создания записи
19class DBsql:
20 """SQLAlchemy based database handler
21 """
22 def __init__(self, user: str, password: str, host: str, port: int, database: str):
23 db_url = f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
24 self.engine = create_engine(db_url, echo=False, future=True)
25 Base.metadata.create_all(self.engine)
26 self.Session = sessionmaker(bind=self.engine)
28 def _execute(self, func: Callable, commit: bool = True, default=None):
29 """
30 unified method to handle session lifecycle and errors
31 """
32 session = self.Session()
33 try:
34 result = func(session)
35 if commit:
36 session.commit()
37 return result
38 except SQLAlchemyError as e:
39 session.rollback()
40 print(f"Database error: {e}")
41 return default
42 finally:
43 session.close()
45 def create(self, item: Dict[str, Any]) -> Optional[int]:
46 """create a new quote record
48 Args:
49 item (Dict[str, Any]): quote data
51 Returns:
52 Optional[int]: new record id or None if error
53 """
54 def _create(session):
55 quote = QuoteModel(**item)
56 session.add(quote)
57 return quote.id
58 return self._execute(_create)
60 def read_all(self) -> List[Dict[str, Any]]:
61 """Read all quote records
63 Returns:
64 List[Dict[str, Any]]: list of dictionary with quote data
65 """
66 def _read_all(session):
67 quotes = session.query(QuoteModel).all()
68 return [{c.name: getattr(q, c.name) for c in q.__table__.columns} for q in quotes]
69 return cast(List[Dict[str, Any]], self._execute(_read_all, commit=False, default=[]))
71 def delete_all(self) -> bool:
72 def _delete_all(session):
73 session.query(QuoteModel).delete()
74 return True
75 return cast(bool, self._execute(_delete_all, default=False))
77 def get_latest(self, n: int = 5) -> List[Dict[str, Any]]:
78 """ Get latest n quotes
80 Args:
81 n (int, optional): Number of quotes to get. Defaults to 5.
83 Returns:
84 List[Dict[str, Any]]: list of dictionary with quote data
85 """
86 def _latest(session):
87 quotes = session.query(QuoteModel).order_by(desc(QuoteModel.timestep)).limit(n).all()
88 return [{c.name: getattr(q, c.name) for c in q.__table__.columns} for q in quotes]
89 return cast(List[Dict[str, Any]], self._execute(_latest, commit=False, default=[]))