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 "title":
 64			f := TitleFilter(qualifierQuery)
 65			result.Label = append(result.Title, f)
 66
 67		case "no":
 68			err := result.parseNoFilter(qualifierQuery)
 69			if err != nil {
 70				return nil, err
 71			}
 72
 73		case "sort":
 74			if sortingDone {
 75				return nil, fmt.Errorf("multiple sorting")
 76			}
 77
 78			err := result.parseSorting(qualifierQuery)
 79			if err != nil {
 80				return nil, err
 81			}
 82
 83			sortingDone = true
 84
 85		default:
 86			return nil, fmt.Errorf("unknow qualifier name %s", qualifierName)
 87		}
 88	}
 89
 90	return result, nil
 91}
 92
 93func splitQuery(query string) []string {
 94	lastQuote := rune(0)
 95	f := func(c rune) bool {
 96		switch {
 97		case c == lastQuote:
 98			lastQuote = rune(0)
 99			return false
100		case lastQuote != rune(0):
101			return false
102		case unicode.In(c, unicode.Quotation_Mark):
103			lastQuote = c
104			return false
105		default:
106			return unicode.IsSpace(c)
107		}
108	}
109
110	return strings.FieldsFunc(query, f)
111}
112
113func removeQuote(field string) string {
114	if len(field) >= 2 {
115		if field[0] == '"' && field[len(field)-1] == '"' {
116			return field[1 : len(field)-1]
117		}
118	}
119	return field
120}
121
122func (q *Query) parseNoFilter(query string) error {
123	switch query {
124	case "label":
125		q.NoFilters = append(q.NoFilters, NoLabelFilter())
126	default:
127		return fmt.Errorf("unknown \"no\" filter %s", query)
128	}
129
130	return nil
131}
132
133func (q *Query) parseSorting(query string) error {
134	switch query {
135	// default ASC
136	case "id-desc":
137		q.OrderBy = OrderById
138		q.OrderDirection = OrderDescending
139	case "id", "id-asc":
140		q.OrderBy = OrderById
141		q.OrderDirection = OrderAscending
142
143	// default DESC
144	case "creation", "creation-desc":
145		q.OrderBy = OrderByCreation
146		q.OrderDirection = OrderDescending
147	case "creation-asc":
148		q.OrderBy = OrderByCreation
149		q.OrderDirection = OrderAscending
150
151	// default DESC
152	case "edit", "edit-desc":
153		q.OrderBy = OrderByEdit
154		q.OrderDirection = OrderDescending
155	case "edit-asc":
156		q.OrderBy = OrderByEdit
157		q.OrderDirection = OrderAscending
158
159	default:
160		return fmt.Errorf("unknow sorting %s", query)
161	}
162
163	return nil
164}