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}