You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2025/08/01 21:53:24 UTC
(superset) branch fix/postgresql-interval-chart-rendering created (now 44c9cc95fe)
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a change to branch fix/postgresql-interval-chart-rendering
in repository https://gitbox.apache.org/repos/asf/superset.git
at 44c9cc95fe fix(charts): handle PostgreSQL INTERVAL type in bar and pie charts
This branch includes the following new commits:
new 44c9cc95fe fix(charts): handle PostgreSQL INTERVAL type in bar and pie charts
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(charts): handle PostgreSQL INTERVAL type in bar and pie charts
Posted by ru...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch fix/postgresql-interval-chart-rendering
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 44c9cc95fe8b23f015fe536d980d79f45de2aac5
Author: Evan Rusackas <ev...@rusackas.com>
AuthorDate: Fri Aug 1 14:52:24 2025 -0700
fix(charts): handle PostgreSQL INTERVAL type in bar and pie charts
PostgreSQL INTERVAL types were causing bar and pie charts to fail rendering when used as metrics. This fix converts INTERVAL values (timedelta objects) to numeric seconds so they can be properly displayed in charts.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <no...@anthropic.com>
---
superset/db_engine_specs/postgres.py | 13 +++++++++++--
tests/unit_tests/db_engine_specs/test_postgres.py | 19 +++++++++++++++++--
2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/superset/db_engine_specs/postgres.py b/superset/db_engine_specs/postgres.py
index b86172cb3a..bb1628310d 100644
--- a/superset/db_engine_specs/postgres.py
+++ b/superset/db_engine_specs/postgres.py
@@ -21,10 +21,10 @@ import logging
import re
from datetime import datetime
from re import Pattern
-from typing import Any, TYPE_CHECKING
+from typing import Any, Callable, TYPE_CHECKING
from flask_babel import gettext as __
-from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION, ENUM, JSON
+from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION, ENUM, INTERVAL, JSON
from sqlalchemy.dialects.postgresql.base import PGInspector
from sqlalchemy.engine.reflection import Inspector
from sqlalchemy.engine.url import URL
@@ -238,8 +238,17 @@ class PostgresEngineSpec(BasicParametersMixin, PostgresBaseEngineSpec):
ENUM(),
GenericDataType.STRING,
),
+ (
+ re.compile(r"^interval", re.IGNORECASE),
+ INTERVAL(),
+ GenericDataType.NUMERIC,
+ ),
)
+ column_type_mutators: dict[Any, Callable[[Any], Any]] = {
+ INTERVAL: lambda v: v.total_seconds() if hasattr(v, "total_seconds") else v,
+ }
+
@classmethod
def get_schema_from_engine_params(
cls,
diff --git a/tests/unit_tests/db_engine_specs/test_postgres.py b/tests/unit_tests/db_engine_specs/test_postgres.py
index 290aa3575c..3fb3e7f674 100644
--- a/tests/unit_tests/db_engine_specs/test_postgres.py
+++ b/tests/unit_tests/db_engine_specs/test_postgres.py
@@ -15,13 +15,13 @@
# specific language governing permissions and limitations
# under the License.
-from datetime import datetime
+from datetime import datetime, timedelta
from typing import Any, Optional
import pytest
from pytest_mock import MockerFixture
from sqlalchemy import column, types
-from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION, ENUM, JSON
+from sqlalchemy.dialects.postgresql import DOUBLE_PRECISION, ENUM, INTERVAL, JSON
from sqlalchemy.engine.interfaces import Dialect
from sqlalchemy.engine.url import make_url
@@ -280,3 +280,18 @@ SELECT * \nFROM my_schema.my_table
LIMIT :param_1
""".strip()
)
+
+
+def test_interval_type_mutator() -> None:
+ """
+ DB Eng Specs (postgres): Test INTERVAL type mutator
+ """
+ # Test timedelta conversion
+ td = timedelta(days=1, hours=2, minutes=30, seconds=45)
+ mutator = spec.column_type_mutators[INTERVAL]
+ assert mutator(td) == 95445.0 # Total seconds: 1*86400 + 2*3600 + 30*60 + 45
+
+ # Test that non-timedelta values pass through unchanged
+ assert mutator("not a timedelta") == "not a timedelta"
+ assert mutator(12345) == 12345
+ assert mutator(None) is None