Skip to content

Commit 8ff679b

Browse files
committed
Fix(table_diff): Properly handle null check for array types in data sample
1 parent 107fe25 commit 8ff679b

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

sqlmesh/core/console.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2711,8 +2711,16 @@ def _cells_match(x: t.Any, y: t.Any) -> bool:
27112711
def _normalize(val: t.Any) -> t.Any:
27122712
# Convert Pandas null to Python null for the purposes of comparison to prevent errors like the following on boolean fields:
27132713
# - TypeError: boolean value of NA is ambiguous
2714-
if pd.isnull(val):
2714+
# note pd.isnull() returns either a bool or a ndarray[bool] depending on if the input
2715+
# is scalar or an array
2716+
isnull = pd.isnull(val)
2717+
2718+
if isinstance(isnull, bool): # scalar
2719+
if isnull:
2720+
val = None
2721+
elif all(isnull): # array
27152722
val = None
2723+
27162724
return list(val) if isinstance(val, (pd.Series, np.ndarray)) else val
27172725

27182726
return _normalize(x) == _normalize(y)

tests/core/test_table_diff.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,69 @@ def test_data_diff_array_dict(sushi_context_fixed_date):
504504
assert stripped_output == stripped_expected
505505

506506

507+
def test_data_diff_array_struct_query():
508+
engine_adapter = DuckDBConnectionConfig().create_engine_adapter()
509+
510+
columns_to_types = {"key": exp.DataType.build("int"), "value": exp.DataType.build("int")}
511+
512+
engine_adapter.create_table("table_diff_source", columns_to_types)
513+
engine_adapter.create_table("table_diff_target", columns_to_types)
514+
515+
engine_adapter.execute(
516+
"insert into table_diff_source (key, value) values (1, 1), (1, 2), (1, 3)"
517+
)
518+
engine_adapter.execute(
519+
"insert into table_diff_target (key, value) values (1, 1), (1, 3), (1, 2)"
520+
)
521+
522+
engine_adapter.execute(
523+
"create view src_view as select key, array_agg(value) as val_arr, map(['k','v'], [10,11]) as val_map from table_diff_source group by 1"
524+
)
525+
engine_adapter.execute(
526+
"create view target_view as select key, array_agg(value) as val_arr, map(['k','v'],[11,10]) as val_map from table_diff_target group by 1"
527+
)
528+
529+
table_diff = TableDiff(
530+
adapter=engine_adapter,
531+
source="src_view",
532+
target="target_view",
533+
source_alias="dev",
534+
target_alias="prod",
535+
on=["key"],
536+
)
537+
538+
diff = table_diff.row_diff()
539+
540+
output = capture_console_output("show_row_diff", row_diff=diff)
541+
542+
assert (
543+
strip_ansi_codes(output)
544+
== """Row Counts:
545+
└── PARTIAL MATCH: 1 rows (100.0%)
546+
547+
COMMON ROWS column comparison stats:
548+
pct_match
549+
val_arr 0.0
550+
val_map 0.0
551+
552+
553+
COMMON ROWS sample data differences:
554+
Column: val_arr
555+
┏━━━━━┳━━━━━━━━━┳━━━━━━━━━┓
556+
┃ key ┃ DEV ┃ PROD ┃
557+
┡━━━━━╇━━━━━━━━━╇━━━━━━━━━┩
558+
│ 1 │ [1 2 3] │ [1 3 2] │
559+
└─────┴─────────┴─────────┘
560+
Column: val_map
561+
┏━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
562+
┃ key ┃ DEV ┃ PROD ┃
563+
┡━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
564+
│ 1 │ {'k': 10, 'v': 11} │ {'k': 11, 'v': 10} │
565+
└─────┴────────────────────┴────────────────────┘
566+
""".strip()
567+
)
568+
569+
507570
def test_data_diff_nullable_booleans():
508571
engine_adapter = DuckDBConnectionConfig().create_engine_adapter()
509572

0 commit comments

Comments
 (0)