11import collections
2+ from typing import Any , Optional , List , Dict , Tuple
23
3- from data_diff .diff_tables import DiffResultWrapper
4- from typing import TypedDict , Any , Optional , List , Dict , Tuple
5-
6-
4+ from runtype import dataclass
75
8- class ColumnsDiff (TypedDict ):
9- removed : List [str ]
10- added : List [str ]
11- changed : List [str ]
6+ from data_diff .diff_tables import DiffResultWrapper
127
138
149def jsonify (diff : DiffResultWrapper ,
1510 with_summary : bool = False ,
16- with_columns : Optional [ColumnsDiff ] = None ) -> 'JsonDiff' :
11+ with_columns : Optional [Dict [ str , List [ str ]] ] = None ) -> 'JsonDiff' :
1712 """
1813 Converts the diff result into a JSON-serializable format.
1914 Optionally add stats summary and schema diff.
@@ -49,8 +44,7 @@ def jsonify(diff: DiffResultWrapper,
4944
5045 columns = None
5146 if with_columns :
52- added , removed , changed = with_columns ['added' ], with_columns ['removed' ], with_columns ['changed' ]
53- columns = _jsonify_columns_diff (added , removed , changed )
47+ columns = _jsonify_columns_diff (with_columns )
5448
5549 is_different = bool (
5650 t1_exclusive_rows
@@ -62,44 +56,34 @@ def jsonify(diff: DiffResultWrapper,
6256 or with_columns ['changed' ]
6357 )
6458 )
65- return {
66- 'isDifferent' : is_different ,
67- 'table1' : list (table1 .table_path ),
68- 'table2' : list (table2 .table_path ),
69- 'rows' : {
70- 'exclusive' : {
71- 'table1' : t1_exclusive_rows_jsonified ,
72- 'table2' : t2_exclusive_rows_jsonified ,
73- },
74- 'diff' : diff_rows_jsonified ,
75- },
76- 'summary' : summary ,
77- 'columns' : columns ,
78- }
79-
80- class JsonDiff (TypedDict ):
81- table1 : List [str ]
82- table2 : List [str ]
83- rows : TypedDict ('Rows' , {
84- 'exclusive' : TypedDict ('Exclusive' , {
85- 'table1' : List ['JsonExclusiveRow' ],
86- 'table2' : List ['JsonExclusiveRow' ],
87- }),
88- 'diff' : List ['JsonDiffRow' ],
89- })
90- summary : Optional ['JsonDiffSummary' ]
91- columns : Optional ['JsonColumnsSummary' ]
92-
93-
94-
95- class JsonExclusiveRowValue (TypedDict ):
59+ return JsonDiff (
60+ isDifferent = is_different ,
61+ table1 = list (table1 .table_path ),
62+ table2 = list (table2 .table_path ),
63+ rows = RowsDiff (
64+ exclusive = ExclusiveDiff (
65+ table1 = t1_exclusive_rows_jsonified ,
66+ table2 = t2_exclusive_rows_jsonified
67+ ),
68+ diff = diff_rows_jsonified ,
69+ ),
70+ summary = summary ,
71+ columns = columns ,
72+ ).json ()
73+
74+
75+
76+ @dataclass
77+ class JsonExclusiveRowValue :
9678 """
9779 Value of a single column in a row
9880 """
9981 isPK : bool
10082 value : Any
10183
102- class JsonDiffRowValue (TypedDict ):
84+
85+ @dataclass
86+ class JsonDiffRowValue :
10387 """
10488 Pair of diffed values for 2 rows with equal PKs
10589 """
@@ -109,35 +93,72 @@ class JsonDiffRowValue(TypedDict):
10993 isPK : bool
11094
11195
112- JsonDiffRow = Dict [str , JsonDiffRowValue ]
113- JsonExclusiveRow = Dict [str , JsonExclusiveRowValue ]
114-
115-
116- class JsonDiffSummary (TypedDict ):
117- rows : TypedDict ('Rows' , {
118- 'total' : TypedDict ('Total' , {
119- 'table1' : int ,
120- 'table2' : int ,
121- }),
122- 'exclusive' : TypedDict ('Exclusive' , {
123- 'table1' : int ,
124- 'table2' : int ,
125- }),
126- 'updated' : int ,
127- 'unchanged' : int ,
128- })
129- stats : TypedDict ('Stats' , {
130- 'diffCounts' : Dict [str , int ],
131- })
132-
133- class JsonColumnsSummary (TypedDict ):
134- exclusive : TypedDict ('Exclusive' , {
135- 'table1' : List [str ],
136- 'table2' : List [str ],
137- })
96+ @dataclass
97+ class Total :
98+ table1 : int
99+ table2 : int
100+
101+
102+ @dataclass
103+ class ExclusiveRows :
104+ table1 : int
105+ table2 : int
106+
107+
108+ @dataclass
109+ class Rows :
110+ total : Total
111+ exclusive : ExclusiveRows
112+ updated : int
113+ unchanged : int
114+
115+
116+ @dataclass
117+ class Stats :
118+ diffCounts : Dict [str , int ]
119+
120+
121+ @dataclass
122+ class JsonDiffSummary :
123+ rows : Rows
124+ stats : Stats
125+
126+
127+ @dataclass
128+ class ExclusiveColumns :
129+ table1 : List [str ]
130+ table2 : List [str ]
131+
132+
133+ @dataclass
134+ class JsonColumnsSummary :
135+ exclusive : ExclusiveColumns
138136 typeChanged : List [str ]
139137
140138
139+ @dataclass
140+ class ExclusiveDiff :
141+ table1 : List [Dict [str , JsonExclusiveRowValue ]]
142+ table2 : List [Dict [str , JsonExclusiveRowValue ]]
143+
144+
145+ @dataclass
146+ class RowsDiff :
147+ exclusive : ExclusiveDiff
148+ diff : List [Dict [str , JsonDiffRowValue ]]
149+
150+
151+ @dataclass
152+ class JsonDiff :
153+ isDifferent : bool
154+ table1 : List [str ]
155+ table2 : List [str ]
156+ rows : RowsDiff
157+ summary : Optional [JsonDiffSummary ]
158+ columns : Optional [JsonColumnsSummary ]
159+
160+ version : str = '1.0.0'
161+
141162
142163def _group_rows (diff_info : DiffResultWrapper ,
143164 schema : List [str ]) -> Tuple [List [Dict [str , Any ]], List [Dict [str , Any ]], List [Dict [str , Any ]]]:
@@ -162,7 +183,7 @@ def _group_rows(diff_info: DiffResultWrapper,
162183 return t1_exclusive_rows , t2_exclusive_rows , diff_rows
163184
164185
165- def _jsonify_diff (row : Dict [str , Any ], key_columns : List [str ]) -> JsonDiffRowValue :
186+ def _jsonify_diff (row : Dict [str , Any ], key_columns : List [str ]) -> Dict [ str , JsonDiffRowValue ] :
166187 columns = collections .defaultdict (dict )
167188 for field , value in row .items ():
168189 if field in ('is_exclusive_a' , 'is_exclusive_b' ):
@@ -182,10 +203,13 @@ def _jsonify_diff(row: Dict[str, Any], key_columns: List[str]) -> JsonDiffRowVal
182203 columns [column_name ]['table2' ] = value
183204 columns [column_name ]['isPK' ] = column_name in key_columns
184205
185- return columns
206+ return {
207+ column : JsonDiffRowValue (** data )
208+ for column , data in columns .items ()
209+ }
186210
187211
188- def _jsonify_exclusive (row : Dict [str , Any ], key_columns : List [str ]) -> JsonExclusiveRow :
212+ def _jsonify_exclusive (row : Dict [str , Any ], key_columns : List [str ]) -> Dict [ str , JsonExclusiveRowValue ] :
189213 columns = collections .defaultdict (dict )
190214 for field , value in row .items ():
191215 if field in ('is_exclusive_a' , 'is_exclusive_b' ):
@@ -200,7 +224,10 @@ def _jsonify_exclusive(row: Dict[str, Any], key_columns: List[str]) -> JsonExclu
200224 column_name = field .replace ('_a' , '' )
201225 columns [column_name ]['isPK' ] = column_name in key_columns
202226 columns [column_name ]['value' ] = value
203- return columns
227+ return {
228+ column : JsonExclusiveRowValue (** data )
229+ for column , data in columns .items ()
230+ }
204231
205232
206233def _jsonify_diff_summary (stats_dict : dict ) -> JsonDiffSummary :
@@ -223,14 +250,11 @@ def _jsonify_diff_summary(stats_dict: dict) -> JsonDiffSummary:
223250 }
224251
225252
226- def _jsonify_columns_diff (added_columns : List [str ],
227- removed_columns : List [str ],
228- changed_columns : List [str ]) -> JsonColumnsSummary :
229- columns = {
230- 'exclusive' : {
231- 'table2' : list (added_columns ),
232- 'table1' : list (removed_columns ),
233- },
234- 'typeChanged' : list (changed_columns ),
235- }
236- return columns
253+ def _jsonify_columns_diff (columns_diff : Dict [str , List [str ]]) -> JsonColumnsSummary :
254+ return JsonColumnsSummary (
255+ exclusive = ExclusiveColumns (
256+ table2 = list (columns_diff .get ('added' , [])),
257+ table1 = list (columns_diff .get ('removed' , [])),
258+ ),
259+ typeChanged = list (columns_diff .get ('changed' , [])),
260+ )
0 commit comments