@@ -129,16 +129,23 @@ export const DataDiffTool = Tool.define("data_diff", {
129129
130130function summarize ( outcome : any ) : string {
131131 if ( ! outcome ) return "complete"
132- if ( outcome . Match ) return "IDENTICAL ✓"
133- if ( outcome . Diff ) {
134- const r = outcome . Diff
132+
133+ // Rust serializes ReladiffOutcome as {mode: "diff"|"profile"|..., stats: {...}, diff_rows: [...] }
134+ if ( outcome . mode === "diff" ) {
135+ const s = outcome . stats ?? { }
136+ const e1 = Number ( s . exclusive_table1 ?? 0 )
137+ const e2 = Number ( s . exclusive_table2 ?? 0 )
138+ const upd = Number ( s . updated ?? 0 )
139+ if ( e1 === 0 && e2 === 0 && upd === 0 ) return "IDENTICAL ✓"
135140 const parts : string [ ] = [ ]
136- if ( r . rows_only_in_source > 0 ) parts . push ( `${ r . rows_only_in_source } only in source` )
137- if ( r . rows_only_in_target > 0 ) parts . push ( `${ r . rows_only_in_target } only in target` )
138- if ( r . rows_updated > 0 ) parts . push ( `${ r . rows_updated } updated` )
139- return parts . length ? parts . join ( ", " ) : "differences found"
141+ if ( e1 > 0 ) parts . push ( `${ e1 } only in source` )
142+ if ( e2 > 0 ) parts . push ( `${ e2 } only in target` )
143+ if ( upd > 0 ) parts . push ( `${ upd } updated` )
144+ return parts . join ( ", " )
140145 }
141- if ( outcome . Profile ) return "profile complete"
146+ if ( outcome . mode === "profile" ) return "profile complete"
147+ if ( outcome . mode === "cascade" ) return "cascade complete"
148+
142149 return "complete"
143150}
144151
@@ -147,45 +154,54 @@ function formatOutcome(outcome: any, source: string, target: string): string {
147154
148155 const lines : string [ ] = [ ]
149156
150- if ( outcome . Match ) {
151- lines . push ( `✓ Tables are IDENTICAL` )
152- const m = outcome . Match
153- if ( m . row_count != null ) lines . push ( ` Rows checked: ${ m . row_count . toLocaleString ( ) } ` )
154- if ( m . algorithm ) lines . push ( ` Algorithm: ${ m . algorithm } ` )
155- return lines . join ( "\n" )
156- }
157+ // Rust serializes ReladiffOutcome as {mode: "diff", diff_rows: [...], stats: {...}}
158+ // stats: rows_table1, rows_table2, exclusive_table1, exclusive_table2, updated, unchanged
159+ if ( outcome . mode === "diff" ) {
160+ const s = outcome . stats ?? { }
161+ const rows1 = Number ( s . rows_table1 ?? 0 )
162+ const rows2 = Number ( s . rows_table2 ?? 0 )
163+ const e1 = Number ( s . exclusive_table1 ?? 0 )
164+ const e2 = Number ( s . exclusive_table2 ?? 0 )
165+ const updated = Number ( s . updated ?? 0 )
166+ const unchanged = Number ( s . unchanged ?? 0 )
167+
168+ if ( e1 === 0 && e2 === 0 && updated === 0 ) {
169+ lines . push ( `✓ Tables are IDENTICAL` )
170+ if ( rows1 > 0 ) lines . push ( ` Rows checked: ${ rows1 . toLocaleString ( ) } ` )
171+ return lines . join ( "\n" )
172+ }
157173
158- if ( outcome . Diff ) {
159- const r = outcome . Diff
160174 lines . push ( `✗ Tables DIFFER` )
161175 lines . push ( `` )
162176 lines . push ( ` Source: ${ source } ` )
163177 lines . push ( ` Target: ${ target } ` )
164178 lines . push ( `` )
165179
166- if ( r . total_source_rows != null ) lines . push ( ` Source rows: ${ r . total_source_rows . toLocaleString ( ) } ` )
167- if ( r . total_target_rows != null ) lines . push ( ` Target rows: ${ r . total_target_rows . toLocaleString ( ) } ` )
168- if ( r . rows_only_in_source > 0 ) lines . push ( ` Only in source: ${ r . rows_only_in_source . toLocaleString ( ) } ` )
169- if ( r . rows_only_in_target > 0 ) lines . push ( ` Only in target: ${ r . rows_only_in_target . toLocaleString ( ) } ` )
170- if ( r . rows_updated > 0 ) lines . push ( ` Updated rows: ${ r . rows_updated . toLocaleString ( ) } ` )
171- if ( r . rows_identical > 0 ) lines . push ( ` Identical rows: ${ r . rows_identical . toLocaleString ( ) } ` )
180+ if ( rows1 > 0 ) lines . push ( ` Source rows: ${ rows1 . toLocaleString ( ) } ` )
181+ if ( rows2 > 0 ) lines . push ( ` Target rows: ${ rows2 . toLocaleString ( ) } ` )
182+ if ( e1 > 0 ) lines . push ( ` Only in source: ${ e1 . toLocaleString ( ) } ` )
183+ if ( e2 > 0 ) lines . push ( ` Only in target: ${ e2 . toLocaleString ( ) } ` )
184+ if ( updated > 0 ) lines . push ( ` Updated rows: ${ updated . toLocaleString ( ) } ` )
185+ if ( unchanged > 0 ) lines . push ( ` Identical rows: ${ unchanged . toLocaleString ( ) } ` )
172186
173- if ( r . sample_diffs ?. length ) {
187+ const diffRows = outcome . diff_rows ?? [ ]
188+ if ( diffRows . length > 0 ) {
174189 lines . push ( `` )
175- lines . push ( ` Sample differences (first ${ r . sample_diffs . length } ):` )
176- for ( const d of r . sample_diffs . slice ( 0 , 5 ) ) {
177- lines . push ( ` key=${ JSON . stringify ( d . key ) } col=${ d . column } : ${ d . source_value } → ${ d . target_value } ` )
190+ lines . push ( ` Sample differences (first ${ Math . min ( diffRows . length , 5 ) } ):` )
191+ for ( const d of diffRows . slice ( 0 , 5 ) ) {
192+ const label = d . sign === "-" ? "source only" : "target only"
193+ lines . push ( ` [${ label } ] ${ d . values ?. join ( " | " ) } ` )
178194 }
179195 }
180196
181197 return lines . join ( "\n" )
182198 }
183199
184- if ( outcome . Profile ) {
185- const p = outcome . Profile
200+ if ( outcome . mode === "profile" ) {
201+ const cols = outcome . column_stats ?? outcome . columns ?? [ ]
186202 lines . push ( `Column Profile Comparison` )
187203 lines . push ( `` )
188- for ( const col of p . columns ?? [ ] ) {
204+ for ( const col of cols ) {
189205 const verdict = col . verdict === "match" ? "✓" : col . verdict === "within_tolerance" ? "~" : "✗"
190206 lines . push ( ` ${ verdict } ${ col . column } : ${ col . verdict } ` )
191207 if ( col . source_stats && col . target_stats ) {
0 commit comments