forked from araddon/qlbridge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdialect_filterql.go
127 lines (118 loc) · 3.61 KB
/
dialect_filterql.go
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package lex
import (
"strings"
)
var (
// FilterStatement a FilterQL statement.
FilterStatement = []*Clause{
{Token: TokenFilter, Lexer: LexFilterClause, Optional: true},
{Token: TokenFrom, Lexer: LexIdentifier, Optional: true},
{Token: TokenLimit, Lexer: LexNumber, Optional: true},
{Token: TokenWith, Lexer: LexJsonOrKeyValue, Optional: true},
{Token: TokenAlias, Lexer: LexIdentifier, Optional: true},
{Token: TokenEOF, Lexer: LexEndOfStatement, Optional: false},
}
// FilterSelectStatement Filter statement that also supports column projection.
FilterSelectStatement = []*Clause{
{Token: TokenSelect, Lexer: LexSelectClause, Optional: false},
{Token: TokenFrom, Lexer: LexIdentifier, Optional: false},
{Token: TokenWhere, Lexer: LexConditionalClause, Optional: true},
{Token: TokenFilter, Lexer: LexFilterClause, Optional: true},
{Token: TokenLimit, Lexer: LexNumber, Optional: true},
{Token: TokenWith, Lexer: LexJsonOrKeyValue, Optional: true},
{Token: TokenAlias, Lexer: LexIdentifier, Optional: true},
{Token: TokenEOF, Lexer: LexEndOfStatement, Optional: false},
}
// FilterQLDialect is a Where Clause filtering language slightly
// more DSL'ish than SQL Where Clause.
FilterQLDialect *Dialect = &Dialect{
Statements: []*Clause{
{Token: TokenFilter, Clauses: FilterStatement},
{Token: TokenSelect, Clauses: FilterSelectStatement},
},
IdentityQuoting: IdentityQuotingWSingleQuote,
}
)
// NewFilterQLLexer creates a new lexer for the input string using FilterQLDialect
// which is dsl for where/filtering.
func NewFilterQLLexer(input string) *Lexer {
return NewLexer(input, FilterQLDialect)
}
// LexFilterClause Handle Filter QL Main Statement
//
// FILTER := ( <filter_bool_expr> | <filter_expr> )
//
// <filter_bool_expr> := ( AND | OR ) '(' ( <filter_bool_expr> | <filter_expr> ) [, ( <filter_bool_expr> | <filter_expr> ) ] ')'
//
// <filter_expr> := <expr>
//
// Examples:
//
// FILTER
/// AND (
// daysago(datefield) < 100
// , domain(url) == "google.com"
// , INCLUDE name_of_filter
// ,
// , OR (
// momentum > 20
// , propensity > 50
// )
// )
// ALIAS myfilter
//
// FILTER x > 7
//
func LexFilterClause(l *Lexer) StateFn {
if l.SkipWhiteSpacesNewLine() {
l.Emit(TokenNewLine)
debugf("%p LexFilterClause emit new line stack=%d", l, len(l.stack))
l.Push("LexFilterClause", LexFilterClause)
return LexFilterClause
}
if l.IsComment() {
l.Push("LexFilterClause", LexFilterClause)
debugf("%p LexFilterClause comment stack=%d", l, len(l.stack))
return LexComment
}
keyWord := strings.ToLower(l.PeekWord())
debugf("%p LexFilterClause r=%-15q stack=%d", l, string(keyWord), len(l.stack))
switch keyWord {
case "from", "with":
return nil
case "include":
l.ConsumeWord(keyWord)
l.Emit(TokenInclude)
l.Push("LexFilterClause", LexFilterClause)
return LexIdentifier
case "and":
l.ConsumeWord(keyWord)
l.Emit(TokenLogicAnd)
l.Push("LexFilterClause", LexFilterClause)
return LexFilterClause
case "or":
l.ConsumeWord(keyWord)
l.Emit(TokenLogicOr)
l.Push("LexFilterClause", LexFilterClause)
return LexFilterClause
case "not":
l.ConsumeWord(keyWord)
l.Emit(TokenNegate)
return LexFilterClause
case "(":
l.ConsumeWord(keyWord)
l.Emit(TokenLeftParenthesis)
l.Push("LexFilterClause", LexFilterClause)
return LexFilterClause
case ",":
l.ConsumeWord(keyWord)
l.Emit(TokenComma)
l.Push("LexFilterClause", LexFilterClause)
return LexFilterClause
case ")":
l.ConsumeWord(keyWord)
l.Emit(TokenRightParenthesis)
return nil
}
return LexExpression
}