2018-09-09 21:21:49 +03:00
|
|
|
package cache
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
2018-09-10 12:12:22 +03:00
|
|
|
"unicode"
|
2018-09-09 21:21:49 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type Query struct {
|
|
|
|
Filters
|
|
|
|
OrderBy
|
|
|
|
OrderDirection
|
|
|
|
}
|
|
|
|
|
2018-09-11 20:46:38 +03:00
|
|
|
// Return an identity query with default sorting (creation-desc)
|
2018-09-10 19:16:16 +03:00
|
|
|
func NewQuery() *Query {
|
2018-09-11 20:46:38 +03:00
|
|
|
return &Query{
|
|
|
|
OrderBy: OrderByCreation,
|
|
|
|
OrderDirection: OrderDescending,
|
|
|
|
}
|
2018-09-10 19:16:16 +03:00
|
|
|
}
|
|
|
|
|
2018-09-09 21:21:49 +03:00
|
|
|
// ParseQuery parse a query DSL
|
|
|
|
//
|
|
|
|
// Ex: "status:open author:descartes sort:edit-asc"
|
|
|
|
//
|
2018-09-10 13:47:05 +03:00
|
|
|
// Supported filter qualifiers and syntax are described in docs/queries.md
|
2018-09-09 21:21:49 +03:00
|
|
|
func ParseQuery(query string) (*Query, error) {
|
2018-09-10 12:12:22 +03:00
|
|
|
fields := splitQuery(query)
|
2018-09-09 21:21:49 +03:00
|
|
|
|
|
|
|
result := &Query{
|
|
|
|
OrderBy: OrderByCreation,
|
|
|
|
OrderDirection: OrderDescending,
|
|
|
|
}
|
|
|
|
|
|
|
|
sortingDone := false
|
|
|
|
|
|
|
|
for _, field := range fields {
|
|
|
|
split := strings.Split(field, ":")
|
|
|
|
if len(split) != 2 {
|
|
|
|
return nil, fmt.Errorf("can't parse \"%s\"", field)
|
|
|
|
}
|
|
|
|
|
2018-09-10 12:12:22 +03:00
|
|
|
qualifierName := split[0]
|
|
|
|
qualifierQuery := removeQuote(split[1])
|
|
|
|
|
|
|
|
switch qualifierName {
|
2018-09-10 13:46:07 +03:00
|
|
|
case "status", "state":
|
2018-09-10 12:12:22 +03:00
|
|
|
f, err := StatusFilter(qualifierQuery)
|
2018-09-09 21:21:49 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
result.Status = append(result.Status, f)
|
|
|
|
|
|
|
|
case "author":
|
2018-09-10 12:12:22 +03:00
|
|
|
f := AuthorFilter(qualifierQuery)
|
2018-09-09 21:21:49 +03:00
|
|
|
result.Author = append(result.Author, f)
|
|
|
|
|
|
|
|
case "label":
|
2018-09-10 12:12:22 +03:00
|
|
|
f := LabelFilter(qualifierQuery)
|
2018-09-09 21:21:49 +03:00
|
|
|
result.Label = append(result.Label, f)
|
|
|
|
|
|
|
|
case "no":
|
2018-09-10 12:12:22 +03:00
|
|
|
err := result.parseNoFilter(qualifierQuery)
|
2018-09-09 21:21:49 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
case "sort":
|
|
|
|
if sortingDone {
|
|
|
|
return nil, fmt.Errorf("multiple sorting")
|
|
|
|
}
|
|
|
|
|
2018-09-10 12:12:22 +03:00
|
|
|
err := result.parseSorting(qualifierQuery)
|
2018-09-09 21:21:49 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
sortingDone = true
|
|
|
|
|
|
|
|
default:
|
2018-09-10 12:12:22 +03:00
|
|
|
return nil, fmt.Errorf("unknow qualifier name %s", qualifierName)
|
2018-09-09 21:21:49 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2018-09-10 12:12:22 +03:00
|
|
|
func splitQuery(query string) []string {
|
|
|
|
lastQuote := rune(0)
|
|
|
|
f := func(c rune) bool {
|
|
|
|
switch {
|
|
|
|
case c == lastQuote:
|
|
|
|
lastQuote = rune(0)
|
|
|
|
return false
|
|
|
|
case lastQuote != rune(0):
|
|
|
|
return false
|
|
|
|
case unicode.In(c, unicode.Quotation_Mark):
|
|
|
|
lastQuote = c
|
|
|
|
return false
|
|
|
|
default:
|
|
|
|
return unicode.IsSpace(c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.FieldsFunc(query, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
func removeQuote(field string) string {
|
|
|
|
if len(field) >= 2 {
|
|
|
|
if field[0] == '"' && field[len(field)-1] == '"' {
|
|
|
|
return field[1 : len(field)-1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return field
|
|
|
|
}
|
|
|
|
|
2018-09-09 21:21:49 +03:00
|
|
|
func (q *Query) parseNoFilter(query string) error {
|
|
|
|
switch query {
|
|
|
|
case "label":
|
|
|
|
q.NoFilters = append(q.NoFilters, NoLabelFilter())
|
|
|
|
default:
|
2018-09-10 19:16:16 +03:00
|
|
|
return fmt.Errorf("unknown \"no\" filter %s", query)
|
2018-09-09 21:21:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (q *Query) parseSorting(query string) error {
|
|
|
|
switch query {
|
|
|
|
// default ASC
|
|
|
|
case "id-desc":
|
|
|
|
q.OrderBy = OrderById
|
|
|
|
q.OrderDirection = OrderDescending
|
|
|
|
case "id", "id-asc":
|
|
|
|
q.OrderBy = OrderById
|
|
|
|
q.OrderDirection = OrderAscending
|
|
|
|
|
|
|
|
// default DESC
|
|
|
|
case "creation", "creation-desc":
|
|
|
|
q.OrderBy = OrderByCreation
|
|
|
|
q.OrderDirection = OrderDescending
|
|
|
|
case "creation-asc":
|
|
|
|
q.OrderBy = OrderByCreation
|
|
|
|
q.OrderDirection = OrderAscending
|
|
|
|
|
|
|
|
// default DESC
|
|
|
|
case "edit", "edit-desc":
|
|
|
|
q.OrderBy = OrderByEdit
|
|
|
|
q.OrderDirection = OrderDescending
|
|
|
|
case "edit-asc":
|
|
|
|
q.OrderBy = OrderByEdit
|
|
|
|
q.OrderDirection = OrderAscending
|
|
|
|
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("unknow sorting %s", query)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|