query.go

  1package cache
  2
  3import (
  4	"fmt"
  5	"strings"
  6	"unicode"
  7)
  8
  9type Query struct {
 10	Filters
 11	OrderBy
 12	OrderDirection
 13}
 14
 15// Return an identity query with default sorting (creation-desc)
 16func NewQuery() *Query {
 17	return &Query{
 18		OrderBy:        OrderByCreation,
 19		OrderDirection: OrderDescending,
 20	}
 21}
 22
 23// ParseQuery parse a query DSL
 24//
 25// Ex: "status:open author:descartes sort:edit-asc"
 26//
 27// Supported filter qualifiers and syntax are described in docs/queries.md
 28func ParseQuery(query string) (*Query, error) {
 29	fields := splitQuery(query)
 30
 31	result := &Query{
 32		OrderBy:        OrderByCreation,
 33		OrderDirection: OrderDescending,
 34	}
 35
 36	sortingDone := false
 37
 38	for _, field := range fields {
 39		split := strings.Split(field, ":")
 40		if len(split) != 2 {
 41			return nil, fmt.Errorf("can't parse \"%s\"", field)
 42		}
 43
 44		qualifierName := split[0]
 45		qualifierQuery := removeQuote(split[1])
 46
 47		switch qualifierName {
 48		case "status", "state":
 49			f, err := StatusFilter(qualifierQuery)
 50			if err != nil {
 51				return nil, err
 52			}
 53			result.Status = append(result.Status, f)
 54
 55		case "author":
 56			f := AuthorFilter(qualifierQuery)
 57			result.Author = append(result.Author, f)
 58
 59		case "label":
 60			f := LabelFilter(qualifierQuery)
 61			result.Label = append(result.Label, f)
 62
 63		case "no":
 64			err := result.parseNoFilter(qualifierQuery)
 65			if err != nil {
 66				return nil, err
 67			}
 68
 69		case "sort":
 70			if sortingDone {
 71				return nil, fmt.Errorf("multiple sorting")
 72			}
 73
 74			err := result.parseSorting(qualifierQuery)
 75			if err != nil {
 76				return nil, err
 77			}
 78
 79			sortingDone = true
 80
 81		default:
 82			return nil, fmt.Errorf("unknow qualifier name %s", qualifierName)
 83		}
 84	}
 85
 86	return result, nil
 87}
 88
 89func splitQuery(query string) []string {
 90	lastQuote := rune(0)
 91	f := func(c rune) bool {
 92		switch {
 93		case c == lastQuote:
 94			lastQuote = rune(0)
 95			return false
 96		case lastQuote != rune(0):
 97			return false
 98		case unicode.In(c, unicode.Quotation_Mark):
 99			lastQuote = c
100			return false
101		default:
102			return unicode.IsSpace(c)
103		}
104	}
105
106	return strings.FieldsFunc(query, f)
107}
108
109func removeQuote(field string) string {
110	if len(field) >= 2 {
111		if field[0] == '"' && field[len(field)-1] == '"' {
112			return field[1 : len(field)-1]
113		}
114	}
115	return field
116}
117
118func (q *Query) parseNoFilter(query string) error {
119	switch query {
120	case "label":
121		q.NoFilters = append(q.NoFilters, NoLabelFilter())
122	default:
123		return fmt.Errorf("unknown \"no\" filter %s", query)
124	}
125
126	return nil
127}
128
129func (q *Query) parseSorting(query string) error {
130	switch query {
131	// default ASC
132	case "id-desc":
133		q.OrderBy = OrderById
134		q.OrderDirection = OrderDescending
135	case "id", "id-asc":
136		q.OrderBy = OrderById
137		q.OrderDirection = OrderAscending
138
139	// default DESC
140	case "creation", "creation-desc":
141		q.OrderBy = OrderByCreation
142		q.OrderDirection = OrderDescending
143	case "creation-asc":
144		q.OrderBy = OrderByCreation
145		q.OrderDirection = OrderAscending
146
147	// default DESC
148	case "edit", "edit-desc":
149		q.OrderBy = OrderByEdit
150		q.OrderDirection = OrderDescending
151	case "edit-asc":
152		q.OrderBy = OrderByEdit
153		q.OrderDirection = OrderAscending
154
155	default:
156		return fmt.Errorf("unknow sorting %s", query)
157	}
158
159	return nil
160}