Skip to content

Commit 7ddd7f6

Browse files
committed
Fix(table_diff): Allow diffing of empty tables
1 parent a837409 commit 7ddd7f6

3 files changed

Lines changed: 57 additions & 1 deletion

File tree

sqlmesh/core/console.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,6 +2135,12 @@ def show_schema_diff(self, schema_diff: SchemaDiff) -> None:
21352135
def show_row_diff(
21362136
self, row_diff: RowDiff, show_sample: bool = True, skip_grain_check: bool = False
21372137
) -> None:
2138+
if row_diff.empty:
2139+
self.console.print(
2140+
"\n[b][red]Neither the source nor the target table contained any records[/red][/b]"
2141+
)
2142+
return
2143+
21382144
source_name = row_diff.source
21392145
if row_diff.source_alias:
21402146
source_name = row_diff.source_alias.upper()

sqlmesh/core/table_diff.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ def target_count(self) -> int:
8383
"""Count of the target."""
8484
return int(self.stats["t_count"])
8585

86+
@property
87+
def empty(self) -> bool:
88+
return (
89+
self.source_count == 0
90+
and self.target_count == 0
91+
and self.s_only_count == 0
92+
and self.t_only_count == 0
93+
)
94+
8695
@property
8796
def count_pct_change(self) -> float:
8897
"""The percentage change of the counts."""
@@ -446,7 +455,7 @@ def name(e: exp.Expression) -> str:
446455

447456
summary_query = exp.select(*summary_sums).from_(table)
448457

449-
stats_df = self.adapter.fetchdf(summary_query, quote_identifiers=True)
458+
stats_df = self.adapter.fetchdf(summary_query, quote_identifiers=True).fillna(0)
450459
stats_df["s_only_count"] = stats_df["s_count"] - stats_df["join_count"]
451460
stats_df["t_only_count"] = stats_df["t_count"] - stats_df["join_count"]
452461
stats = stats_df.iloc[0].to_dict()

tests/core/test_table_diff.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,3 +695,44 @@ def test_data_diff_multiple_models(sushi_context_fixed_date, capsys, caplog):
695695
skip_grain_check=False,
696696
)
697697
assert len(diffs) == 0
698+
699+
700+
def test_data_diff_empty_tables():
701+
engine_adapter = DuckDBConnectionConfig().create_engine_adapter()
702+
703+
columns_to_types_src = {
704+
"key": exp.DataType.build("int"),
705+
"value": exp.DataType.build("varchar"),
706+
}
707+
columns_to_types_target = {
708+
"key": exp.DataType.build("int"),
709+
"value2": exp.DataType.build("varchar"),
710+
}
711+
712+
engine_adapter.create_table("table_diff_source", columns_to_types_src)
713+
engine_adapter.create_table("table_diff_target", columns_to_types_target)
714+
715+
table_diff = TableDiff(
716+
adapter=engine_adapter,
717+
source="table_diff_source",
718+
target="table_diff_target",
719+
source_alias="dev",
720+
target_alias="prod",
721+
on=["key"],
722+
)
723+
724+
# should show the schema diff
725+
schema_diff = table_diff.schema_diff()
726+
assert len(schema_diff.added) == 1
727+
assert schema_diff.added[0][0] == "value2"
728+
assert len(schema_diff.removed) == 1
729+
assert schema_diff.removed[0][0] == "value"
730+
731+
# should not error on the row diff
732+
row_diff = table_diff.row_diff()
733+
assert row_diff.empty
734+
735+
output = capture_console_output("show_row_diff", row_diff=row_diff)
736+
assert (
737+
strip_ansi_codes(output) == "Neither the source nor the target table contained any records"
738+
)

0 commit comments

Comments
 (0)