Mercurial > gemma
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 |