diff --git a/app/dbmanager.py b/app/dbmanager.py index 52ec902..9f8c2ca 100644 --- a/app/dbmanager.py +++ b/app/dbmanager.py @@ -18,6 +18,7 @@ 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() DatabaseManager.__instance = self else: raise Exception("Attempted to create a second DatabaseManager instance") diff --git a/app/dbtables.py b/app/dbtables.py index c12b8cc..f19b928 100644 --- a/app/dbtables.py +++ b/app/dbtables.py @@ -48,9 +48,11 @@ class PlaydatesTable(Model): id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) lastplayed: Mapped[dt.datetime] = mapped_column(index=True) - track_id: Mapped[int] = mapped_column(ForeignKey("tracks.id")) + track_id: Mapped[int] = mapped_column(ForeignKey("tracks.id", ondelete="CASCADE")) track: Mapped["TracksTable"] = relationship( - "TracksTable", back_populates="playdates" + "TracksTable", + back_populates="playdates", + cascade="all, delete-orphan", ) def __repr__(self) -> str: @@ -103,10 +105,11 @@ class PlaylistRowsTable(Model): ) playlist: Mapped[PlaylistsTable] = relationship(back_populates="rows") - track_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tracks.id")) + track_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tracks.id", ondelete="CASCADE")) track: Mapped["TracksTable"] = relationship( "TracksTable", back_populates="playlistrows", + cascade="all, delete-orphan", ) played: Mapped[bool] = mapped_column( Boolean, nullable=False, index=False, default=False @@ -127,7 +130,9 @@ class QueriesTable(Model): query: Mapped[str] = mapped_column( String(2048), index=False, default="", nullable=False ) - playlist_id: Mapped[int] = mapped_column(ForeignKey("playlists.id"), index=True) + playlist_id: Mapped[int] = mapped_column( + ForeignKey("playlists.id", ondelete="CASCADE"), index=True + ) playlist: Mapped[PlaylistsTable] = relationship(back_populates="query") def __repr__(self) -> str: diff --git a/app/models.py b/app/models.py index a4443e3..49c79a3 100644 --- a/app/models.py +++ b/app/models.py @@ -36,7 +36,6 @@ if DATABASE_URL is None: if "unittest" in sys.modules and "sqlite" not in DATABASE_URL: raise ValueError("Unit tests running on non-Sqlite database") db = DatabaseManager.get_instance(DATABASE_URL, engine_options=Config.ENGINE_OPTIONS).db -# db.create_all() # Database classes diff --git a/migrations/env.py b/migrations/env.py deleted file mode 100644 index 027fd36..0000000 --- a/migrations/env.py +++ /dev/null @@ -1,27 +0,0 @@ -from importlib import import_module -from alembic import context -from alchemical.alembic.env import run_migrations - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# import the application's Alchemical instance -try: - import_mod, db_name = config.get_main_option('alchemical_db', '').split( - ':') - db = getattr(import_module(import_mod), db_name) -except (ModuleNotFoundError, AttributeError): - raise ValueError( - 'Could not import the Alchemical database instance. ' - 'Ensure that the alchemical_db setting in alembic.ini is correct.' - ) - -# run the migration engine -# The dictionary provided as second argument includes options to pass to the -# Alembic context. For details on what other options are available, see -# https://alembic.sqlalchemy.org/en/latest/autogenerate.html -run_migrations(db, { - 'render_as_batch': True, - 'compare_type': True, -}) diff --git a/migrations/env.py b/migrations/env.py new file mode 120000 index 0000000..200c230 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1 @@ +env.py.DEBUG \ No newline at end of file diff --git a/migrations/env.py.NODEBUG b/migrations/env.py.NODEBUG new file mode 100644 index 0000000..027fd36 --- /dev/null +++ b/migrations/env.py.NODEBUG @@ -0,0 +1,27 @@ +from importlib import import_module +from alembic import context +from alchemical.alembic.env import run_migrations + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# import the application's Alchemical instance +try: + import_mod, db_name = config.get_main_option('alchemical_db', '').split( + ':') + db = getattr(import_module(import_mod), db_name) +except (ModuleNotFoundError, AttributeError): + raise ValueError( + 'Could not import the Alchemical database instance. ' + 'Ensure that the alchemical_db setting in alembic.ini is correct.' + ) + +# run the migration engine +# The dictionary provided as second argument includes options to pass to the +# Alembic context. For details on what other options are available, see +# https://alembic.sqlalchemy.org/en/latest/autogenerate.html +run_migrations(db, { + 'render_as_batch': True, + 'compare_type': True, +}) diff --git a/migrations/versions/014f2d4c88a5_add_data_for_query_playlists.py b/migrations/versions/014f2d4c88a5_add_data_for_query_playlists.py deleted file mode 100644 index 7562809..0000000 --- a/migrations/versions/014f2d4c88a5_add_data_for_query_playlists.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Add data for query playlists - -Revision ID: 014f2d4c88a5 -Revises: 33c04e3c12c8 -Create Date: 2024-12-30 14:23:36.924478 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '014f2d4c88a5' -down_revision = '33c04e3c12c8' -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('query', sa.String(length=2048), nullable=False), - sa.Column('playlist_id', sa.Integer(), nullable=False), - sa.ForeignKeyConstraint(['playlist_id'], ['playlists.id'], ), - sa.PrimaryKeyConstraint('id') - ) - with op.batch_alter_table('queries', schema=None) as batch_op: - batch_op.create_index(batch_op.f('ix_queries_playlist_id'), ['playlist_id'], unique=False) - - # ### end Alembic commands ### - - -def downgrade_() -> None: - # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table('queries', schema=None) as batch_op: - batch_op.drop_index(batch_op.f('ix_queries_playlist_id')) - - op.drop_table('queries') - # ### end Alembic commands ### - diff --git a/migrations/versions/c76e865ccb85_index_for_notesolours_substring.py b/migrations/versions/c76e865ccb85_index_for_notesolours_substring.py new file mode 100644 index 0000000..6850c31 --- /dev/null +++ b/migrations/versions/c76e865ccb85_index_for_notesolours_substring.py @@ -0,0 +1,68 @@ +"""Index for notesolours substring + +Revision ID: c76e865ccb85 +Revises: 33c04e3c12c8 +Create Date: 2025-02-07 18:21:01.760057 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'c76e865ccb85' +down_revision = '33c04e3c12c8' +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! ### + with op.batch_alter_table('notecolours', schema=None) as batch_op: + batch_op.create_index(batch_op.f('ix_notecolours_substring'), ['substring'], unique=False) + + with op.batch_alter_table('playdates', schema=None) as batch_op: + batch_op.drop_constraint('fk_playdates_track_id_tracks', type_='foreignkey') + batch_op.create_foreign_key(None, 'tracks', ['track_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('playlist_rows', schema=None) as batch_op: + batch_op.drop_constraint('playlist_rows_ibfk_1', type_='foreignkey') + batch_op.create_foreign_key(None, 'tracks', ['track_id'], ['id'], ondelete='CASCADE') + + with op.batch_alter_table('queries', schema=None) as batch_op: + batch_op.drop_constraint('fk_queries_playlist_id_playlists', type_='foreignkey') + batch_op.create_foreign_key(None, 'playlists', ['playlist_id'], ['id'], ondelete='CASCADE') + + # ### end Alembic commands ### + + +def downgrade_() -> None: + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('queries', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key('fk_queries_playlist_id_playlists', 'playlists', ['playlist_id'], ['id']) + + with op.batch_alter_table('playlist_rows', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key('playlist_rows_ibfk_1', 'tracks', ['track_id'], ['id']) + + with op.batch_alter_table('playdates', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.create_foreign_key('fk_playdates_track_id_tracks', 'tracks', ['track_id'], ['id']) + + with op.batch_alter_table('notecolours', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_notecolours_substring')) + + # ### end Alembic commands ### +