Skip to content

Commit 7c153e3

Browse files
authored
Fix: Make the missing schema warning less noisy (#1025)
1 parent 828b37c commit 7c153e3

File tree

2 files changed

+64
-16
lines changed

2 files changed

+64
-16
lines changed

sqlmesh/core/model/definition.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -462,13 +462,14 @@ def update_schema(self, schema: MappingSchema) -> None:
462462
else:
463463
# Reset the entire mapping if at least one upstream dependency is missing from the mapping
464464
# to prevent partial mappings from being used.
465-
logger.warning(
466-
"Missing schema for model '%s' referenced in model '%s'. Run `sqlmesh create_external_models` "
467-
"and / or make sure that the model '%s' can be rendered at parse time",
468-
dep,
469-
self.name,
470-
dep,
471-
)
465+
if self.contains_star_projection:
466+
logger.warning(
467+
"Missing schema for model '%s' referenced in model '%s'. Run `sqlmesh create_external_models` "
468+
"and / or make sure that the model '%s' can be rendered at parse time",
469+
dep,
470+
self.name,
471+
dep,
472+
)
472473
self.mapping_schema.clear()
473474
return
474475

@@ -481,6 +482,12 @@ def depends_on(self) -> t.Set[str]:
481482
"""
482483
return self.depends_on_ or set()
483484

485+
@property
486+
def contains_star_projection(self) -> t.Optional[bool]:
487+
"""Returns True if the model contains a star projection, False if it does not, and None if this
488+
cannot be determined at parse time."""
489+
return False
490+
484491
@property
485492
def columns_to_types(self) -> t.Optional[t.Dict[str, exp.DataType]]:
486493
"""Returns the mapping of column names to types of this model."""
@@ -756,21 +763,22 @@ def depends_on(self) -> t.Set[str]:
756763
self._depends_on -= {self.name}
757764
return self._depends_on
758765

766+
@property
767+
def contains_star_projection(self) -> t.Optional[bool]:
768+
columns_to_types = self._extract_columns_to_types()
769+
if columns_to_types is None:
770+
return None
771+
return "*" in columns_to_types
772+
759773
@property
760774
def columns_to_types(self) -> t.Optional[t.Dict[str, exp.DataType]]:
761775
if self.columns_to_types_ is not None:
762776
return self.columns_to_types_
763777

764-
if self._columns_to_types is None:
765-
query = self._query_renderer.render()
766-
if query is None:
767-
return None
768-
self._columns_to_types = d.extract_columns_to_types(query)
769-
770-
if "*" in self._columns_to_types:
778+
columns_to_types = self._extract_columns_to_types()
779+
if columns_to_types and "*" in columns_to_types:
771780
return None
772-
773-
return self._columns_to_types
781+
return columns_to_types
774782

775783
@property
776784
def column_descriptions(self) -> t.Dict[str, str]:
@@ -873,6 +881,13 @@ def _query_renderer(self) -> QueryRenderer:
873881
)
874882
return self.__query_renderer
875883

884+
def _extract_columns_to_types(self) -> t.Optional[t.Dict[str, exp.DataType]]:
885+
if self._columns_to_types is None:
886+
query = self._query_renderer.render()
887+
if query is not None:
888+
self._columns_to_types = d.extract_columns_to_types(query)
889+
return self._columns_to_types
890+
876891
def __repr__(self) -> str:
877892
return f"Model<name: {self.name}, query: {str(self.query)[0:30]}>"
878893

tests/core/test_model.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
model,
2626
)
2727
from sqlmesh.core.model.common import parse_expression
28+
from sqlmesh.core.renderer import QueryRenderer
2829
from sqlmesh.utils.date import to_datetime, to_timestamp
2930
from sqlmesh.utils.errors import ConfigError
3031
from sqlmesh.utils.metaprogramming import Executable
@@ -1443,6 +1444,8 @@ def test_check_schema_mapping_when_rendering_at_runtime(assert_exp_eq):
14431444

14441445
# Simulate a query that cannot be rendered at parse time.
14451446
with patch.object(SqlModel, "render_query", return_value=None) as render_query_mock:
1447+
assert not model.columns_to_types
1448+
14461449
schema = MappingSchema(normalize=False)
14471450
schema.add_table("table_b", {"b": exp.DataType.build("int")})
14481451
model.update_schema(schema)
@@ -1456,3 +1459,33 @@ def test_check_schema_mapping_when_rendering_at_runtime(assert_exp_eq):
14561459
assert_exp_eq(
14571460
model.render_query(), """SELECT * FROM "table_a" AS "table_a", "table_b" AS "table_b" """
14581461
)
1462+
1463+
1464+
def test_contains_star_projection():
1465+
expression_with_star = d.parse(
1466+
"""
1467+
MODEL (name db.table);
1468+
SELECT * FROM table_a
1469+
"""
1470+
)
1471+
1472+
model = load_model(expression_with_star)
1473+
assert model.contains_star_projection
1474+
assert model.columns_to_types is None
1475+
1476+
# Simulate a query that cannot be rendered at parse time.
1477+
with patch.object(QueryRenderer, "render", return_value=None) as render_query_mock:
1478+
model._columns_to_types = None
1479+
assert model.contains_star_projection is None
1480+
assert model.columns_to_types is None
1481+
1482+
expression_without_star = d.parse(
1483+
"""
1484+
MODEL (name db.table);
1485+
SELECT a FROM table_a
1486+
"""
1487+
)
1488+
1489+
model = load_model(expression_without_star)
1490+
assert model.contains_star_projection is False
1491+
assert "a" in model.columns_to_types

0 commit comments

Comments
 (0)