// Projection parsing: the [DISTINCT] item-list plus the shared // ORDER BY / OFFSET|SKIP / LIMIT suffix (used by RETURN and the standalone // ORDER BY statement). Split from parser.go, which holds the query and // clause parsing.
package parser import ( ) // parseProjection is: [DISTINCT] item[, item]* [ORDER BY ...] [OFFSET|SKIP // n] [LIMIT n]; an item is `*` or expr [AS alias]. func ( *parser) () (*ast.Projection, error) { := &ast.Projection{} .Distinct = .acceptKw("distinct") for { if .acceptTok(TokStar) { .Star = true } else { , := .parseExpr() if != nil { return nil, } := ast.ReturnItem{Expr: } if .acceptKw("as") { , := .identName("an alias") if != nil { return nil, } .Alias = } .Items = append(.Items, ) } if !.acceptTok(TokComma) { break } } if := .parseProjectionTail(); != nil { return nil, } return , nil } // parseProjectionTail parses the optional ORDER BY / OFFSET / LIMIT // suffix into proj -- shared by RETURN and the standalone ORDER BY // statement (which sorts the binding table mid-pipeline). func ( *parser) ( *ast.Projection) error { if .acceptKw("order") { if := .expectKw("by"); != nil { return } for { , := .parseExpr() if != nil { return } := ast.SortItem{Expr: } if .acceptKw("desc") { .Desc = true } else { .acceptKw("asc") } .OrderBy = append(.OrderBy, ) if !.acceptTok(TokComma) { break } } } if .acceptKw("offset") || .acceptKw("skip") { , := .parseCount("OFFSET") if != nil { return } .Skip = & } if .acceptKw("limit") { , := .parseCount("LIMIT") if != nil { return } .Limit = & } return nil } // parseCount reads a non-negative integer argument of OFFSET/LIMIT. func ( *parser) ( string) (uint64, *Error) { , := .expect(TokInt, +" count") if != nil { return 0, } , := strconv.ParseUint(.Text, 10, 64) if != nil { return 0, errf(.Pos, "bad %s count %q", , .Text) } return , nil }