Address comments

This commit is contained in:
Beto Dealmeida
2026-03-10 11:22:10 -04:00
parent a9ece0b151
commit 4d377537e2
5 changed files with 33 additions and 49 deletions

View File

@@ -21,7 +21,7 @@ from abc import ABC, abstractmethod
from typing import Any, Generic, TypeVar from typing import Any, Generic, TypeVar
from pydantic import BaseModel from pydantic import BaseModel
from superset_core.semantic_layers.semantic_view import SemanticView from superset_core.semantic_layers.view import SemanticView
ConfigT = TypeVar("ConfigT", bound=BaseModel) ConfigT = TypeVar("ConfigT", bound=BaseModel)
SemanticViewT = TypeVar("SemanticViewT", bound="SemanticView") SemanticViewT = TypeVar("SemanticViewT", bound="SemanticView")

View File

@@ -25,29 +25,6 @@ from typing import Type as TypeOf
import pyarrow as pa import pyarrow as pa
__all__ = [
"BINARY",
"BOOLEAN",
"DATE",
"DATETIME",
"DECIMAL",
"Day",
"Dimension",
"Hour",
"INTEGER",
"INTERVAL",
"Minute",
"Month",
"NUMBER",
"OBJECT",
"Quarter",
"Second",
"STRING",
"TIME",
"Week",
"Year",
]
class Type: class Type:
""" """
@@ -216,7 +193,7 @@ class Metric:
name: str name: str
type: TypeOf[Type] type: TypeOf[Type]
definition: str | None definition: str | None = None
description: str | None = None description: str | None = None

View File

