-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsearch.go
152 lines (131 loc) · 4.14 KB
/
search.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package ud859
import (
"fmt"
"sort"
"strings"
"time"
"unicode"
"golang.org/x/net/context"
"google.golang.org/appengine/delay"
"google.golang.org/appengine/search"
)
// conferenceDoc defines an indexed Conference.
type conferenceDoc struct {
WebsafeKey search.Atom `json:"websafeKey" search:"KEY"`
Name string `json:"name" search:"NAME"`
Description string `json:"description" search:"DESCRIPTION"`
Organizer string `json:"organizerDisplayName" search:"ORGANIZER"`
Topics string `json:"topics" search:"TOPIC"`
City string `json:"city" search:"CITY"`
StartDate time.Time `json:"startDate" search:"START_DATE"`
EndDate time.Time `json:"endDate" search:"END_DATE"`
Month float64 `json:"-" search:"MONTH"`
MaxAttendees float64 `json:"maxAttendees" search:"MAX_ATTENDEES"`
SeatsAvailable float64 `json:"seatsAvailable" search:"SEATS_AVAILABLE"`
}
// fromConference creates a conferenceDoc from a Conference.
func fromConference(c *Conference) *conferenceDoc {
return &conferenceDoc{
WebsafeKey: search.Atom(c.WebsafeKey),
Name: c.Name,
Description: c.Description,
Organizer: c.Organizer,
Topics: strings.Join(c.Topics, " "),
City: c.City,
StartDate: c.StartDate,
EndDate: c.EndDate,
Month: float64(c.StartDate.Month()),
MaxAttendees: float64(c.MaxAttendees),
SeatsAvailable: float64(c.SeatsAvailable),
}
}
// fromConferenceDoc creates a Conference from a conferenceDoc.
func fromConferenceDoc(doc *conferenceDoc) *Conference {
return &Conference{
WebsafeKey: string(doc.WebsafeKey),
Name: doc.Name,
Description: doc.Description,
Organizer: doc.Organizer,
Topics: strings.Split(doc.Topics, " "),
City: doc.City,
StartDate: doc.StartDate.UTC(),
EndDate: doc.EndDate.UTC(),
Month: int(doc.StartDate.Month()),
MaxAttendees: int(doc.MaxAttendees),
SeatsAvailable: int(doc.SeatsAvailable),
}
}
// query returns the query string to apply to the search index.
func (q ConferenceQueryForm) query() string {
var str string
for _, filter := range q.Filters {
field := filter.Field
op := filter.Op
if op == NE {
field = "NOT " + field
op = EQ
}
if field == "KEY" {
str += fmt.Sprintf("%s = %q ", field, filter.Value)
continue
}
switch v := filter.Value.(type) {
case string:
str += fmt.Sprintf("%s = (%s) ", field, strings.Map(alphaNumeric, v))
case time.Time:
str += fmt.Sprintf("%s %s %s ", field, op, v.Format("2006-01-02"))
default:
str += fmt.Sprintf("%s %s %v ", field, op, v)
}
}
return str
}
func alphaNumeric(r rune) rune {
if unicode.IsLetter(r) || unicode.IsNumber(r) {
return r
}
return ' '
}
func searchConferences(c context.Context, form *ConferenceQueryForm) (*Conferences, error) {
index, err := search.Open("Conference")
if err != nil {
return nil, errInternalServer(err, "unable to open search index")
}
it := index.Search(c, form.query(), nil)
conferences := new(Conferences)
for {
doc := new(conferenceDoc)
_, err := it.Next(doc)
if err == search.Done {
break
} else if err != nil {
return nil, errInternalServer(err, "unable to search index")
}
conference := fromConferenceDoc(doc)
conferences.Items = append(conferences.Items, conference)
}
sort.Sort(conferences)
return conferences, nil
}
func isTesting() bool {
return clientID == "YOUR-CLIENT-ID"
}
func indexConference(c context.Context, conference *Conference) error {
if isTesting() {
// when testing, update the index without delay
return indexConferenceNow(c, conference)
}
return indexConferenceDelay.Call(c, conference)
}
var indexConferenceDelay = delay.Func("index_conference", indexConferenceNow)
func indexConferenceNow(c context.Context, conference *Conference) error {
index, err := search.Open("Conference")
if err != nil {
return errInternalServer(err, "unable to open search index")
}
_, err = index.Put(c, conference.WebsafeKey, fromConference(conference))
if err != nil {
return errInternalServer(err, "unable to index conference")
}
return nil
}