From 915cb11d573ca7ddd02cdb9b6188f1266e7aa27e Mon Sep 17 00:00:00 2001 From: John Davis Date: Fri, 31 Mar 2023 18:07:10 -0400 Subject: [PATCH] Drop views --- lib/galaxy/model/mapping.py | 2 - lib/galaxy/model/view/__init__.py | 78 --------------------------- lib/galaxy/model/view/utils.py | 75 -------------------------- test/unit/data/model/test_views.py | 84 ------------------------------ 4 files changed, 239 deletions(-) delete mode 100644 lib/galaxy/model/view/__init__.py delete mode 100644 lib/galaxy/model/view/utils.py delete mode 100644 test/unit/data/model/test_views.py diff --git a/lib/galaxy/model/mapping.py b/lib/galaxy/model/mapping.py index 2f0b8752d39f..48c718388766 100644 --- a/lib/galaxy/model/mapping.py +++ b/lib/galaxy/model/mapping.py @@ -12,7 +12,6 @@ from galaxy.model.orm.engine_factory import build_engine from galaxy.model.security import GalaxyRBACAgent from galaxy.model.triggers.update_audit_table import install as install_timestamp_triggers -from galaxy.model.view.utils import install_views log = logging.getLogger(__name__) @@ -66,7 +65,6 @@ def init( def create_additional_database_objects(engine): install_timestamp_triggers(engine) - install_views(engine) def configure_model_mapping( diff --git a/lib/galaxy/model/view/__init__.py b/lib/galaxy/model/view/__init__.py deleted file mode 100644 index 04fd7d648709..000000000000 --- a/lib/galaxy/model/view/__init__.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Galaxy sql view models -""" -from sqlalchemy import Integer -from sqlalchemy.orm import registry -from sqlalchemy.sql import ( - column, - text, -) - -from galaxy.model.view.utils import View - - -class HistoryDatasetCollectionJobStateSummary(View): - name = "collection_job_state_summary_view" - - aggregate_state_query = """ -SELECT - hdca_id, - SUM(CASE WHEN state = 'new' THEN 1 ELSE 0 END) AS new, - SUM(CASE WHEN state = 'resubmitted' THEN 1 ELSE 0 END) AS resubmitted, - SUM(CASE WHEN state = 'waiting' THEN 1 ELSE 0 END) AS waiting, - SUM(CASE WHEN state = 'queued' THEN 1 ELSE 0 END) AS queued, - SUM(CASE WHEN state = 'running' THEN 1 ELSE 0 END) AS running, - SUM(CASE WHEN state = 'ok' THEN 1 ELSE 0 END) AS ok, - SUM(CASE WHEN state = 'error' THEN 1 ELSE 0 END) AS error, - SUM(CASE WHEN state = 'failed' THEN 1 ELSE 0 END) AS failed, - SUM(CASE WHEN state = 'paused' THEN 1 ELSE 0 END) AS paused, - SUM(CASE WHEN state = 'skipped' THEN 1 ELSE 0 END) AS skipped, - SUM(CASE WHEN state = 'deleted' THEN 1 ELSE 0 END) AS deleted, - SUM(CASE WHEN state = 'deleted_new' THEN 1 ELSE 0 END) AS deleted_new, - SUM(CASE WHEN state = 'upload' THEN 1 ELSE 0 END) AS upload, - SUM(CASE WHEN job_id IS NOT NULL THEN 1 ELSE 0 END) AS all_jobs -FROM ( - SELECT hdca.id AS hdca_id, job.id AS job_id, job.state as state - FROM history_dataset_collection_association hdca - LEFT JOIN implicit_collection_jobs icj - ON icj.id = hdca.implicit_collection_jobs_id - LEFT JOIN implicit_collection_jobs_job_association icjja - ON icj.id = icjja.implicit_collection_jobs_id - LEFT JOIN job - ON icjja.job_id = job.id - - UNION - - SELECT hdca.id AS hdca_id, job.id AS job_id, job.state AS state - FROM history_dataset_collection_association hdca - LEFT JOIN job - ON hdca.job_id = job.id -) jobstates -GROUP BY jobstates.hdca_id -""" - - __view__ = text(aggregate_state_query).columns( - column("hdca_id", Integer), - column("new", Integer), - column("resubmitted", Integer), - column("waiting", Integer), - column("queued", Integer), - column("running", Integer), - column("ok", Integer), - column("error", Integer), - column("failed", Integer), - column("paused", Integer), - column("skipped", Integer), - column("deleted", Integer), - column("deleted_new", Integer), - column("upload", Integer), - column("all_jobs", Integer), - ) - pkeys = {"hdca_id"} - __table__ = View._make_table(name, __view__, pkeys) - - -mapper_registry = registry() -mapper_registry.map_imperatively( - HistoryDatasetCollectionJobStateSummary, HistoryDatasetCollectionJobStateSummary.__table__ -) diff --git a/lib/galaxy/model/view/utils.py b/lib/galaxy/model/view/utils.py deleted file mode 100644 index 14c4cbca8dba..000000000000 --- a/lib/galaxy/model/view/utils.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -View wrappers -""" -from inspect import getmembers - -from sqlalchemy import ( - Column, - MetaData, - Table, -) -from sqlalchemy.ext import compiler -from sqlalchemy.schema import DDLElement - - -class View: - """Base class for Views.""" - - @staticmethod - def _make_table(name, selectable, pkeys): - """Create a view. - - :param name: The name of the view. - :param selectable: SQLAlchemy selectable. - :param pkeys: set of primary keys for the selectable. - """ - columns = [Column(c.name, c.type, primary_key=(c.name in pkeys)) for c in selectable.subquery().columns] - # We do not use the metadata object from model.mapping.py that contains all the Table objects - # because that would create a circular import (create_view is called from View objects - # in model.view; but those View objects are imported into model.mapping.py where the - # metadata object we need is defined). Thus, we do not use the after_create/before_drop - # hooks to automate creating/dropping views. Instead, this is taken care of in install_views(). - - # The metadata object passed to Table() should be empty: this table is internal to a View - # object and is not intended to be created in the database. - return Table(name, MetaData(), *columns) - - -class CreateView(DDLElement): - def __init__(self, name, selectable): - self.name = name - self.selectable = selectable - - -class DropView(DDLElement): - def __init__(self, name): - self.name = name - - -@compiler.compiles(CreateView) -def compile_create_view(element, compiler, **kw): - compiled_selectable = compiler.sql_compiler.process(element.selectable, literal_binds=True) - return f"CREATE VIEW {element.name} AS {compiled_selectable}" - - -@compiler.compiles(DropView) -def compile_drop_view(element, compiler, **kw): - return f"DROP VIEW IF EXISTS {element.name}" - - -def is_view_model(o): - return hasattr(o, "__view__") and issubclass(o, View) - - -def install_views(engine): - import galaxy.model.view - - views = getmembers(galaxy.model.view, is_view_model) - for _, view in views: - # adding DropView here because our unit-testing calls this function when - # it mocks the app and CreateView will attempt to rebuild an existing - # view in a database that is already made, the right answer is probably - # to change the sql that gest emitted when CreateView is rendered. - with engine.begin() as conn: - conn.execute(DropView(view.name)) - conn.execute(CreateView(view.name, view.__view__)) diff --git a/test/unit/data/model/test_views.py b/test/unit/data/model/test_views.py deleted file mode 100644 index 433c24eb6522..000000000000 --- a/test/unit/data/model/test_views.py +++ /dev/null @@ -1,84 +0,0 @@ -import pytest -from sqlalchemy import ( - Column, - Integer, - MetaData, - Table, -) -from sqlalchemy.sql import ( - column, - text, -) - -from galaxy.model.database_utils import ( - create_database, - sqlalchemy_engine, -) -from galaxy.model.unittest_utils.model_testing_utils import ( - drop_database, - replace_database_in_url, - skip_if_not_mysql_uri, - skip_if_not_postgres_uri, -) -from galaxy.model.view.utils import ( - CreateView, - View, -) - - -@pytest.fixture -def view(): - # A View class we would add to galaxy.model.view - class TestView(View): - name = "testview" - __view__ = text("SELECT id, foo FROM testfoo").columns(column("id", Integer), column("foo", Integer)) - pkeys = {"id"} - View._make_table(name, __view__, pkeys) - - return TestView - - -@skip_if_not_postgres_uri -def test_postgres_create_view(database_name, postgres_url, view): - metadata = MetaData() - make_table(metadata) # table from which the view will select - url = replace_database_in_url(postgres_url, database_name) - query = f"SELECT 1 FROM information_schema.views WHERE table_name = '{view.name}'" - create_database(postgres_url, database_name) - run_view_test(url, metadata, view, query) - drop_database(postgres_url, database_name) - - -def test_sqlite_create_view(sqlite_memory_url, view): - metadata = MetaData() - make_table(metadata) # table from which the view will select - url = sqlite_memory_url - query = f"SELECT 1 FROM sqlite_master WHERE type='view' AND name='{view.name}'" - run_view_test(url, metadata, view, query) - - -@skip_if_not_mysql_uri -def test_mysql_create_view(database_name, mysql_url, view): - metadata = MetaData() - make_table(metadata) # table from which the view will select - url = replace_database_in_url(mysql_url, database_name) - query = f"SELECT 1 FROM information_schema.views WHERE table_name = '{view.name}'" - create_database(mysql_url, database_name) - run_view_test(url, metadata, view, query) - drop_database(mysql_url, database_name) - - -def make_table(metadata): - users = Table( - "testfoo", metadata, Column("id", Integer, primary_key=True), Column("foo", Integer), Column("bar", Integer) - ) - return users - - -def run_view_test(url, metadata, view, query): - with sqlalchemy_engine(url) as engine: - with engine.begin() as conn: - metadata.create_all(conn) # create table in database - conn.execute(CreateView(view.name, view.__view__)) # create view in database - result = conn.execute(text(query)).fetchall() - assert len(result) == 1 # assert that view exists in database