diff pkg/controllers/importqueue.go @ 3194:eeff2cc4ff9d

controllers: re-factored the SQL filter to a tree like structure to be of more general use.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 08 May 2019 13:11:30 +0200
parents 54a3e40cfbed
children 4c254651d80b
line wrap: on
line diff
--- a/pkg/controllers/importqueue.go	Wed May 08 12:45:21 2019 +0200
+++ b/pkg/controllers/importqueue.go	Wed May 08 13:11:30 2019 +0200
@@ -132,30 +132,22 @@
 	return &ta
 }
 
-func buildFilters(req *http.Request) (l, b, a *filterBuilder, err error) {
+type filledStmt struct {
+	stmt strings.Builder
+	args []interface{}
+}
 
-	l = new(filterBuilder)
-	a = new(filterBuilder)
-	b = new(filterBuilder)
+func buildFilters(req *http.Request) (*filledStmt, *filledStmt, *filledStmt, error) {
+
+	var l, a, b filterAnd
 
 	var noBefore, noAfter bool
 
-	var counting bool
-
-	switch count := strings.ToLower(req.FormValue("count")); count {
-	case "1", "t", "true":
-		counting = true
-		l.stmt.WriteString(selectImportsCountSQL)
-	default:
-		l.stmt.WriteString(selectImportsSQL)
-	}
-	a.stmt.WriteString(selectAfterSQL)
-	b.stmt.WriteString(selectBeforeSQL)
-
-	cond := func(format string, v ...interface{}) {
-		l.and(format, v...)
-		a.and(format, v...)
-		b.and(format, v...)
+	cond := func(format string, args ...interface{}) {
+		term := &filterTerm{format: format, args: args}
+		l = append(l, term)
+		a = append(l, term)
+		b = append(b, term)
 	}
 
 	if query := req.FormValue("query"); query != "" {
@@ -181,23 +173,23 @@
 	}
 
 	if from := req.FormValue("from"); from != "" {
-		var fromTime time.Time
-		if fromTime, err = time.Parse(models.ImportTimeFormat, from); err != nil {
-			return
+		fromTime, err := time.Parse(models.ImportTimeFormat, from)
+		if err != nil {
+			return nil, nil, nil, err
 		}
-		l.and(" enqueued >= $%d ", fromTime)
-		b.and(" enqueued < $%d", fromTime)
+		l = append(l, buildFilterTerm("enqueued >= $%d", fromTime))
+		b = append(b, buildFilterTerm("enqueued < $%d", fromTime))
 	} else {
 		noBefore = true
 	}
 
 	if to := req.FormValue("to"); to != "" {
-		var toTime time.Time
-		if toTime, err = time.Parse(models.ImportTimeFormat, to); err != nil {
-			return
+		toTime, err := time.Parse(models.ImportTimeFormat, to)
+		if err != nil {
+			return nil, nil, nil, err
 		}
-		l.and(" enqueued <= $%d ", toTime)
-		a.and(" enqueued > $%d", toTime)
+		l = append(l, buildFilterTerm("enqueued <= $%d", toTime))
+		a = append(a, buildFilterTerm("enqueued > $%d", toTime))
 	} else {
 		noAfter = true
 	}
@@ -207,32 +199,58 @@
 		cond(" id IN (SELECT id FROM warned) ")
 	}
 
-	if !l.hasCond {
-		l.stmt.WriteString(" TRUE ")
+	fl := &filledStmt{}
+	fa := &filledStmt{}
+	fb := &filledStmt{}
+
+	fa.stmt.WriteString(selectAfterSQL)
+	fb.stmt.WriteString(selectBeforeSQL)
+
+	var counting bool
+
+	switch count := strings.ToLower(req.FormValue("count")); count {
+	case "1", "t", "true":
+		counting = true
+		fl.stmt.WriteString(selectImportsCountSQL)
+	default:
+		fl.stmt.WriteString(selectImportsSQL)
 	}
-	if !b.hasCond {
-		b.stmt.WriteString(" TRUE ")
+
+	if len(l) == 0 {
+		fl.stmt.WriteString(" TRUE ")
+	} else {
+		l.serialize(&fl.stmt, &fl.args)
 	}
-	if !a.hasCond {
-		a.stmt.WriteString(" TRUE ")
+
+	if len(b) == 0 {
+		fb.stmt.WriteString(" TRUE ")
+	} else {
+		b.serialize(&fb.stmt, &fb.args)
+	}
+
+	if len(a) == 0 {
+		fa.stmt.WriteString(" TRUE ")
+	} else {
+		a.serialize(&fa.stmt, &fa.args)
 	}
 
 	if !counting {
-		l.stmt.WriteString(" ORDER BY enqueued DESC ")
-		a.stmt.WriteString(" ORDER BY enqueued LIMIT 1")
-		b.stmt.WriteString(" ORDER BY enqueued DESC LIMIT 1")
+		fl.stmt.WriteString(" ORDER BY enqueued DESC ")
+		fa.stmt.WriteString(" ORDER BY enqueued LIMIT 1")
+		fb.stmt.WriteString(" ORDER BY enqueued DESC LIMIT 1")
 	}
 
 	if noBefore {
-		b = nil
+		fb = nil
 	}
 	if noAfter {
-		a = nil
+		fa = nil
 	}
-	return
+
+	return fl, fb, fa, nil
 }
 
-func neighbored(ctx context.Context, conn *sql.Conn, fb *filterBuilder) *models.ImportTime {
+func neighbored(ctx context.Context, conn *sql.Conn, fb *filledStmt) *models.ImportTime {
 
 	var when time.Time
 	err := conn.QueryRowContext(ctx, fb.stmt.String(), fb.args...).Scan(&when)
@@ -252,7 +270,7 @@
 	conn *sql.Conn,
 ) (jr JSONResult, err error) {
 
-	var list, before, after *filterBuilder
+	var list, before, after *filledStmt
 
 	if list, before, after, err = buildFilters(req); err != nil {
 		return