github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/schema/alterschema/modifycolumn_test.go (about) 1 // Copyright 2019 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 alterschema 16 17 import ( 18 "context" 19 "testing" 20 21 "github.com/dolthub/go-mysql-server/sql" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 25 "github.com/dolthub/dolt/go/libraries/doltcore/dtestutils" 26 "github.com/dolthub/dolt/go/libraries/doltcore/row" 27 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 28 "github.com/dolthub/dolt/go/libraries/doltcore/schema/typeinfo" 29 "github.com/dolthub/dolt/go/libraries/doltcore/table/editor" 30 "github.com/dolthub/dolt/go/store/types" 31 ) 32 33 func TestModifyColumn(t *testing.T) { 34 alteredTypeSch := dtestutils.CreateSchema( 35 schema.NewColumn("newId", dtestutils.IdTag, types.StringKind, true, schema.NotNullConstraint{}), 36 schema.NewColumn("name", dtestutils.NameTag, types.StringKind, false, schema.NotNullConstraint{}), 37 schema.NewColumn("age", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 38 schema.NewColumn("is_married", dtestutils.IsMarriedTag, types.BoolKind, false, schema.NotNullConstraint{}), 39 schema.NewColumn("title", dtestutils.TitleTag, types.StringKind, false), 40 ) 41 ti, err := typeinfo.FromSqlType(sql.TinyText) 42 require.NoError(t, err) 43 newNameColSameTag, err := schema.NewColumnWithTypeInfo("name", dtestutils.NameTag, ti, false, "", false, "", schema.NotNullConstraint{}) 44 require.NoError(t, err) 45 alteredTypeSch2 := dtestutils.CreateSchema( 46 schema.NewColumn("id", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 47 newNameColSameTag, 48 schema.NewColumn("age", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 49 schema.NewColumn("is_married", dtestutils.IsMarriedTag, types.BoolKind, false, schema.NotNullConstraint{}), 50 schema.NewColumn("title", dtestutils.TitleTag, types.StringKind, false), 51 ) 52 53 tests := []struct { 54 name string 55 existingColumn schema.Column 56 newColumn schema.Column 57 order *ColumnOrder 58 expectedSchema schema.Schema 59 expectedRows []row.Row 60 expectedErr string 61 }{ 62 { 63 name: "column rename", 64 existingColumn: schema.NewColumn("id", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 65 newColumn: schema.NewColumn("newId", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 66 expectedSchema: dtestutils.CreateSchema( 67 schema.NewColumn("newId", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 68 schema.NewColumn("name", dtestutils.NameTag, types.StringKind, false, schema.NotNullConstraint{}), 69 schema.NewColumn("age", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 70 schema.NewColumn("is_married", dtestutils.IsMarriedTag, types.BoolKind, false, schema.NotNullConstraint{}), 71 schema.NewColumn("title", dtestutils.TitleTag, types.StringKind, false), 72 ), 73 expectedRows: dtestutils.TypedRows, 74 }, 75 { 76 name: "remove null constraint", 77 existingColumn: schema.NewColumn("age", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 78 newColumn: schema.NewColumn("newAge", dtestutils.AgeTag, types.UintKind, false), 79 expectedSchema: dtestutils.CreateSchema( 80 schema.NewColumn("id", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 81 schema.NewColumn("name", dtestutils.NameTag, types.StringKind, false, schema.NotNullConstraint{}), 82 schema.NewColumn("newAge", dtestutils.AgeTag, types.UintKind, false), 83 schema.NewColumn("is_married", dtestutils.IsMarriedTag, types.BoolKind, false, schema.NotNullConstraint{}), 84 schema.NewColumn("title", dtestutils.TitleTag, types.StringKind, false), 85 ), 86 expectedRows: dtestutils.TypedRows, 87 }, 88 { 89 name: "reorder first", 90 existingColumn: schema.NewColumn("age", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 91 newColumn: schema.NewColumn("newAge", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 92 order: &ColumnOrder{First: true}, 93 expectedSchema: dtestutils.CreateSchema( 94 schema.NewColumn("newAge", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 95 schema.NewColumn("id", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 96 schema.NewColumn("name", dtestutils.NameTag, types.StringKind, false, schema.NotNullConstraint{}), 97 schema.NewColumn("is_married", dtestutils.IsMarriedTag, types.BoolKind, false, schema.NotNullConstraint{}), 98 schema.NewColumn("title", dtestutils.TitleTag, types.StringKind, false), 99 ), 100 expectedRows: dtestutils.TypedRows, 101 }, 102 { 103 name: "reorder middle", 104 existingColumn: schema.NewColumn("age", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 105 newColumn: schema.NewColumn("newAge", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 106 order: &ColumnOrder{After: "is_married"}, 107 expectedSchema: dtestutils.CreateSchema( 108 schema.NewColumn("id", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 109 schema.NewColumn("name", dtestutils.NameTag, types.StringKind, false, schema.NotNullConstraint{}), 110 schema.NewColumn("is_married", dtestutils.IsMarriedTag, types.BoolKind, false, schema.NotNullConstraint{}), 111 schema.NewColumn("newAge", dtestutils.AgeTag, types.UintKind, false, schema.NotNullConstraint{}), 112 schema.NewColumn("title", dtestutils.TitleTag, types.StringKind, false), 113 ), 114 expectedRows: dtestutils.TypedRows, 115 }, 116 { 117 name: "tag collision", 118 existingColumn: schema.NewColumn("id", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 119 newColumn: schema.NewColumn("newId", dtestutils.NameTag, types.UUIDKind, true, schema.NotNullConstraint{}), 120 expectedErr: "two different columns with the same tag", 121 }, 122 { 123 name: "name collision", 124 existingColumn: schema.NewColumn("id", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 125 newColumn: schema.NewColumn("name", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 126 expectedErr: "A column with the name name already exists", 127 }, 128 { 129 name: "type change", 130 existingColumn: schema.NewColumn("id", dtestutils.IdTag, types.UUIDKind, true, schema.NotNullConstraint{}), 131 newColumn: schema.NewColumn("newId", dtestutils.IdTag, types.StringKind, true, schema.NotNullConstraint{}), 132 expectedSchema: alteredTypeSch, 133 expectedRows: []row.Row{ 134 dtestutils.NewRow( 135 alteredTypeSch, 136 types.String("00000000-0000-0000-0000-000000000000"), 137 types.String("Bill Billerson"), 138 types.Uint(32), 139 types.Bool(true), 140 types.String("Senior Dufus"), 141 ), 142 dtestutils.NewRow( 143 alteredTypeSch, 144 types.String("00000000-0000-0000-0000-000000000001"), 145 types.String("John Johnson"), 146 types.Uint(25), 147 types.Bool(false), 148 types.String("Dufus"), 149 ), 150 dtestutils.NewRow( 151 alteredTypeSch, 152 types.String("00000000-0000-0000-0000-000000000002"), 153 types.String("Rob Robertson"), 154 types.Uint(21), 155 types.Bool(false), 156 types.String(""), 157 ), 158 }, 159 }, 160 { 161 name: "type change same tag", 162 existingColumn: schema.NewColumn("name", dtestutils.NameTag, types.StringKind, false, schema.NotNullConstraint{}), 163 newColumn: newNameColSameTag, 164 expectedSchema: alteredTypeSch2, 165 expectedRows: dtestutils.TypedRows, 166 }, 167 } 168 169 for _, tt := range tests { 170 t.Run(tt.name, func(t *testing.T) { 171 dEnv := dtestutils.CreateEnvWithSeedData(t) 172 ctx := context.Background() 173 174 root, err := dEnv.WorkingRoot(ctx) 175 assert.NoError(t, err) 176 tbl, _, err := root.GetTable(ctx, tableName) 177 assert.NoError(t, err) 178 179 updatedTable, err := ModifyColumn(ctx, tbl, tt.existingColumn, tt.newColumn, tt.order) 180 if len(tt.expectedErr) > 0 { 181 require.Error(t, err) 182 assert.Contains(t, err.Error(), tt.expectedErr) 183 return 184 } else { 185 require.NoError(t, err) 186 } 187 188 sch, err := updatedTable.GetSchema(ctx) 189 require.NoError(t, err) 190 index := sch.Indexes().GetByName(dtestutils.IndexName) 191 assert.NotNil(t, index) 192 tt.expectedSchema.Indexes().AddIndex(index) 193 require.Equal(t, tt.expectedSchema, sch) 194 195 rowData, err := updatedTable.GetRowData(ctx) 196 require.NoError(t, err) 197 198 var foundRows []row.Row 199 err = rowData.Iter(ctx, func(key, value types.Value) (stop bool, err error) { 200 tpl, err := row.FromNoms(tt.expectedSchema, key.(types.Tuple), value.(types.Tuple)) 201 202 if err != nil { 203 return false, err 204 } 205 206 foundRows = append(foundRows, tpl) 207 return false, nil 208 }) 209 210 assert.NoError(t, err) 211 assert.Equal(t, tt.expectedRows, foundRows) 212 213 updatedIndexRows, err := updatedTable.GetIndexRowData(context.Background(), index.Name()) 214 require.NoError(t, err) 215 expectedIndexRows, err := editor.RebuildIndex(context.Background(), updatedTable, index.Name()) 216 require.NoError(t, err) 217 if uint64(len(foundRows)) != updatedIndexRows.Len() || !updatedIndexRows.Equals(expectedIndexRows) { 218 t.Error("index contents are incorrect") 219 } 220 }) 221 } 222 }