Create queries table
This commit is contained in:
parent
64ccb485b5
commit
985629446a
@ -18,7 +18,8 @@ class DatabaseManager:
|
||||
def __init__(self, database_url: str, **kwargs: dict) -> None:
|
||||
if DatabaseManager.__instance is None:
|
||||
self.db = Alchemical(database_url, **kwargs)
|
||||
self.db.create_all()
|
||||
# Database managed by Alembic so no create_all() required
|
||||
# self.db.create_all()
|
||||
DatabaseManager.__instance = self
|
||||
else:
|
||||
raise Exception("Attempted to create a second DatabaseManager instance")
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
# Standard library imports
|
||||
from typing import Optional
|
||||
from dataclasses import asdict
|
||||
import datetime as dt
|
||||
import json
|
||||
|
||||
# PyQt imports
|
||||
|
||||
@ -13,13 +15,37 @@ from sqlalchemy import (
|
||||
String,
|
||||
)
|
||||
from sqlalchemy.ext.associationproxy import association_proxy
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.engine.interfaces import Dialect
|
||||
from sqlalchemy.orm import (
|
||||
Mapped,
|
||||
mapped_column,
|
||||
relationship,
|
||||
)
|
||||
from sqlalchemy.types import TypeDecorator, TEXT
|
||||
|
||||
# App imports
|
||||
from classes import Filter
|
||||
|
||||
|
||||
class JSONEncodedDict(TypeDecorator):
|
||||
"""
|
||||
Custom JSON Type for MariaDB (since native JSON type is just LONGTEXT)
|
||||
"""
|
||||
|
||||
impl = TEXT
|
||||
|
||||
def process_bind_param(self, value: dict | None, dialect: Dialect) -> str | None:
|
||||
"""Convert Python dictionary to JSON string before saving."""
|
||||
if value is None:
|
||||
return None
|
||||
return json.dumps(value, default=lambda o: o.__dict__)
|
||||
|
||||
def process_result_value(self, value: str | None, dialect: Dialect) -> dict | None:
|
||||
"""Convert JSON string back to Python dictionary after retrieval."""
|
||||
if value is None:
|
||||
return None
|
||||
return json.loads(value)
|
||||
|
||||
|
||||
# Database classes
|
||||
@ -128,15 +154,24 @@ class QueriesTable(Model):
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||
sql: Mapped[str] = mapped_column(
|
||||
String(2048), index=False, default="", nullable=False
|
||||
)
|
||||
favourite: Mapped[bool] = mapped_column(
|
||||
Boolean, nullable=False, index=False, default=False
|
||||
)
|
||||
_filter_data: Mapped[dict | None] = mapped_column("filter_data", JSONEncodedDict, nullable=True)
|
||||
favourite: Mapped[bool] = mapped_column(Boolean, nullable=False, index=False, default=False)
|
||||
|
||||
def _get_filter(self) -> Filter:
|
||||
"""Convert stored JSON dictionary to a Filter object."""
|
||||
if isinstance(self._filter_data, dict):
|
||||
return Filter(**self._filter_data)
|
||||
return Filter() # Default object if None or invalid data
|
||||
|
||||
def _set_filter(self, value: Filter | None) -> None:
|
||||
"""Convert a Filter object to JSON before storing."""
|
||||
self._filter_data = asdict(value) if isinstance(value, Filter) else None
|
||||
|
||||
# Single definition of `filter`
|
||||
filter = property(_get_filter, _set_filter)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Queries(id={self.id}, name={self.name}, sql={self.sql}>"
|
||||
return f"<QueriesTable(id={self.id}, name={self.name}, filter={self.filter})>"
|
||||
|
||||
|
||||
class SettingsTable(Model):
|
||||
|
||||
@ -608,6 +608,25 @@ class PlaylistRows(dbtables.PlaylistRowsTable):
|
||||
session.connection().execute(stmt, sqla_map)
|
||||
|
||||
|
||||
class Queries(dbtables.QueriesTable):
|
||||
def __init__(
|
||||
self, session: Session, name: str, filter: dbtables.Filter, favourite: bool = False
|
||||
) -> None:
|
||||
"""Create new query"""
|
||||
|
||||
self.name = name
|
||||
self.filter = filter
|
||||
self.favourite = favourite
|
||||
session.add(self)
|
||||
session.commit()
|
||||
|
||||
@classmethod
|
||||
def get_all_queries(cls, session: Session) -> Sequence["Queries"]:
|
||||
"""Returns a list of all queries ordered by name"""
|
||||
|
||||
return session.scalars(select(cls).order_by(cls.name)).all()
|
||||
|
||||
|
||||
class Settings(dbtables.SettingsTable):
|
||||
def __init__(self, session: Session, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
47
migrations/versions/4fc2a9a82ab0_create_queries_table.py
Normal file
47
migrations/versions/4fc2a9a82ab0_create_queries_table.py
Normal file
@ -0,0 +1,47 @@
|
||||
"""create queries table
|
||||
|
||||
Revision ID: 4fc2a9a82ab0
|
||||
Revises: ab475332d873
|
||||
Create Date: 2025-02-26 13:13:25.118489
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import dbtables
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '4fc2a9a82ab0'
|
||||
down_revision = 'ab475332d873'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade(engine_name: str) -> None:
|
||||
globals()["upgrade_%s" % engine_name]()
|
||||
|
||||
|
||||
def downgrade(engine_name: str) -> None:
|
||||
globals()["downgrade_%s" % engine_name]()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def upgrade_() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('queries',
|
||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||
sa.Column('name', sa.String(length=128), nullable=False),
|
||||
sa.Column('filter_data', dbtables.JSONEncodedDict(), nullable=True),
|
||||
sa.Column('favourite', sa.Boolean(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade_() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('queries')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
Loading…
Reference in New Issue
Block a user