105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package dbr
|
|
|
|
import (
|
|
"bytes"
|
|
"reflect"
|
|
)
|
|
|
|
// Eq is a map column -> value pairs which must be matched in a query
|
|
type Eq map[string]interface{}
|
|
|
|
type whereFragment struct {
|
|
Condition string
|
|
Values []interface{}
|
|
EqualityMap map[string]interface{}
|
|
}
|
|
|
|
func newWhereFragment(whereSqlOrMap interface{}, args []interface{}) *whereFragment {
|
|
switch pred := whereSqlOrMap.(type) {
|
|
case string:
|
|
return &whereFragment{Condition: pred, Values: args}
|
|
case map[string]interface{}:
|
|
return &whereFragment{EqualityMap: pred}
|
|
case Eq:
|
|
return &whereFragment{EqualityMap: map[string]interface{}(pred)}
|
|
default:
|
|
panic("Invalid argument passed to Where. Pass a string or an Eq map.")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Invariant: only called when len(fragments) > 0
|
|
func writeWhereFragmentsToSql(fragments []*whereFragment, sql *bytes.Buffer, args *[]interface{}) {
|
|
anyConditions := false
|
|
for _, f := range fragments {
|
|
if f.Condition != "" {
|
|
if anyConditions {
|
|
sql.WriteString(" AND (")
|
|
} else {
|
|
sql.WriteRune('(')
|
|
anyConditions = true
|
|
}
|
|
sql.WriteString(f.Condition)
|
|
sql.WriteRune(')')
|
|
if len(f.Values) > 0 {
|
|
*args = append(*args, f.Values...)
|
|
}
|
|
} else if f.EqualityMap != nil {
|
|
anyConditions = writeEqualityMapToSql(f.EqualityMap, sql, args, anyConditions)
|
|
} else {
|
|
panic("invalid equality map")
|
|
}
|
|
}
|
|
}
|
|
|
|
func writeEqualityMapToSql(eq map[string]interface{}, sql *bytes.Buffer, args *[]interface{}, anyConditions bool) bool {
|
|
for k, v := range eq {
|
|
if v == nil {
|
|
anyConditions = writeWhereCondition(sql, k, " IS NULL", anyConditions)
|
|
} else {
|
|
vVal := reflect.ValueOf(v)
|
|
|
|
if vVal.Kind() == reflect.Array || vVal.Kind() == reflect.Slice {
|
|
vValLen := vVal.Len()
|
|
if vValLen == 0 {
|
|
if vVal.IsNil() {
|
|
anyConditions = writeWhereCondition(sql, k, " IS NULL", anyConditions)
|
|
} else {
|
|
if anyConditions {
|
|
sql.WriteString(" AND (1=0)")
|
|
} else {
|
|
sql.WriteString("(1=0)")
|
|
}
|
|
}
|
|
} else if vValLen == 1 {
|
|
anyConditions = writeWhereCondition(sql, k, " = ?", anyConditions)
|
|
*args = append(*args, vVal.Index(0).Interface())
|
|
} else {
|
|
anyConditions = writeWhereCondition(sql, k, " IN ?", anyConditions)
|
|
*args = append(*args, v)
|
|
}
|
|
} else {
|
|
anyConditions = writeWhereCondition(sql, k, " = ?", anyConditions)
|
|
*args = append(*args, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
return anyConditions
|
|
}
|
|
|
|
func writeWhereCondition(sql *bytes.Buffer, k string, pred string, anyConditions bool) bool {
|
|
if anyConditions {
|
|
sql.WriteString(" AND (")
|
|
} else {
|
|
sql.WriteRune('(')
|
|
anyConditions = true
|
|
}
|
|
Quoter.writeQuotedColumn(k, sql)
|
|
sql.WriteString(pred)
|
|
sql.WriteRune(')')
|
|
|
|
return anyConditions
|
|
}
|