|
5 | 5 | import types |
6 | 6 | import re |
7 | 7 | import typing as t |
| 8 | +from difflib import unified_diff |
8 | 9 | from functools import cached_property, partial |
9 | 10 | from pathlib import Path |
10 | 11 |
|
@@ -798,6 +799,75 @@ def text_diff(self, other: Node, rendered: bool = False) -> str: |
798 | 799 | other.dialect, |
799 | 800 | ).strip() |
800 | 801 |
|
| 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 | + |
801 | 871 | return text_diff |
802 | 872 |
|
803 | 873 | def set_time_format(self, default_time_format: str = c.DEFAULT_TIME_COLUMN_FORMAT) -> None: |
|
0 commit comments