mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
105 lines
2.3 KiB
Go
105 lines
2.3 KiB
Go
package query
|
|
|
|
import (
|
|
"errors"
|
|
"pilosa/db"
|
|
"strconv"
|
|
|
|
"tux21b.org/v1/gocql/uuid"
|
|
)
|
|
|
|
var InvalidQueryError = errors.New("Invalid query format.")
|
|
|
|
type QueryParser struct{}
|
|
|
|
func (qp *QueryParser) walkInputs(tokens []Token) ([]QueryInput, uint64) {
|
|
// BITMAP
|
|
if tokens[0].Type == TYPE_ID {
|
|
// TODO: look for frame type in the tokens list
|
|
b, err := strconv.Atoi(tokens[0].Text)
|
|
bitmap_id := uint64(b)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
// if the next 2 tokens are comma-frame, then we have a frame, else set to a default
|
|
frame_type := "general"
|
|
profile_id := 0
|
|
if len(tokens) > 4 && tokens[2].Type == TYPE_FRAME && tokens[4].Type == TYPE_PROFILE {
|
|
frame_type = tokens[2].Text
|
|
profile_id, err = strconv.Atoi(tokens[4].Text)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
} else if len(tokens) > 2 && tokens[2].Type == TYPE_FRAME {
|
|
frame_type = tokens[2].Text
|
|
} else if len(tokens) > 2 && tokens[2].Type == TYPE_PROFILE {
|
|
profile_id, err = strconv.Atoi(tokens[2].Text)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
bm := db.Bitmap{bitmap_id, frame_type}
|
|
return []QueryInput{&bm}, uint64(profile_id)
|
|
}
|
|
|
|
// LIST OF QUERIES
|
|
qi := []QueryInput{}
|
|
open_parens := -1 // >=0 means i'm inside the search for end paren
|
|
start := 0
|
|
for i := 0; i < len(tokens); i++ {
|
|
if tokens[i].Type == TYPE_FUNC && open_parens == -1 {
|
|
start = i
|
|
} else if tokens[i].Type == TYPE_LP {
|
|
open_parens++
|
|
} else if tokens[i].Type == TYPE_RP {
|
|
if open_parens == 0 {
|
|
q, err := qp.walk(tokens[start : i+1])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
qi = append(qi, q)
|
|
open_parens = -1
|
|
} else {
|
|
open_parens--
|
|
}
|
|
}
|
|
}
|
|
return qi, 0
|
|
}
|
|
|
|
func (qp *QueryParser) walk(tokens []Token) (*Query, error) {
|
|
|
|
if tokens[0].Type != TYPE_FUNC {
|
|
panic("BAD!")
|
|
}
|
|
if tokens[1].Type != TYPE_LP {
|
|
panic("BAD!")
|
|
}
|
|
|
|
q := new(Query)
|
|
id := uuid.RandomUUID()
|
|
q.Id = &id
|
|
q.Operation = tokens[0].Text
|
|
|
|
// scan from open to close paren
|
|
open_parens := 0
|
|
for i := 2; i < len(tokens); i++ {
|
|
// 1 must be "("
|
|
if tokens[i].Type == TYPE_LP {
|
|
open_parens++
|
|
} else if tokens[i].Type == TYPE_RP {
|
|
if open_parens == 0 {
|
|
if i == len(tokens)-1 {
|
|
q.Inputs, q.ProfileId = qp.walkInputs(tokens[2:i])
|
|
}
|
|
} else {
|
|
open_parens--
|
|
}
|
|
}
|
|
}
|
|
return q, nil
|
|
}
|
|
|
|
func (qp *QueryParser) Parse(tokens []Token) (*Query, error) {
|
|
return qp.walk(tokens)
|
|
}
|