From ab18d74a518f9158a71005f4b9cdb5d87fd5d3a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Nieto?= <jose.carlos@menteslibres.net>
Date: Sun, 24 May 2015 06:58:05 -0500
Subject: [PATCH] Moving some shared logic to sqlutil.

---
 postgresql/collection.go           | 142 +-------------------------
 postgresql/result.go               |   4 +-
 util/schema/{main.go => schema.go} |   0
 util/sqlutil/convert.go            | 159 +++++++++++++++++++++++++++++
 util/{main.go => util.go}          |   0
 5 files changed, 162 insertions(+), 143 deletions(-)
 rename util/schema/{main.go => schema.go} (100%)
 create mode 100644 util/sqlutil/convert.go
 rename util/{main.go => util.go} (100%)

diff --git a/postgresql/collection.go b/postgresql/collection.go
index cfcc4b47..5af92202 100644
--- a/postgresql/collection.go
+++ b/postgresql/collection.go
@@ -24,7 +24,6 @@ package postgresql
 import (
 	"database/sql"
 	"fmt"
-	"reflect"
 	"strings"
 
 	"github.com/jmoiron/sqlx"
@@ -42,147 +41,8 @@ type table struct {
 	names      []string
 }
 
-func whereValues(term interface{}) (where sqlgen.Where, args []interface{}) {
-	args = []interface{}{}
-
-	switch t := term.(type) {
-	case []interface{}:
-		for i := range t {
-			w, v := whereValues(t[i])
-			args = append(args, v...)
-			where.Conditions = append(where.Conditions, w.Conditions...)
-		}
-		return
-	case db.And:
-		var op sqlgen.And
-		for i := range t {
-			k, v := whereValues(t[i])
-			args = append(args, v...)
-			op.Conditions = append(op.Conditions, k.Conditions...)
-		}
-		where.Conditions = append(where.Conditions, &op)
-		return
-	case db.Or:
-		var op sqlgen.Or
-		for i := range t {
-			w, v := whereValues(t[i])
-			args = append(args, v...)
-			op.Conditions = append(op.Conditions, w.Conditions...)
-		}
-		where.Conditions = append(where.Conditions, &op)
-		return
-	case db.Raw:
-		if s, ok := t.Value.(string); ok {
-			where.Conditions = append(where.Conditions, sqlgen.RawValue(s))
-		}
-		return
-	case db.Cond:
-		cv, v := columnValues(t)
-		args = append(args, v...)
-		for i := range cv.ColumnValues {
-			where.Conditions = append(where.Conditions, cv.ColumnValues[i])
-		}
-		return
-	case db.Constrainer:
-		cv, v := columnValues(t.Constraint())
-		args = append(args, v...)
-		for i := range cv.ColumnValues {
-			where.Conditions = append(where.Conditions, cv.ColumnValues[i])
-		}
-		return
-	}
-
-	panic(fmt.Sprintf(db.ErrUnknownConditionType.Error(), term))
-}
-
-func interfaceArgs(value interface{}) (args []interface{}) {
-	if value == nil {
-		return nil
-	}
-
-	v := reflect.ValueOf(value)
-
-	switch v.Type().Kind() {
-	case reflect.Slice:
-		var i, total int
-
-		total = v.Len()
-		if total > 0 {
-			args = make([]interface{}, total)
-
-			for i = 0; i < total; i++ {
-				args[i] = v.Index(i).Interface()
-			}
-
-			return args
-		}
-		return nil
-	default:
-		args = []interface{}{value}
-	}
-
-	return args
-}
-
-func columnValues(cond db.Cond) (columnValues sqlgen.ColumnValues, args []interface{}) {
-	args = []interface{}{}
-
-	for column, value := range cond {
-		columnValue := sqlgen.ColumnValue{}
-
-		// Guessing operator from input, or using a default one.
-		column := strings.TrimSpace(column)
-		chunks := strings.SplitN(column, ` `, 2)
-
-		columnValue.Column = sqlgen.ColumnWithName(chunks[0])
-
-		if len(chunks) > 1 {
-			columnValue.Operator = chunks[1]
-		} else {
-			columnValue.Operator = defaultOperator
-		}
-
-		switch value := value.(type) {
-		case db.Func:
-			v := interfaceArgs(value.Args)
-			columnValue.Operator = value.Name
-
-			if v == nil {
-				// A function with no arguments.
-				columnValue.Value = sqlgen.RawValue(`()`)
-			} else {
-				// A function with one or more arguments.
-				columnValue.Value = sqlgen.RawValue(fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(v)-1)))
-			}
-
-			args = append(args, v...)
-		default:
-			v := interfaceArgs(value)
-
-			l := len(v)
-			if v == nil || l == 0 {
-				// Nil value given.
-				columnValue.Value = sqlgen.RawValue(psqlNull)
-			} else {
-				if l > 1 {
-					// Array value given.
-					columnValue.Value = sqlgen.RawValue(fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(v)-1)))
-				} else {
-					// Single value given.
-					columnValue.Value = sqlPlaceholder
-				}
-				args = append(args, v...)
-			}
-		}
-
-		columnValues.ColumnValues = append(columnValues.ColumnValues, &columnValue)
-	}
-
-	return columnValues, args
-}
-
 func (t *table) Find(terms ...interface{}) db.Result {
-	where, arguments := whereValues(terms)
+	where, arguments := sqlutil.ToWhereWithArguments(terms)
 
 	result := &result{
 		table:     t,
diff --git a/postgresql/result.go b/postgresql/result.go
index b1d145b0..f289f229 100644
--- a/postgresql/result.go
+++ b/postgresql/result.go
@@ -68,7 +68,7 @@ func (r *result) setCursor() error {
 
 // Sets conditions for reducing the working set.
 func (r *result) Where(terms ...interface{}) db.Result {
-	r.where, r.arguments = whereValues(terms)
+	r.where, r.arguments = sqlutil.ToWhereWithArguments(terms)
 	return r
 }
 
@@ -152,7 +152,7 @@ func (r *result) Select(fields ...interface{}) db.Result {
 		var col sqlgen.Fragment
 		switch value := fields[i].(type) {
 		case db.Func:
-			v := interfaceArgs(value.Args)
+			v := sqlutil.ToInterfaceArguments(value.Args)
 			var s string
 			if len(v) == 0 {
 				s = fmt.Sprintf(`%s()`, value.Name)
diff --git a/util/schema/main.go b/util/schema/schema.go
similarity index 100%
rename from util/schema/main.go
rename to util/schema/schema.go
diff --git a/util/sqlutil/convert.go b/util/sqlutil/convert.go
new file mode 100644
index 00000000..19446268
--- /dev/null
+++ b/util/sqlutil/convert.go
@@ -0,0 +1,159 @@
+package sqlutil
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+	"upper.io/db"
+	"upper.io/db/util/sqlgen"
+)
+
+var (
+	sqlPlaceholder     = sqlgen.RawValue(`?`)
+	sqlNull            = sqlgen.RawValue(`NULL`)
+	sqlDefaultOperator = "="
+)
+
+// ToWhereWithArguments converts the given db.Cond parameters into a sqlgen.Where
+// value.
+func ToWhereWithArguments(term interface{}) (where sqlgen.Where, args []interface{}) {
+	args = []interface{}{}
+
+	switch t := term.(type) {
+	case []interface{}:
+		for i := range t {
+			w, v := ToWhereWithArguments(t[i])
+			args = append(args, v...)
+			where.Conditions = append(where.Conditions, w.Conditions...)
+		}
+		return
+	case db.And:
+		var op sqlgen.And
+		for i := range t {
+			k, v := ToWhereWithArguments(t[i])
+			args = append(args, v...)
+			op.Conditions = append(op.Conditions, k.Conditions...)
+		}
+		where.Conditions = append(where.Conditions, &op)
+		return
+	case db.Or:
+		var op sqlgen.Or
+		for i := range t {
+			w, v := ToWhereWithArguments(t[i])
+			args = append(args, v...)
+			op.Conditions = append(op.Conditions, w.Conditions...)
+		}
+		where.Conditions = append(where.Conditions, &op)
+		return
+	case db.Raw:
+		if s, ok := t.Value.(string); ok {
+			where.Conditions = append(where.Conditions, sqlgen.RawValue(s))
+		}
+		return
+	case db.Cond:
+		cv, v := ToColumnValues(t)
+		args = append(args, v...)
+		for i := range cv.ColumnValues {
+			where.Conditions = append(where.Conditions, cv.ColumnValues[i])
+		}
+		return
+	case db.Constrainer:
+		cv, v := ToColumnValues(t.Constraint())
+		args = append(args, v...)
+		for i := range cv.ColumnValues {
+			where.Conditions = append(where.Conditions, cv.ColumnValues[i])
+		}
+		return
+	}
+
+	panic(fmt.Sprintf(db.ErrUnknownConditionType.Error(), term))
+}
+
+// ToInterfaceArguments converts the given value into an array of interfaces.
+func ToInterfaceArguments(value interface{}) (args []interface{}) {
+	if value == nil {
+		return nil
+	}
+
+	v := reflect.ValueOf(value)
+
+	switch v.Type().Kind() {
+	case reflect.Slice:
+		var i, total int
+
+		total = v.Len()
+		if total > 0 {
+			args = make([]interface{}, total)
+
+			for i = 0; i < total; i++ {
+				args[i] = v.Index(i).Interface()
+			}
+
+			return args
+		}
+		return nil
+	default:
+		args = []interface{}{value}
+	}
+
+	return args
+}
+
+// ToColumnValues converts the given db.Cond into a sqlgen.ColumnValues struct.
+func ToColumnValues(cond db.Cond) (ToColumnValues sqlgen.ColumnValues, args []interface{}) {
+
+	args = []interface{}{}
+
+	for column, value := range cond {
+		columnValue := sqlgen.ColumnValue{}
+
+		// Guessing operator from input, or using a default one.
+		column := strings.TrimSpace(column)
+		chunks := strings.SplitN(column, ` `, 2)
+
+		columnValue.Column = sqlgen.ColumnWithName(chunks[0])
+
+		if len(chunks) > 1 {
+			columnValue.Operator = chunks[1]
+		} else {
+			columnValue.Operator = sqlDefaultOperator
+		}
+
+		switch value := value.(type) {
+		case db.Func:
+			v := ToInterfaceArguments(value.Args)
+			columnValue.Operator = value.Name
+
+			if v == nil {
+				// A function with no arguments.
+				columnValue.Value = sqlgen.RawValue(`()`)
+			} else {
+				// A function with one or more arguments.
+				columnValue.Value = sqlgen.RawValue(fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(v)-1)))
+			}
+
+			args = append(args, v...)
+		default:
+			v := ToInterfaceArguments(value)
+
+			l := len(v)
+			if v == nil || l == 0 {
+				// Nil value given.
+				columnValue.Value = sqlNull
+			} else {
+				if l > 1 {
+					// Array value given.
+					columnValue.Value = sqlgen.RawValue(fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(v)-1)))
+				} else {
+					// Single value given.
+					columnValue.Value = sqlPlaceholder
+				}
+				args = append(args, v...)
+			}
+		}
+
+		ToColumnValues.ColumnValues = append(ToColumnValues.ColumnValues, &columnValue)
+	}
+
+	return ToColumnValues, args
+}
diff --git a/util/main.go b/util/util.go
similarity index 100%
rename from util/main.go
rename to util/util.go
-- 
GitLab