summaryrefslogtreecommitdiff
path: root/internal/mapr/token.go
blob: 77362f79db50a3bd778ffb5f2660f09ae911c262 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package mapr

import (
	"strings"
)

var keywords = [...]string{"select", "from", "where", "set", "group", "rorder",
	"order", "interval", "limit", "outfile", "logformat"}

// Represents a parsed token, used to parse the mapr query.
type token struct {
	str            string
	isBareword     bool
	quotesStripped bool
}

func (t token) isKeyword() bool {
	if !t.isBareword {
		return false
	}
	for _, keyword := range keywords {
		if strings.ToLower(t.str) == keyword {
			return true
		}
	}
	return false
}

func (t token) String() string {
	return t.str
}

func tokenize(queryStr string) []token {
	var tokens []token
	for i, part := range strings.Split(queryStr, "\"") {
		// Even i, means that it is not a quoted string
		if i%2 == 0 {
			commasStripped := strings.Replace(part, ",", " ", -1)
			for _, tokenStr := range strings.Fields(commasStripped) {
				token := token{
					str:        tokenStr,
					isBareword: true,
				}
				tokens = append(tokens, token)
			}
			continue
		}
		// Add whole quoted string as a token
		token := token{
			str:        part,
			isBareword: false,
		}
		tokens = append(tokens, token)
	}
	return tokens
}

func tokensConsume(tokens []token) ([]token, []token) {
	//dlog.Common.Trace("=====================")
	var consumed []token
	for i, t := range tokens {
		if t.isKeyword() {
			//dlog.Common.Trace("keyword", t)
			return tokens[i:], consumed
		}
		// strip escapes, such as ` from `foo`, this allows to use keywords as field names
		length := len(t.str)
		if length == 0 {
			continue
		}
		if t.str[0] == '`' && t.str[length-1] == '`' {
			stripped := t.str[1 : length-1]
			//dlog.Common.Trace("stripped", stripped)
			t := token{
				str:            stripped,
				isBareword:     t.isBareword,
				quotesStripped: true,
			}
			consumed = append(consumed, t)
			continue
		}
		//dlog.Common.Trace("bare", token)
		consumed = append(consumed, t)
	}
	//dlog.Common.Trace("result", consumed)
	return nil, consumed
}

func tokensConsumeStr(tokens []token) ([]token, []string) {
	var strings []string
	tokens, found := tokensConsume(tokens)
	for _, token := range found {
		strings = append(strings, token.str)
	}
	return tokens, strings
}

func tokensConsumeOptional(tokens []token, optional string) []token {
	if len(tokens) < 1 {
		return tokens
	}
	//if strings.ToLower(tokens[0].str) == strings.ToLower(optional) {
	if strings.EqualFold(tokens[0].str, optional) {
		return tokens[1:]
	}
	return tokens
}