diff pkg/controllers/common.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/common.go	Wed May 08 12:45:21 2019 +0200
+++ b/pkg/controllers/common.go	Wed May 08 13:11:30 2019 +0200
@@ -18,26 +18,61 @@
 	"strings"
 )
 
-type filterBuilder struct {
-	stmt    strings.Builder
-	args    []interface{}
-	hasCond bool
+type (
+	filterNode interface {
+		serialize(*strings.Builder, *[]interface{})
+	}
+
+	filterTerm struct {
+		format string
+		args   []interface{}
+	}
+
+	filterNot struct {
+		filterNode
+	}
+
+	filterAnd []filterNode
+	filterOr  []filterNode
+)
+
+func (ft *filterTerm) serialize(stmt *strings.Builder, args *[]interface{}) {
+	indices := make([]interface{}, len(ft.args))
+	for i := range indices {
+		indices[i] = len(*args) + i + 1
+	}
+	fmt.Fprintf(stmt, ft.format, indices...)
+	*args = append(*args, (*ft).args...)
 }
 
-func (fb *filterBuilder) arg(format string, v ...interface{}) {
-	indices := make([]interface{}, len(v))
-	for i := range indices {
-		indices[i] = len(fb.args) + i + 1
+func buildFilterTerm(format string, args ...interface{}) *filterTerm {
+	return &filterTerm{format: format, args: args}
+}
+
+func (fa filterAnd) serialize(stmt *strings.Builder, args *[]interface{}) {
+	for i, node := range fa {
+		if i > 0 {
+			stmt.WriteString(" AND ")
+		}
+		stmt.WriteByte('(')
+		node.serialize(stmt, args)
+		stmt.WriteByte(')')
 	}
-	fmt.Fprintf(&fb.stmt, format, indices...)
-	fb.args = append(fb.args, v...)
 }
 
-func (fb *filterBuilder) and(format string, v ...interface{}) {
-	if fb.hasCond {
-		fb.stmt.WriteString(" AND ")
-	} else {
-		fb.hasCond = true
+func (fo filterOr) serialize(stmt *strings.Builder, args *[]interface{}) {
+	for i, node := range fo {
+		if i > 0 {
+			stmt.WriteString(" OR ")
+		}
+		stmt.WriteByte('(')
+		node.serialize(stmt, args)
+		stmt.WriteByte(')')
 	}
-	fb.arg(format, v...)
 }
+
+func (fn *filterNot) serialize(stmt *strings.Builder, args *[]interface{}) {
+	stmt.WriteString("NOT (")
+	fn.filterNode.serialize(stmt, args)
+	stmt.WriteByte(')')
+}