Skip to content

Commit 5165e2a

Browse files
committed
add metadata diff debugging script
1 parent 9cc63f0 commit 5165e2a

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

examples/sushi/models/customers.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ WITH current_marketing_outer AS (
2626
)
2727
SELECT DISTINCT
2828
o.customer_id::INT AS customer_id, -- this comment should not be registered
29-
m.status,
30-
d.zip
29+
m.status::TEXT,
30+
d.zip::TEXT
3131
FROM sushi.orders AS o
3232
LEFT JOIN (
3333
WITH current_marketing AS (

sqlmesh/core/model/definition.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import types
66
import re
77
import typing as t
8+
from difflib import unified_diff
89
from functools import cached_property, partial
910
from pathlib import Path
1011

@@ -798,6 +799,75 @@ def text_diff(self, other: Node, rendered: bool = False) -> str:
798799
other.dialect,
799800
).strip()
800801

802+
if not text_diff and self.metadata_hash != other.metadata_hash:
803+
804+
def _expr_debug(expr: t.Optional[exp.Expression]) -> t.Optional[t.Dict[str, t.Any]]:
805+
if expr is None:
806+
return None
807+
return {
808+
"sql": expr.sql(dialect=self.dialect),
809+
"meta_sql": expr.meta.get("sql"),
810+
"meta_dialect": expr.meta.get("dialect"),
811+
}
812+
813+
def _call_debug(call: t.Tuple[str, t.Dict[str, exp.Expression]]) -> t.Dict[str, t.Any]:
814+
name, args = call
815+
return {
816+
"name": name,
817+
"args": {k: _expr_debug(v) for k, v in sorted(args.items())},
818+
}
819+
820+
def _metadata_debug(model: _Model) -> t.Dict[str, t.Any]:
821+
return {
822+
"metadata_hash": model.metadata_hash,
823+
"dialect": model.dialect,
824+
"owner": model.owner,
825+
"description": model.description,
826+
"cron": model.cron,
827+
"cron_tz": model.cron_tz.key if model.cron_tz else None,
828+
"start": str(model.start) if model.start else None,
829+
"end": str(model.end) if model.end else None,
830+
"retention": str(model.retention) if model.retention else None,
831+
"batch_size": str(model.batch_size) if model.batch_size is not None else None,
832+
"batch_concurrency": (
833+
str(model.batch_concurrency)
834+
if model.batch_concurrency is not None
835+
else None
836+
),
837+
"mapping_schema": model.mapping_schema,
838+
"tags": sorted(model.tags),
839+
"kind": {
840+
"name": model.kind.name.value,
841+
"metadata_hash_values": model.kind.metadata_hash_values,
842+
},
843+
"project": model.project,
844+
"allow_partials": str(model.allow_partials),
845+
"session_properties": _expr_debug(model.session_properties_),
846+
"grains": [_expr_debug(g) for g in model.grains],
847+
"references": [_expr_debug(r) for r in model.references],
848+
"all_references_json": sorted(
849+
ref.json(sort_keys=True) for ref in model.all_references
850+
),
851+
"audit_metadata_hash_values": model._audit_metadata_hash_values(),
852+
"audits": [_call_debug(a) for a in sorted(model.audits, key=lambda a: a[0])],
853+
"signals": [
854+
_call_debug((n, args))
855+
for n, args in sorted(model.signals, key=lambda x: x[0])
856+
],
857+
"grants": model.grants,
858+
"grants_target_layer": model.grants_target_layer,
859+
"dbt_node_info": (
860+
model.dbt_node_info.json(sort_keys=True) if model.dbt_node_info else None
861+
),
862+
"additional_metadata": model._additional_metadata,
863+
}
864+
865+
a = json.dumps(_metadata_debug(self), sort_keys=True, indent=2).splitlines()
866+
b = json.dumps(_metadata_debug(other), sort_keys=True, indent=2).splitlines()
867+
text_diff = "\n".join(
868+
unified_diff(a, b, fromfile="metadata(old)", tofile="metadata(new)", lineterm="")
869+
).strip()
870+
801871
return text_diff
802872

803873
def set_time_format(self, default_time_format: str = c.DEFAULT_TIME_COLUMN_FORMAT) -> None:

0 commit comments

Comments
 (0)