mikebridge commented on code in PR #45133:
URL: https://github.com/apache/superset/pull/45133#discussion_r4253187744
##########
superset/semantic_layers/mapper.py:
##########
@@ -771,30 +774,94 @@ def _convert_query_object_filter(
)
return filters or None
- value = _coerce_filter_value(value, dimension)
-
- operator = OPERATOR_MAP.get(operator_str)
+ operator: Operator | None = OPERATOR_MAP.get(operator_str)
if not operator:
# Unknown operator - raise error to prevent unauthorized access
raise ValueError(f"Unsupported filter operator: {operator_str}")
- return {
+ value: FilterValues | frozenset[FilterValues]
+ if operator in {Operator.IN, Operator.NOT_IN}:
+ # Coerce before deduplicating: equal raw values (0 and False) may
differ
+ # in validity for the selected dimension's type.
+ value = (
+ frozenset(
+ _coerce_scalar_filter_value(item, dimension) for item in
raw_value
+ )
+ if isinstance(raw_value, (list, tuple))
+ else _coerce_scalar_filter_value(raw_value, dimension)
+ )
+ elif operator in {Operator.IS_NULL, Operator.IS_NOT_NULL}:
+ value = None
+ else:
+ # Match the native datasource's scalar handling of collection inputs.
+ scalar: FilterValues = (
+ (raw_value[0] if raw_value else None)
+ if isinstance(raw_value, (list, tuple))
+ else raw_value
+ )
+ value = _coerce_scalar_filter_value(scalar, dimension)
+ if value is None and operator not in {Operator.EQUALS,
Operator.NOT_EQUALS}:
+ raise QueryObjectValidationError(
+ "Must specify a value for this comparison."
+ )
+
+ return _normalize_membership_filter(
Filter(
type=PredicateType.WHERE,
column=dimension,
operator=operator,
value=value,
)
- }
+ )
-def _coerce_filter_value(
- value: FilterValues | frozenset[FilterValues],
- dimension: Dimension,
-) -> FilterValues | frozenset[FilterValues]:
- if isinstance(value, frozenset):
- return frozenset(_coerce_scalar_filter_value(v, dimension) for v in
value)
- return _coerce_scalar_filter_value(value, dimension)
+def _normalize_membership_filter(filter_: Filter) -> set[FilterExpression]:
+ """Normalize NULL equality/membership and reject empty membership
selections."""
+ negated: bool = filter_.operator in {Operator.NOT_EQUALS, Operator.NOT_IN}
+ null_filter: Filter = replace(
+ filter_,
+ operator=Operator.IS_NOT_NULL if negated else Operator.IS_NULL,
+ value=None,
+ )
+ if filter_.operator in {Operator.EQUALS, Operator.NOT_EQUALS}:
+ return {null_filter} if filter_.value is None else {filter_}
+ if filter_.operator not in {Operator.IN, Operator.NOT_IN}:
+ return {filter_}
+
+ values: frozenset[FilterValues] = (
+ frozenset(filter_.value)
+ if isinstance(filter_.value, (tuple, frozenset))
+ else frozenset({filter_.value})
+ )
+ if not values:
+ raise QueryObjectValidationError("Semantic IN/NOT IN filters cannot be
empty.")
+ if None not in values:
+ return {filter_}
+
+ non_null_values: frozenset[FilterValues] = values - {None}
+ if not non_null_values:
+ return {null_filter}
+ comparison: Filter = replace(filter_, value=non_null_values)
+ if negated:
+ return {comparison, null_filter}
Review Comment:
Good catch — I reproduced this against host 48312c66 and paired Snowflake
ac54ee9f. The existing plain Filter renders IN plus OR IS NULL correctly, while
the normalized group is rejected; enabling the flag alone also fails on the
provider’s leaf-only operator/type reads. Could we land complete grouped
rendering and main/group-limit predicate handling in #5484 before considering
this addressed? I recommend that over a generic host fallback, which cannot
guarantee NULL semantics for undeclared providers. The complete compatibility
change exceeds this feedback pass’s small-fix scope, so I have returned the
rollout options for a scope decision; no fix is published and I am leaving this
unresolved.
Assessment performed with Codex; no new code delta or independent Claude
implementation review yet.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]