github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/diff/diffsplitter_test.go (about) 1 // Copyright 2022 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package diff 16 17 import ( 18 "testing" 19 20 "github.com/dolthub/go-mysql-server/sql" 21 "github.com/dolthub/go-mysql-server/sql/types" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 ) 25 26 type splitRow struct { 27 old, new RowDiff 28 } 29 30 func TestDiffSplitter(t *testing.T) { 31 type testcase struct { 32 name string 33 diffQuerySch sql.Schema 34 tableSch sql.Schema 35 diffQueryRows []sql.Row 36 expectedRows []splitRow 37 } 38 39 testcases := []testcase{ 40 { 41 name: "changed rows", 42 diffQuerySch: sql.Schema{ 43 intCol("from_a"), 44 intCol("from_b"), 45 intCol("to_a"), 46 intCol("to_b"), 47 strCol("diff_type"), 48 }, 49 tableSch: sql.Schema{ 50 intCol("a"), 51 intCol("b"), 52 }, 53 diffQueryRows: []sql.Row{ 54 {nil, nil, 1, 2, "added"}, 55 {3, 4, nil, nil, "removed"}, 56 {5, 6, 5, 100, "modified"}, 57 }, 58 expectedRows: []splitRow{ 59 { 60 old: emptyRowDiff(2), 61 new: RowDiff{ 62 Row: sql.Row{1, 2}, 63 RowDiff: Added, 64 ColDiffs: []ChangeType{Added, Added}, 65 }, 66 }, 67 { 68 old: RowDiff{ 69 Row: sql.Row{3, 4}, 70 RowDiff: Removed, 71 ColDiffs: []ChangeType{Removed, Removed}, 72 }, 73 new: emptyRowDiff(2), 74 }, 75 { 76 old: RowDiff{ 77 Row: sql.Row{5, 6}, 78 RowDiff: ModifiedOld, 79 ColDiffs: []ChangeType{None, ModifiedOld}, 80 }, 81 new: RowDiff{ 82 Row: sql.Row{5, 100}, 83 RowDiff: ModifiedNew, 84 ColDiffs: []ChangeType{None, ModifiedNew}, 85 }, 86 }, 87 }, 88 }, 89 { 90 name: "added and removed column", 91 diffQuerySch: sql.Schema{ 92 strCol("from_a"), 93 intCol("from_b"), 94 intCol("to_b"), 95 intCol("to_c"), 96 strCol("diff_type"), 97 }, 98 tableSch: sql.Schema{ 99 strCol("a"), 100 intCol("b"), 101 intCol("c"), 102 }, 103 diffQueryRows: []sql.Row{ 104 {nil, nil, 1, 2, "added"}, 105 {"three", 4, nil, nil, "removed"}, 106 {"five", 6, 6, 100, "modified"}, 107 }, 108 expectedRows: []splitRow{ 109 { 110 old: emptyRowDiff(3), 111 new: RowDiff{ 112 Row: sql.Row{nil, 1, 2}, 113 RowDiff: Added, 114 ColDiffs: []ChangeType{None, Added, Added}, 115 }, 116 }, 117 { 118 old: RowDiff{ 119 Row: sql.Row{"three", 4, nil}, 120 RowDiff: Removed, 121 ColDiffs: []ChangeType{Removed, Removed, None}, 122 }, 123 new: emptyRowDiff(3), 124 }, 125 { 126 old: RowDiff{ 127 Row: sql.Row{"five", 6, nil}, 128 RowDiff: ModifiedOld, 129 ColDiffs: []ChangeType{ModifiedOld, None, ModifiedOld}, 130 }, 131 new: RowDiff{ 132 Row: sql.Row{nil, 6, 100}, 133 RowDiff: ModifiedNew, 134 ColDiffs: []ChangeType{ModifiedNew, None, ModifiedNew}, 135 }, 136 }, 137 }, 138 }, 139 { 140 name: "column changes", 141 diffQuerySch: sql.Schema{ 142 intCol("from_a"), 143 intCol("from_b"), 144 intCol("from_c"), 145 strCol("to_a"), // type change 146 // col b dropped 147 intCol("to_c"), 148 strCol("to_d"), // added col 149 strCol("diff_type"), 150 }, 151 tableSch: sql.Schema{ 152 // union schemas prefers "from" 153 intCol("a"), 154 intCol("b"), 155 intCol("c"), 156 intCol("d"), 157 }, 158 diffQueryRows: []sql.Row{ 159 {1, 2, 3, "1", 3, 4, "modified"}, 160 {5, 6, 7, "5", 17, 8, "modified"}, 161 {nil, 10, 11, "9", nil, 12, "modified"}, 162 }, 163 expectedRows: []splitRow{ 164 { 165 old: RowDiff{ 166 Row: sql.Row{1, 2, 3, nil}, 167 RowDiff: ModifiedOld, 168 ColDiffs: []ChangeType{None, ModifiedOld, None, ModifiedOld}, 169 }, 170 new: RowDiff{ 171 // todo(andy): should type changes generate a column diff? 172 Row: sql.Row{"1", nil, 3, 4}, 173 RowDiff: ModifiedNew, 174 ColDiffs: []ChangeType{None, ModifiedNew, None, ModifiedNew}, 175 }, 176 }, 177 { 178 old: RowDiff{ 179 Row: sql.Row{5, 6, 7, nil}, 180 RowDiff: ModifiedOld, 181 ColDiffs: []ChangeType{None, ModifiedOld, ModifiedOld, ModifiedOld}, 182 }, 183 new: RowDiff{ 184 // todo(andy): should type changes generate a column diff? 185 Row: sql.Row{"5", nil, 17, 8}, 186 RowDiff: ModifiedNew, 187 ColDiffs: []ChangeType{None, ModifiedNew, ModifiedNew, ModifiedNew}, 188 }, 189 }, 190 { 191 old: RowDiff{ 192 Row: sql.Row{nil, 10, 11, nil}, 193 RowDiff: ModifiedOld, 194 ColDiffs: []ChangeType{ModifiedOld, ModifiedOld, ModifiedOld, ModifiedOld}, 195 }, 196 new: RowDiff{ 197 Row: sql.Row{"9", nil, nil, 12}, 198 RowDiff: ModifiedNew, 199 ColDiffs: []ChangeType{ModifiedNew, ModifiedNew, ModifiedNew, ModifiedNew}, 200 }, 201 }, 202 }, 203 }, 204 { 205 name: "new table", 206 diffQuerySch: sql.Schema{ 207 intCol("to_a"), 208 intCol("to_b"), 209 strCol("diff_type"), 210 }, 211 tableSch: sql.Schema{ 212 intCol("a"), 213 intCol("b"), 214 }, 215 diffQueryRows: []sql.Row{ 216 {1, 2, "added"}, 217 {3, 4, "added"}, 218 }, 219 expectedRows: []splitRow{ 220 { 221 old: emptyRowDiff(2), 222 new: RowDiff{ 223 Row: sql.Row{1, 2}, 224 RowDiff: Added, 225 ColDiffs: []ChangeType{Added, Added}, 226 }, 227 }, 228 { 229 old: emptyRowDiff(2), 230 new: RowDiff{ 231 Row: sql.Row{3, 4}, 232 RowDiff: Added, 233 ColDiffs: []ChangeType{Added, Added}, 234 }, 235 }, 236 }, 237 }, 238 { 239 name: "dropped table", 240 diffQuerySch: sql.Schema{ 241 intCol("from_a"), 242 intCol("from_b"), 243 strCol("diff_type"), 244 }, 245 tableSch: sql.Schema{ 246 intCol("a"), 247 intCol("b"), 248 }, 249 diffQueryRows: []sql.Row{ 250 {1, 2, "removed"}, 251 {3, 4, "removed"}, 252 }, 253 expectedRows: []splitRow{ 254 { 255 new: emptyRowDiff(2), 256 old: RowDiff{ 257 Row: sql.Row{1, 2}, 258 RowDiff: Removed, 259 ColDiffs: []ChangeType{Removed, Removed}, 260 }, 261 }, 262 { 263 new: emptyRowDiff(2), 264 old: RowDiff{ 265 Row: sql.Row{3, 4}, 266 RowDiff: Removed, 267 ColDiffs: []ChangeType{Removed, Removed}, 268 }, 269 }, 270 }, 271 }, 272 } 273 274 for _, tc := range testcases { 275 t.Run(tc.name, func(t *testing.T) { 276 ds, err := NewDiffSplitter(tc.diffQuerySch, tc.tableSch) 277 require.NoError(t, err) 278 279 var splitRows []splitRow 280 for _, row := range tc.diffQueryRows { 281 old, new, err := ds.SplitDiffResultRow(row) 282 require.NoError(t, err) 283 splitRows = append(splitRows, splitRow{old, new}) 284 } 285 286 assert.Equal(t, tc.expectedRows, splitRows) 287 }) 288 } 289 } 290 291 func emptyRowDiff(columns int) RowDiff { 292 return RowDiff{ 293 ColDiffs: make([]ChangeType, columns), 294 } 295 } 296 297 func strCol(name string) *sql.Column { 298 return &sql.Column{Name: name, Type: types.Text} 299 } 300 301 func intCol(name string) *sql.Column { 302 return &sql.Column{Name: name, Type: types.Int64} 303 }