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  }