comparison pkg/controllers/importqueue.go @ 2671:8f3facf902dd import-overview-rework

Filter prev/next, too.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Thu, 14 Mar 2019 17:25:33 +0100
parents d7b1dd25f91f
children b997e1fd1d3d
comparison
equal deleted inserted replaced
2670:d7b1dd25f91f 2671:8f3facf902dd
49 username, 49 username,
50 signer, 50 signer,
51 summary IS NOT NULL AS has_summary, 51 summary IS NOT NULL AS has_summary,
52 imports.id IN (SELECT id FROM warned) AS has_warnings 52 imports.id IN (SELECT id FROM warned) AS has_warnings
53 FROM import.imports 53 FROM import.imports
54 WHERE
54 ` 55 `
55 selectImportSummaySQL = ` 56 selectImportSummaySQL = `
56 SELECT summary FROM import.imports WHERE id = $1` 57 SELECT summary FROM import.imports WHERE id = $1`
57 58
58 selectHasNoRunningImportSQL = ` 59 selectHasNoRunningImportSQL = `
74 deleteImportSQL = ` 75 deleteImportSQL = `
75 DELETE FROM import.imports WHERE id = $1` 76 DELETE FROM import.imports WHERE id = $1`
76 77
77 selectBeforeSQL = ` 78 selectBeforeSQL = `
78 SELECT enqueued FROM import.imports 79 SELECT enqueued FROM import.imports
79 WHERE enqueued < $1 ORDER BY enqueued LIMIT 1` 80 WHERE
81 `
80 82
81 selectAfterSQL = ` 83 selectAfterSQL = `
82 SELECT enqueued FROM import.imports 84 SELECT enqueued FROM import.imports
83 WHERE enqueued > $1 ORDER BY enqueued LIMIT 1` 85 WHERE
86 `
84 ) 87 )
85 88
86 func toInt8Array(txt string) *pgtype.Int8Array { 89 func toInt8Array(txt string) *pgtype.Int8Array {
87 parts := strings.Split(txt, ",") 90 parts := strings.Split(txt, ",")
88 var ints []int64 91 var ints []int64
149 fb.hasCond = true 152 fb.hasCond = true
150 } 153 }
151 fb.arg(format, v...) 154 fb.arg(format, v...)
152 } 155 }
153 156
154 func queryImportListStmt( 157 func buildFilters(req *http.Request) (l, b, a *filterBuilder, err error) {
155 conn *sql.Conn, 158
156 req *http.Request, 159 l = new(filterBuilder)
157 ) (*sql.Rows, error) { 160 a = new(filterBuilder)
158 161 b = new(filterBuilder)
159 var fb filterBuilder 162
160 163 var noBefore, noAfter bool
161 fb.stmt.WriteString(selectImportsSQL) 164
162 165 l.stmt.WriteString(selectImportsSQL)
163 fb.stmt.WriteString(" WHERE ") 166 a.stmt.WriteString(selectAfterSQL)
167 b.stmt.WriteString(selectBeforeSQL)
164 168
165 if st := req.FormValue("states"); st != "" { 169 if st := req.FormValue("states"); st != "" {
166 states := toTextArray(st, imports.ImportStateNames) 170 states := toTextArray(st, imports.ImportStateNames)
167 fb.cond(" state = ANY($%d) ", states) 171 l.cond(" state = ANY($%d) ", states)
172 a.cond(" state = ANY($%d) ", states)
173 b.cond(" state = ANY($%d) ", states)
168 } 174 }
169 175
170 if ks := req.FormValue("kinds"); ks != "" { 176 if ks := req.FormValue("kinds"); ks != "" {
171 kinds := toTextArray(ks, imports.ImportKindNames()) 177 kinds := toTextArray(ks, imports.ImportKindNames())
172 fb.cond(" kind = ANY($%d) ", kinds) 178 l.cond(" kind = ANY($%d) ", kinds)
179 a.cond(" kind = ANY($%d) ", kinds)
180 b.cond(" kind = ANY($%d) ", kinds)
173 } 181 }
174 182
175 if idss := req.FormValue("ids"); idss != "" { 183 if idss := req.FormValue("ids"); idss != "" {
176 ids := toInt8Array(idss) 184 ids := toInt8Array(idss)
177 fb.cond(" id = ANY($%d) ", ids) 185 l.cond(" id = ANY($%d) ", ids)
186 a.cond(" id = ANY($%d) ", ids)
187 b.cond(" id = ANY($%d) ", ids)
178 } 188 }
179 189
180 if from := req.FormValue("from"); from != "" { 190 if from := req.FormValue("from"); from != "" {
181 fromTime, err := time.Parse(models.ImportTimeFormat, from) 191 var fromTime time.Time
182 if err != nil { 192 if fromTime, err = time.Parse(models.ImportTimeFormat, from); err != nil {
183 return nil, err 193 return
184 } 194 }
185 fb.cond(" enqueued >= $%d ", fromTime) 195 l.cond(" enqueued >= $%d ", fromTime)
196 b.cond(" enqueued < $%d", fromTime)
197 } else {
198 noBefore = true
186 } 199 }
187 200
188 if to := req.FormValue("to"); to != "" { 201 if to := req.FormValue("to"); to != "" {
189 toTime, err := time.Parse(models.ImportTimeFormat, to) 202 var toTime time.Time
190 if err != nil { 203 if toTime, err = time.Parse(models.ImportTimeFormat, to); err != nil {
191 return nil, err 204 return
192 } 205 }
193 fb.cond(" enqueued <= $%d ", toTime) 206 l.cond(" enqueued <= $%d ", toTime)
207 a.cond(" enqueued > $%d", toTime)
208 } else {
209 noAfter = true
194 } 210 }
195 211
196 switch warn := strings.ToLower(req.FormValue("warnings")); warn { 212 switch warn := strings.ToLower(req.FormValue("warnings")); warn {
197 case "1", "t", "true": 213 case "1", "t", "true":
198 fb.cond(" id IN (SELECT id FROM warned) ") 214 l.cond(" id IN (SELECT id FROM warned) ")
199 } 215 a.cond(" id IN (SELECT id FROM warned) ")
200 216 b.cond(" id IN (SELECT id FROM warned) ")
201 if !fb.hasCond { 217 }
202 fb.stmt.WriteString(" TRUE ") 218
203 } 219 if !l.hasCond {
204 220 l.stmt.WriteString(" TRUE ")
205 fb.stmt.WriteString(" ORDER BY enqueued DESC ") 221 }
206 222 if !b.hasCond {
207 return conn.QueryContext(req.Context(), fb.stmt.String(), fb.args...) 223 b.stmt.WriteString(" TRUE ")
208 } 224 }
209 225 if !a.hasCond {
210 func enqueued(ctx context.Context, conn *sql.Conn, what, query string) *models.ImportTime { 226 a.stmt.WriteString(" TRUE ")
211 if what == "" { 227 }
212 return nil 228
213 } 229 l.stmt.WriteString(" ORDER BY enqueued DESC ")
214 230 a.stmt.WriteString(" ORDER BY enqueued ")
215 t, err := time.Parse(models.ImportTimeFormat, what) 231 b.stmt.WriteString(" ORDER BY enqueued ")
216 if err != nil { 232
217 log.Printf("warn: %v\n", err) 233 if noBefore {
218 return nil 234 b = nil
219 } 235 }
236 if noAfter {
237 a = nil
238 }
239 return
240 }
241
242 func neighbored(ctx context.Context, conn *sql.Conn, fb *filterBuilder) *models.ImportTime {
220 243
221 var when time.Time 244 var when time.Time
222 err = conn.QueryRowContext(ctx, query, t).Scan(&when) 245 err := conn.QueryRowContext(ctx, fb.stmt.String(), fb.args...).Scan(&when)
223 switch { 246 switch {
224 case err == sql.ErrNoRows: 247 case err == sql.ErrNoRows:
225 return nil 248 return nil
226 case err != nil: 249 case err != nil:
227 log.Printf("warn: %v\n", err) 250 log.Printf("warn: %v\n", err)
228 return nil 251 return nil
229 } 252 }
230
231 return &models.ImportTime{when} 253 return &models.ImportTime{when}
232 }
233 func enqueuedBefore(conn *sql.Conn, req *http.Request) *models.ImportTime {
234 return enqueued(req.Context(), conn, req.FormValue("from"), selectBeforeSQL)
235 }
236
237 func enqueuedAfter(conn *sql.Conn, req *http.Request) *models.ImportTime {
238 return enqueued(req.Context(), conn, req.FormValue("to"), selectAfterSQL)
239 } 254 }
240 255
241 func listImports( 256 func listImports(
242 _ interface{}, 257 _ interface{},
243 req *http.Request, 258 req *http.Request,
244 conn *sql.Conn, 259 conn *sql.Conn,
245 ) (jr JSONResult, err error) { 260 ) (jr JSONResult, err error) {
246 261
262 var list, before, after *filterBuilder
263
264 if list, before, after, err = buildFilters(req); err != nil {
265 return
266 }
267
268 ctx := req.Context()
269
247 var rows *sql.Rows 270 var rows *sql.Rows
248 rows, err = queryImportListStmt(conn, req) 271 if rows, err = conn.QueryContext(ctx, list.stmt.String(), list.args...); err != nil {
249 if err != nil {
250 return 272 return
251 } 273 }
252 defer rows.Close() 274 defer rows.Close()
253 275
254 imports := make([]*models.Import, 0, 20) 276 imports := make([]*models.Import, 0, 20)
255 277
256 var signer sql.NullString 278 var signer sql.NullString
257 279
258 for rows.Next() { 280 for rows.Next() {
259 var it models.Import 281 var it models.Import
282 var enqueued time.Time
260 if err = rows.Scan( 283 if err = rows.Scan(
261 &it.ID, 284 &it.ID,
262 &it.State, 285 &it.State,
263 &it.Enqueued, 286 &enqueued,
264 &it.Kind, 287 &it.Kind,
265 &it.User, 288 &it.User,
266 &signer, 289 &signer,
267 &it.Summary, 290 &it.Summary,
268 &it.Warnings, 291 &it.Warnings,
270 return 293 return
271 } 294 }
272 if signer.Valid { 295 if signer.Valid {
273 it.Signer = signer.String 296 it.Signer = signer.String
274 } 297 }
298 it.Enqueued = models.ImportTime{enqueued}
275 imports = append(imports, &it) 299 imports = append(imports, &it)
276 } 300 }
277 301
278 if err = rows.Err(); err != nil { 302 if err = rows.Err(); err != nil {
279 return 303 return
304 }
305
306 var prev, next *models.ImportTime
307
308 if before != nil {
309 prev = neighbored(ctx, conn, before)
310 }
311
312 if after != nil {
313 next = neighbored(ctx, conn, after)
280 } 314 }
281 315
282 jr = JSONResult{ 316 jr = JSONResult{
283 Result: struct { 317 Result: struct {
284 Prev *models.ImportTime `json:"prev,omitempty"` 318 Prev *models.ImportTime `json:"prev,omitempty"`
285 Next *models.ImportTime `json:"next,omitempty"` 319 Next *models.ImportTime `json:"next,omitempty"`
286 Imports []*models.Import `json:"imports"` 320 Imports []*models.Import `json:"imports"`
287 }{ 321 }{
288 Imports: imports, 322 Imports: imports,
289 Prev: enqueuedBefore(conn, req), 323 Prev: prev,
290 Next: enqueuedAfter(conn, req), 324 Next: next,
291 }, 325 },
292 } 326 }
293 return 327 return
294 } 328 }
295 329