mirror of
https://github.com/apache/superset.git
synced 2026-08-29 11:31:16 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1cadf39ce8 | ||
|
|
876b8641e2 |
@@ -390,3 +390,19 @@ def get_session() -> scoped_session:
|
||||
:returns: The SQLAlchemy scoped session instance.
|
||||
"""
|
||||
raise NotImplementedError("Function will be replaced during initialization")
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Dataset",
|
||||
"Database",
|
||||
"Chart",
|
||||
"Dashboard",
|
||||
"User",
|
||||
"Role",
|
||||
"Group",
|
||||
"Tag",
|
||||
"KeyValue",
|
||||
"Subject",
|
||||
"CoreModel",
|
||||
"get_session",
|
||||
]
|
||||
|
||||
@@ -183,3 +183,10 @@ def prompt(
|
||||
"MCP prompt decorator not initialized. "
|
||||
"This decorator should be replaced during Superset startup."
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"tool",
|
||||
"prompt",
|
||||
"ToolAnnotations",
|
||||
]
|
||||
|
||||
@@ -55,3 +55,9 @@ class SavedQueryDAO(BaseDAO[SavedQuery]):
|
||||
model_cls = None
|
||||
base_filter = None
|
||||
id_column_name = "id"
|
||||
|
||||
|
||||
__all__ = [
|
||||
"QueryDAO",
|
||||
"SavedQueryDAO",
|
||||
]
|
||||
|
||||
@@ -71,3 +71,9 @@ class SavedQuery(CoreModel):
|
||||
database_id: int | None
|
||||
description: str | None
|
||||
user_id: int | None
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Query",
|
||||
"SavedQuery",
|
||||
]
|
||||
|
||||
@@ -46,3 +46,6 @@ def get_sqlglot_dialect(database: "Database") -> Dialects:
|
||||
:returns: The SQLGlot dialect enum corresponding to the database.
|
||||
"""
|
||||
raise NotImplementedError("Function will be replaced during initialization")
|
||||
|
||||
|
||||
__all__ = ["get_sqlglot_dialect"]
|
||||
|
||||
@@ -165,3 +165,13 @@ class AsyncQueryHandle:
|
||||
:returns: True if cancellation was successful
|
||||
"""
|
||||
raise NotImplementedError("Method will be replaced during initialization")
|
||||
|
||||
|
||||
__all__ = [
|
||||
"QueryStatus",
|
||||
"QueryOptions",
|
||||
"QueryResult",
|
||||
"StatementResult",
|
||||
"AsyncQueryHandle",
|
||||
"CacheOptions",
|
||||
]
|
||||
|
||||
@@ -27,3 +27,6 @@ class RestApi(BaseApi):
|
||||
"""
|
||||
|
||||
allow_browser_login = True
|
||||
|
||||
|
||||
__all__ = ["RestApi"]
|
||||
|
||||
@@ -98,3 +98,6 @@ def api(
|
||||
"API decorator not initialized. "
|
||||
"This decorator should be replaced during Superset startup."
|
||||
)
|
||||
|
||||
|
||||
__all__ = ["api"]
|
||||
|
||||
@@ -164,3 +164,6 @@ class AbstractSemanticViewDAO(BaseDAO[SemanticViewModel]):
|
||||
:return: SemanticViewModel instance or None
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
__all__ = ["AbstractSemanticLayerDAO", "AbstractSemanticViewDAO"]
|
||||
|
||||
@@ -97,3 +97,6 @@ def semantic_layer(
|
||||
"Semantic layer decorator not initialized. "
|
||||
"This decorator should be replaced during Superset startup."
|
||||
)
|
||||
|
||||
|
||||
__all__ = ["semantic_layer"]
|
||||
|
||||
@@ -80,3 +80,6 @@ class SemanticViewModel(CoreModel):
|
||||
semantic_layer_uuid: UUID
|
||||
created_on: datetime | None
|
||||
changed_on: datetime | None
|
||||
|
||||
|
||||
__all__ = ["SemanticLayerModel", "SemanticViewModel"]
|
||||
|
||||
@@ -71,3 +71,6 @@ class TaskDAO(BaseDAO[Task]):
|
||||
:returns: Task instance or None if not found or not active
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
__all__ = ["TaskDAO"]
|
||||
|
||||
@@ -144,3 +144,9 @@ def get_context() -> TaskContext:
|
||||
)
|
||||
"""
|
||||
raise NotImplementedError("Function will be replaced during initialization")
|
||||
|
||||
|
||||
__all__ = [
|
||||
"task",
|
||||
"get_context",
|
||||
]
|
||||
|
||||
@@ -161,3 +161,9 @@ class TaskSubscriber(CoreModel):
|
||||
changed_on: datetime | None
|
||||
created_by_fk: int | None
|
||||
changed_by_fk: int | None
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Task",
|
||||
"TaskSubscriber",
|
||||
]
|
||||
|
||||
@@ -226,3 +226,12 @@ class TaskContext(ABC):
|
||||
cleanup_partial_work()
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
__all__ = [
|
||||
"TaskStatus",
|
||||
"TaskScope",
|
||||
"TaskProperties",
|
||||
"TaskContext",
|
||||
"TaskOptions",
|
||||
]
|
||||
|
||||
+9
-6
@@ -28,6 +28,14 @@ const Wrapper = styled.div`
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.ant-tabs {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-tabs-body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-tabs-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -80,12 +88,7 @@ export const ResultsPaneOnDashboard = ({
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Tabs
|
||||
fullHeight
|
||||
activeKey={activeTabKey}
|
||||
onChange={setActiveTabKey}
|
||||
items={items}
|
||||
/>
|
||||
<Tabs activeKey={activeTabKey} onChange={setActiveTabKey} items={items} />
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
-8
@@ -25,15 +25,9 @@ import {
|
||||
} from 'spec/helpers/testing-library';
|
||||
import { ChartMetadata, ChartPlugin, VizType } from '@superset-ui/core';
|
||||
import { setupAGGridModules } from '@superset-ui/core/components/ThemedAgGridReact';
|
||||
import Tabs from '@superset-ui/core/components/Tabs';
|
||||
import { ResultsPaneOnDashboard } from '../components';
|
||||
import { createResultsPaneOnDashboardProps } from './fixture';
|
||||
|
||||
jest.mock('@superset-ui/core/components/Tabs', () => {
|
||||
const actual = jest.requireActual('@superset-ui/core/components/Tabs');
|
||||
return { __esModule: true, ...actual, default: jest.fn(actual.default) };
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
setupAGGridModules();
|
||||
});
|
||||
@@ -112,8 +106,6 @@ describe('ResultsPaneOnDashboard', () => {
|
||||
expect(
|
||||
await findByText('No results were returned for this query'),
|
||||
).toBeVisible();
|
||||
const [tabsProps] = (Tabs as unknown as jest.Mock).mock.calls[0];
|
||||
expect(tabsProps).toEqual(expect.objectContaining({ fullHeight: true }));
|
||||
});
|
||||
|
||||
test('render errorMessage', async () => {
|
||||
|
||||
+19
-1
@@ -1539,7 +1539,25 @@ class SQLStatement(BaseSQLStatement[exp.Expression]):
|
||||
:return: The parsed predicate.
|
||||
"""
|
||||
_check_script_length(predicate, self.engine)
|
||||
return sqlglot.parse_one(predicate, dialect=self._dialect)
|
||||
try:
|
||||
return sqlglot.parse_one(predicate, dialect=self._dialect)
|
||||
except sqlglot.errors.ParseError as ex:
|
||||
kwargs = (
|
||||
{
|
||||
"highlight": ex.errors[0]["highlight"],
|
||||
"line": ex.errors[0]["line"],
|
||||
"column": ex.errors[0]["col"],
|
||||
}
|
||||
if ex.errors
|
||||
else {}
|
||||
)
|
||||
raise SupersetParseError(predicate, self.engine, **kwargs) from ex
|
||||
except sqlglot.errors.SqlglotError as ex:
|
||||
raise SupersetParseError(
|
||||
predicate,
|
||||
self.engine,
|
||||
message="Unable to parse predicate",
|
||||
) from ex
|
||||
|
||||
def apply_rls(
|
||||
self,
|
||||
|
||||
@@ -5578,6 +5578,41 @@ def test_parse_predicate_length_check() -> None:
|
||||
stmt.parse_predicate("x" * 101)
|
||||
|
||||
|
||||
def test_parse_predicate_invalid_sql_raises_superset_parse_error() -> None:
|
||||
"""
|
||||
A syntactically invalid RLS predicate raises ``SupersetParseError``.
|
||||
|
||||
``parse_predicate`` is reachable via ``apply_rls`` for any RLS clause
|
||||
configured on a queried table; an invalid clause must surface as the
|
||||
typed 422 parse error rather than leaking a raw ``sqlglot`` exception.
|
||||
"""
|
||||
stmt = SQLStatement("SELECT 1", "postgresql")
|
||||
with pytest.raises(SupersetParseError) as excinfo:
|
||||
stmt.parse_predicate("a >")
|
||||
assert excinfo.value.status == 422
|
||||
|
||||
|
||||
def test_parse_predicate_sqlglot_error_raises_superset_parse_error(
|
||||
mocker: MockerFixture,
|
||||
) -> None:
|
||||
"""
|
||||
A non-``ParseError`` ``sqlglot`` failure also surfaces as a typed error.
|
||||
|
||||
``parse_predicate`` catches the generic ``SqlglotError`` base class as a
|
||||
fallback so any sqlglot failure (e.g. tokenize errors) is converted into a
|
||||
``SupersetParseError`` rather than leaking a raw sqlglot exception.
|
||||
"""
|
||||
# Build the statement before patching, since the constructor also parses.
|
||||
stmt = SQLStatement("SELECT 1", "postgresql")
|
||||
mocker.patch(
|
||||
"sqlglot.parse_one",
|
||||
side_effect=sqlglot.errors.SqlglotError("boom"),
|
||||
)
|
||||
with pytest.raises(SupersetParseError) as excinfo:
|
||||
stmt.parse_predicate("a > 1")
|
||||
assert excinfo.value.status == 422
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_small_parse_cap")
|
||||
def test_transpile_to_dialect_length_check() -> None:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user