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  }