2016-03-16 08:04:26 +01:00
|
|
|
package boil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"unicode"
|
2016-05-02 08:34:25 +02:00
|
|
|
|
2016-06-08 07:45:34 +02:00
|
|
|
"github.com/nullbio/sqlboiler/strmangle"
|
2016-03-16 08:04:26 +01:00
|
|
|
)
|
|
|
|
|
2016-05-02 08:34:25 +02:00
|
|
|
// SetComplement subtracts the elements in b from a
|
|
|
|
func SetComplement(a []string, b []string) []string {
|
|
|
|
c := make([]string, 0, len(a))
|
|
|
|
|
|
|
|
for _, aVal := range a {
|
|
|
|
found := false
|
|
|
|
for _, bVal := range b {
|
|
|
|
if aVal == bVal {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
c = append(c, aVal)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetIntersect returns the elements that are common in a and b
|
|
|
|
func SetIntersect(a []string, b []string) []string {
|
|
|
|
c := make([]string, 0, len(a))
|
|
|
|
|
|
|
|
for _, aVal := range a {
|
|
|
|
found := false
|
|
|
|
for _, bVal := range b {
|
|
|
|
if aVal == bVal {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if found {
|
|
|
|
c = append(c, aVal)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
// NonZeroDefaultSet returns the fields included in the
|
|
|
|
// defaults slice that are non zero values
|
|
|
|
func NonZeroDefaultSet(defaults []string, obj interface{}) []string {
|
|
|
|
c := make([]string, 0, len(defaults))
|
|
|
|
|
2016-05-17 12:00:56 +02:00
|
|
|
val := reflect.Indirect(reflect.ValueOf(obj))
|
2016-05-02 08:34:25 +02:00
|
|
|
|
|
|
|
for _, d := range defaults {
|
|
|
|
fieldName := strmangle.TitleCase(d)
|
|
|
|
field := val.FieldByName(fieldName)
|
|
|
|
if !field.IsValid() {
|
|
|
|
panic(fmt.Sprintf("Could not find field name %s in type %T", fieldName, obj))
|
|
|
|
}
|
|
|
|
|
|
|
|
zero := reflect.Zero(field.Type())
|
|
|
|
if !reflect.DeepEqual(zero.Interface(), field.Interface()) {
|
|
|
|
c = append(c, d)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2016-06-07 09:08:00 +02:00
|
|
|
// SortByKeys returns a new ordered slice based on the keys ordering
|
2016-06-07 08:21:00 +02:00
|
|
|
func SortByKeys(keys []string, strs []string) []string {
|
|
|
|
c := make([]string, len(strs))
|
|
|
|
|
|
|
|
index := 0
|
|
|
|
Outer:
|
|
|
|
for _, v := range keys {
|
|
|
|
for _, k := range strs {
|
|
|
|
if v == k {
|
|
|
|
c[index] = v
|
|
|
|
index++
|
|
|
|
|
|
|
|
if index > len(strs)-1 {
|
|
|
|
break Outer
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2016-05-02 08:34:25 +02:00
|
|
|
// GenerateParamFlags generates the SQL statement parameter flags
|
|
|
|
// For example, $1,$2,$3 etc. It will start counting at startAt.
|
|
|
|
func GenerateParamFlags(colCount int, startAt int) string {
|
|
|
|
return strmangle.GenerateParamFlags(colCount, startAt)
|
|
|
|
}
|
|
|
|
|
2016-04-23 13:54:24 +02:00
|
|
|
// WherePrimaryKeyIn generates a "in" string for where queries
|
|
|
|
// For example: (col1, col2) IN (($1, $2), ($3, $4))
|
|
|
|
func WherePrimaryKeyIn(numRows int, keyNames ...string) string {
|
|
|
|
in := &bytes.Buffer{}
|
|
|
|
|
|
|
|
if len(keyNames) == 0 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
in.WriteByte('(')
|
|
|
|
for i := 0; i < len(keyNames); i++ {
|
|
|
|
in.WriteString(`"` + keyNames[i] + `"`)
|
|
|
|
if i < len(keyNames)-1 {
|
|
|
|
in.WriteByte(',')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
in.WriteString(") IN (")
|
|
|
|
|
|
|
|
c := 1
|
|
|
|
for i := 0; i < numRows; i++ {
|
|
|
|
for y := 0; y < len(keyNames); y++ {
|
|
|
|
if len(keyNames) > 1 && y == 0 {
|
|
|
|
in.WriteByte('(')
|
|
|
|
}
|
|
|
|
|
|
|
|
in.WriteString(fmt.Sprintf("$%d", c))
|
|
|
|
c++
|
|
|
|
|
|
|
|
if len(keyNames) > 1 && y == len(keyNames)-1 {
|
|
|
|
in.WriteByte(')')
|
|
|
|
}
|
|
|
|
|
|
|
|
if i != numRows-1 || y != len(keyNames)-1 {
|
|
|
|
in.WriteByte(',')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
in.WriteByte(')')
|
|
|
|
|
|
|
|
return in.String()
|
|
|
|
}
|
|
|
|
|
2016-03-16 08:04:26 +01:00
|
|
|
// SelectNames returns the column names for a select statement
|
2016-03-19 07:22:10 +01:00
|
|
|
// Eg: col1, col2, col3
|
2016-03-16 08:04:26 +01:00
|
|
|
func SelectNames(results interface{}) string {
|
|
|
|
var names []string
|
|
|
|
|
2016-05-17 12:00:56 +02:00
|
|
|
structValue := reflect.Indirect(reflect.ValueOf(results))
|
2016-03-16 08:04:26 +01:00
|
|
|
|
|
|
|
structType := structValue.Type()
|
|
|
|
for i := 0; i < structValue.NumField(); i++ {
|
|
|
|
field := structType.Field(i)
|
|
|
|
var name string
|
|
|
|
|
|
|
|
if db := field.Tag.Get("db"); len(db) != 0 {
|
|
|
|
name = db
|
|
|
|
} else {
|
|
|
|
name = goVarToSQLName(field.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
names = append(names, name)
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.Join(names, ", ")
|
|
|
|
}
|
|
|
|
|
2016-04-13 15:51:58 +02:00
|
|
|
// WhereClause returns the where clause for an sql statement
|
2016-03-19 07:22:10 +01:00
|
|
|
// eg: col1=$1 AND col2=$2 AND col3=$3
|
2016-05-02 08:34:25 +02:00
|
|
|
func WhereClause(columns []string) string {
|
2016-03-16 08:04:26 +01:00
|
|
|
names := make([]string, 0, len(columns))
|
|
|
|
|
2016-05-02 08:34:25 +02:00
|
|
|
for _, c := range columns {
|
2016-03-16 08:04:26 +01:00
|
|
|
names = append(names, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, c := range names {
|
|
|
|
names[i] = fmt.Sprintf("%s=$%d", c, i+1)
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.Join(names, " AND ")
|
|
|
|
}
|
|
|
|
|
2016-03-19 07:22:10 +01:00
|
|
|
// Update returns the column list for an update statement SET clause
|
|
|
|
// eg: col1=$1,col2=$2,col3=$3
|
|
|
|
func Update(columns map[string]interface{}) string {
|
|
|
|
names := make([]string, 0, len(columns))
|
|
|
|
|
|
|
|
for c := range columns {
|
|
|
|
names = append(names, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(names)
|
|
|
|
|
|
|
|
for i, c := range names {
|
|
|
|
names[i] = fmt.Sprintf("%s=$%d", c, i+1)
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.Join(names, ",")
|
|
|
|
}
|
|
|
|
|
2016-04-13 15:51:58 +02:00
|
|
|
// SetParamNames takes a slice of columns and returns a comma seperated
|
|
|
|
// list of parameter names for a template statement SET clause.
|
|
|
|
// eg: col1=$1,col2=$2,col3=$3
|
|
|
|
func SetParamNames(columns []string) string {
|
|
|
|
names := make([]string, 0, len(columns))
|
|
|
|
counter := 0
|
|
|
|
for _, c := range columns {
|
|
|
|
counter++
|
|
|
|
names = append(names, fmt.Sprintf("%s=$%d", c, counter))
|
|
|
|
}
|
|
|
|
return strings.Join(names, ",")
|
|
|
|
}
|
|
|
|
|
|
|
|
// WherePrimaryKey returns the where clause using start as the $ flag index
|
|
|
|
// For example, if start was 2 output would be: "colthing=$2 AND colstuff=$3"
|
|
|
|
func WherePrimaryKey(start int, pkeys ...string) string {
|
|
|
|
var output string
|
|
|
|
for i, c := range pkeys {
|
|
|
|
output = fmt.Sprintf("%s%s=$%d", output, c, start)
|
|
|
|
start++
|
|
|
|
|
|
|
|
if i < len(pkeys)-1 {
|
|
|
|
output = fmt.Sprintf("%s AND ", output)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return output
|
|
|
|
}
|
|
|
|
|
2016-03-16 08:04:26 +01:00
|
|
|
// goVarToSQLName converts a go variable name to a column name
|
|
|
|
// example: HelloFriendID to hello_friend_id
|
|
|
|
func goVarToSQLName(name string) string {
|
|
|
|
str := &bytes.Buffer{}
|
|
|
|
isUpper, upperStreak := false, false
|
|
|
|
|
|
|
|
for i := 0; i < len(name); i++ {
|
|
|
|
c := rune(name[i])
|
|
|
|
if unicode.IsDigit(c) || unicode.IsLower(c) {
|
|
|
|
isUpper = false
|
|
|
|
upperStreak = false
|
|
|
|
|
|
|
|
str.WriteRune(c)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if isUpper {
|
|
|
|
upperStreak = true
|
|
|
|
} else if i != 0 {
|
|
|
|
str.WriteByte('_')
|
|
|
|
}
|
|
|
|
isUpper = true
|
|
|
|
|
|
|
|
if j := i + 1; j < len(name) && upperStreak && unicode.IsLower(rune(name[j])) {
|
|
|
|
str.WriteByte('_')
|
|
|
|
}
|
|
|
|
|
|
|
|
str.WriteRune(unicode.ToLower(c))
|
|
|
|
}
|
|
|
|
|
|
|
|
return str.String()
|
|
|
|
}
|