@@ -2,8 +2,10 @@ package main
2
2
3
3
import (
4
4
"context"
5
+ "io"
5
6
"net/http"
6
7
"regexp"
8
+ "strings"
7
9
8
10
// Packages
9
11
router "github.com/mutablelogic/go-server/pkg/httprouter"
@@ -12,6 +14,7 @@ import (
12
14
13
15
// Namespace imports
14
16
. "github.com/mutablelogic/go-server"
17
+ . "github.com/mutablelogic/go-sqlite"
15
18
)
16
19
17
20
///////////////////////////////////////////////////////////////////////////////
@@ -30,18 +33,45 @@ type IndexResponse struct {
30
33
Status string `json:"status,omitempty"`
31
34
}
32
35
36
+ type QueryRequest struct {
37
+ Query string `json:"q"`
38
+ Offset uint `json:"offset"`
39
+ Limit uint `json:"limit"`
40
+ }
41
+
42
+ type QueryResponse struct {
43
+ Query string `json:"q"`
44
+ Offset uint `json:"offset,omitempty"`
45
+ Limit uint `json:"limit,omitempty"`
46
+ Results []ResultResponse `json:"results"`
47
+ }
48
+
49
+ type ResultResponse struct {
50
+ Id int64 `json:"id"`
51
+ Offset int64 `json:"offset"`
52
+ Rank float64 `json:"rank"`
53
+ Index string `json:"index"`
54
+ File FileResponse `json:"file"`
55
+ }
56
+
57
+ type FileResponse struct {
58
+ Parent string `json:"parent"`
59
+ Filename string `json:"filename"`
60
+ }
61
+
33
62
///////////////////////////////////////////////////////////////////////////////
34
63
// ROUTES
35
64
36
65
var (
37
- reRoutePing = regexp .MustCompile (`^/?$` )
66
+ reRoutePing = regexp .MustCompile (`^/?$` )
67
+ reRouteQuery = regexp .MustCompile (`^/q/?$` )
38
68
)
39
69
40
70
///////////////////////////////////////////////////////////////////////////////
41
71
// CONSTANTS
42
72
43
73
const (
44
- maxResultLimit = 1000
74
+ maxResultLimit = 100
45
75
)
46
76
47
77
///////////////////////////////////////////////////////////////////////////////
@@ -53,6 +83,11 @@ func (p *plugin) AddHandlers(ctx context.Context, provider Provider) error {
53
83
return err
54
84
}
55
85
86
+ // Add handler for search
87
+ if err := provider .AddHandlerFuncEx (ctx , reRouteQuery , p .ServeQuery ); err != nil {
88
+ return err
89
+ }
90
+
56
91
// Return success
57
92
return nil
58
93
}
@@ -107,6 +142,74 @@ func (p *plugin) ServePing(w http.ResponseWriter, req *http.Request) {
107
142
router .ServeJSON (w , response , http .StatusOK , 2 )
108
143
}
109
144
145
+ func (p * plugin ) ServeQuery (w http.ResponseWriter , req * http.Request ) {
146
+ // Get a connection
147
+ conn := p .pool .Get ()
148
+ if conn == nil {
149
+ router .ServeError (w , http .StatusBadGateway , "No connection" )
150
+ return
151
+ }
152
+ defer p .pool .Put (conn )
153
+
154
+ // Decode the query
155
+ var query QueryRequest
156
+ if err := router .RequestQuery (req , & query ); err != nil {
157
+ router .ServeError (w , http .StatusBadRequest , err .Error ())
158
+ return
159
+ }
160
+
161
+ // Check query, offset and limit
162
+ query .Limit = uintMin (query .Limit , maxResultLimit )
163
+ query .Query = strings .TrimSpace (query .Query )
164
+ if query .Query == "" {
165
+ router .ServeError (w , http .StatusBadRequest , "missing q parameter" )
166
+ return
167
+ }
168
+
169
+ // Make a response
170
+ response := QueryResponse {
171
+ Query : query .Query ,
172
+ Offset : query .Offset ,
173
+ Limit : query .Limit ,
174
+ Results : make ([]ResultResponse , 0 , query .Limit ),
175
+ }
176
+
177
+ // Perform the query and collate the results
178
+ if err := conn .Do (req .Context (), 0 , func (txn SQTransaction ) error {
179
+ r , err := txn .Query (indexer .Query (p .store .Schema ()).WithLimitOffset (query .Limit , query .Offset ), query .Query )
180
+ if err != nil {
181
+ return err
182
+ }
183
+ n := int64 (0 )
184
+ for {
185
+ rows , err := r .Next ()
186
+ if err == io .EOF {
187
+ return nil
188
+ } else if err != nil {
189
+ return err
190
+ } else {
191
+ n = n + 1
192
+ }
193
+ response .Results = append (response .Results , ResultResponse {
194
+ Id : rows [0 ].(int64 ),
195
+ Offset : n + int64 (query .Offset ) - 1 ,
196
+ Rank : rows [1 ].(float64 ),
197
+ Index : rows [2 ].(string ),
198
+ File : FileResponse {
199
+ Parent : rows [3 ].(string ),
200
+ Filename : rows [4 ].(string ),
201
+ },
202
+ })
203
+ }
204
+ }); err != nil {
205
+ router .ServeError (w , http .StatusBadRequest , err .Error ())
206
+ return
207
+ }
208
+
209
+ // Serve response
210
+ router .ServeJSON (w , response , http .StatusOK , 2 )
211
+ }
212
+
110
213
///////////////////////////////////////////////////////////////////////////////
111
214
// PRIVATE METHODS
112
215
0 commit comments