github.com/iasthc/atlas/cmd/atlas@v0.0.0-20230523071841-73246df3f88d/internal/sqlparse/pgparse/pgparse_test.go (about) 1 // Copyright 2021-present The Atlas Authors. All rights reserved. 2 // This source code is licensed under the Apache 2.0 license found 3 // in the LICENSE file in the root directory of this source tree. 4 5 package pgparse_test 6 7 import ( 8 "strconv" 9 "testing" 10 11 "github.com/iasthc/atlas/cmd/atlas/internal/sqlparse/pgparse" 12 "github.com/iasthc/atlas/sql/migrate" 13 "github.com/iasthc/atlas/sql/postgres" 14 "github.com/iasthc/atlas/sql/schema" 15 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestFixChange_RenameColumns(t *testing.T) { 20 var p pgparse.Parser 21 _, err := p.FixChange( 22 nil, 23 "ALTER TABLE t RENAME COLUMN c1 TO c2", 24 nil, 25 ) 26 require.Error(t, err) 27 28 _, err = p.FixChange( 29 nil, 30 "ALTER TABLE t RENAME COLUMN c1 TO c2", 31 schema.Changes{&schema.AddTable{}}, 32 ) 33 require.Error(t, err) 34 35 changes, err := p.FixChange( 36 nil, 37 "ALTER TABLE t RENAME COLUMN c1 TO c2", 38 schema.Changes{ 39 &schema.ModifyTable{ 40 Changes: schema.Changes{ 41 &schema.DropColumn{C: schema.NewColumn("c1")}, 42 &schema.AddColumn{C: schema.NewColumn("c2")}, 43 }, 44 }, 45 }, 46 ) 47 require.NoError(t, err) 48 require.Equal( 49 t, 50 schema.Changes{ 51 &schema.ModifyTable{ 52 Changes: schema.Changes{ 53 &schema.RenameColumn{From: schema.NewColumn("c1"), To: schema.NewColumn("c2")}, 54 }, 55 }, 56 }, 57 changes, 58 ) 59 } 60 61 func TestFixChange_RenameIndexes(t *testing.T) { 62 var p pgparse.Parser 63 changes, err := p.FixChange( 64 nil, 65 "ALTER INDEX IF EXISTS i1 RENAME TO i2", 66 schema.Changes{ 67 &schema.ModifyTable{ 68 Changes: schema.Changes{ 69 &schema.DropIndex{I: schema.NewIndex("i1")}, 70 &schema.AddIndex{I: schema.NewIndex("i2")}, 71 }, 72 }, 73 }, 74 ) 75 require.NoError(t, err) 76 require.Equal( 77 t, 78 schema.Changes{ 79 &schema.ModifyTable{ 80 Changes: schema.Changes{ 81 &schema.RenameIndex{From: schema.NewIndex("i1"), To: schema.NewIndex("i2")}, 82 }, 83 }, 84 }, 85 changes, 86 ) 87 } 88 89 func TestFixChange_CreateIndexCon(t *testing.T) { 90 var p pgparse.Parser 91 changes, err := p.FixChange( 92 nil, 93 "CREATE INDEX i1 ON t1 (c1)", 94 schema.Changes{ 95 &schema.ModifyTable{ 96 T: schema.NewTable("t1"), 97 Changes: schema.Changes{ 98 &schema.AddIndex{I: schema.NewIndex("i1")}, 99 }, 100 }, 101 }, 102 ) 103 require.NoError(t, err) 104 // No changes. 105 require.Equal( 106 t, 107 schema.Changes{ 108 &schema.ModifyTable{ 109 T: schema.NewTable("t1"), 110 Changes: schema.Changes{ 111 &schema.AddIndex{ 112 I: schema.NewIndex("i1"), 113 }, 114 }, 115 }, 116 }, 117 changes, 118 ) 119 120 changes, err = p.FixChange( 121 nil, 122 "CREATE INDEX CONCURRENTLY i1 ON t1 (c1)", 123 schema.Changes{ 124 &schema.ModifyTable{ 125 T: schema.NewTable("t1"), 126 Changes: schema.Changes{ 127 &schema.AddIndex{I: schema.NewIndex("i1")}, 128 }, 129 }, 130 }, 131 ) 132 require.NoError(t, err) 133 // Should add the "Concurrently" clause to the AddIndex command. 134 require.Equal( 135 t, 136 schema.Changes{ 137 &schema.ModifyTable{ 138 T: schema.NewTable("t1"), 139 Changes: schema.Changes{ 140 &schema.AddIndex{ 141 I: schema.NewIndex("i1"), 142 Extra: []schema.Clause{ 143 &postgres.Concurrently{}, 144 }, 145 }, 146 }, 147 }, 148 }, 149 changes, 150 ) 151 152 changes, err = p.FixChange( 153 nil, 154 "CREATE INDEX CONCURRENTLY i1 ON t1 (c1)", 155 schema.Changes{ 156 &schema.ModifyTable{ 157 T: schema.NewTable("t1"), 158 Changes: schema.Changes{ 159 &schema.AddIndex{ 160 I: schema.NewIndex("i1"), 161 Extra: []schema.Clause{ 162 &postgres.Concurrently{}, 163 }, 164 }, 165 }, 166 }, 167 }, 168 ) 169 require.NoError(t, err) 170 // The "Concurrently" clause should not be added if it already exists. 171 require.Equal( 172 t, 173 schema.Changes{ 174 &schema.ModifyTable{ 175 T: schema.NewTable("t1"), 176 Changes: schema.Changes{ 177 &schema.AddIndex{ 178 I: schema.NewIndex("i1"), 179 Extra: []schema.Clause{ 180 &postgres.Concurrently{}, 181 }, 182 }, 183 }, 184 }, 185 }, 186 changes, 187 ) 188 } 189 190 func TestFixChange_RenameTable(t *testing.T) { 191 var p pgparse.Parser 192 changes, err := p.FixChange( 193 nil, 194 "ALTER TABLE t1 RENAME TO t2", 195 schema.Changes{ 196 &schema.DropTable{T: schema.NewTable("t1")}, 197 &schema.AddTable{T: schema.NewTable("t2")}, 198 &schema.AddTable{T: schema.NewTable("t3")}, 199 }, 200 ) 201 require.NoError(t, err) 202 require.Equal( 203 t, 204 schema.Changes{ 205 &schema.RenameTable{From: schema.NewTable("t1"), To: schema.NewTable("t2")}, 206 &schema.AddTable{T: schema.NewTable("t3")}, 207 }, 208 changes, 209 ) 210 } 211 212 func TestColumnFilledBefore(t *testing.T) { 213 for i, tt := range []struct { 214 file string 215 pos int 216 wantFilled bool 217 wantErr bool 218 }{ 219 { 220 file: `UPDATE t SET c = NULL;`, 221 pos: 100, 222 }, 223 { 224 file: `UPDATE t SET c = 2;`, 225 }, 226 { 227 file: `UPDATE t SET c = 2;`, 228 }, 229 { 230 file: `UPDATE t SET c = 2;`, 231 pos: 100, 232 wantFilled: true, 233 }, 234 { 235 file: `UPDATE t SET c = 2 WHERE c IS NULL;`, 236 pos: 100, 237 wantFilled: true, 238 }, 239 { 240 file: `UPDATE t SET c = 2 WHERE c IS NOT NULL;`, 241 pos: 100, 242 wantFilled: false, 243 }, 244 { 245 file: `UPDATE t SET c = 2 WHERE c <> NULL`, 246 pos: 100, 247 wantFilled: false, 248 }, 249 { 250 file: ` 251 ALTER TABLE t MODIFY COLUMN c INT NOT NULL; 252 UPDATE t SET c = 2 WHERE c IS NULL; 253 `, 254 pos: 2, 255 wantFilled: false, 256 }, 257 { 258 file: ` 259 UPDATE t SET c = 2 WHERE c IS NULL; 260 ALTER TABLE t MODIFY COLUMN c INT NOT NULL; 261 `, 262 pos: 30, 263 wantFilled: true, 264 }, 265 } { 266 t.Run(strconv.Itoa(i), func(t *testing.T) { 267 var ( 268 p pgparse.Parser 269 f = migrate.NewLocalFile("file", []byte(tt.file)) 270 ) 271 filled, err := p.ColumnFilledBefore(f, schema.NewTable("t"), schema.NewColumn("c"), tt.pos) 272 require.Equal(t, err != nil, tt.wantErr, err) 273 require.Equal(t, filled, tt.wantFilled) 274 }) 275 } 276 } 277 278 func TestCreateViewAfter(t *testing.T) { 279 for i, tt := range []struct { 280 file string 281 pos int 282 wantCreated bool 283 wantErr bool 284 }{ 285 { 286 file: ` 287 ALTER TABLE old RENAME TO new; 288 CREATE VIEW old AS SELECT * FROM new; 289 `, 290 pos: 1, 291 wantCreated: true, 292 }, 293 { 294 file: ` 295 ALTER TABLE old RENAME TO new; 296 CREATE VIEW old AS SELECT * FROM users; 297 `, 298 pos: 1, 299 }, 300 { 301 file: ` 302 ALTER TABLE old RENAME TO new; 303 CREATE VIEW old AS (SELECT * FROM "new"); 304 `, 305 pos: 1, 306 }, 307 { 308 file: ` 309 ALTER TABLE old RENAME TO new; 310 CREATE VIEW old AS SELECT * FROM new; 311 `, 312 pos: 100, 313 }, 314 { 315 file: ` 316 ALTER TABLE old RENAME TO new; 317 CREATE VIEW old AS SELECT a, b, c FROM new; 318 `, 319 wantCreated: true, 320 }, 321 } { 322 t.Run(strconv.Itoa(i), func(t *testing.T) { 323 var ( 324 p pgparse.Parser 325 f = migrate.NewLocalFile("file", []byte(tt.file)) 326 ) 327 created, err := p.CreateViewAfter(f, "old", "new", tt.pos) 328 require.Equal(t, err != nil, tt.wantErr, err) 329 require.Equal(t, created, tt.wantCreated) 330 }) 331 } 332 }