package q import ( "fmt" "testing" ) type ParsingTest struct { input string expected Query } func TestParseSelectStatement_StateMachine(t *testing.T) { var testSqlStatements = []ParsingTest{ { input: "SELECT * FROM users WHERE age >= 30", expected: &Select{ Type: SELECT, Table: Table{Name: "users"}, IsWildcard: true, Conditionals: []Conditional{ { Key: "age", Operator: ">=", Value: "30", }, }, }, }, { input: "SELECT CustomerName, City FROM Customers", expected: &Select{ Type: SELECT, Table: Table{Name: "Customers"}, IsWildcard: false, Columns: []Column{ { Name: "CustomerName", }, { Name: "City", }, }, }, }, { input: "SELECT CustomerName AS Customer, City AS town FROM Customers AS People", expected: &Select{ Type: SELECT, Table: Table{Name: "Customers", Alias: "People"}, IsWildcard: false, Columns: []Column{ { Name: "CustomerName", Alias: "Customer", }, { Name: "City", Alias: "town", }, }, }, }, { input: "SELECT * FROM Orders ORDER BY StreetNumber, CountryCode;", expected: &Select{ Type: SELECT, Table: Table{Name: "Orders"}, IsWildcard: true, OrderBys: []OrderBy{ { Key: "StreetNumber", }, { Key: "CountryCode", }, }, }, }, { input: "SELECT * FROM ZipCodes ORDER BY Code ASC, StateName DESC", expected: &Select{ Type: SELECT, Table: Table{Name: "ZipCodes"}, IsWildcard: true, OrderBys: []OrderBy{ { Key: "Code", IsDescend: false, }, { Key: "StateName", IsDescend: true, }, }, }, }, { input: "SELECT id, streetNumber AS streetNum, streetName, city, state FROM Addresses WHERE state = 'AL' AND zip > 9000 OR zip <= 12000 ORDER BY zip DESC, streetNumber", expected: &Select{ Type: SELECT, Table: Table{Name: "Addresses"}, IsWildcard: false, Columns: []Column{ { Name: "id", }, { Name: "streetNumber", Alias: "streetNum", }, { Name: "streetName", }, { Name: "city", }, { Name: "state", }, }, Conditionals: []Conditional{ { Key: "state", Operator: "=", Value: "'AL'", }, { Key: "zip", Operator: ">", Value: "9000", Extension: "AND", }, { Key: "zip", Operator: "<=", Value: "12000", Extension: "OR", }, }, OrderBys: []OrderBy{ { Key: "zip", IsDescend: true, }, { Key: "streetNumber", IsDescend: false, }, }, }, }, { input: "SELECT ProductID, ProductName, CategoryName FROM Products INNER JOIN Categories ON Products.CategoryID = Categories.CategoryID AND Products.SupplierID = Categories.SupplierID LEFT JOIN Stores ON Products.StoreID = Stores.ID ;", expected: &Select{ Type: SELECT, Table: Table{Name: "Products"}, Columns: []Column{ {Name: "ProductID"}, {Name: "ProductName"}, {Name: "CategoryName"}, }, Joins: []Join{ { Type: INNER, MainTable: Table{ Name: "Products", }, JoiningTable: Table{ Name: "Categories", }, Ons: []Conditional{ { Key: "Products.CategoryID", Operator: "=", Value: "Categories.CategoryID", }, { Key: "Products.SupplierID", Operator: "=", Value: "Categories.SupplierID", Extension: "AND", }, }, }, { Type: LEFT, MainTable: Table{ Name: "Products", }, JoiningTable: Table{ Name: "Stores", }, Ons: []Conditional{ { Key: "Products.StoreID", Operator: "=", Value: "Stores.ID", }, }, }, }, }, }, } for _, sql := range testSqlStatements { testName := fmt.Sprintf("%s", sql.input) expected := sql.expected.(*Select) t.Run(testName, func(t *testing.T) { answer, err := Parse(sql.input) if err != nil { t.Error(err) return } answerAsSelect := answer.(*Select) if answerAsSelect.Type != expected.Type { t.Errorf("got %d for Select.Type, expected %d", answerAsSelect.Type, expected.Type) } if answerAsSelect.IsWildcard != expected.IsWildcard { t.Errorf("got %#v for Select.IsWildcard, expected %#v", answerAsSelect.IsWildcard, expected.IsWildcard) } if answerAsSelect.Table.Name != expected.Table.Name { t.Errorf("got %s for Select.Table.Name, expected %s", answerAsSelect.Table.Name, expected.Table.Name) } if answerAsSelect.Table.Alias != expected.Table.Alias { t.Errorf("got %s for Select.Table.Alias, expected %s", answerAsSelect.Table.Alias, expected.Table.Alias) } if len(answerAsSelect.Columns) != len(expected.Columns) { t.Errorf("got %d number of columns for Select.Columns, expected %d", len(answerAsSelect.Columns), len(expected.Columns)) } else { for i, expectedColumn := range expected.Columns { if expectedColumn.Name != answerAsSelect.Columns[i].Name { t.Errorf("got %s for Select.Column[%d].Name, expected %s", answerAsSelect.Columns[i].Name, i, expectedColumn.Name) } if expectedColumn.Alias != answerAsSelect.Columns[i].Alias { t.Errorf("got %s for Select.Column[%d].Alias, expected %s", answerAsSelect.Columns[i].Alias, i, expectedColumn.Alias) } if expectedColumn.AggregateFunction != answerAsSelect.Columns[i].AggregateFunction { t.Errorf("got %d for Select.Column[%d].AggregateFunction, expected %d", answerAsSelect.Columns[i].AggregateFunction, i, expectedColumn.AggregateFunction) } } } if len(answerAsSelect.Conditionals) != len(expected.Conditionals) { t.Errorf("got %d number of conditionals for Select.Conditionals, expected %d", len(answerAsSelect.Conditionals), len(expected.Conditionals)) } else { for i, expectedCondition := range expected.Conditionals { if expectedCondition.Key != answerAsSelect.Conditionals[i].Key { t.Errorf("got %s for Select.Conditionals[%d].Key, expected %s", answerAsSelect.Conditionals[i].Key, i, expectedCondition.Key) } if expectedCondition.Operator != answerAsSelect.Conditionals[i].Operator { t.Errorf("got %s for Select.Conditionals[%d].Operator, expected %s", answerAsSelect.Conditionals[i].Operator, i, expectedCondition.Operator) } if expectedCondition.Value != answerAsSelect.Conditionals[i].Value { t.Errorf("got %s for Select.Conditionals[%d].Value, expected %s", answerAsSelect.Conditionals[i].Value, i, expectedCondition.Value) } if expectedCondition.Extension != answerAsSelect.Conditionals[i].Extension { t.Errorf("got %s for Select.Conditionals[%d].Extension, expected %s", answerAsSelect.Conditionals[i].Extension, i, expectedCondition.Extension) } } } if len(answerAsSelect.OrderBys) != len(expected.OrderBys) { t.Errorf("got %d number of orderBys for Select.OrderBys, expected %d", len(answerAsSelect.OrderBys), len(expected.OrderBys)) } else { for i, expectedOrderBy := range expected.OrderBys { if expectedOrderBy.Key != answerAsSelect.OrderBys[i].Key { t.Errorf("got %s for Select.OrderBys[%d].Key, expected %s", answerAsSelect.OrderBys[i].Key, i, expectedOrderBy.Key) } if expectedOrderBy.IsDescend != answerAsSelect.OrderBys[i].IsDescend { t.Errorf("got %#v for Select.OrderBys[%d].IsDescend, expected %#v", answerAsSelect.OrderBys[i].IsDescend, i, expectedOrderBy.IsDescend) } } } if len(answerAsSelect.Joins) != len(expected.Joins) { t.Errorf("got %d number of joins for Select.Joinss, expected %d", len(answerAsSelect.Joins), len(expected.Joins)) } else { for i, expectedJoin := range expected.Joins { if answerAsSelect.Joins[i].Type != expectedJoin.Type { t.Errorf("got %d for Select.Joins[%d].Type, expected %d", answerAsSelect.Joins[i].Type, i, expectedJoin.Type) } if answerAsSelect.Joins[i].MainTable.Name != expectedJoin.MainTable.Name { t.Errorf("got %s for Select.Joins[%d].MainTable.Name, expected %s", answerAsSelect.Joins[i].MainTable.Name, i, expectedJoin.MainTable.Name) } if answerAsSelect.Joins[i].MainTable.Alias != expectedJoin.MainTable.Alias { t.Errorf("got %s for Select.Joins[%d].MainTable.Alias, expected %s", answerAsSelect.Joins[i].MainTable.Alias, i, expectedJoin.MainTable.Alias) } if answerAsSelect.Joins[i].JoiningTable.Name != expectedJoin.JoiningTable.Name { t.Errorf("got %s for Select.Joins[%d].JoiningTable.Name, expected %s", answerAsSelect.Joins[i].JoiningTable.Name, i, expectedJoin.JoiningTable.Name) } if answerAsSelect.Joins[i].JoiningTable.Alias != expectedJoin.JoiningTable.Alias { t.Errorf("got %s for Select.Joins[%d].JoiningTable.Alias, expected %s", answerAsSelect.Joins[i].JoiningTable.Alias, i, expectedJoin.JoiningTable.Alias) } if len(answerAsSelect.Joins[i].Ons) != len(expectedJoin.Ons) { t.Errorf("got %d number of ons for Select.Joins.Ons, expected %d", len(answerAsSelect.Joins[i].Ons), len(expectedJoin.Ons)) } else { for on_i, expectedCondition := range expected.Joins[i].Ons { if expectedCondition.Key != answerAsSelect.Joins[i].Ons[on_i].Key { t.Errorf("got %s for Select.Conditionals[%d].Key, expected %s", answerAsSelect.Joins[i].Ons[on_i].Key, on_i, expectedCondition.Key) } if expectedCondition.Operator != answerAsSelect.Joins[i].Ons[on_i].Operator { t.Errorf("got %s for Select.Conditionals[%d].Operator, expected %s", answerAsSelect.Joins[i].Ons[on_i].Operator, on_i, expectedCondition.Operator) } if expectedCondition.Value != answerAsSelect.Joins[i].Ons[on_i].Value { t.Errorf("got %s for Select.Conditionals[%d].Value, expected %s", answerAsSelect.Joins[i].Ons[on_i].Value, on_i, expectedCondition.Value) } if expectedCondition.Extension != answerAsSelect.Joins[i].Ons[on_i].Extension { t.Errorf("got %s for Select.Conditionals[%d].Extension, expected %s", answerAsSelect.Joins[i].Ons[on_i].Extension, on_i, expectedCondition.Extension) } } } } } }) } }