mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 00:55:55 +00:00
Make PQL case-insensitive about call names.
Use "" strings for fixed string names. In startCall(), look up the lowercase conversion of a call name in a table mapping all-lowercase representations to canonical case, so we don't have to chase down everyplace in the rest of the code base that assumes "Row" is capitalized exactly like that.
This commit is contained in:
parent
18ed02d7fb
commit
28d18920b9
4 changed files with 1767 additions and 1082 deletions
19
pql/ast.go
19
pql/ast.go
|
|
@ -33,6 +33,10 @@ type Query struct {
|
|||
}
|
||||
|
||||
func (q *Query) startCall(name string) {
|
||||
// Coerce every name into a canonical form if we know of one.
|
||||
if canon, ok := canonicalCaps[strings.ToLower(name)]; ok {
|
||||
name = canon
|
||||
}
|
||||
newCall := &Call{Name: name}
|
||||
q.callStack = append(q.callStack, &callStackElem{call: newCall})
|
||||
|
||||
|
|
@ -478,6 +482,21 @@ var callInfoByFunc = map[string]callInfo{
|
|||
},
|
||||
}
|
||||
|
||||
// We want to allow case-insensitive names, but we want to continue using
|
||||
// friendly easy-to-read names like "SetRowAttrs", not "setrowattrs". So,
|
||||
// we make a map; put in a ToLower() string, get back the canonical
|
||||
// capitalization. This might not have seemed like the best strategy if we
|
||||
// didn't already have so much code relying on the exact strings.
|
||||
var canonicalCaps = makeCanonicalMap(callInfoByFunc)
|
||||
|
||||
func makeCanonicalMap(from map[string]callInfo) map[string]string {
|
||||
m := make(map[string]string, len(from))
|
||||
for k := range from {
|
||||
m[strings.ToLower(k)] = k
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// CheckCallInfo tries to validate that arguments are correct and valid for the
|
||||
// given call. It does not guarantee checking all possible errors; for instance,
|
||||
// if an argument is a field name, CheckCallInfo can't validate that the field
|
||||
|
|
|
|||
|
|
@ -193,6 +193,23 @@ func TestParser_Parse(t *testing.T) {
|
|||
t.Fatalf("unexpected call: %#v", q.Calls[0])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("MixedCase", func(t *testing.T) {
|
||||
q, err := pql.ParseString(`roW(x=3)`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(q.Calls[0],
|
||||
&pql.Call{
|
||||
Name: "Row",
|
||||
Args: map[string]interface{}{
|
||||
"x": int64(3),
|
||||
},
|
||||
},
|
||||
) {
|
||||
t.Fatalf("unexpected call: %#v", q.Calls[0])
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestUnquote(t *testing.T) {
|
||||
|
|
|
|||
20
pql/pql.peg
20
pql/pql.peg
|
|
@ -6,16 +6,16 @@ type PQL Peg {
|
|||
|
||||
|
||||
Calls <- sp (Call sp)* !.
|
||||
Call <- 'Set' {p.startCall("Set")} open col comma args (comma timestamp)? close {p.endCall()}
|
||||
/ 'SetRowAttrs' {p.startCall("SetRowAttrs")} open posfield comma row 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()}
|
||||
/ 'ClearRow' {p.startCall("ClearRow")} open arg close {p.endCall()}
|
||||
/ 'Store' {p.startCall("Store")} open Call comma arg close {p.endCall()}
|
||||
/ 'TopN' {p.startCall("TopN")} open posfield (comma allargs)? close {p.endCall()}
|
||||
/ 'Rows' {p.startCall("Rows")} open posfield (comma allargs)? close {p.endCall()}
|
||||
/ 'Range' {p.startCall("Range")} open field sp '=' sp value comma 'from='? {p.addField("from")} timestampfmt {p.addVal(text)} comma 'to='? sp {p.addField("to")} timestampfmt {p.addVal(text)} close {p.endCall()}
|
||||
/ < IDENT > { p.startCall(text ) } open allargs comma? close { p.endCall() }
|
||||
Call <- "Set" {p.startCall("Set")} open col comma args (comma timestamp)? close {p.endCall()}
|
||||
/ "SetRowAttrs" {p.startCall("SetRowAttrs")} open posfield comma row 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()}
|
||||
/ "ClearRow" {p.startCall("ClearRow")} open arg close {p.endCall()}
|
||||
/ "Store" {p.startCall("Store")} open Call comma arg close {p.endCall()}
|
||||
/ "TopN" {p.startCall("TopN")} open posfield (comma allargs)? close {p.endCall()}
|
||||
/ "Rows" {p.startCall("Rows")} open posfield (comma allargs)? close {p.endCall()}
|
||||
/ "Range" {p.startCall("Range")} open field sp '=' sp value comma 'from='? {p.addField("from")} timestampfmt {p.addVal(text)} comma 'to='? sp {p.addField("to")} timestampfmt {p.addVal(text)} close {p.endCall()}
|
||||
/ < IDENT > { p.startCall(text) } open allargs comma? close { p.endCall() }
|
||||
allargs <- Call (comma Call)* (comma args)? / args / sp
|
||||
args <- arg (comma args)? sp
|
||||
arg <- field sp '=' sp value
|
||||
|
|
|
|||
2793
pql/pql.peg.go
2793
pql/pql.peg.go
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue