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