github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqx/dot_test.go (about) 1 package sqx_test 2 3 import ( 4 "bufio" 5 "reflect" 6 "strings" 7 "testing" 8 9 "github.com/bingoohuang/gg/pkg/sqx" 10 _ "github.com/mattn/go-sqlite3" 11 "github.com/stretchr/testify/assert" 12 ) 13 14 type mss = map[string]string 15 16 func TestGetTag(t *testing.T) { 17 tests := []struct { 18 line, want string 19 attrs mss 20 }{ 21 {"SELECT 1+1", "", nil}, 22 {"-- Some Comment", "", mss{"Some": "", "Comment": ""}}, 23 {"-- name: ", "", mss{"name": ""}}, 24 { 25 "-- name: find-users-by-name dbtype: mysql", "find-users-by-name", 26 mss{"name": "find-users-by-name", "dbtype": "mysql"}, 27 }, 28 {" -- name: save-user ", "save-user", mss{"name": "save-user"}}, 29 } 30 31 for _, c := range tests { 32 attrs, name := sqx.ParseDotTag(c.line, "--", "name") 33 if name != c.want { 34 t.Errorf("isTag('%s') == %s, expect %s", c.line, name, c.want) 35 } 36 37 if !reflect.DeepEqual(attrs, c.attrs) { 38 t.Errorf("attrsOfTag('%s') == %v, expect %v", c.line, attrs, c.attrs) 39 } 40 } 41 } 42 43 func TestScannerRun(t *testing.T) { 44 sqlFile := ` 45 -- name: all-users 46 -- Finds all users 47 SELECT * from USER 48 -- name: empty-query-should-not-be-stored 49 -- name: save-user 50 INSERT INTO users (?, ?, ?) 51 ` 52 53 scanner := &sqx.DotScanner{} 54 queries := scanner.Run(bufio.NewScanner(strings.NewReader(sqlFile))) 55 56 numberOfQueries := len(queries) 57 expectedQueries := 2 58 59 if numberOfQueries != expectedQueries { 60 t.Errorf("Scanner/Run() has %d queries instead of %d", 61 numberOfQueries, expectedQueries) 62 } 63 } 64 65 func TestLoad(t *testing.T) { 66 _, err := sqx.DotSQLLoad(strings.NewReader("")) 67 assert.Nil(t, err) 68 } 69 70 func TestLoadFromFile(t *testing.T) { 71 dot, err := sqx.DotSQLLoadFile("./non-existent.sql") 72 assert.NotNil(t, err, "error expected to be non-nil, got nil") 73 assert.Nil(t, dot, "dotsql instance expected to be nil, got non-nil") 74 75 dot, err = sqx.DotSQLLoadFile("testdata/test_schema.sql") 76 assert.Nil(t, err) 77 78 assert.NotNil(t, dot, "dotsql instance expected to be non-nil, got nil") 79 } 80 81 func TestLoadFromString(t *testing.T) { 82 _, err := sqx.DotSQLLoadString("") 83 assert.Nil(t, err) 84 } 85 86 func TestRaw(t *testing.T) { 87 expectedQuery := "SELECT 1+1" 88 89 dot, err := sqx.DotSQLLoadString("--name: my-query\n" + expectedQuery) 90 assert.Nil(t, err) 91 92 eval, err := dot.Raw("my-query") 93 assert.Nil(t, err) 94 95 got, _ := eval.Eval(map[string]interface{}{}) 96 got = strings.TrimSpace(got) 97 assert.Equal(t, expectedQuery, got, "Raw() == '%s', expected '%s'", got, expectedQuery) 98 } 99 100 func TestQueries(t *testing.T) { 101 expectedQueryMap := map[string]string{ 102 "select": "SELECT *\nfrom users", 103 "insert": "INSERT INTO users (?, ?, ?)", 104 } 105 106 dot, err := sqx.DotSQLLoadString(` 107 -- name: select 108 SELECT * 109 from users; 110 111 -- name: insert 112 INSERT INTO users (?, ?, ?) 113 `) 114 assert.Nil(t, err) 115 116 got := dot.Dots 117 118 if len(got) != len(expectedQueryMap) { 119 t.Errorf("QueryMap() len (%d) differ from expected (%d)", len(got), len(expectedQueryMap)) 120 } 121 122 for name, query := range got { 123 if query.RawSQL() != expectedQueryMap[name] { 124 t.Errorf("QueryMap()[%s] == '%s', expected '%s'", name, query, expectedQueryMap[name]) 125 } 126 } 127 } 128 129 func TestParseSQL(t *testing.T) { 130 parsed, err := sqx.ParseSQL("", "insert into person(name, age) values(:name, :age)") 131 assert.Nil(t, err) 132 assert.Equal(t, &sqx.SQLParsed{ 133 RawStmt: "insert into person(name, age) values(?, ?)", 134 BindBy: sqx.ByName, 135 Vars: []string{"name", "age"}, 136 MaxSeq: 2, 137 }, parsed) 138 139 parsed, err = sqx.ParseSQL("", "insert into person(name, age) values(:1, :2)") 140 assert.Nil(t, err) 141 assert.Equal(t, &sqx.SQLParsed{ 142 RawStmt: "insert into person(name, age) values(?, ?)", 143 BindBy: sqx.BySeq, 144 Vars: []string{"1", "2"}, 145 MaxSeq: 2, 146 }, parsed) 147 148 parsed, err = sqx.ParseSQL("", "insert into person(name, age) values(:, :)") 149 assert.Nil(t, err) 150 assert.Equal(t, &sqx.SQLParsed{ 151 RawStmt: "insert into person(name, age) values(?, ?)", 152 BindBy: sqx.ByAuto, 153 Vars: []string{"", ""}, 154 MaxSeq: 2, 155 }, parsed) 156 157 parsed, err = sqx.ParseSQL("", "insert into person(name, age) values('a', 'b')") 158 assert.Nil(t, err) 159 assert.Equal(t, &sqx.SQLParsed{ 160 RawStmt: "insert into person(name, age) values('a', 'b')", 161 BindBy: sqx.ByNone, 162 Vars: []string{}, 163 }, parsed) 164 165 parsed, err = sqx.ParseSQL("auto", "insert into person(name, age) values(:, :age)") 166 assert.Nil(t, parsed) 167 assert.NotNil(t, err) 168 } 169 170 func TestConvertSQLLines(t *testing.T) { 171 that := assert.New(t) 172 173 that.Equal([]string{"a\nb\nc"}, sqx.ConvertSQLLines([]string{"a", "b", "c"})) 174 that.Equal([]string{"--a", "b\nc"}, sqx.ConvertSQLLines([]string{"--a", "b", "c"})) 175 that.Equal([]string{"-- if", "b", "-- end"}, sqx.ConvertSQLLines([]string{"-- if", "b", "-- end"})) 176 that.Equal([]string{"-- if", "b", "-- end"}, sqx.ConvertSQLLines([]string{"/* if */ b /* end */"})) 177 that.Equal([]string{"-- if", "b", "-- end"}, sqx.ConvertSQLLines([]string{"/* if */ ", "b", " /* end */"})) 178 that.Equal([]string{"-- if", "b\nc", "-- end"}, sqx.ConvertSQLLines([]string{"/* if */ ", "b", "c", " /* end */"})) 179 that.Equal([]string{"-- if", "b\nc", "-- end"}, sqx.ConvertSQLLines([]string{"/* if ", "*/b", "c/*", " end */"})) 180 } 181 182 func TestParseDynamicSQL(t *testing.T) { 183 that := assert.New(t) 184 185 { 186 lines, part, err := sqx.ParseDynamicSQL([]string{"-- if a", "b", "-- end"}) 187 that.Nil(err) 188 that.Equal(3, lines) 189 that.Equal(&sqx.MultiPart{Parts: []sqx.SQLPart{ 190 &sqx.IfPart{ 191 Conditions: []sqx.IfCondition{ 192 { 193 Expr: "a", 194 Part: &sqx.MultiPart{ 195 Parts: []sqx.SQLPart{&sqx.LiteralPart{Literal: "b"}}, 196 }, 197 }, 198 }, 199 Else: nil, 200 }, 201 }}, part) 202 } 203 204 { 205 lines, part, err := sqx.ParseDynamicSQL([]string{"-- if a", "b", "-- else ", "c", "-- end"}) 206 that.Nil(err) 207 that.Equal(5, lines) 208 that.Equal(&sqx.MultiPart{Parts: []sqx.SQLPart{ 209 &sqx.IfPart{ 210 Conditions: []sqx.IfCondition{ 211 { 212 Expr: "a", 213 Part: &sqx.MultiPart{ 214 Parts: []sqx.SQLPart{&sqx.LiteralPart{Literal: "b"}}, 215 }, 216 }, 217 }, 218 Else: &sqx.MultiPart{ 219 Parts: []sqx.SQLPart{&sqx.LiteralPart{Literal: "c"}}, 220 }, 221 }, 222 }}, part) 223 } 224 225 { 226 // nolint:lll 227 lines, part, err := sqx.ParseDynamicSQL([]string{"-- if a", "-- if b", "b", "-- end", "-- else ", "-- if c", "c", "-- end", "-- end"}) 228 that.Nil(err) 229 that.Equal(9, lines) 230 that.Equal(&sqx.MultiPart{Parts: []sqx.SQLPart{ 231 &sqx.IfPart{ 232 Conditions: []sqx.IfCondition{ 233 { 234 Expr: "a", 235 Part: &sqx.MultiPart{ 236 Parts: []sqx.SQLPart{ 237 &sqx.IfPart{ 238 Conditions: []sqx.IfCondition{ 239 { 240 Expr: "b", 241 Part: &sqx.MultiPart{ 242 Parts: []sqx.SQLPart{&sqx.LiteralPart{Literal: "b"}}, 243 }, 244 }, 245 }, 246 }, 247 }, 248 }, 249 }, 250 }, 251 Else: &sqx.MultiPart{ 252 Parts: []sqx.SQLPart{ 253 &sqx.IfPart{ 254 Conditions: []sqx.IfCondition{ 255 { 256 Expr: "c", 257 Part: &sqx.MultiPart{ 258 Parts: []sqx.SQLPart{&sqx.LiteralPart{Literal: "c"}}, 259 }, 260 }, 261 }, 262 }, 263 }, 264 }, 265 }, 266 }}, part) 267 } 268 269 { 270 lines, part, err := sqx.ParseDynamicSQL([]string{"-- if a", "a", "-- elseif b ", "b", "-- end"}) 271 that.Nil(err) 272 that.Equal(5, lines) 273 that.Equal(&sqx.MultiPart{Parts: []sqx.SQLPart{ 274 &sqx.IfPart{ 275 Conditions: []sqx.IfCondition{ 276 { 277 Expr: "a", 278 Part: &sqx.MultiPart{ 279 Parts: []sqx.SQLPart{&sqx.LiteralPart{Literal: "a"}}, 280 }, 281 }, { 282 Expr: "b", 283 Part: &sqx.MultiPart{ 284 Parts: []sqx.SQLPart{&sqx.LiteralPart{Literal: "b"}}, 285 }, 286 }, 287 }, 288 }, 289 }}, part) 290 } 291 292 { 293 // nolint:lll 294 lines, part, err := sqx.ParseDynamicSQL([]string{"-- if a", "-- if b", "ab", "-- elseif c ", "ac", "-- end", "-- end"}) 295 that.Nil(err) 296 that.Equal(7, lines) 297 that.Equal(&sqx.MultiPart{Parts: []sqx.SQLPart{ 298 &sqx.IfPart{ 299 Conditions: []sqx.IfCondition{ 300 { 301 Expr: "a", 302 Part: &sqx.MultiPart{ 303 Parts: []sqx.SQLPart{ 304 &sqx.IfPart{ 305 Conditions: []sqx.IfCondition{ 306 { 307 Expr: "b", 308 Part: &sqx.MultiPart{ 309 Parts: []sqx.SQLPart{&sqx.LiteralPart{Literal: "ab"}}, 310 }, 311 }, { 312 Expr: "c", 313 Part: &sqx.MultiPart{ 314 Parts: []sqx.SQLPart{&sqx.LiteralPart{Literal: "ac"}}, 315 }, 316 }, 317 }, 318 }, 319 }, 320 }, 321 }, 322 }, 323 }, 324 }}, part) 325 } 326 327 { 328 lines, part, err := sqx.ParseDynamicSQL([]string{ 329 "-- if a", "-- if b", "ab", "-- elseif c ", "ac", "-- end", 330 "-- else ", "x", "-- end", 331 }) 332 that.Nil(err) 333 that.Equal(9, lines) 334 that.Equal(&sqx.MultiPart{Parts: []sqx.SQLPart{ 335 &sqx.IfPart{ 336 Conditions: []sqx.IfCondition{ 337 { 338 Expr: "a", 339 Part: &sqx.MultiPart{ 340 Parts: []sqx.SQLPart{ 341 &sqx.IfPart{ 342 Conditions: []sqx.IfCondition{ 343 { 344 Expr: "b", 345 Part: &sqx.MultiPart{Parts: []sqx.SQLPart{ 346 &sqx.LiteralPart{Literal: "ab"}, 347 }}, 348 }, { 349 Expr: "c", 350 Part: &sqx.MultiPart{Parts: []sqx.SQLPart{ 351 &sqx.LiteralPart{Literal: "ac"}, 352 }}, 353 }, 354 }, 355 }, 356 }, 357 }, 358 }, 359 }, 360 Else: &sqx.MultiPart{Parts: []sqx.SQLPart{&sqx.LiteralPart{ 361 Literal: "x", 362 }}}, 363 }, 364 }}, part) 365 } 366 }