github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/sqle/sqlfmt/row_fmt_test.go (about) 1 // Copyright 2020 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 sqlfmt 16 17 import ( 18 "testing" 19 20 "github.com/google/uuid" 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/require" 23 24 "github.com/dolthub/dolt/go/libraries/doltcore/dtestutils" 25 "github.com/dolthub/dolt/go/libraries/doltcore/row" 26 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 27 "github.com/dolthub/dolt/go/libraries/doltcore/schema/typeinfo" 28 "github.com/dolthub/dolt/go/store/types" 29 ) 30 31 const expectedDropSql = "DROP TABLE `table_name`;" 32 const expectedDropIfExistsSql = "DROP TABLE IF EXISTS `table_name`;" 33 const expectedAddColSql = "ALTER TABLE `table_name` ADD `c0` BIGINT NOT NULL;" 34 const expectedDropColSql = "ALTER TABLE `table_name` DROP `first_name`;" 35 const expectedRenameColSql = "ALTER TABLE `table_name` RENAME COLUMN `id` TO `pk`;" 36 const expectedRenameTableSql = "RENAME TABLE `table_name` TO `new_table_name`;" 37 38 type test struct { 39 name string 40 row row.Row 41 sch schema.Schema 42 expectedOutput string 43 } 44 45 func TestTableDropStmt(t *testing.T) { 46 stmt := DropTableStmt("table_name") 47 48 assert.Equal(t, expectedDropSql, stmt) 49 } 50 51 func TestTableDropIfExistsStmt(t *testing.T) { 52 stmt := DropTableIfExistsStmt("table_name") 53 54 assert.Equal(t, expectedDropIfExistsSql, stmt) 55 } 56 57 func TestAlterTableAddColStmt(t *testing.T) { 58 newColDef := "`c0` BIGINT NOT NULL" 59 stmt := AlterTableAddColStmt("table_name", newColDef) 60 61 assert.Equal(t, expectedAddColSql, stmt) 62 } 63 64 func TestAlterTableDropColStmt(t *testing.T) { 65 stmt := AlterTableDropColStmt("table_name", "first_name") 66 67 assert.Equal(t, expectedDropColSql, stmt) 68 } 69 70 func TestAlterTableRenameColStmt(t *testing.T) { 71 stmt := AlterTableRenameColStmt("table_name", "id", "pk") 72 73 assert.Equal(t, expectedRenameColSql, stmt) 74 } 75 76 func TestRenameTableStmt(t *testing.T) { 77 stmt := RenameTableStmt("table_name", "new_table_name") 78 79 assert.Equal(t, expectedRenameTableSql, stmt) 80 } 81 82 func TestRowAsInsertStmt(t *testing.T) { 83 id := uuid.MustParse("00000000-0000-0000-0000-000000000000") 84 tableName := "people" 85 86 tests := []test{ 87 { 88 name: "simple row", 89 row: dtestutils.NewTypedRow(id, "some guy", 100, false, strPointer("normie")), 90 sch: dtestutils.TypedSchema, 91 expectedOutput: "INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) VALUES ('00000000-0000-0000-0000-000000000000','some guy',100,FALSE,'normie');", 92 }, 93 { 94 name: "embedded quotes", 95 row: dtestutils.NewTypedRow(id, `It's "Mister Perfect" to you`, 100, false, strPointer("normie")), 96 sch: dtestutils.TypedSchema, 97 expectedOutput: "INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) VALUES ('00000000-0000-0000-0000-000000000000','It\\'s \\\"Mister Perfect\\\" to you',100,FALSE,'normie');", 98 }, 99 { 100 name: "null values", 101 row: dtestutils.NewTypedRow(id, "some guy", 100, false, nil), 102 sch: dtestutils.TypedSchema, 103 expectedOutput: "INSERT INTO `people` (`id`,`name`,`age`,`is_married`,`title`) VALUES ('00000000-0000-0000-0000-000000000000','some guy',100,FALSE,NULL);", 104 }, 105 } 106 107 trickySch := dtestutils.CreateSchema( 108 schema.NewColumn("a name with spaces", 0, types.FloatKind, false), 109 schema.NewColumn("anotherColumn", 1, types.IntKind, true), 110 ) 111 112 tests = append(tests, test{ 113 name: "negative values and columns with spaces", 114 row: dtestutils.NewRow(trickySch, types.Float(-3.14), types.Int(-42)), 115 sch: trickySch, 116 expectedOutput: "INSERT INTO `people` (`a name with spaces`,`anotherColumn`) VALUES (-3.14,-42);", 117 }) 118 119 for _, tt := range tests { 120 t.Run(tt.name, func(t *testing.T) { 121 stmt, err := RowAsInsertStmt(tt.row, tableName, tt.sch) 122 assert.NoError(t, err) 123 assert.Equal(t, tt.expectedOutput, stmt) 124 }) 125 } 126 } 127 128 func TestRowAsDeleteStmt(t *testing.T) { 129 tableName := "tricky" 130 trickySch := dtestutils.CreateSchema( 131 schema.NewColumn("anotherCol", 0, types.FloatKind, false), 132 schema.NewColumn("a name with spaces", 1, types.IntKind, true), 133 ) 134 135 tests := []test{ 136 { 137 name: "negative values and columns with spaces", 138 row: dtestutils.NewRow(trickySch, types.Float(-3.14), types.Int(-42)), 139 sch: trickySch, 140 expectedOutput: "DELETE FROM `tricky` WHERE (`a name with spaces`=-42);", 141 }, 142 } 143 144 for _, tt := range tests { 145 t.Run(tt.name, func(t *testing.T) { 146 stmt, err := RowAsDeleteStmt(tt.row, tableName, tt.sch) 147 assert.NoError(t, err) 148 assert.Equal(t, tt.expectedOutput, stmt) 149 }) 150 } 151 } 152 153 func TestRowAsUpdateStmt(t *testing.T) { 154 id := uuid.MustParse("00000000-0000-0000-0000-000000000000") 155 tableName := "people" 156 157 tests := []test{ 158 { 159 name: "simple row", 160 row: dtestutils.NewTypedRow(id, "some guy", 100, false, strPointer("normie")), 161 sch: dtestutils.TypedSchema, 162 expectedOutput: "UPDATE `people` SET `name`='some guy',`age`=100,`is_married`=FALSE,`title`='normie' WHERE (`id`='00000000-0000-0000-0000-000000000000');", 163 }, 164 { 165 name: "embedded quotes", 166 row: dtestutils.NewTypedRow(id, `It's "Mister Perfect" to you`, 100, false, strPointer("normie")), 167 sch: dtestutils.TypedSchema, 168 expectedOutput: "UPDATE `people` SET `name`='It\\'s \\\"Mister Perfect\\\" to you',`age`=100,`is_married`=FALSE,`title`='normie' WHERE (`id`='00000000-0000-0000-0000-000000000000');", 169 }, 170 { 171 name: "null values", 172 row: dtestutils.NewTypedRow(id, "some guy", 100, false, nil), 173 sch: dtestutils.TypedSchema, 174 expectedOutput: "UPDATE `people` SET `name`='some guy',`age`=100,`is_married`=FALSE,`title`=NULL WHERE (`id`='00000000-0000-0000-0000-000000000000');", 175 }, 176 } 177 178 trickySch := dtestutils.CreateSchema( 179 schema.NewColumn("a name with spaces", 0, types.FloatKind, false), 180 schema.NewColumn("anotherColumn", 1, types.IntKind, true), 181 ) 182 183 tests = append(tests, test{ 184 name: "negative values and columns with spaces", 185 row: dtestutils.NewRow(trickySch, types.Float(-3.14), types.Int(-42)), 186 sch: trickySch, 187 expectedOutput: "UPDATE `people` SET `a name with spaces`=-3.14 WHERE (`anotherColumn`=-42);", 188 }) 189 190 for _, tt := range tests { 191 t.Run(tt.name, func(t *testing.T) { 192 stmt, err := RowAsUpdateStmt(tt.row, tableName, tt.sch) 193 assert.NoError(t, err) 194 assert.Equal(t, tt.expectedOutput, stmt) 195 }) 196 } 197 } 198 199 func TestValueAsSqlString(t *testing.T) { 200 tu, _ := uuid.Parse("00000000-0000-0000-0000-000000000000") 201 202 tests := []struct { 203 name string 204 val types.Value 205 ti typeinfo.TypeInfo 206 exp string 207 }{ 208 { 209 name: "bool(true)", 210 val: types.Bool(true), 211 ti: typeinfo.BoolType, 212 exp: "TRUE", 213 }, 214 { 215 name: "bool(false)", 216 val: types.Bool(false), 217 ti: typeinfo.BoolType, 218 exp: "FALSE", 219 }, 220 { 221 name: "uuid", 222 val: types.UUID(tu), 223 ti: typeinfo.UuidType, 224 exp: "'00000000-0000-0000-0000-000000000000'", 225 }, 226 { 227 name: "string", 228 val: types.String("leviosa"), 229 ti: typeinfo.StringDefaultType, 230 exp: "'leviosa'", 231 }, 232 { 233 // borrowed from vitess 234 name: "escape string", 235 val: types.String("\x00'\"\b\n\r\t\x1A\\"), 236 ti: typeinfo.StringDefaultType, 237 exp: "'\\0\\'\\\"\\b\\n\\r\\t\\Z\\\\'", 238 }, 239 } 240 241 for _, test := range tests { 242 t.Run(test.name, func(t *testing.T) { 243 act, err := valueAsSqlString(test.ti, test.val) 244 require.NoError(t, err) 245 assert.Equal(t, test.exp, act) 246 }) 247 } 248 } 249 250 func strPointer(s string) *string { 251 return &s 252 }