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