You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ma...@apache.org on 2025/07/16 19:26:49 UTC
(superset) branch fix_cube_dataset_issue created (now 4be5ee2f4b)
This is an automated email from the ASF dual-hosted git repository.
maximebeauchemin pushed a change to branch fix_cube_dataset_issue
in repository https://gitbox.apache.org/repos/asf/superset.git
at 4be5ee2f4b fix: dataset endpoint @ /rowlevelsecurity/related/tables doesn't apply filters as expected
This branch includes the following new commits:
new 4be5ee2f4b fix: dataset endpoint @ /rowlevelsecurity/related/tables doesn't apply filters as expected
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(superset) 01/01: fix: dataset endpoint @ /rowlevelsecurity/related/tables doesn't apply filters as expected
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
maximebeauchemin pushed a commit to branch fix_cube_dataset_issue
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 4be5ee2f4b54f5a22921cb9aee8d92735d7ea6c7
Author: Maxime Beauchemin <ma...@gmail.com>
AuthorDate: Wed Jul 16 12:24:57 2025 -0700
fix: dataset endpoint @ /rowlevelsecurity/related/tables doesn't apply filters as expected
## Summary
This PR fixes an issue where the filter parameter in the Row Level Security (RLS) related tables endpoint
(`/api/v1/rowlevelsecurity/related/tables`) was not being applied. When users tried to search for specific tables
in the RLS CRUD UI, all tables were returned regardless of the filter value.
## Problem
The `/api/v1/rowlevelsecurity/related/tables?q=(filter:mult,page:1,page_size:100)` endpoint was ignoring the
`filter` parameter because:
- The RLS API was missing the proper filter configuration for the `tables` field
- Without this configuration, the `_get_related_filter` method in the base API didn't know which field to filter on
## Solution
1. **Created a new filter class** `FilterRelatedTables` in `superset/views/filters.py` that:
- Performs case-insensitive substring matching using SQLAlchemy's `ilike` with wildcards
- Filters tables by their `table_name` field
- Follows the same pattern as other "contains" filters in the codebase (e.g., `FilterRelatedOwners`,
`DashboardTitleOrSlugFilter`)
2. **Updated the RLS API configuration** to use this filter:
```python
related_field_filters = {
"tables": RelatedFieldFilter("table_name", FilterRelatedTables),
"changed_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
}
Testing
Added a new test test_rls_tables_related_api_with_filter that verifies:
- Filtering with a matching substring returns only tables containing that substring
- Filtering with a non-existent substring returns no results
- The filter is case-insensitive
Changes
- superset/views/filters.py: Added FilterRelatedTables class
- superset/row_level_security/api.py: Added filter configuration for tables field
- tests/integration_tests/security/row_level_security_tests.py: Added test for filter functionality
Impact
This fix improves the user experience in the RLS CRUD interface by allowing users to efficiently search and filter
tables when creating or editing row-level security rules.
---
superset/row_level_security/api.py | 2 ++
superset/views/filters.py | 19 +++++++++++++++++++
.../security/row_level_security_tests.py | 22 ++++++++++++++++++++++
3 files changed, 43 insertions(+)
diff --git a/superset/row_level_security/api.py b/superset/row_level_security/api.py
index 7ea0959842..24e9dd4935 100644
--- a/superset/row_level_security/api.py
+++ b/superset/row_level_security/api.py
@@ -55,6 +55,7 @@ from superset.views.filters import (
BaseFilterRelatedRoles,
BaseFilterRelatedUsers,
FilterRelatedOwners,
+ FilterRelatedTables,
)
logger = logging.getLogger(__name__)
@@ -135,6 +136,7 @@ class RLSRestApi(BaseSupersetModelRestApi):
allowed_rel_fields = {"tables", "roles", "created_by", "changed_by"}
related_field_filters = {
+ "tables": RelatedFieldFilter("table_name", FilterRelatedTables),
"changed_by": RelatedFieldFilter("first_name", FilterRelatedOwners),
}
base_related_field_filters = {
diff --git a/superset/views/filters.py b/superset/views/filters.py
index 19407219e2..ad9dc8c38a 100644
--- a/superset/views/filters.py
+++ b/superset/views/filters.py
@@ -102,3 +102,22 @@ class BaseFilterRelatedRoles(BaseFilter): # pylint: disable=too-few-public-meth
return extra_filters(query)
return query
+
+
+class FilterRelatedTables(BaseFilter): # pylint: disable=too-few-public-methods
+ """
+ A filter to allow searching for related tables.
+ Use in the api by adding something like:
+ related_field_filters = {
+ "tables": RelatedFieldFilter("table_name", FilterRelatedTables),
+ }
+ """
+
+ name = lazy_gettext("Table")
+ arg_name = "tables"
+
+ def apply(self, query: Query, value: Optional[Any]) -> Query:
+ from superset.connectors.sqla.models import SqlaTable
+
+ like_value = "%" + cast(str, value) + "%"
+ return query.filter(SqlaTable.table_name.ilike(like_value))
diff --git a/tests/integration_tests/security/row_level_security_tests.py b/tests/integration_tests/security/row_level_security_tests.py
index b31c4fa136..653b1feaf7 100644
--- a/tests/integration_tests/security/row_level_security_tests.py
+++ b/tests/integration_tests/security/row_level_security_tests.py
@@ -555,6 +555,28 @@ class TestRowLevelSecurityWithRelatedAPI(SupersetTestCase):
assert len(result) == len(db_tables)
assert db_table_names == received_tables
+ def test_rls_tables_related_api_with_filter(self):
+ self.login(ADMIN_USERNAME)
+ # Test with filter that should match 'birth_names'
+ params = prison.dumps({"filter": "birth", "page": 0, "page_size": 100})
+ rv = self.client.get(f"/api/v1/rowlevelsecurity/related/tables?q={params}")
+ assert rv.status_code == 200
+ data = json.loads(rv.data.decode("utf-8"))
+ result = data["result"]
+ received_tables = {table["text"] for table in result}
+ # Should only return tables with 'birth' in the name
+ assert all("birth" in table_name.lower() for table_name in received_tables)
+ assert len(result) >= 1 # At least birth_names should be returned
+
+ # Test with filter that should match nothing
+ params = prison.dumps({"filter": "nonexistent", "page": 0, "page_size": 100})
+ rv = self.client.get(f"/api/v1/rowlevelsecurity/related/tables?q={params}")
+ assert rv.status_code == 200
+ data = json.loads(rv.data.decode("utf-8"))
+ result = data["result"]
+ assert len(result) == 0
+ assert data["count"] == 0
+
def test_rls_roles_related_api(self):
self.login(ADMIN_USERNAME)
params = prison.dumps({"page": 0, "page_size": 100})