diff --git a/materializationengine/blueprints/client/api2.py b/materializationengine/blueprints/client/api2.py index 3353bf31e..d16763bc9 100644 --- a/materializationengine/blueprints/client/api2.py +++ b/materializationengine/blueprints/client/api2.py @@ -3518,7 +3518,9 @@ def get_table_schema(table): elif isinstance(column.type, Numeric): column_type = "number" else: - raise ValueError(f"Unsupported column type: {column.type}") + raise ValueError( + f"Unsupported column type for column '{column.name}': {column.type}" + ) properties[column.name] = {"type": column_type} if format: @@ -3619,6 +3621,13 @@ def get( schemas = {} for view_dict in dumped_views: view_name = view_dict["table_name"] - table = meta_db.database.get_view_table(view_name) - schemas[view_name] = get_table_schema(table) + try: + table = meta_db.database.get_view_table(view_name) + schemas[view_name] = get_table_schema(table) + except Exception as e: + # Degrade gracefully: one bad view shouldn't 500 the whole endpoint. + current_app.logger.warning( + f"Failed to build schema for view '{view_name}': {e}" + ) + schemas[view_name] = {"error": str(e)} return schemas, 200 diff --git a/materializationengine/workflows/deltalake_export.py b/materializationengine/workflows/deltalake_export.py index 2666502db..95bdd5899 100644 --- a/materializationengine/workflows/deltalake_export.py +++ b/materializationengine/workflows/deltalake_export.py @@ -15,20 +15,17 @@ import polars as pl import pyarrow as pa import shapely + +# Registers geoalchemy2's Geometry type with SQLAlchemy's PostGIS dialect so +# the inspector recognizes 'geometry' columns during reflection instead of +# warning "Did not recognize type 'geometry'". Import for the side effect only. +import geoalchemy2 # noqa: F401 from celery.utils.log import get_task_logger from sqlalchemy import inspect, text -from sqlalchemy.dialects.postgresql import BYTEA - -# Register a minimal geometry type so SQLAlchemy's inspector doesn't warn -# "Did not recognize type 'geometry'" during reflection. We decode WKB -# ourselves — all SQLAlchemy needs to know is that it's binary. -from sqlalchemy.dialects.postgresql import dialect as _pg_dialect from sqlalchemy.engine import Engine from materializationengine.celery_init import celery -_pg_dialect.ischema_names["geometry"] = BYTEA - celery_logger = get_task_logger(__name__) # Columns to drop from every Delta Lake export by default. @@ -237,9 +234,7 @@ def _get_geometry_columns(connection_string: str, name: str) -> list[str]: """Return PostGIS geometry column names on *name*, in ordinal order. Detects columns via ``information_schema.columns.udt_name = 'geometry'``, - which works identically for tables, views, and materialized views. This is - necessary because we alias the SQLAlchemy ``geometry`` type to ``BYTEA`` for - reflection, so the inspector cannot distinguish geometry from plain bytea. + which works identically for tables, views, and materialized views. """ _validate_identifier(name) rows = _adbc_fetchall(