feat: parse joins
This commit is contained in:
parent
bb9c71c49e
commit
2f7d996485
118
q/parse.go
118
q/parse.go
@ -7,6 +7,16 @@ import (
|
||||
"github.com/DataDog/go-sqllexer"
|
||||
)
|
||||
|
||||
// Find first token in array that matches condition
|
||||
func FindTokenInArray(tokens []Token, condition func(Token) bool) (*Token, int) {
|
||||
for i, element := range tokens {
|
||||
if condition(element) {
|
||||
return &element, i
|
||||
}
|
||||
}
|
||||
return nil, -1
|
||||
}
|
||||
|
||||
type Token = sqllexer.Token
|
||||
|
||||
type parser struct {
|
||||
@ -352,10 +362,16 @@ func parseJoins(p *parser) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var joinTokenRanges []Token
|
||||
type FoundJoinSubslices struct {
|
||||
Tokens []Token
|
||||
StartingIndexInGreaterStatement int
|
||||
}
|
||||
|
||||
for i := 0; i < len(foundJoinKeywords); i++ {
|
||||
startRangeIndex := foundJoinKeywords[i].Index
|
||||
var joinTokenRanges []FoundJoinSubslices
|
||||
|
||||
for i, foundJoin := range foundJoinKeywords {
|
||||
|
||||
startRangeIndex := foundJoin.Index
|
||||
var endRangeIndex int
|
||||
|
||||
if i == (len(foundJoinKeywords) - 1) {
|
||||
@ -364,7 +380,101 @@ func parseJoins(p *parser) error {
|
||||
endRangeIndex = foundJoinKeywords[i+1].Index
|
||||
}
|
||||
|
||||
joinTokenRanges = append(joinTokenRanges, p.tokens[startRangeIndex:endRangeIndex]...)
|
||||
joinTokenRanges = append(joinTokenRanges, FoundJoinSubslices{
|
||||
Tokens: p.tokens[startRangeIndex:endRangeIndex],
|
||||
StartingIndexInGreaterStatement: startRangeIndex,
|
||||
})
|
||||
}
|
||||
|
||||
for _, joinRange := range joinTokenRanges {
|
||||
var workingJoin Join
|
||||
workingJoin.MainTable = selectQuery.Table
|
||||
|
||||
// check for the join type by looking backwards in the greater statement
|
||||
joinTypeSearchIndex := joinRange.StartingIndexInGreaterStatement - 1
|
||||
for ; joinTypeSearchIndex >= 0; joinTypeSearchIndex-- {
|
||||
if p.tokens[joinTypeSearchIndex].Type == sqllexer.KEYWORD {
|
||||
switch strings.ToUpper(p.tokens[joinTypeSearchIndex].Value) {
|
||||
case "LEFT":
|
||||
workingJoin.Type = LEFT
|
||||
break
|
||||
case "RIGHT":
|
||||
workingJoin.Type = RIGHT
|
||||
break
|
||||
case "FULL":
|
||||
workingJoin.Type = FULL
|
||||
break
|
||||
case "SELF":
|
||||
workingJoin.Type = SELF
|
||||
break
|
||||
case "INNER":
|
||||
workingJoin.Type = INNER
|
||||
default:
|
||||
workingJoin.Type = INNER
|
||||
}
|
||||
break // Stop after finding first keyword
|
||||
}
|
||||
}
|
||||
|
||||
// Find joined table name
|
||||
for i := 1; i < len(joinRange.Tokens); i++ {
|
||||
if joinRange.Tokens[i].Type == sqllexer.IDENT {
|
||||
workingJoin.JoiningTable.Name = joinRange.Tokens[i].Value
|
||||
break // Stop after finding first IDENT
|
||||
// TODO: make sure you dont have to check for aliases
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//var ons []Conditional
|
||||
var workingOn Conditional
|
||||
|
||||
_, foundOnTokenIndex := FindTokenInArray(joinRange.Tokens, func(t Token) bool {
|
||||
return t.Type == sqllexer.KEYWORD && strings.ToUpper(t.Value) == "ON"
|
||||
})
|
||||
|
||||
fmt.Printf("Found ON at '%d'\n", foundOnTokenIndex)
|
||||
|
||||
if foundOnTokenIndex < 0 {
|
||||
selectQuery.Joins = append(selectQuery.Joins, workingJoin)
|
||||
continue
|
||||
}
|
||||
|
||||
for i := foundOnTokenIndex + 1; i < len(joinRange.Tokens); i++ {
|
||||
t := &joinRange.Tokens[i]
|
||||
|
||||
if t.Type == sqllexer.KEYWORD && strings.ToUpper(t.Value) != "AND" && strings.ToUpper(t.Value) != "OR" && strings.ToUpper(t.Value) != "NOT" {
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Printf("Currently at '%d', reading '%s'\n", i, t.Value)
|
||||
|
||||
if t.Type == sqllexer.IDENT {
|
||||
if workingOn.Key == "" {
|
||||
workingOn.Key = t.Value
|
||||
} else {
|
||||
workingOn.Value = t.Value
|
||||
}
|
||||
} else if t.Type == sqllexer.OPERATOR {
|
||||
workingOn.Operator = t.Value
|
||||
} else if t.Type == sqllexer.BOOLEAN || t.Type == sqllexer.NULL || t.Type == sqllexer.STRING || t.Type == sqllexer.NUMBER {
|
||||
workingOn.Value = t.Value
|
||||
} else if t.Type == sqllexer.KEYWORD {
|
||||
if strings.ToUpper(t.Value) == "AND" || strings.ToUpper(t.Value) == "OR" {
|
||||
workingOn.Extension = strings.ToUpper(t.Value)
|
||||
}
|
||||
}
|
||||
|
||||
if workingOn.Key != "" && workingOn.Operator != "" && workingOn.Value != "" {
|
||||
workingJoin.Ons = append(workingJoin.Ons, workingOn)
|
||||
fmt.Println("Adding ON to workingJoin")
|
||||
fmt.Println(workingOn)
|
||||
workingOn = Conditional{}
|
||||
}
|
||||
}
|
||||
|
||||
selectQuery.Joins = append(selectQuery.Joins, workingJoin)
|
||||
workingJoin = Join{}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -164,6 +164,9 @@ func TestParseSelectStatement_StateMachine(t *testing.T) {
|
||||
{
|
||||
Type: INNER,
|
||||
MainTable: Table{
|
||||
Name: "Products",
|
||||
},
|
||||
JoiningTable: Table{
|
||||
Name: "Categories",
|
||||
},
|
||||
Ons: []Conditional{
|
||||
@ -277,17 +280,17 @@ func TestParseSelectStatement_StateMachine(t *testing.T) {
|
||||
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.Conditionals[on_i].Key {
|
||||
t.Errorf("got %s for Select.Conditionals[%d].Key, expected %s", answerAsSelect.Conditionals[on_i].Key, on_i, expectedCondition.Key)
|
||||
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.Conditionals[on_i].Operator {
|
||||
t.Errorf("got %s for Select.Conditionals[%d].Operator, expected %s", answerAsSelect.Conditionals[on_i].Operator, on_i, expectedCondition.Operator)
|
||||
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.Conditionals[on_i].Value {
|
||||
t.Errorf("got %s for Select.Conditionals[%d].Value, expected %s", answerAsSelect.Conditionals[on_i].Value, on_i, expectedCondition.Value)
|
||||
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.Conditionals[on_i].Extension {
|
||||
t.Errorf("got %s for Select.Conditionals[%d].Extension, expected %s", answerAsSelect.Conditionals[on_i].Extension, on_i, expectedCondition.Extension)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user