Add CREATE CONTINUOUS QUERY parsing.
parent
7288a778c3
commit
143f8a0fd5
|
@ -28,6 +28,7 @@ func (_ *DeleteStatement) node() {}
|
|||
func (_ *ListSeriesStatement) node() {}
|
||||
func (_ *DropSeriesStatement) node() {}
|
||||
func (_ *ListContinuousQueriesStatement) node() {}
|
||||
func (_ *CreateContinuousQueryStatement) node() {}
|
||||
func (_ *DropContinuousQueryStatement) node() {}
|
||||
|
||||
func (_ Fields) node() {}
|
||||
|
@ -65,6 +66,7 @@ func (_ *DeleteStatement) stmt() {}
|
|||
func (_ *ListSeriesStatement) stmt() {}
|
||||
func (_ *DropSeriesStatement) stmt() {}
|
||||
func (_ *ListContinuousQueriesStatement) stmt() {}
|
||||
func (_ *CreateContinuousQueryStatement) stmt() {}
|
||||
func (_ *DropContinuousQueryStatement) stmt() {}
|
||||
|
||||
// Expr represents an expression that can be evaluated to a value.
|
||||
|
@ -134,6 +136,13 @@ type DropSeriesStatement struct {
|
|||
// ListContinuousQueriesStatement represents a command for listing continuous queries.
|
||||
type ListContinuousQueriesStatement struct{}
|
||||
|
||||
// CreateContinuousQueriesStatement represents a command for creating a continuous query.
|
||||
type CreateContinuousQueryStatement struct {
|
||||
Name string
|
||||
Source *SelectStatement
|
||||
Target string
|
||||
}
|
||||
|
||||
// DropContinuousQueriesStatement represents a command for removing a continuous query.
|
||||
type DropContinuousQueryStatement struct {
|
||||
Name string
|
||||
|
|
|
@ -21,13 +21,15 @@ func NewParser(r io.Reader) *Parser {
|
|||
|
||||
// ParseQuery parses an InfluxQL string and returns a Query AST object.
|
||||
func (p *Parser) ParseQuery() (*Query, error) {
|
||||
// If there's only whitespace then return no statements.
|
||||
if tok, _, _ := p.scanIgnoreWhitespace(); tok == EOF {
|
||||
return &Query{}, nil
|
||||
}
|
||||
p.unscan()
|
||||
|
||||
// Otherwise parse statements until EOF.
|
||||
var statements Statements
|
||||
for {
|
||||
// Read statements until we reach the end.
|
||||
if tok, _, _ := p.scanIgnoreWhitespace(); tok == EOF {
|
||||
break
|
||||
}
|
||||
p.unscan()
|
||||
|
||||
// Read the next statement.
|
||||
s, err := p.ParseStatement()
|
||||
|
@ -35,7 +37,15 @@ func (p *Parser) ParseQuery() (*Query, error) {
|
|||
return nil, err
|
||||
}
|
||||
statements = append(statements, s)
|
||||
|
||||
// Expect a semicolon or EOF after the statement.
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != SEMICOLON && tok != EOF {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{";", "EOF"}, pos)
|
||||
} else if tok == EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &Query{Statements: statements}, nil
|
||||
}
|
||||
|
||||
|
@ -56,6 +66,12 @@ func (p *Parser) ParseStatement() (Statement, error) {
|
|||
} else {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"SERIES", "CONTINUOUS"}, pos)
|
||||
}
|
||||
case CREATE:
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok == CONTINUOUS {
|
||||
return p.parseCreateContinuousQueryStatement()
|
||||
} else {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"CONTINUOUS"}, pos)
|
||||
}
|
||||
case DROP:
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok == SERIES {
|
||||
return p.parseDropSeriesStatement()
|
||||
|
@ -116,11 +132,6 @@ func (p *Parser) parseSelectStatement() (*SelectStatement, error) {
|
|||
}
|
||||
stmt.Ascending = ascending
|
||||
|
||||
// Expect a semicolon or EOF at the end
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != SEMICOLON && tok != EOF {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{";", "EOF"}, pos)
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
|
@ -143,11 +154,6 @@ func (p *Parser) parseDeleteStatement() (*DeleteStatement, error) {
|
|||
}
|
||||
stmt.Condition = condition
|
||||
|
||||
// Expect a semicolon or EOF at the end
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != SEMICOLON && tok != EOF {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{";", "EOF"}, pos)
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
|
@ -155,12 +161,6 @@ func (p *Parser) parseDeleteStatement() (*DeleteStatement, error) {
|
|||
// This function assumes the "LIST SERIES" tokens have already been consumed.
|
||||
func (p *Parser) parseListSeriesStatement() (*ListSeriesStatement, error) {
|
||||
stmt := &ListSeriesStatement{}
|
||||
|
||||
// Expect a semicolon or EOF at the end
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != SEMICOLON && tok != EOF {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{";", "EOF"}, pos)
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
|
@ -176,11 +176,6 @@ func (p *Parser) parseDropSeriesStatement() (*DropSeriesStatement, error) {
|
|||
}
|
||||
stmt.Name = lit
|
||||
|
||||
// Expect a semicolon or EOF at the end
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != SEMICOLON && tok != EOF {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{";", "EOF"}, pos)
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
|
@ -194,11 +189,53 @@ func (p *Parser) parseListContinuousQueriesStatement() (*ListContinuousQueriesSt
|
|||
return nil, newParseError(tokstr(tok, lit), []string{"QUERIES"}, pos)
|
||||
}
|
||||
|
||||
// Expect a semicolon or EOF at the end
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != SEMICOLON && tok != EOF {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{";", "EOF"}, pos)
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
// parseCreateContinuousQueriesStatement parses a string and returns a CreateContinuousQueryStatement.
|
||||
// This function assumes the "CREATE CONTINUOUS" tokens have already been consumed.
|
||||
func (p *Parser) parseCreateContinuousQueryStatement() (*CreateContinuousQueryStatement, error) {
|
||||
stmt := &CreateContinuousQueryStatement{}
|
||||
|
||||
// Expect a "QUERY" token.
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != QUERY {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"QUERY"}, pos)
|
||||
}
|
||||
|
||||
// Read the id of the query to create.
|
||||
tok, pos, lit := p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
}
|
||||
stmt.Name = lit
|
||||
|
||||
// Expect an "AS SELECT" keyword.
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != AS {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"AS"}, pos)
|
||||
}
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != SELECT {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"SELECT"}, pos)
|
||||
}
|
||||
|
||||
// Read the select statement to be used as the source.
|
||||
source, err := p.parseSelectStatement()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt.Source = source
|
||||
|
||||
// Expect an INTO keyword.
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != INTO {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"INTO"}, pos)
|
||||
}
|
||||
|
||||
// Read the target of the query.
|
||||
tok, pos, lit = p.scanIgnoreWhitespace()
|
||||
if tok != IDENT && tok != STRING {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{"identifier", "string"}, pos)
|
||||
}
|
||||
stmt.Target = lit
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
|
@ -219,11 +256,6 @@ func (p *Parser) parseDropContinuousQueryStatement() (*DropContinuousQueryStatem
|
|||
}
|
||||
stmt.Name = lit
|
||||
|
||||
// Expect a semicolon or EOF at the end
|
||||
if tok, pos, lit := p.scanIgnoreWhitespace(); tok != SEMICOLON && tok != EOF {
|
||||
return nil, newParseError(tokstr(tok, lit), []string{";", "EOF"}, pos)
|
||||
}
|
||||
|
||||
return stmt, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,19 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
stmt: &influxql.ListContinuousQueriesStatement{},
|
||||
},
|
||||
|
||||
// CREATE CONTINUOUS QUERY statement
|
||||
{
|
||||
s: `CREATE CONTINUOUS QUERY myquery AS SELECT count() FROM myseries INTO foo`,
|
||||
stmt: &influxql.CreateContinuousQueryStatement{
|
||||
Name: "myquery",
|
||||
Source: &influxql.SelectStatement{
|
||||
Fields: influxql.Fields{&influxql.Field{Expr: &influxql.Call{Name: "count"}}},
|
||||
Source: &influxql.Series{Name: "myseries"},
|
||||
},
|
||||
Target: "foo",
|
||||
},
|
||||
},
|
||||
|
||||
// DROP CONTINUOUS QUERY statement
|
||||
{
|
||||
s: `DROP CONTINUOUS QUERY myquery`,
|
||||
|
@ -119,7 +132,6 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
{s: `SELECT`, err: `found EOF, expected identifier, string, number, bool at line 1, char 8`},
|
||||
{s: `blah blah`, err: `found blah, expected SELECT at line 1, char 1`},
|
||||
{s: `SELECT field X`, err: `found X, expected FROM at line 1, char 14`},
|
||||
{s: `SELECT field FROM "series" WHERE X Y`, err: `found Y, expected ;, EOF at line 1, char 36`},
|
||||
{s: `SELECT field FROM "series" WHERE X +;`, err: `found ;, expected identifier, string, number, bool at line 1, char 37`},
|
||||
{s: `SELECT field FROM myseries GROUP`, err: `found EOF, expected BY at line 1, char 34`},
|
||||
{s: `SELECT field FROM myseries LIMIT`, err: `found EOF, expected number at line 1, char 34`},
|
||||
|
@ -134,16 +146,11 @@ func TestParser_ParseStatement(t *testing.T) {
|
|||
{s: `DELETE`, err: `found EOF, expected FROM at line 1, char 8`},
|
||||
{s: `DELETE FROM`, err: `found EOF, expected identifier, string at line 1, char 13`},
|
||||
{s: `DELETE FROM myseries WHERE`, err: `found EOF, expected identifier, string, number, bool at line 1, char 28`},
|
||||
{s: `DELETE FROM myseries 123`, err: `found 123, expected ;, EOF at line 1, char 22`},
|
||||
{s: `LIST SERIES x`, err: `found x, expected ;, EOF at line 1, char 13`},
|
||||
{s: `DROP SERIES`, err: `found EOF, expected identifier, string at line 1, char 13`},
|
||||
{s: `DROP SERIES myseries X`, err: `found X, expected ;, EOF at line 1, char 22`},
|
||||
{s: `LIST CONTINUOUS`, err: `found EOF, expected QUERIES at line 1, char 17`},
|
||||
{s: `LIST CONTINUOUS QUERIES x`, err: `found x, expected ;, EOF at line 1, char 25`},
|
||||
{s: `LIST FOO`, err: `found FOO, expected SERIES, CONTINUOUS at line 1, char 6`},
|
||||
{s: `DROP CONTINUOUS`, err: `found EOF, expected QUERY at line 1, char 17`},
|
||||
{s: `DROP CONTINUOUS QUERY`, err: `found EOF, expected identifier, string at line 1, char 23`},
|
||||
{s: `DROP CONTINUOUS QUERY myseries X`, err: `found X, expected ;, EOF at line 1, char 32`},
|
||||
{s: `DROP FOO`, err: `found FOO, expected SERIES, CONTINUOUS at line 1, char 6`},
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ const (
|
|||
AS
|
||||
ASC
|
||||
BY
|
||||
CREATE
|
||||
CONTINUOUS
|
||||
DELETE
|
||||
DESC
|
||||
|
@ -110,6 +111,7 @@ var tokens = [...]string{
|
|||
AS: "AS",
|
||||
ASC: "ASC",
|
||||
BY: "BY",
|
||||
CREATE: "CREATE",
|
||||
CONTINUOUS: "CONTINUOUS",
|
||||
DELETE: "DELETE",
|
||||
DESC: "DESC",
|
||||
|
|
Loading…
Reference in New Issue