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