Skip to content

Commit 290c6c3

Browse files
authored
Fix: external models hash and is_breaking (#897)
* Fix: external models hash and is_breaking * move order
1 parent f24d075 commit 290c6c3

File tree

4 files changed

+34
-8
lines changed

4 files changed

+34
-8
lines changed

sqlmesh/core/config/categorizer.py

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class CategorizerConfig(BaseConfig):
2727
seed: the auto categorization mode for Seed models.
2828
"""
2929

30+
external: AutoCategorizationMode = AutoCategorizationMode.FULL
3031
python: AutoCategorizationMode = AutoCategorizationMode.OFF
3132
sql: AutoCategorizationMode = AutoCategorizationMode.FULL
3233
seed: AutoCategorizationMode = AutoCategorizationMode.FULL

sqlmesh/core/model/definition.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ def is_breaking_change(self, previous: Model) -> t.Optional[bool]:
487487
True if this model instance represents a breaking change, False if it's a non-breaking change
488488
and None if the nature of the change can't be determined.
489489
"""
490-
return None
490+
raise NotImplementedError
491491

492492
def _run_hooks(
493493
self,
@@ -885,6 +885,9 @@ def render_definition(self, include_python: bool = True) -> t.List[exp.Expressio
885885
def is_python(self) -> bool:
886886
return True
887887

888+
def is_breaking_change(self, previous: Model) -> t.Optional[bool]:
889+
return None
890+
888891
def __repr__(self) -> str:
889892
return f"Model<name: {self.name}, entrypoint: {self.entrypoint}>"
890893

@@ -894,6 +897,13 @@ class ExternalModel(_Model):
894897

895898
source_type: Literal["external"] = "external"
896899

900+
def is_breaking_change(self, previous: Model) -> t.Optional[bool]:
901+
if not isinstance(previous, ExternalModel):
902+
return None
903+
if not previous.columns_to_types.items() - self.columns_to_types.items():
904+
return False
905+
return None
906+
897907

898908
Model = Annotated[
899909
t.Union[SqlModel, SeedModel, PythonModel, ExternalModel], Field(discriminator="source_type")

sqlmesh/core/snapshot/definition.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ def __eq__(self, other: t.Any) -> bool:
517517
return isinstance(other, Snapshot) and self.fingerprint == other.fingerprint
518518

519519
def __hash__(self) -> int:
520-
return hash((self.__class__, self.fingerprint))
520+
return hash((self.__class__, self.name, self.fingerprint))
521521

522522
def add_interval(self, start: TimeLike, end: TimeLike, is_dev: bool = False) -> None:
523523
"""Add a newly processed time interval to the snapshot.
@@ -915,16 +915,14 @@ def serialize_hooks(hooks: t.List[HookCall]) -> t.Iterable[str]:
915915
data.append(macro.definition)
916916
elif isinstance(model, PythonModel):
917917
data.append(model.entrypoint)
918-
for column_name, column_type in model.columns_to_types.items():
919-
data.append(column_name)
920-
data.append(str(column_type))
921918
elif isinstance(model, SeedModel):
922919
for column_name, column_hash in model.column_hashes.items():
923920
data.append(column_name)
924921
data.append(column_hash)
925-
for column_name, column_type in (model.columns_to_types_ or {}).items():
926-
data.append(column_name)
927-
data.append(column_type.sql())
922+
923+
for column_name, column_type in (model.columns_to_types_ or {}).items():
924+
data.append(column_name)
925+
data.append(column_type.sql())
928926

929927
if isinstance(model.kind, kind.IncrementalByTimeRangeKind):
930928
data.append(model.kind.time_column.column)

tests/core/test_model.py

+17
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
SeedKind,
1717
SqlModel,
1818
TimeColumn,
19+
create_external_model,
1920
create_seed_model,
2021
load_model,
2122
model,
@@ -1088,3 +1089,19 @@ def test_model_ctas_query():
10881089
)
10891090

10901091
assert load_model(expressions).ctas_query({}).sql() == "SELECT 1 AS a FROM b AS b WHERE FALSE"
1092+
1093+
1094+
def test_is_breaking_change():
1095+
model = create_external_model("a", columns={"a": "int", "b": "int"})
1096+
assert model.is_breaking_change(create_external_model("a", columns={"a": "int"})) is False
1097+
assert model.is_breaking_change(create_external_model("a", columns={"a": "text"})) is None
1098+
assert (
1099+
model.is_breaking_change(create_external_model("a", columns={"a": "int", "b": "int"}))
1100+
is False
1101+
)
1102+
assert (
1103+
model.is_breaking_change(
1104+
create_external_model("a", columns={"a": "int", "b": "int", "c": "int"})
1105+
)
1106+
is None
1107+
)

0 commit comments

Comments
 (0)