package q import ( "fmt" "strings" "github.com/DataDog/go-sqllexer" ) // 126 rich mar drive type Select struct { Table string Columns []string Conditionals []Conditional OrderBys []OrderBy IsWildcard bool IsDistinct bool } type OrderBy struct { Key string IsDescend bool } func (q *Select) GetFullSql() string { var workingSqlSlice []string workingSqlSlice = append(workingSqlSlice, "SELECT") if q.IsWildcard { workingSqlSlice = append(workingSqlSlice, "*") } else { for i, column := range q.Columns { if i < (len(q.Columns) - 1) { workingSqlSlice = append(workingSqlSlice, column+",") } else { workingSqlSlice = append(workingSqlSlice, column) } } } workingSqlSlice = append(workingSqlSlice, "FROM "+q.Table) // TODO: need to account for `AND` and `OR`s and stuff for _, condition := range q.Conditionals { workingSqlSlice = append(workingSqlSlice, condition.Key) workingSqlSlice = append(workingSqlSlice, condition.Operator) workingSqlSlice = append(workingSqlSlice, condition.Value) } fullSql := strings.Join(workingSqlSlice, " ") return fullSql } func mutateSelectFromKeyword(query *Select, keyword string) { switch strings.ToUpper(keyword) { case "DISTINCT": query.IsDistinct = true } } // TODO: make this an array of tokens instead func unshiftBuffer(buf *[10]string, value string) { for i := 9; i >= 1; i-- { buf[i] = buf[i-1] } buf[0] = value } func ParseSelectStatement(sql string) Select { query := Select{} passedSELECT := false passedColumns := false passedFROM := false passedTable := false passedWHERE := false passedConditionals := false passedOrderBy := false lookBehindBuffer := [10]string{} // TODO: make this an array of tokens instead var workingConditional = Conditional{} var columns []string var orderBys []OrderBy lexer := sqllexer.New(sql) for { token := lexer.Scan() if IsTokenEndOfStatement(token) { break } if !passedSELECT && strings.ToUpper(token.Value) != "SELECT" { break } else if !passedSELECT { passedSELECT = true continue } // For any keywords that are before the columns or wildcard if passedSELECT && len(columns) == 0 && !passedColumns { if token.Type == sqllexer.KEYWORD { mutateSelectFromKeyword(&query, token.Value) continue } } if !passedColumns { if token.Type == sqllexer.WILDCARD { passedColumns = true columns = make([]string, 0) query.IsWildcard = true continue } else if token.Type == sqllexer.IDENT { columns = append(columns, token.Value) continue } else if token.Type == sqllexer.PUNCTUATION || token.Type == sqllexer.SPACE { continue } else { passedColumns = true query.Columns = columns continue } } if !passedFROM && strings.ToUpper(token.Value) == "FROM" { passedFROM = true continue } else if !passedFROM { // continue // TODO: make sure to check for other keywords that are allowed } if !passedTable && token.Type == sqllexer.IDENT { passedTable = true query.Table = token.Value continue } else if !passedTable { continue } if !passedWHERE && token.Type == sqllexer.KEYWORD && strings.ToUpper(token.Value) == "WHERE" { passedWHERE = true continue } if passedWHERE && !passedConditionals { if token.Type == sqllexer.IDENT { workingConditional.Key = token.Value } else if token.Type == sqllexer.OPERATOR { workingConditional.Operator = token.Value } else if token.Type == sqllexer.BOOLEAN || token.Type == sqllexer.NULL || token.Type == sqllexer.STRING || token.Type == sqllexer.NUMBER { workingConditional.Value = token.Value } // TODO: add captire for data type if workingConditional.Key != "" && workingConditional.Operator != "" && workingConditional.Value != "" { query.Conditionals = append(query.Conditionals, workingConditional) workingConditional = Conditional{} passedConditionals = true } continue } // Checking For ORDER BY if !passedOrderBy && token.Type == sqllexer.KEYWORD { unshiftBuffer(&lookBehindBuffer, token.Value) if strings.ToUpper(lookBehindBuffer[1]) == "ORDER" && strings.ToUpper(lookBehindBuffer[0]) == "BY" { passedOrderBy = true } fmt.Printf("VALUE: %s %s \n", lookBehindBuffer[1], lookBehindBuffer[0]) } if passedOrderBy && token.Type == sqllexer.IDENT { orderBys = append(orderBys, OrderBy{ Key: token.Value, // TODO: need to be able to get the ASC or DESC keyword too }) query.OrderBys = orderBys } } return query }