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}