@@ -77,7 +77,7 @@ class SemanticView(ABC):
""" """
@abstractmethod @abstractmethod
def get_dataframe( def get_table(
self, self,
metrics: list[Metric], metrics: list[Metric],
dimensions: list[Dimension], dimensions: list[Dimension],
@@ -107,3 +107,23 @@ class SemanticView(ABC):
""" """
Execute a query and return the number of rows the result would have. Execute a query and return the number of rows the result would have.
""" """
@abstractmethod
def get_compatible_metrics(
self,
selected_metrics: set[Metric],
selected_dimensions: set[Dimension],
) -> set[Metric]:
"""
Return metrics compatible with the selected dimensions.
"""
@abstractmethod
def get_compatible_dimensions(
self,
selected_metrics: set[Metric],
selected_dimensions: set[Dimension],
) -> set[Dimension]:
"""
Return dimensions compatible with the selected metrics.
"""

View File

@@ -30,7 +30,6 @@ from typing import Any, cast, Sequence, TypeGuard
import numpy as np import numpy as np
import pyarrow as pa import pyarrow as pa
from superset_core.semantic_layers.semantic_view import SemanticViewFeature
from superset_core.semantic_layers.types import ( from superset_core.semantic_layers.types import (
AdhocExpression, AdhocExpression,
Day, Day,
@@ -54,6 +53,7 @@ from superset_core.semantic_layers.types import (
Week, Week,
Year, Year,
) )
from superset_core.semantic_layers.view import SemanticViewFeature
from superset.common.db_query_status import QueryStatus from superset.common.db_query_status import QueryStatus
from superset.common.query_object import QueryObject from superset.common.query_object import QueryObject
@@ -348,8 +348,6 @@ def map_query_object(query_object: ValidatedQueryObject) -> list[SemanticQuery]:
time_offset, time_offset,
all_dimensions, all_dimensions,
) )
print(">>", filters)
queries.append( queries.append(
SemanticQuery( SemanticQuery(
metrics=metrics, metrics=metrics,
@@ -603,8 +601,8 @@ def _convert_query_object_filter(
operator = operator_mapping.get(operator_str) operator = operator_mapping.get(operator_str)
if not operator: if not operator:
# Unknown operator - create adhoc filter # Unknown operator - raise error to prevent unauthorized access
return None raise ValueError(f"Unsupported filter operator: {operator_str}")
return { return {
Filter( Filter(

View File

@@ -22,7 +22,6 @@ import pandas as pd
import pyarrow as pa import pyarrow as pa
import pytest import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from superset_core.semantic_layers.semantic_view import SemanticViewFeature
from superset_core.semantic_layers.types import ( from superset_core.semantic_layers.types import (
AdhocExpression, AdhocExpression,
Day, Day,
@@ -48,6 +47,7 @@ from superset_core.semantic_layers.types import (
Week, Week,
Year, Year,
) )
from superset_core.semantic_layers.view import SemanticViewFeature
from superset.semantic_layers.mapper import ( from superset.semantic_layers.mapper import (
_convert_query_object_filter, _convert_query_object_filter,
@@ -59,12 +59,18 @@ from superset.semantic_layers.mapper import (
_get_order_from_query_object, _get_order_from_query_object,
_get_time_bounds, _get_time_bounds,
_get_time_filter, _get_time_filter,
_normalize_column,
_validate_filters,
_validate_granularity,
_validate_group_limit,
_validate_metrics,
get_results, get_results,
map_query_object, map_query_object,
validate_query_object, validate_query_object,
ValidatedQueryObject, ValidatedQueryObject,
ValidatedQueryObjectFilterClause, ValidatedQueryObjectFilterClause,
) )
from superset.superset_typing import AdhocColumn
from superset.utils.core import FilterOperator from superset.utils.core import FilterOperator
# Alias for convenience # Alias for convenience
@@ -1717,9 +1723,6 @@ def test_normalize_column_adhoc_not_in_dimensions() -> None:
""" """
Test _normalize_column raises error for AdhocColumn with sqlExpression not in dims. Test _normalize_column raises error for AdhocColumn with sqlExpression not in dims.
""" """
from superset.semantic_layers.mapper import _normalize_column
from superset.superset_typing import AdhocColumn
dimension_names = {"category", "region"} dimension_names = {"category", "region"}
adhoc_column: AdhocColumn = { adhoc_column: AdhocColumn = {
"isColumnReference": True, "isColumnReference": True,
@@ -1734,9 +1737,6 @@ def test_normalize_column_adhoc_missing_sql_expression() -> None:
""" """
Test _normalize_column raises error for AdhocColumn without sqlExpression. Test _normalize_column raises error for AdhocColumn without sqlExpression.
""" """
from superset.semantic_layers.mapper import _normalize_column
from superset.superset_typing import AdhocColumn
dimension_names = {"category", "region"} dimension_names = {"category", "region"}
adhoc_column: AdhocColumn = { adhoc_column: AdhocColumn = {
"isColumnReference": True, "isColumnReference": True,
@@ -1750,9 +1750,6 @@ def test_normalize_column_adhoc_valid(mock_datasource: MagicMock) -> None:
""" """
Test _normalize_column with valid AdhocColumn reference. Test _normalize_column with valid AdhocColumn reference.
""" """
from superset.semantic_layers.mapper import _normalize_column
from superset.superset_typing import AdhocColumn
dimension_names = {"category", "region"} dimension_names = {"category", "region"}
adhoc_column: AdhocColumn = { adhoc_column: AdhocColumn = {
"isColumnReference": True, "isColumnReference": True,
@@ -2115,8 +2112,6 @@ def test_validate_metrics_adhoc_error(
""" """
Test validation error for adhoc metrics. Test validation error for adhoc metrics.
""" """
from superset.semantic_layers.mapper import _validate_metrics
mock_datasource = mocker.Mock() mock_datasource = mocker.Mock()
category_dim = Dimension("category", "category", STRING, "category", "Category") category_dim = Dimension("category", "category", STRING, "category", "Category")
sales_metric = Metric("total_sales", "total_sales", NUMBER, "SUM(amount)", "Sales") sales_metric = Metric("total_sales", "total_sales", NUMBER, "SUM(amount)", "Sales")
@@ -2139,7 +2134,6 @@ def test_validate_filters_adhoc_column_error(
""" """
Test validation error for adhoc column in filter. Test validation error for adhoc column in filter.
""" """
from superset.semantic_layers.mapper import _validate_filters
query_object = mocker.Mock() query_object = mocker.Mock()
query_object.filter = [ query_object.filter = [
@@ -2160,7 +2154,6 @@ def test_validate_filters_missing_operator_error(
""" """
Test validation error for filter without operator. Test validation error for filter without operator.
""" """
from superset.semantic_layers.mapper import _validate_filters
query_object = mocker.Mock() query_object = mocker.Mock()
query_object.filter = [ query_object.filter = [
@@ -2481,7 +2474,6 @@ def test_validate_filters_empty(mocker: MockerFixture) -> None:
""" """
Test _validate_filters with empty filter list (the loop doesn't run). Test _validate_filters with empty filter list (the loop doesn't run).
""" """
from superset.semantic_layers.mapper import _validate_filters
query_object = mocker.Mock() query_object = mocker.Mock()
query_object.filter = [] # Empty filter list query_object.filter = [] # Empty filter list
@@ -2494,7 +2486,6 @@ def test_validate_granularity_valid(mocker: MockerFixture) -> None:
""" """
Test _validate_granularity with valid granularity and time grain. Test _validate_granularity with valid granularity and time grain.
""" """
from superset.semantic_layers.mapper import _validate_granularity
mock_datasource = mocker.Mock() mock_datasource = mocker.Mock()
time_dim = Dimension("order_date", "order_date", STRING, "order_date", "Date", Day) time_dim = Dimension("order_date", "order_date", STRING, "order_date", "Date", Day)
@@ -2514,7 +2505,6 @@ def test_validate_group_limit_valid(mocker: MockerFixture) -> None:
""" """
Test _validate_group_limit with valid group limit settings. Test _validate_group_limit with valid group limit settings.
""" """
from superset.semantic_layers.mapper import _validate_group_limit
mock_datasource = mocker.Mock() mock_datasource = mocker.Mock()
category_dim = Dimension("category", "category", STRING, "category", "Category") category_dim = Dimension("category", "category", STRING, "category", "Category")
@@ -2647,7 +2637,6 @@ def test_validate_filters_with_valid_filters(mocker: MockerFixture) -> None:
Test _validate_filters with valid filters that pass validation. Test _validate_filters with valid filters that pass validation.
This covers the branch where the loop completes without raising. This covers the branch where the loop completes without raising.
""" """
from superset.semantic_layers.mapper import _validate_filters
query_object = mocker.Mock() query_object = mocker.Mock()
query_object.filter = [ query_object.filter = [