From 6d93e41e7f8092d8ddeb2b63827b0f7b3d26244c Mon Sep 17 00:00:00 2001 From: Seebs Date: Tue, 22 Feb 2022 16:20:09 -0600 Subject: [PATCH] catch the panic we throw for an invalid timestamp We recover from some specific panics deeper in the PEG parser, but when we added the invalid timestamp, we didn't add it to the list we catch and handle gracefully. Add test case for this, and test case for successful parsing. Also add the word "valid" to the error message so people don't get as confused by it. --- pql/parser.go | 4 ++-- pql/parser_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/pql/parser.go b/pql/parser.go index 514870503..57f0d22ab 100644 --- a/pql/parser.go +++ b/pql/parser.go @@ -15,7 +15,7 @@ import ( // error strings in the parser const duplicateArgErrorMessage = "duplicate argument provided" const intOutOfRangeError = "integer is not in signed 64-bit range" -const invalidTimestampError = "string is not a timestamp" +const invalidTimestampError = "string is not a valid timestamp" // parser represents a parser for the PQL language. type parser struct { @@ -66,7 +66,7 @@ func (p *parser) Parse() (*Query, error) { if !ok { return nil, fmt.Errorf("unexpected parser error of type %T: %[1]v", v) } - if strings.HasPrefix(errorMessage, duplicateArgErrorMessage) || strings.HasPrefix(errorMessage, intOutOfRangeError) { + if strings.HasPrefix(errorMessage, duplicateArgErrorMessage) || strings.HasPrefix(errorMessage, intOutOfRangeError) || strings.HasPrefix(errorMessage, invalidTimestampError) { return nil, fmt.Errorf("%s", v) } else { panic(v) diff --git a/pql/parser_test.go b/pql/parser_test.go index 3cfa612a8..b829d6079 100644 --- a/pql/parser_test.go +++ b/pql/parser_test.go @@ -5,6 +5,7 @@ import ( "reflect" "strings" "testing" + "time" "github.com/molecula/featurebase/v3/pql" _ "github.com/molecula/featurebase/v3/test" @@ -197,6 +198,33 @@ func TestParser_Parse(t *testing.T) { } }) + t.Run("Timestamp", func(t *testing.T) { + twos := "2022-02-22T22:22:22Z" + date, err := time.Parse(time.RFC3339, twos) + if err != nil { + t.Fatal(err) + } + q, err := pql.ParseString(`Row(x>'2022-02-22T22:22:22Z')`) + if err != nil { + t.Fatal(err) + } else if !reflect.DeepEqual(q.Calls[0], + &pql.Call{ + Name: "Row", + Args: map[string]interface{}{ + "x": &pql.Condition{Op: pql.GT, Value: date}, + }, + }, + ) { + t.Fatalf("unexpected call: %#v", q.Calls[0]) + } + q, err = pql.ParseString(`Row(x>'2024-04-24T24:24:24Z')`) + if err == nil { + t.Fatal("no error parsing invalid date") + } else if !strings.Contains(err.Error(), "not a valid timestamp") { + t.Fatalf("expected error for invalid timestamp, got: %s", err.Error()) + } + }) + t.Run("VariousSpaces", func(t *testing.T) { q, err := pql.ParseString(`TopN( x )`) if err != nil {