This is an automated email from the ASF dual-hosted git repository. beto pushed a commit to branch explorable in repository https://gitbox.apache.org/repos/asf/superset.git
commit dfc6aad5f07b050b47412496fb3b283f1ec264c4 Author: Beto Dealmeida <[email protected]> AuthorDate: Fri Oct 17 14:38:31 2025 -0400 Working on GroupFilter --- superset/semantic_layers/snowflake_.py | 56 ++++++++++++++++++++++++++++++++-- superset/semantic_layers/types.py | 18 +++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/superset/semantic_layers/snowflake_.py b/superset/semantic_layers/snowflake_.py index c86305934e..15eb8c1048 100644 --- a/superset/semantic_layers/snowflake_.py +++ b/superset/semantic_layers/snowflake_.py @@ -47,12 +47,14 @@ from superset.semantic_layers.types import ( Dimension, Filter, FilterValues, + GroupLimit, INTEGER, Metric, NativeFilter, NUMBER, OBJECT, Operator, + OrderDirection, PredicateType, STRING, TIME, @@ -608,8 +610,11 @@ class SnowflakeExplorable: metrics: list[Metric], dimensions: list[Dimension], filters: set[Filter | NativeFilter] | None = None, + order: list[tuple[Metric | Dimension, OrderDirection]] | None = None, limit: int | None = None, offset: int | None = None, + *, + group_limit: GroupLimit | None = None, ) -> DataFrame: """ Execute a query and return the results as a Pandas DataFrame. @@ -617,18 +622,60 @@ class SnowflakeExplorable: if not metrics and not dimensions: return DataFrame() - query, parameters = self._get_query(metrics, dimensions, filters, limit, offset) + query, parameters = self._get_query( + metrics, + dimensions, + filters, + order, + limit, + offset, + group_limit, + ) connection_parameters = get_connection_parameters(self.configuration) with connect(**connection_parameters) as connection: return connection.cursor().execute(query, parameters).fetch_pandas_all() + def get_row_count( + self, + metrics: list[Metric], + dimensions: list[Dimension], + filters: set[Filter | NativeFilter] | None = None, + order: list[tuple[Metric | Dimension, OrderDirection]] | None = None, + limit: int | None = None, + offset: int | None = None, + *, + group_limit: GroupLimit | None = None, + ) -> int: + """ + Execute a query and return the number of rows the result would have. + """ + if not metrics and not dimensions: + return 0 + + query, parameters = self._get_query( + metrics, + dimensions, + filters, + order, + limit, + offset, + group_limit, + ) + query = f"SELECT COUNT(*) FROM ({query}) AS subquery" # noqa: S608 + connection_parameters = get_connection_parameters(self.configuration) + with connect(**connection_parameters) as connection: + return connection.cursor().execute(query, parameters).fechone()[0] + def _get_query( self, metrics: list[Metric], dimensions: list[Dimension], filters: set[Filter | NativeFilter] | None = None, + order: list[tuple[Metric | Dimension, OrderDirection]] | None = None, limit: int | None = None, offset: int | None = None, + *, + group_limit: GroupLimit | None = None, ) -> tuple[str, tuple[FilterValues]]: """ Build a query to fetch data from the explorable. @@ -653,6 +700,9 @@ class SnowflakeExplorable: having_clause, having_parameters = self._build_predicates( {filter_ for filter_ in filters if filter_.type == PredicateType.HAVING} ) + order_clause = ", ".join( + f"{element.id} {direction.value}" for element, direction in (order or []) + ) query = dedent( f""" @@ -663,13 +713,13 @@ class SnowflakeExplorable: {"WHERE " + where_clause if where_clause else ""} ) {"HAVING " + having_clause if having_clause else ""} + {"ORDER BY " + order_clause if order_clause else ""} {"LIMIT " + str(limit) if limit is not None else ""} {"OFFSET " + str(offset) if offset is not None else ""} """ # noqa: S608 ) - parameters = where_parameters + having_parameters - return query, parameters + return query, where_parameters + having_parameters __repr__ = uid diff --git a/superset/semantic_layers/types.py b/superset/semantic_layers/types.py index 048fbb6ab3..c43d46b691 100644 --- a/superset/semantic_layers/types.py +++ b/superset/semantic_layers/types.py @@ -198,3 +198,21 @@ class Filter: class NativeFilter: type: PredicateType definition: str + + +class OrderDirection(enum.Enum): + ASC = "ASC" + DESC = "DESC" + + +@dataclass(frozen=True) +class GroupLimit: + """ + Limit query to top/bottom N combinations of specified dimensions. + """ + + dimensions: list[Dimension] + top: int + metric: Metric | None + direction: OrderDirection = OrderDirection.DESC + group_others: bool = False
