mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-06 08:35:55 +00:00
Parser and test updates
This commit is contained in:
parent
1a2fa51b63
commit
5bf9af4df3
4 changed files with 1160 additions and 1125 deletions
14
pql/ast.go
14
pql/ast.go
|
|
@ -213,7 +213,7 @@ func (q *Query) WriteCallN() int {
|
|||
var n int
|
||||
for _, call := range q.Calls {
|
||||
switch call.Name {
|
||||
case "SetBit", "ClearBit", "SetRowAttrs", "SetColumnAttrs":
|
||||
case "Set", "Clear", "SetRowAttrs", "SetColumnAttrs":
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
|
@ -253,6 +253,18 @@ type Call struct {
|
|||
Children []*Call
|
||||
}
|
||||
|
||||
// FieldArg determines which key-value pair contains the field and rowID,
|
||||
// in the case of arguments like Set(colID, field=rowID).
|
||||
// Returns the field as a string if present, or an error if not.
|
||||
func (c *Call) FieldArg() (string, error) {
|
||||
for arg := range c.Args {
|
||||
if !strings.HasPrefix(arg, "_") {
|
||||
return arg, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("No field argument specified")
|
||||
}
|
||||
|
||||
// UintArg is for reading the value at key from call.Args as a uint64. If the
|
||||
// key is not in Call.Args, the value of the returned bool will be false, and
|
||||
// the error will be nil. The value is assumed to be a uint64 or an int64 and
|
||||
|
|
|
|||
15
pql/pql.peg
15
pql/pql.peg
|
|
@ -6,10 +6,10 @@ type PQL Peg {
|
|||
|
||||
|
||||
Calls <- whitesp (Call whitesp)* !.
|
||||
Call <- 'Set' {p.startCall("Set")} open uintcol comma args (comma timestamp)? close {p.endCall()}
|
||||
Call <- 'Set' {p.startCall("Set")} open col comma args (comma timestamp)? close {p.endCall()}
|
||||
/ 'SetRowAttrs' {p.startCall("SetRowAttrs")} open posfield comma uintrow comma args close {p.endCall()}
|
||||
/ 'SetColumnAttrs' {p.startCall("SetColumnAttrs")} open posfield comma uintcol comma args close {p.endCall()}
|
||||
/ 'Clear' {p.startCall("Clear")} open uintcol comma args close {p.endCall()}
|
||||
/ 'SetColumnAttrs' {p.startCall("SetColumnAttrs")} open col comma args close {p.endCall()}
|
||||
/ 'Clear' {p.startCall("Clear")} open col comma args close {p.endCall()}
|
||||
/ 'TopN' {p.startCall("TopN")} open posfield (comma allargs)? close {p.endCall()}
|
||||
/ 'Range' {p.startCall("Range")} open (timerange / conditional / arg) close {p.endCall()}
|
||||
/ < IDENT > { p.startCall(buffer[begin:end] ) } open allargs comma? close { p.endCall() }
|
||||
|
|
@ -51,11 +51,14 @@ doublequotedstring <- ( [^"\\\n] / '\\n' / '\\\"' / '\\\'' / '\\\\' )*
|
|||
singlequotedstring <- ( [^'\\\n] / '\\n' / '\\\"' / '\\\'' / '\\\\' )*
|
||||
|
||||
fieldExpr <- [[A-Z]] ( [[A-Z]] / [0-9] / '_' )*
|
||||
field <- <fieldExpr> { p.addField(buffer[begin:end]) }
|
||||
field <- <fieldExpr / reserved> { p.addField(buffer[begin:end]) }
|
||||
reserved <- ('_row' / '_col' / '_start' / '_end' / '_timestamp' / '_field')
|
||||
posfield <- <fieldExpr> { p.addPosStr("_field", buffer[begin:end]) }
|
||||
uint <- [1-9] [0-9]* / '0'
|
||||
uintrow <- <uint>{p.addPosNum("_row", buffer[begin:end])}
|
||||
uintcol <- <uint>{p.addPosNum("_col", buffer[begin:end])}
|
||||
col <- ( <uint> {p.addPosNum("_col", buffer[begin:end])}
|
||||
/ '"' <doublequotedstring> '"' {p.addPosStr("_col", buffer[begin:end])}
|
||||
)
|
||||
|
||||
open <- '(' sp
|
||||
close <- ')' sp
|
||||
|
|
@ -64,7 +67,7 @@ comma <- sp ',' whitesp
|
|||
lbrack <- '[' sp
|
||||
rbrack <- sp ']' sp
|
||||
whitesp <- ( ' ' / '\t' / '\n' )*
|
||||
IDENT <- !('Set(' / 'SetRowAttrs(' / 'SetColumnAttrs(' / 'Clear(' / 'TopN(' / 'Range(') [[A-Z]] ([[A-Z]] / [0-9])*
|
||||
IDENT <- [[A-Z]] ([[A-Z]] / [0-9])*
|
||||
|
||||
|
||||
timestampbasicfmt <- [0-9][0-9][0-9][0-9]'-'[01][0-9]'-'[0-3][0-9]'T'[0-9][0-9]':'[0-9][0-9]
|
||||
|
|
|
|||
2169
pql/pql.peg.go
2169
pql/pql.peg.go
File diff suppressed because it is too large
Load diff
|
|
@ -47,6 +47,13 @@ SetBit(Union(Zitmap(row==4), Intersect(Qitmap(blah>4), Ritmap(field="http://zoo9
|
|||
|
||||
}
|
||||
|
||||
func TestOldPQL(t *testing.T) {
|
||||
_, err := ParseString(`SetBit(f=11, col=1)`)
|
||||
if err != nil {
|
||||
t.Fatalf("should have parsed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPEGWorking(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
@ -59,7 +66,11 @@ func TestPEGWorking(t *testing.T) {
|
|||
ncalls: 0},
|
||||
{
|
||||
name: "Set",
|
||||
input: "Set(1, a=4)",
|
||||
input: "Set(2, f=10)",
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "SetTime",
|
||||
input: "Set(2, f=1, 1999-12-31T00:00)",
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "DoubleSet",
|
||||
|
|
@ -143,11 +154,11 @@ func TestPEGWorking(t *testing.T) {
|
|||
ncalls: 1},
|
||||
{
|
||||
name: "SetColumnAttrs",
|
||||
input: "SetColumnAttrs(blah, 9, a=47)",
|
||||
input: "SetColumnAttrs(9, a=47)",
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "SetColumnAttrs2args",
|
||||
input: "SetColumnAttrs(blah, 9, a=47, b=bval)",
|
||||
input: "SetColumnAttrs(9, a=47, b=bval)",
|
||||
ncalls: 1},
|
||||
{
|
||||
name: "Clear",
|
||||
|
|
@ -233,12 +244,6 @@ func TestPEGErrors(t *testing.T) {
|
|||
name string
|
||||
input string
|
||||
}{
|
||||
{
|
||||
name: "SetEmpty",
|
||||
input: "Set()"},
|
||||
{
|
||||
name: "SetNoCol",
|
||||
input: "Set(a=4)"},
|
||||
{
|
||||
name: "SetNoParens",
|
||||
input: "Set"},
|
||||
|
|
@ -248,24 +253,12 @@ func TestPEGErrors(t *testing.T) {
|
|||
{
|
||||
name: "SetTimestampNoArg",
|
||||
input: "Set(1, 2017-04-03T19:34)"},
|
||||
{
|
||||
name: "SetRowAttrsNoField",
|
||||
input: "SetRowAttrs(a=4)"},
|
||||
{
|
||||
name: "SetColumnAttrsNoField",
|
||||
input: "SetColumnAttrs(a=4)"},
|
||||
{
|
||||
name: "ClearNoCol",
|
||||
input: "Clear(a=4)"},
|
||||
{
|
||||
name: "SetStartingComma",
|
||||
input: "Set(, 1, a=4)"},
|
||||
{
|
||||
name: "StartinCommaArb",
|
||||
input: "Zeeb(, a=4)"},
|
||||
{
|
||||
name: "TopN No Field",
|
||||
input: "TopN(a=77)"},
|
||||
{
|
||||
name: "SetRowAttrs0args",
|
||||
input: "SetRowAttrs(blah, 9)"},
|
||||
|
|
@ -320,13 +313,12 @@ func TestPQLDeepEquality(t *testing.T) {
|
|||
}},
|
||||
{
|
||||
name: "SetColumnAttrs",
|
||||
call: "SetColumnAttrs(myfield, 9, z=4)",
|
||||
call: "SetColumnAttrs(9, z=4)",
|
||||
exp: &Call{
|
||||
Name: "SetColumnAttrs",
|
||||
Args: map[string]interface{}{
|
||||
"z": int64(4),
|
||||
"_field": "myfield",
|
||||
"_col": int64(9),
|
||||
"z": int64(4),
|
||||
"_col": int64(9),
|
||||
},
|
||||
}},
|
||||
{
|
||||
|
|
@ -472,6 +464,51 @@ func TestPQLDeepEquality(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "Sum",
|
||||
call: "Sum(field=f)",
|
||||
exp: &Call{
|
||||
Name: "Sum",
|
||||
Args: map[string]interface{}{
|
||||
"field": "f",
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "SumChild",
|
||||
call: "Sum(Row(), field=f)",
|
||||
exp: &Call{
|
||||
Name: "Sum",
|
||||
Args: map[string]interface{}{
|
||||
"field": "f",
|
||||
},
|
||||
Children: []*Call{
|
||||
{Name: "Row"},
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "MinChild",
|
||||
call: "Min(Row(), field=f)",
|
||||
exp: &Call{
|
||||
Name: "Min",
|
||||
Args: map[string]interface{}{
|
||||
"field": "f",
|
||||
},
|
||||
Children: []*Call{
|
||||
{Name: "Row"},
|
||||
},
|
||||
}},
|
||||
{
|
||||
name: "MaxChild",
|
||||
call: "Max(Row(), field=f)",
|
||||
exp: &Call{
|
||||
Name: "Max",
|
||||
Args: map[string]interface{}{
|
||||
"field": "f",
|
||||
},
|
||||
Children: []*Call{
|
||||
{Name: "Row"},
|
||||
},
|
||||
}},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue