diff --git a/pytest.ini b/pytest.ini index f518cbb21e23..c01b6d6bb491 100644 --- a/pytest.ini +++ b/pytest.ini @@ -32,7 +32,7 @@ filterwarnings = error:"Query" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning error:"SavedQuery" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning error:"SqlaTable" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning -# error:"SqlMetric" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning + error:"SqlMetric" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning error:"TableColumn" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning error:"TaggedObject" object is being merged into a Session:sqlalchemy.exc.RemovedIn20Warning error:The autoload parameter is deprecated:sqlalchemy.exc.RemovedIn20Warning diff --git a/superset/commands/dataset/duplicate.py b/superset/commands/dataset/duplicate.py index 7ada72690deb..85cfe2904122 100644 --- a/superset/commands/dataset/duplicate.py +++ b/superset/commands/dataset/duplicate.py @@ -101,7 +101,7 @@ def run(self) -> Model: db.session.add_all(columns) table.columns = columns - table.metrics = [ + metrics = [ SqlMetric( metric_name=m.metric_name, verbose_name=m.verbose_name, @@ -115,6 +115,9 @@ def run(self) -> Model: ) for m in self._base_model.metrics ] + db.session.add_all(metrics) + table.metrics = metrics + return table def validate(self) -> None: diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 2987da3f6898..09d9a65a049c 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -401,6 +401,7 @@ def add_missing_metrics(self, metrics: list[SqlMetric]) -> None: for metric in metrics: if metric.metric_name not in existing_metrics: metric.table_id = self.id + db.session.add(metric) self.metrics.append(metric) @property @@ -1207,6 +1208,7 @@ class SqlMetric(AuditMixinNullable, ImportExportMixin, CertificationMixin, Model table: Mapped["SqlaTable"] = relationship( "SqlaTable", back_populates="metrics", + cascade_backrefs=False, ) export_fields = [ @@ -1305,6 +1307,7 @@ class SqlaTable( SqlMetric, back_populates="table", cascade="all, delete-orphan", + cascade_backrefs=False, passive_deletes=True, ) metric_class = SqlMetric diff --git a/superset/examples/birth_names.py b/superset/examples/birth_names.py index 372d974c693c..d7501dbcbde8 100644 --- a/superset/examples/birth_names.py +++ b/superset/examples/birth_names.py @@ -144,7 +144,9 @@ def _add_table_metrics(datasource: SqlaTable) -> None: if not any(col.metric_name == "sum__num" for col in metrics): col = str(column("num").compile(db.engine)) - metrics.append(SqlMetric(metric_name="sum__num", expression="SUM(%s)" % col)) + metric = SqlMetric(metric_name="sum__num", expression="SUM(%s)" % col) + db.session.add(metric) + metrics.append(metric) for col in columns: if col.column_name == "ds": # type: ignore diff --git a/superset/examples/world_bank.py b/superset/examples/world_bank.py index 57413ca28ea3..c81c0b7b5ee6 100644 --- a/superset/examples/world_bank.py +++ b/superset/examples/world_bank.py @@ -107,9 +107,9 @@ def load_world_bank_health_n_pop( # pylint: disable=too-many-locals if not any(col.metric_name == metric for col in tbl.metrics): aggr_func = metric[:3] col = str(column(metric[5:]).compile(db.engine)) - tbl.metrics.append( - SqlMetric(metric_name=metric, expression=f"{aggr_func}({col})") - ) + metric_it = SqlMetric(metric_name=metric, expression=f"{aggr_func}({col})") + db.session.add(metric_it) + tbl.metrics.append(metric_it) tbl.fetch_metadata() diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index 4f282829cd77..2d21c8a62cd7 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -299,7 +299,8 @@ def virtual_dataset(): TableColumn(column_name="col6", type="INTEGER", table=dataset), ] - SqlMetric(metric_name="count", expression="count(*)", table=dataset) + metric = SqlMetric(metric_name="count", expression="count(*)", table=dataset) + db.session.add(metric) db.session.add_all(columns) db.session.add(dataset) db.session.commit() @@ -342,7 +343,8 @@ def virtual_dataset_with_comments(): TableColumn(column_name="col6", type="INTEGER", table=dataset), ] - SqlMetric(metric_name="count", expression="count(*)", table=dataset) + metric = SqlMetric(metric_name="count", expression="count(*)", table=dataset) + db.session.add(metric) db.session.add(dataset) db.session.add_all(columns) db.session.commit() @@ -411,7 +413,8 @@ def physical_dataset(): table=dataset, ), ] - SqlMetric(metric_name="count", expression="count(*)", table=dataset) + metric = SqlMetric(metric_name="count", expression="count(*)", table=dataset) + db.session.add(metric) db.session.add(dataset) db.session.add_all(columns) db.session.commit() @@ -447,7 +450,8 @@ def virtual_dataset_comma_in_column_value(): TableColumn(column_name="col2", type="VARCHAR(255)", table=dataset), ] - SqlMetric(metric_name="count", expression="count(*)", table=dataset) + metric = SqlMetric(metric_name="count", expression="count(*)", table=dataset) + db.session.add(metric) db.session.add(dataset) db.session.add_all(columns) db.session.commit() diff --git a/tests/integration_tests/datasets/api_tests.py b/tests/integration_tests/datasets/api_tests.py index 5c6d8eb7eb2a..f87ca1674ce0 100644 --- a/tests/integration_tests/datasets/api_tests.py +++ b/tests/integration_tests/datasets/api_tests.py @@ -124,6 +124,7 @@ def insert_dataset( db.session.add_all(columns) table.columns = columns if metrics: + db.session.add_all(metrics) table.metrics = metrics db.session.add(table) db.session.commit() diff --git a/tests/integration_tests/db_engine_specs/base_engine_spec_tests.py b/tests/integration_tests/db_engine_specs/base_engine_spec_tests.py index 8ffbaba0701d..ec9ad2dd44f9 100644 --- a/tests/integration_tests/db_engine_specs/base_engine_spec_tests.py +++ b/tests/integration_tests/db_engine_specs/base_engine_spec_tests.py @@ -214,7 +214,7 @@ def test_jinja_calculated_column_in_order_by(self) -> None: SELECT/WHERE/GROUP BY. """ table = self.get_table(name="birth_names") - TableColumn( + column = TableColumn( column_name="gender_cc_jinja", type="VARCHAR(255)", table=table, @@ -225,6 +225,7 @@ def test_jinja_calculated_column_in_order_by(self) -> None: end """, ) + db.session.add(column) table.database.sqlalchemy_uri = "sqlite://" query_obj: QueryObjectDict = { diff --git a/tests/integration_tests/fixtures/energy_dashboard.py b/tests/integration_tests/fixtures/energy_dashboard.py index 78425e2c8a95..054b60155072 100644 --- a/tests/integration_tests/fixtures/energy_dashboard.py +++ b/tests/integration_tests/fixtures/energy_dashboard.py @@ -80,9 +80,9 @@ def _create_energy_table() -> list[Slice]: if not any(col.metric_name == "sum__value" for col in table.metrics): col = str(column("value").compile(db.engine)) - table.metrics.append( - SqlMetric(metric_name="sum__value", expression=f"SUM({col})") - ) + metric = SqlMetric(metric_name="sum__value", expression=f"SUM({col})") + db.session.add(metric) + table.metrics.append(metric) table.fetch_metadata() slices = [] diff --git a/tests/integration_tests/sqla_models_tests.py b/tests/integration_tests/sqla_models_tests.py index 298fdeb785b9..380e646881f3 100644 --- a/tests/integration_tests/sqla_models_tests.py +++ b/tests/integration_tests/sqla_models_tests.py @@ -182,12 +182,13 @@ def test_jinja_metrics_and_calc_columns(self, mock_username: MagicMock) -> None: type="VARCHAR(100)", table=table, ) - SqlMetric( + metric = SqlMetric( metric_name="count_timegrain", expression="count('{{ 'bar_' + time_grain }}')", table=table, ) db.session.add(column) + db.session.add(metric) db.session.commit() sqla_query = table.get_sqla_query(**base_query_obj) @@ -215,6 +216,7 @@ def test_jinja_metric_macro(self, mock_dataset_id_from_context): metric = SqlMetric( metric_name="count_jinja_metric", expression="count(*)", table=table ) + db.session.add(metric) db.session.commit() base_query_obj = { @@ -557,8 +559,9 @@ def text_column_table(app_context: AppContext): database=get_example_database(), ) column = TableColumn(column_name="foo", type="VARCHAR(255)", table=table) - SqlMetric(metric_name="count", expression="count(*)", table=table) + metric = SqlMetric(metric_name="count", expression="count(*)", table=table) db.session.add(column) + db.session.add(metric) return table @@ -738,7 +741,8 @@ def test_should_generate_closed_and_open_time_filter_range(login_as_admin): is_dttm=True, ) db.session.add(column) - SqlMetric(metric_name="count", expression="count(*)", table=table) + metric = SqlMetric(metric_name="count", expression="count(*)", table=table) + db.session.add(metric) result_object = table.query( { "metrics": ["count"], @@ -1016,17 +1020,17 @@ def test_extra_cache_keys_in_dataset_metrics_and_columns( ), ] db.session.add_all(columns) + metric = SqlMetric( + metric_name="variable_profit", + expression="SUM(price) * {{ url_param('multiplier') }}", + ) + db.session.add(metric) table = SqlaTable( table_name="test_has_no_extra_cache_keys_table", sql="SELECT 'abc' as user", database=get_example_database(), columns=columns, - metrics=[ - SqlMetric( - metric_name="variable_profit", - expression="SUM(price) * {{ url_param('multiplier') }}", - ), - ], + metrics=[metric], ) query_obj: dict[str, Any] = { "granularity": None, @@ -1189,6 +1193,7 @@ def test_generic_metric_filtering_without_chart_flag(login_as_admin): expression="COUNT(*)", table=table, ) + db.session.add(metric) table.metrics = [metric] db.session.add(table) @@ -1247,6 +1252,7 @@ def test_column_ordering_without_chart_flag(login_as_admin): metric_x = SqlMetric(metric_name="metric_x", expression="COUNT(*)", table=table) metric_y = SqlMetric(metric_name="metric_y", expression="SUM(val)", table=table) + db.session.add_all([metric_x, metric_y]) table.metrics = [metric_x, metric_y] db.session.add(table)