Got insert testing in a better state
* Split up insert function for testing * Add DBType to global state * Move test reflection helpers to testing.go * Add incremental seed to randomizeField to avoid duplicate constraint error messages * Fixed Viper SSL default bug * Fixed pgpass SSL inclusion bug * Add MakeStringMap strmangle helper * Change test errors from error to skip
This commit is contained in:
parent
f054f2f754
commit
4036786b6a
25 changed files with 778 additions and 781 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
/cmd/sqlboiler/sqlboiler
|
/cmd/sqlboiler/sqlboiler
|
||||||
sqlboiler.toml
|
sqlboiler.toml
|
||||||
models/
|
models/
|
||||||
|
testschema.sql
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package bdb
|
package bdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nullbio/sqlboiler/strmangle"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Column holds information about a database column.
|
// Column holds information about a database column.
|
||||||
|
@ -10,6 +13,7 @@ import (
|
||||||
type Column struct {
|
type Column struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
|
DBType string
|
||||||
Default string
|
Default string
|
||||||
Nullable bool
|
Nullable bool
|
||||||
}
|
}
|
||||||
|
@ -24,6 +28,17 @@ func ColumnNames(cols []Column) []string {
|
||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ColumnDBTypes of the columns.
|
||||||
|
func ColumnDBTypes(cols []Column) map[string]string {
|
||||||
|
types := map[string]string{}
|
||||||
|
|
||||||
|
for _, c := range cols {
|
||||||
|
types[strmangle.TitleCase(c.Name)] = c.DBType
|
||||||
|
}
|
||||||
|
|
||||||
|
return types
|
||||||
|
}
|
||||||
|
|
||||||
// FilterColumnsByDefault generates the list of columns that have default values
|
// FilterColumnsByDefault generates the list of columns that have default values
|
||||||
func FilterColumnsByDefault(defaults bool, columns []Column) []Column {
|
func FilterColumnsByDefault(defaults bool, columns []Column) []Column {
|
||||||
var cols []Column
|
var cols []Column
|
||||||
|
@ -71,7 +86,9 @@ var (
|
||||||
rgxByteaDefaultValue = regexp.MustCompile(`(?i)\\x([0-9A-F]*)`)
|
rgxByteaDefaultValue = regexp.MustCompile(`(?i)\\x([0-9A-F]*)`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultValues returns the Go converted values of the default value columns
|
// DefaultValues returns the Go converted values of the default value columns.
|
||||||
|
// For the time columns it will return time.Now() since we cannot extract
|
||||||
|
// the true time from the default value string.
|
||||||
func DefaultValues(columns []Column) []string {
|
func DefaultValues(columns []Column) []string {
|
||||||
var dVals []string
|
var dVals []string
|
||||||
|
|
||||||
|
@ -89,17 +106,34 @@ func DefaultValues(columns []Column) []string {
|
||||||
switch c.Type {
|
switch c.Type {
|
||||||
case "null.Uint", "null.Uint8", "null.Uint16", "null.Uint32", "null.Uint64",
|
case "null.Uint", "null.Uint8", "null.Uint16", "null.Uint32", "null.Uint64",
|
||||||
"null.Int", "null.Int8", "null.Int16", "null.Int32", "null.Int64",
|
"null.Int", "null.Int8", "null.Int16", "null.Int32", "null.Int64",
|
||||||
"uint", "uint8", "uint16", "uint32", "uint64",
|
"null.Float32", "null.Float64":
|
||||||
"int", "int8", "int16", "int32", "int64",
|
dVals = append(dVals,
|
||||||
"null.Float32", "null.Float64", "float32", "float64":
|
fmt.Sprintf(`null.New%s(%s, true)`,
|
||||||
dVals = append(dVals, dVal)
|
strings.TrimPrefix(c.Type, "null."),
|
||||||
case "null.Bool", "bool":
|
dVal),
|
||||||
|
)
|
||||||
|
case "uint", "uint8", "uint16", "uint32", "uint64",
|
||||||
|
"int", "int8", "int16", "int32", "int64", "float32", "float64":
|
||||||
|
dVals = append(dVals, fmt.Sprintf(`%s(%s)`, c.Type, dVal))
|
||||||
|
case "null.Bool":
|
||||||
|
m = rgxBoolDefaultValue.FindStringSubmatch(dVal)
|
||||||
|
if len(m) == 0 {
|
||||||
|
dVals = append(dVals, `null.NewBool(false, true)`)
|
||||||
|
}
|
||||||
|
dVals = append(dVals, fmt.Sprintf(`null.NewBool(%s, true)`, strings.ToLower(dVal)))
|
||||||
|
case "bool":
|
||||||
m = rgxBoolDefaultValue.FindStringSubmatch(dVal)
|
m = rgxBoolDefaultValue.FindStringSubmatch(dVal)
|
||||||
if len(m) == 0 {
|
if len(m) == 0 {
|
||||||
dVals = append(dVals, "false")
|
dVals = append(dVals, "false")
|
||||||
}
|
}
|
||||||
dVals = append(dVals, strings.ToLower(m[0]))
|
dVals = append(dVals, strings.ToLower(m[0]))
|
||||||
case "null.Time", "time.Time", "null.String", "string":
|
case "null.Time":
|
||||||
|
dVals = append(dVals, fmt.Sprintf(`null.NewTime(time.Now(), true)`))
|
||||||
|
case "time.Time":
|
||||||
|
dVals = append(dVals, `time.Now()`)
|
||||||
|
case "null.String":
|
||||||
|
dVals = append(dVals, fmt.Sprintf(`null.NewString("%s", true)`, dVal))
|
||||||
|
case "string":
|
||||||
dVals = append(dVals, `"`+dVal+`"`)
|
dVals = append(dVals, `"`+dVal+`"`)
|
||||||
case "[]byte":
|
case "[]byte":
|
||||||
m := rgxByteaDefaultValue.FindStringSubmatch(dVal)
|
m := rgxByteaDefaultValue.FindStringSubmatch(dVal)
|
||||||
|
|
|
@ -20,6 +20,21 @@ func TestColumnNames(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestColumnDBTypes(t *testing.T) {
|
||||||
|
cols := []Column{
|
||||||
|
Column{Name: "test_one", DBType: "integer"},
|
||||||
|
Column{Name: "test_two", DBType: "interval"},
|
||||||
|
}
|
||||||
|
|
||||||
|
res := ColumnDBTypes(cols)
|
||||||
|
if res["TestOne"] != "integer" {
|
||||||
|
t.Errorf(`Expected res["TestOne"]="integer", got: %s`, res["TestOne"])
|
||||||
|
}
|
||||||
|
if res["TestTwo"] != "interval" {
|
||||||
|
t.Errorf(`Expected res["TestOne"]="interval", got: %s`, res["TestOne"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFilterColumnsByDefault(t *testing.T) {
|
func TestFilterColumnsByDefault(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ func (p *PostgresDriver) Columns(tableName string) ([]bdb.Column, error) {
|
||||||
|
|
||||||
column := bdb.Column{
|
column := bdb.Column{
|
||||||
Name: colName,
|
Name: colName,
|
||||||
Type: colType,
|
DBType: colType,
|
||||||
Default: colDefault,
|
Default: colDefault,
|
||||||
Nullable: Nullable == "YES",
|
Nullable: Nullable == "YES",
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ func (p *PostgresDriver) ForeignKeyInfo(tableName string) ([]bdb.ForeignKey, err
|
||||||
// as a Column object.
|
// as a Column object.
|
||||||
func (p *PostgresDriver) TranslateColumnType(c bdb.Column) bdb.Column {
|
func (p *PostgresDriver) TranslateColumnType(c bdb.Column) bdb.Column {
|
||||||
if c.Nullable {
|
if c.Nullable {
|
||||||
switch c.Type {
|
switch c.DBType {
|
||||||
case "bigint", "bigserial":
|
case "bigint", "bigserial":
|
||||||
c.Type = "null.Int64"
|
c.Type = "null.Int64"
|
||||||
case "integer", "serial":
|
case "integer", "serial":
|
||||||
|
@ -222,19 +222,19 @@ func (p *PostgresDriver) TranslateColumnType(c bdb.Column) bdb.Column {
|
||||||
c.Type = "null.Float64"
|
c.Type = "null.Float64"
|
||||||
case "real":
|
case "real":
|
||||||
c.Type = "null.Float32"
|
c.Type = "null.Float32"
|
||||||
case "bit", "bit varying", "character", "character varying", "cidr", "inet", "json", "macaddr", "text", "uuid", "xml":
|
case "bit", "interval", "bit varying", "character", "character varying", "cidr", "inet", "json", "macaddr", "text", "uuid", "xml":
|
||||||
c.Type = "null.String"
|
c.Type = "null.String"
|
||||||
case "bytea":
|
case "bytea":
|
||||||
c.Type = "[]byte"
|
c.Type = "[]byte"
|
||||||
case "boolean":
|
case "boolean":
|
||||||
c.Type = "null.Bool"
|
c.Type = "null.Bool"
|
||||||
case "date", "interval", "time", "timestamp without time zone", "timestamp with time zone":
|
case "date", "time", "timestamp without time zone", "timestamp with time zone":
|
||||||
c.Type = "null.Time"
|
c.Type = "null.Time"
|
||||||
default:
|
default:
|
||||||
c.Type = "null.String"
|
c.Type = "null.String"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch c.Type {
|
switch c.DBType {
|
||||||
case "bigint", "bigserial":
|
case "bigint", "bigserial":
|
||||||
c.Type = "int64"
|
c.Type = "int64"
|
||||||
case "integer", "serial":
|
case "integer", "serial":
|
||||||
|
@ -245,13 +245,13 @@ func (p *PostgresDriver) TranslateColumnType(c bdb.Column) bdb.Column {
|
||||||
c.Type = "float64"
|
c.Type = "float64"
|
||||||
case "real":
|
case "real":
|
||||||
c.Type = "float32"
|
c.Type = "float32"
|
||||||
case "bit", "bit varying", "character", "character varying", "cidr", "inet", "json", "macaddr", "text", "uuid", "xml":
|
case "bit", "interval", "bit varying", "character", "character varying", "cidr", "inet", "json", "macaddr", "text", "uuid", "xml":
|
||||||
c.Type = "string"
|
c.Type = "string"
|
||||||
case "bytea":
|
case "bytea":
|
||||||
c.Type = "[]byte"
|
c.Type = "[]byte"
|
||||||
case "boolean":
|
case "boolean":
|
||||||
c.Type = "bool"
|
c.Type = "bool"
|
||||||
case "date", "interval", "time", "timestamp without time zone", "timestamp with time zone":
|
case "date", "time", "timestamp without time zone", "timestamp with time zone":
|
||||||
c.Type = "time.Time"
|
c.Type = "time.Time"
|
||||||
default:
|
default:
|
||||||
c.Type = "string"
|
c.Type = "string"
|
||||||
|
|
406
boil/reflect.go
406
boil/reflect.go
|
@ -3,36 +3,9 @@ package boil
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"math/rand"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/nullbio/sqlboiler/strmangle"
|
"github.com/nullbio/sqlboiler/strmangle"
|
||||||
"gopkg.in/nullbio/null.v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
typeNullFloat32 = reflect.TypeOf(null.Float32{})
|
|
||||||
typeNullFloat64 = reflect.TypeOf(null.Float64{})
|
|
||||||
typeNullInt = reflect.TypeOf(null.Int{})
|
|
||||||
typeNullInt8 = reflect.TypeOf(null.Int8{})
|
|
||||||
typeNullInt16 = reflect.TypeOf(null.Int16{})
|
|
||||||
typeNullInt32 = reflect.TypeOf(null.Int32{})
|
|
||||||
typeNullInt64 = reflect.TypeOf(null.Int64{})
|
|
||||||
typeNullUint = reflect.TypeOf(null.Uint{})
|
|
||||||
typeNullUint8 = reflect.TypeOf(null.Uint8{})
|
|
||||||
typeNullUint16 = reflect.TypeOf(null.Uint16{})
|
|
||||||
typeNullUint32 = reflect.TypeOf(null.Uint32{})
|
|
||||||
typeNullUint64 = reflect.TypeOf(null.Uint64{})
|
|
||||||
typeNullString = reflect.TypeOf(null.String{})
|
|
||||||
typeNullBool = reflect.TypeOf(null.Bool{})
|
|
||||||
typeNullTime = reflect.TypeOf(null.Time{})
|
|
||||||
typeTime = reflect.TypeOf(time.Time{})
|
|
||||||
|
|
||||||
rgxValidTime = regexp.MustCompile(`[2-9]+`)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bind executes the query and inserts the
|
// Bind executes the query and inserts the
|
||||||
|
@ -124,111 +97,6 @@ func BindAll(rows *sql.Rows, selectCols []string, obj interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkType(obj interface{}) (reflect.Type, bool, error) {
|
|
||||||
val := reflect.ValueOf(obj)
|
|
||||||
typ := val.Type()
|
|
||||||
kind := val.Kind()
|
|
||||||
|
|
||||||
if kind != reflect.Ptr {
|
|
||||||
return nil, false, fmt.Errorf("Bind must be given pointers to structs but got type: %s, kind: %s", typ.String(), kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
typ = typ.Elem()
|
|
||||||
kind = typ.Kind()
|
|
||||||
isSlice := false
|
|
||||||
|
|
||||||
switch kind {
|
|
||||||
case reflect.Slice:
|
|
||||||
typ = typ.Elem()
|
|
||||||
kind = typ.Kind()
|
|
||||||
isSlice = true
|
|
||||||
case reflect.Struct:
|
|
||||||
return typ, isSlice, nil
|
|
||||||
default:
|
|
||||||
return nil, false, fmt.Errorf("Bind was given an invalid object must be []*T or *T but got type: %s, kind: %s", typ.String(), kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
if kind != reflect.Ptr {
|
|
||||||
return nil, false, fmt.Errorf("Bind must be given pointers to structs but got type: %s, kind: %s", typ.String(), kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
typ = typ.Elem()
|
|
||||||
kind = typ.Kind()
|
|
||||||
|
|
||||||
if kind != reflect.Struct {
|
|
||||||
return nil, false, fmt.Errorf("Bind must be a struct but got type: %s, kind: %s", typ.String(), kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
return typ, isSlice, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsZeroValue checks if the variables with matching columns in obj
|
|
||||||
// are or are not zero values, depending on whether shouldZero is true or false
|
|
||||||
func IsZeroValue(obj interface{}, shouldZero bool, columns ...string) []error {
|
|
||||||
val := reflect.Indirect(reflect.ValueOf(obj))
|
|
||||||
|
|
||||||
var errs []error
|
|
||||||
for _, c := range columns {
|
|
||||||
field := val.FieldByName(strmangle.TitleCase(c))
|
|
||||||
if !field.IsValid() {
|
|
||||||
panic(fmt.Sprintf("Unable to find variable with column name %s", c))
|
|
||||||
}
|
|
||||||
|
|
||||||
zv := reflect.Zero(field.Type())
|
|
||||||
if shouldZero && !reflect.DeepEqual(field.Interface(), zv.Interface()) {
|
|
||||||
errs = append(errs, fmt.Errorf("Column with name %s is not zero value: %#v, %#v", c, field.Interface(), zv.Interface()))
|
|
||||||
} else if !shouldZero && reflect.DeepEqual(field.Interface(), zv.Interface()) {
|
|
||||||
errs = append(errs, fmt.Errorf("Column with name %s is zero value: %#v, %#v", c, field.Interface(), zv.Interface()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsValueMatch checks whether the variables in obj with matching column names
|
|
||||||
// match the values in the values slice.
|
|
||||||
func IsValueMatch(obj interface{}, columns []string, values []interface{}) []error {
|
|
||||||
val := reflect.Indirect(reflect.ValueOf(obj))
|
|
||||||
|
|
||||||
var errs []error
|
|
||||||
for i, c := range columns {
|
|
||||||
field := val.FieldByName(strmangle.TitleCase(c))
|
|
||||||
if !field.IsValid() {
|
|
||||||
panic(fmt.Sprintf("Unable to find variable with column name %s", c))
|
|
||||||
}
|
|
||||||
|
|
||||||
typ := field.Type().String()
|
|
||||||
if typ == "time.Time" || typ == "null.Time" {
|
|
||||||
var timeField reflect.Value
|
|
||||||
var valTimeStr string
|
|
||||||
if typ == "time.Time" {
|
|
||||||
valTimeStr = values[i].(time.Time).String()
|
|
||||||
timeField = field
|
|
||||||
} else {
|
|
||||||
valTimeStr = values[i].(null.Time).Time.String()
|
|
||||||
timeField = field.FieldByName("Time")
|
|
||||||
validField := field.FieldByName("Valid")
|
|
||||||
if validField.Interface() != values[i].(null.Time).Valid {
|
|
||||||
errs = append(errs, fmt.Errorf("Null.Time column with name %s Valid field does not match: %v ≠ %v", c, values[i].(null.Time).Valid, validField.Interface()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rgxValidTime.MatchString(valTimeStr) && timeField.Interface() == reflect.Zero(timeField.Type()).Interface()) ||
|
|
||||||
(!rgxValidTime.MatchString(valTimeStr) && timeField.Interface() != reflect.Zero(timeField.Type()).Interface()) {
|
|
||||||
errs = append(errs, fmt.Errorf("Time column with name %s Time field does not match: %v ≠ %v", c, values[i], timeField.Interface()))
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(field.Interface(), values[i]) {
|
|
||||||
errs = append(errs, fmt.Errorf("Column with name %s does not match value: %#v ≠ %#v", c, values[i], field.Interface()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStructValues returns the values (as interface) of the matching columns in obj
|
// GetStructValues returns the values (as interface) of the matching columns in obj
|
||||||
func GetStructValues(obj interface{}, columns ...string) []interface{} {
|
func GetStructValues(obj interface{}, columns ...string) []interface{} {
|
||||||
ret := make([]interface{}, len(columns))
|
ret := make([]interface{}, len(columns))
|
||||||
|
@ -270,277 +138,3 @@ func GetStructPointers(obj interface{}, columns ...string) []interface{} {
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandomizeSlice takes a pointer to a slice of pointers to objects
|
|
||||||
// and fills the pointed to objects with random data.
|
|
||||||
// It will ignore the fields in the blacklist.
|
|
||||||
func RandomizeSlice(obj interface{}, blacklist ...string) error {
|
|
||||||
ptrSlice := reflect.ValueOf(obj)
|
|
||||||
typ := ptrSlice.Type()
|
|
||||||
ptrSlice = ptrSlice.Elem()
|
|
||||||
kind := typ.Kind()
|
|
||||||
|
|
||||||
var structTyp reflect.Type
|
|
||||||
|
|
||||||
for i, exp := range []reflect.Kind{reflect.Ptr, reflect.Slice, reflect.Ptr, reflect.Struct} {
|
|
||||||
if i != 0 {
|
|
||||||
typ = typ.Elem()
|
|
||||||
kind = typ.Kind()
|
|
||||||
}
|
|
||||||
|
|
||||||
if kind != exp {
|
|
||||||
return fmt.Errorf("[%d] RandomizeSlice object type should be *[]*Type but was: %s", i, ptrSlice.Type().String())
|
|
||||||
}
|
|
||||||
|
|
||||||
if kind == reflect.Struct {
|
|
||||||
structTyp = typ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < ptrSlice.Len(); i++ {
|
|
||||||
o := ptrSlice.Index(i)
|
|
||||||
o.Set(reflect.New(structTyp))
|
|
||||||
if err := RandomizeStruct(o.Interface(), blacklist...); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RandomizeStruct takes an object and fills it with random data.
|
|
||||||
// It will ignore the fields in the blacklist.
|
|
||||||
func RandomizeStruct(str interface{}, blacklist ...string) error {
|
|
||||||
// Don't modify blacklist
|
|
||||||
copyBlacklist := make([]string, len(blacklist))
|
|
||||||
copy(copyBlacklist, blacklist)
|
|
||||||
blacklist = copyBlacklist
|
|
||||||
|
|
||||||
sort.Strings(blacklist)
|
|
||||||
|
|
||||||
// Check if it's pointer
|
|
||||||
value := reflect.ValueOf(str)
|
|
||||||
kind := value.Kind()
|
|
||||||
if kind != reflect.Ptr {
|
|
||||||
return fmt.Errorf("Outer element should be a pointer, given a non-pointer: %T", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if it's a struct
|
|
||||||
value = value.Elem()
|
|
||||||
kind = value.Kind()
|
|
||||||
if kind != reflect.Struct {
|
|
||||||
return fmt.Errorf("Inner element should be a struct, given a non-struct: %T", str)
|
|
||||||
}
|
|
||||||
|
|
||||||
typ := value.Type()
|
|
||||||
nFields := value.NumField()
|
|
||||||
|
|
||||||
// Iterate through fields, randomizing
|
|
||||||
for i := 0; i < nFields; i++ {
|
|
||||||
fieldVal := value.Field(i)
|
|
||||||
fieldTyp := typ.Field(i)
|
|
||||||
|
|
||||||
found := sort.Search(len(blacklist), func(i int) bool {
|
|
||||||
return blacklist[i] == fieldTyp.Name
|
|
||||||
})
|
|
||||||
if found != len(blacklist) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := randomizeField(fieldVal); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// randDate generates a random time.Time between 1850 and 2050.
|
|
||||||
// Only the Day/Month/Year columns are set so that Dates and DateTimes do
|
|
||||||
// not cause mismatches in the test data comparisons.
|
|
||||||
func randDate() time.Time {
|
|
||||||
t := time.Date(
|
|
||||||
1850+rand.Intn(200),
|
|
||||||
time.Month(1+rand.Intn(12)),
|
|
||||||
1+rand.Intn(25),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
time.UTC,
|
|
||||||
)
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func randomizeField(field reflect.Value) error {
|
|
||||||
kind := field.Kind()
|
|
||||||
typ := field.Type()
|
|
||||||
|
|
||||||
var newVal interface{}
|
|
||||||
|
|
||||||
if kind == reflect.Struct {
|
|
||||||
b := rand.Intn(2) == 1
|
|
||||||
switch typ {
|
|
||||||
case typeNullBool:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewBool(rand.Intn(2) == 1, b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewBool(false, false)
|
|
||||||
}
|
|
||||||
case typeNullString:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewString(randStr(1), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewString("", false)
|
|
||||||
}
|
|
||||||
case typeNullTime:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewTime(randDate(), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewTime(time.Time{}, false)
|
|
||||||
}
|
|
||||||
case typeTime:
|
|
||||||
newVal = randDate()
|
|
||||||
case typeNullFloat32:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewFloat32(float32(rand.Intn(9))/10.0+float32(rand.Intn(9)), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewFloat32(0.0, false)
|
|
||||||
}
|
|
||||||
case typeNullFloat64:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewFloat64(float64(rand.Intn(9))/10.0+float64(rand.Intn(9)), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewFloat64(0.0, false)
|
|
||||||
}
|
|
||||||
case typeNullInt:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewInt(rand.Int(), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewInt(0, false)
|
|
||||||
}
|
|
||||||
case typeNullInt8:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewInt8(int8(rand.Intn(int(math.MaxInt8))), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewInt8(0, false)
|
|
||||||
}
|
|
||||||
case typeNullInt16:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewInt16(int16(rand.Intn(int(math.MaxInt16))), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewInt16(0, false)
|
|
||||||
}
|
|
||||||
case typeNullInt32:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewInt32(rand.Int31(), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewInt32(0, false)
|
|
||||||
}
|
|
||||||
case typeNullInt64:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewInt64(rand.Int63(), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewInt64(0, false)
|
|
||||||
}
|
|
||||||
case typeNullUint:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewUint(uint(rand.Int()), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewUint(0, false)
|
|
||||||
}
|
|
||||||
case typeNullUint8:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewUint8(uint8(rand.Intn(int(math.MaxInt8))), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewUint8(0, false)
|
|
||||||
}
|
|
||||||
case typeNullUint16:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewUint16(uint16(rand.Intn(int(math.MaxInt16))), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewUint16(0, false)
|
|
||||||
}
|
|
||||||
case typeNullUint32:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewUint32(uint32(rand.Int31()), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewUint32(0, false)
|
|
||||||
}
|
|
||||||
case typeNullUint64:
|
|
||||||
if b {
|
|
||||||
newVal = null.NewUint64(uint64(rand.Int63()), b)
|
|
||||||
} else {
|
|
||||||
newVal = null.NewUint64(0, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch kind {
|
|
||||||
case reflect.Float32:
|
|
||||||
newVal = float32(rand.Intn(9))/10.0 + float32(rand.Intn(9))
|
|
||||||
case reflect.Float64:
|
|
||||||
newVal = float64(rand.Intn(9))/10.0 + float64(rand.Intn(9))
|
|
||||||
case reflect.Int:
|
|
||||||
newVal = rand.Int()
|
|
||||||
case reflect.Int8:
|
|
||||||
newVal = int8(rand.Intn(int(math.MaxInt8)))
|
|
||||||
case reflect.Int16:
|
|
||||||
newVal = int16(rand.Intn(int(math.MaxInt16)))
|
|
||||||
case reflect.Int32:
|
|
||||||
newVal = rand.Int31()
|
|
||||||
case reflect.Int64:
|
|
||||||
newVal = rand.Int63()
|
|
||||||
case reflect.Uint:
|
|
||||||
newVal = uint(rand.Int())
|
|
||||||
case reflect.Uint8:
|
|
||||||
newVal = uint8(rand.Intn(int(math.MaxInt8)))
|
|
||||||
case reflect.Uint16:
|
|
||||||
newVal = uint16(rand.Intn(int(math.MaxInt16)))
|
|
||||||
case reflect.Uint32:
|
|
||||||
newVal = uint32(rand.Int31())
|
|
||||||
case reflect.Uint64:
|
|
||||||
newVal = uint64(rand.Int63())
|
|
||||||
case reflect.Bool:
|
|
||||||
var b bool
|
|
||||||
if rand.Intn(2) == 1 {
|
|
||||||
b = true
|
|
||||||
}
|
|
||||||
newVal = b
|
|
||||||
case reflect.String:
|
|
||||||
newVal = randStr(1)
|
|
||||||
case reflect.Slice:
|
|
||||||
sliceVal := typ.Elem()
|
|
||||||
if sliceVal.Kind() != reflect.Uint8 {
|
|
||||||
return fmt.Errorf("unsupported slice type: %T", typ.String())
|
|
||||||
}
|
|
||||||
newVal = randByteSlice(5 + rand.Intn(20))
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported type: %T", typ.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
field.Set(reflect.ValueOf(newVal))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
|
|
||||||
func randStr(ln int) string {
|
|
||||||
str := make([]byte, ln)
|
|
||||||
for i := 0; i < ln; i++ {
|
|
||||||
str[i] = byte(alphabet[rand.Intn(len(alphabet))])
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
func randByteSlice(ln int) []byte {
|
|
||||||
str := make([]byte, ln)
|
|
||||||
for i := 0; i < ln; i++ {
|
|
||||||
str[i] = byte(rand.Intn(256))
|
|
||||||
}
|
|
||||||
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,115 +19,6 @@ func TestBindAll(t *testing.T) {
|
||||||
t.Errorf("Not implemented")
|
t.Errorf("Not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsZeroValue(t *testing.T) {
|
|
||||||
o := struct {
|
|
||||||
A []byte
|
|
||||||
B time.Time
|
|
||||||
C null.Time
|
|
||||||
D null.Int64
|
|
||||||
E int64
|
|
||||||
}{}
|
|
||||||
|
|
||||||
if errs := IsZeroValue(o, true, "A", "B", "C", "D", "E"); errs != nil {
|
|
||||||
for _, e := range errs {
|
|
||||||
t.Errorf("%s", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
colNames := []string{"A", "B", "C", "D", "E"}
|
|
||||||
for _, c := range colNames {
|
|
||||||
if err := IsZeroValue(o, true, c); err != nil {
|
|
||||||
t.Errorf("Expected %s to be zero value: %s", c, err[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
o.A = []byte("asdf")
|
|
||||||
o.B = time.Now()
|
|
||||||
o.C = null.NewTime(time.Now(), false)
|
|
||||||
o.D = null.NewInt64(2, false)
|
|
||||||
o.E = 5
|
|
||||||
|
|
||||||
if errs := IsZeroValue(o, false, "A", "B", "C", "D", "E"); errs != nil {
|
|
||||||
for _, e := range errs {
|
|
||||||
t.Errorf("%s", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range colNames {
|
|
||||||
if err := IsZeroValue(o, false, c); err != nil {
|
|
||||||
t.Errorf("Expected %s to be non-zero value: %s", c, err[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsValueMatch(t *testing.T) {
|
|
||||||
var errs []error
|
|
||||||
var values []interface{}
|
|
||||||
|
|
||||||
o := struct {
|
|
||||||
A []byte
|
|
||||||
B time.Time
|
|
||||||
C null.Time
|
|
||||||
D null.Int64
|
|
||||||
E int64
|
|
||||||
}{}
|
|
||||||
|
|
||||||
values = []interface{}{
|
|
||||||
[]byte(nil),
|
|
||||||
time.Time{},
|
|
||||||
null.Time{},
|
|
||||||
null.Int64{},
|
|
||||||
int64(0),
|
|
||||||
}
|
|
||||||
|
|
||||||
cols := []string{"A", "B", "C", "D", "E"}
|
|
||||||
errs = IsValueMatch(o, cols, values)
|
|
||||||
if errs != nil {
|
|
||||||
for _, e := range errs {
|
|
||||||
t.Errorf("%s", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
values = []interface{}{
|
|
||||||
[]byte("hi"),
|
|
||||||
time.Date(2007, 11, 2, 1, 1, 1, 1, time.UTC),
|
|
||||||
null.NewTime(time.Date(2007, 11, 2, 1, 1, 1, 1, time.UTC), true),
|
|
||||||
null.NewInt64(5, false),
|
|
||||||
int64(6),
|
|
||||||
}
|
|
||||||
|
|
||||||
errs = IsValueMatch(o, cols, values)
|
|
||||||
// Expect 6 errors
|
|
||||||
// 5 for each column and an additional 1 for the invalid Valid field match
|
|
||||||
if len(errs) != 6 {
|
|
||||||
t.Errorf("Expected 6 errors, got: %d", len(errs))
|
|
||||||
for _, e := range errs {
|
|
||||||
t.Errorf("%s", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
o.A = []byte("hi")
|
|
||||||
o.B = time.Date(2007, 11, 2, 1, 1, 1, 1, time.UTC)
|
|
||||||
o.C = null.NewTime(time.Date(2007, 11, 2, 1, 1, 1, 1, time.UTC), true)
|
|
||||||
o.D = null.NewInt64(5, false)
|
|
||||||
o.E = 6
|
|
||||||
|
|
||||||
errs = IsValueMatch(o, cols, values)
|
|
||||||
if errs != nil {
|
|
||||||
for _, e := range errs {
|
|
||||||
t.Errorf("%s", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
o.B = time.Date(2007, 11, 2, 2, 2, 2, 2, time.UTC)
|
|
||||||
errs = IsValueMatch(o, cols, values)
|
|
||||||
if errs != nil {
|
|
||||||
for _, e := range errs {
|
|
||||||
t.Errorf("%s", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetStructValues(t *testing.T) {
|
func TestGetStructValues(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
timeThing := time.Now()
|
timeThing := time.Now()
|
||||||
|
@ -192,89 +83,3 @@ func TestGetStructPointers(t *testing.T) {
|
||||||
t.Errorf("Expected 5, got %d", *o.ID)
|
t.Errorf("Expected 5, got %d", *o.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckType(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
type Thing struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
validTest := []struct {
|
|
||||||
Input interface{}
|
|
||||||
IsSlice bool
|
|
||||||
TypeName string
|
|
||||||
}{
|
|
||||||
{&[]*Thing{}, true, "boil.Thing"},
|
|
||||||
{[]Thing{}, false, ""},
|
|
||||||
{&[]Thing{}, false, ""},
|
|
||||||
{Thing{}, false, ""},
|
|
||||||
{new(int), false, ""},
|
|
||||||
{5, false, ""},
|
|
||||||
{&Thing{}, false, "boil.Thing"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, test := range validTest {
|
|
||||||
typ, isSlice, err := checkType(test.Input)
|
|
||||||
if err != nil {
|
|
||||||
if len(test.TypeName) > 0 {
|
|
||||||
t.Errorf("%d) Type: %T %#v - should have succeded but got err: %v", i, test.Input, test.Input, err)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if isSlice != test.IsSlice {
|
|
||||||
t.Errorf("%d) Type: %T %#v - succeded but wrong isSlice value: %t, want %t", i, test.Input, test.Input, isSlice, test.IsSlice)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got := typ.String(); got != test.TypeName {
|
|
||||||
t.Errorf("%d) Type: %T %#v - succeded but wrong type name: %s, want: %s", i, test.Input, test.Input, got, test.TypeName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRandomizeStruct(t *testing.T) {
|
|
||||||
var testStruct = struct {
|
|
||||||
Int int
|
|
||||||
Int64 int64
|
|
||||||
Float64 float64
|
|
||||||
Bool bool
|
|
||||||
Time time.Time
|
|
||||||
String string
|
|
||||||
ByteSlice []byte
|
|
||||||
|
|
||||||
Ignore int
|
|
||||||
|
|
||||||
NullInt null.Int
|
|
||||||
NullFloat64 null.Float64
|
|
||||||
NullBool null.Bool
|
|
||||||
NullString null.String
|
|
||||||
NullTime null.Time
|
|
||||||
}{}
|
|
||||||
|
|
||||||
err := RandomizeStruct(&testStruct, "Ignore")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if testStruct.Ignore != 0 {
|
|
||||||
t.Error("blacklisted value was filled in:", testStruct.Ignore)
|
|
||||||
}
|
|
||||||
|
|
||||||
if testStruct.Int == 0 &&
|
|
||||||
testStruct.Int64 == 0 &&
|
|
||||||
testStruct.Float64 == 0 &&
|
|
||||||
testStruct.Bool == false &&
|
|
||||||
testStruct.Time.IsZero() &&
|
|
||||||
testStruct.String == "" &&
|
|
||||||
testStruct.ByteSlice == nil {
|
|
||||||
t.Errorf("the regular values are not being randomized: %#v", testStruct)
|
|
||||||
}
|
|
||||||
|
|
||||||
if testStruct.NullInt.Valid == false &&
|
|
||||||
testStruct.NullFloat64.Valid == false &&
|
|
||||||
testStruct.NullBool.Valid == false &&
|
|
||||||
testStruct.NullString.Valid == false &&
|
|
||||||
testStruct.NullTime.Valid == false {
|
|
||||||
t.Errorf("the null values are not being randomized: %#v", testStruct)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
395
boil/testing.go
Normal file
395
boil/testing.go
Normal file
|
@ -0,0 +1,395 @@
|
||||||
|
package boil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/nullbio/sqlboiler/strmangle"
|
||||||
|
"gopkg.in/nullbio/null.v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
typeNullFloat32 = reflect.TypeOf(null.Float32{})
|
||||||
|
typeNullFloat64 = reflect.TypeOf(null.Float64{})
|
||||||
|
typeNullInt = reflect.TypeOf(null.Int{})
|
||||||
|
typeNullInt8 = reflect.TypeOf(null.Int8{})
|
||||||
|
typeNullInt16 = reflect.TypeOf(null.Int16{})
|
||||||
|
typeNullInt32 = reflect.TypeOf(null.Int32{})
|
||||||
|
typeNullInt64 = reflect.TypeOf(null.Int64{})
|
||||||
|
typeNullUint = reflect.TypeOf(null.Uint{})
|
||||||
|
typeNullUint8 = reflect.TypeOf(null.Uint8{})
|
||||||
|
typeNullUint16 = reflect.TypeOf(null.Uint16{})
|
||||||
|
typeNullUint32 = reflect.TypeOf(null.Uint32{})
|
||||||
|
typeNullUint64 = reflect.TypeOf(null.Uint64{})
|
||||||
|
typeNullString = reflect.TypeOf(null.String{})
|
||||||
|
typeNullBool = reflect.TypeOf(null.Bool{})
|
||||||
|
typeNullTime = reflect.TypeOf(null.Time{})
|
||||||
|
typeTime = reflect.TypeOf(time.Time{})
|
||||||
|
|
||||||
|
rgxValidTime = regexp.MustCompile(`[2-9]+`)
|
||||||
|
)
|
||||||
|
|
||||||
|
type seed int
|
||||||
|
|
||||||
|
var sd = new(seed)
|
||||||
|
|
||||||
|
func (s *seed) nextInt() int {
|
||||||
|
nextInt := int(*s)
|
||||||
|
*s++
|
||||||
|
return nextInt
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZeroValue checks if the variables with matching columns in obj
|
||||||
|
// are or are not zero values, depending on whether shouldZero is true or false
|
||||||
|
func IsZeroValue(obj interface{}, shouldZero bool, columns ...string) []error {
|
||||||
|
val := reflect.Indirect(reflect.ValueOf(obj))
|
||||||
|
|
||||||
|
var errs []error
|
||||||
|
for _, c := range columns {
|
||||||
|
field := val.FieldByName(strmangle.TitleCase(c))
|
||||||
|
if !field.IsValid() {
|
||||||
|
panic(fmt.Sprintf("Unable to find variable with column name %s", c))
|
||||||
|
}
|
||||||
|
|
||||||
|
zv := reflect.Zero(field.Type())
|
||||||
|
if shouldZero && !reflect.DeepEqual(field.Interface(), zv.Interface()) {
|
||||||
|
errs = append(errs, fmt.Errorf("Column with name %s is not zero value: %#v, %#v", c, field.Interface(), zv.Interface()))
|
||||||
|
} else if !shouldZero && reflect.DeepEqual(field.Interface(), zv.Interface()) {
|
||||||
|
errs = append(errs, fmt.Errorf("Column with name %s is zero value: %#v, %#v", c, field.Interface(), zv.Interface()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValueMatch checks whether the variables in obj with matching column names
|
||||||
|
// match the values in the values slice.
|
||||||
|
func IsValueMatch(obj interface{}, columns []string, values []interface{}) []error {
|
||||||
|
val := reflect.Indirect(reflect.ValueOf(obj))
|
||||||
|
|
||||||
|
var errs []error
|
||||||
|
for i, c := range columns {
|
||||||
|
field := val.FieldByName(strmangle.TitleCase(c))
|
||||||
|
if !field.IsValid() {
|
||||||
|
panic(fmt.Sprintf("Unable to find variable with column name %s", c))
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := field.Type().String()
|
||||||
|
if typ == "time.Time" || typ == "null.Time" {
|
||||||
|
var timeField reflect.Value
|
||||||
|
var valTimeStr string
|
||||||
|
if typ == "time.Time" {
|
||||||
|
valTimeStr = values[i].(time.Time).String()
|
||||||
|
timeField = field
|
||||||
|
} else {
|
||||||
|
valTimeStr = values[i].(null.Time).Time.String()
|
||||||
|
timeField = field.FieldByName("Time")
|
||||||
|
validField := field.FieldByName("Valid")
|
||||||
|
if validField.Interface() != values[i].(null.Time).Valid {
|
||||||
|
errs = append(errs, fmt.Errorf("Null.Time column with name %s Valid field does not match: %v ≠ %v", c, values[i].(null.Time).Valid, validField.Interface()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rgxValidTime.MatchString(valTimeStr) && timeField.Interface() == reflect.Zero(timeField.Type()).Interface()) ||
|
||||||
|
(!rgxValidTime.MatchString(valTimeStr) && timeField.Interface() != reflect.Zero(timeField.Type()).Interface()) {
|
||||||
|
errs = append(errs, fmt.Errorf("Time column with name %s Time field does not match: %v ≠ %v", c, values[i], timeField.Interface()))
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(field.Interface(), values[i]) {
|
||||||
|
errs = append(errs, fmt.Errorf("Column with name %s does not match value: %#v ≠ %#v", c, values[i], field.Interface()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomizeSlice takes a pointer to a slice of pointers to objects
|
||||||
|
// and fills the pointed to objects with random data.
|
||||||
|
// It will ignore the fields in the blacklist.
|
||||||
|
func RandomizeSlice(obj interface{}, colTypes map[string]string, blacklist ...string) error {
|
||||||
|
ptrSlice := reflect.ValueOf(obj)
|
||||||
|
typ := ptrSlice.Type()
|
||||||
|
ptrSlice = ptrSlice.Elem()
|
||||||
|
kind := typ.Kind()
|
||||||
|
|
||||||
|
var structTyp reflect.Type
|
||||||
|
|
||||||
|
for i, exp := range []reflect.Kind{reflect.Ptr, reflect.Slice, reflect.Ptr, reflect.Struct} {
|
||||||
|
if i != 0 {
|
||||||
|
typ = typ.Elem()
|
||||||
|
kind = typ.Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
if kind != exp {
|
||||||
|
return fmt.Errorf("[%d] RandomizeSlice object type should be *[]*Type but was: %s", i, ptrSlice.Type().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if kind == reflect.Struct {
|
||||||
|
structTyp = typ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < ptrSlice.Len(); i++ {
|
||||||
|
o := ptrSlice.Index(i)
|
||||||
|
o.Set(reflect.New(structTyp))
|
||||||
|
if err := RandomizeStruct(o.Interface(), colTypes, blacklist...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomizeStruct takes an object and fills it with random data.
|
||||||
|
// It will ignore the fields in the blacklist.
|
||||||
|
func RandomizeStruct(str interface{}, colTypes map[string]string, blacklist ...string) error {
|
||||||
|
// Don't modify blacklist
|
||||||
|
copyBlacklist := make([]string, len(blacklist))
|
||||||
|
copy(copyBlacklist, blacklist)
|
||||||
|
blacklist = copyBlacklist
|
||||||
|
|
||||||
|
sort.Strings(blacklist)
|
||||||
|
|
||||||
|
// Check if it's pointer
|
||||||
|
value := reflect.ValueOf(str)
|
||||||
|
kind := value.Kind()
|
||||||
|
if kind != reflect.Ptr {
|
||||||
|
return fmt.Errorf("Outer element should be a pointer, given a non-pointer: %T", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a struct
|
||||||
|
value = value.Elem()
|
||||||
|
kind = value.Kind()
|
||||||
|
if kind != reflect.Struct {
|
||||||
|
return fmt.Errorf("Inner element should be a struct, given a non-struct: %T", str)
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := value.Type()
|
||||||
|
nFields := value.NumField()
|
||||||
|
|
||||||
|
// Iterate through fields, randomizing
|
||||||
|
for i := 0; i < nFields; i++ {
|
||||||
|
fieldVal := value.Field(i)
|
||||||
|
fieldTyp := typ.Field(i)
|
||||||
|
|
||||||
|
found := sort.Search(len(blacklist), func(i int) bool {
|
||||||
|
return blacklist[i] == fieldTyp.Name
|
||||||
|
})
|
||||||
|
if found != len(blacklist) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldDBType := colTypes[typ.Field(i).Name]
|
||||||
|
if err := randomizeField(fieldVal, fieldDBType); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// randDate generates a random time.Time between 1850 and 2050.
|
||||||
|
// Only the Day/Month/Year columns are set so that Dates and DateTimes do
|
||||||
|
// not cause mismatches in the test data comparisons.
|
||||||
|
func randDate(sd int) time.Time {
|
||||||
|
t := time.Date(
|
||||||
|
1850+rand.Intn(sd),
|
||||||
|
time.Month(1+rand.Intn(12)),
|
||||||
|
1+rand.Intn(25),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
time.UTC,
|
||||||
|
)
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func randomizeField(field reflect.Value, fieldType string) error {
|
||||||
|
kind := field.Kind()
|
||||||
|
typ := field.Type()
|
||||||
|
|
||||||
|
var newVal interface{}
|
||||||
|
|
||||||
|
if kind == reflect.Struct {
|
||||||
|
b := rand.Intn(2) == 1
|
||||||
|
switch typ {
|
||||||
|
case typeNullBool:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewBool(sd.nextInt()%2 == 0, b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewBool(false, false)
|
||||||
|
}
|
||||||
|
case typeNullString:
|
||||||
|
if b {
|
||||||
|
if fieldType == "interval" {
|
||||||
|
newVal = null.NewString(strconv.Itoa((sd.nextInt()%26)+2)+" days", b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewString(randStr(1, sd.nextInt()), b)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newVal = null.NewString("", false)
|
||||||
|
}
|
||||||
|
case typeNullTime:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewTime(randDate(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewTime(time.Time{}, false)
|
||||||
|
}
|
||||||
|
case typeTime:
|
||||||
|
newVal = randDate(sd.nextInt())
|
||||||
|
case typeNullFloat32:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewFloat32(float32(sd.nextInt()%10)/10.0+float32(sd.nextInt()%10), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewFloat32(0.0, false)
|
||||||
|
}
|
||||||
|
case typeNullFloat64:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewFloat64(float64(sd.nextInt()%10)/10.0+float64(sd.nextInt()%10), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewFloat64(0.0, false)
|
||||||
|
}
|
||||||
|
case typeNullInt:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewInt(sd.nextInt(), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewInt(0, false)
|
||||||
|
}
|
||||||
|
case typeNullInt8:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewInt8(int8(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewInt8(0, false)
|
||||||
|
}
|
||||||
|
case typeNullInt16:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewInt16(int16(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewInt16(0, false)
|
||||||
|
}
|
||||||
|
case typeNullInt32:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewInt32(int32(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewInt32(0, false)
|
||||||
|
}
|
||||||
|
case typeNullInt64:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewInt64(int64(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewInt64(0, false)
|
||||||
|
}
|
||||||
|
case typeNullUint:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewUint(uint(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewUint(0, false)
|
||||||
|
}
|
||||||
|
case typeNullUint8:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewUint8(uint8(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewUint8(0, false)
|
||||||
|
}
|
||||||
|
case typeNullUint16:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewUint16(uint16(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewUint16(0, false)
|
||||||
|
}
|
||||||
|
case typeNullUint32:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewUint32(uint32(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewUint32(0, false)
|
||||||
|
}
|
||||||
|
case typeNullUint64:
|
||||||
|
if b {
|
||||||
|
newVal = null.NewUint64(uint64(sd.nextInt()), b)
|
||||||
|
} else {
|
||||||
|
newVal = null.NewUint64(0, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch kind {
|
||||||
|
case reflect.Float32:
|
||||||
|
newVal = float32(float32(sd.nextInt()%10)/10.0 + float32(sd.nextInt()%10))
|
||||||
|
case reflect.Float64:
|
||||||
|
newVal = float64(float64(sd.nextInt()%10)/10.0 + float64(sd.nextInt()%10))
|
||||||
|
case reflect.Int:
|
||||||
|
newVal = sd.nextInt()
|
||||||
|
case reflect.Int8:
|
||||||
|
newVal = int8(sd.nextInt())
|
||||||
|
case reflect.Int16:
|
||||||
|
newVal = int16(sd.nextInt())
|
||||||
|
case reflect.Int32:
|
||||||
|
newVal = int32(sd.nextInt())
|
||||||
|
case reflect.Int64:
|
||||||
|
newVal = int64(sd.nextInt())
|
||||||
|
case reflect.Uint:
|
||||||
|
newVal = uint(sd.nextInt())
|
||||||
|
case reflect.Uint8:
|
||||||
|
newVal = uint8(sd.nextInt())
|
||||||
|
case reflect.Uint16:
|
||||||
|
newVal = uint16(sd.nextInt())
|
||||||
|
case reflect.Uint32:
|
||||||
|
newVal = uint32(sd.nextInt())
|
||||||
|
case reflect.Uint64:
|
||||||
|
newVal = uint64(sd.nextInt())
|
||||||
|
case reflect.Bool:
|
||||||
|
if sd.nextInt()%2 == 0 {
|
||||||
|
newVal = true
|
||||||
|
} else {
|
||||||
|
newVal = false
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
if fieldType == "interval" {
|
||||||
|
newVal = strconv.Itoa((sd.nextInt()%26)+2) + " days"
|
||||||
|
} else {
|
||||||
|
newVal = randStr(1, sd.nextInt())
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
sliceVal := typ.Elem()
|
||||||
|
if sliceVal.Kind() != reflect.Uint8 {
|
||||||
|
return fmt.Errorf("unsupported slice type: %T", typ.String())
|
||||||
|
}
|
||||||
|
newVal = randByteSlice(5+rand.Intn(20), sd.nextInt())
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported type: %T", typ.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
field.Set(reflect.ValueOf(newVal))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
|
func randStr(ln int, s int) string {
|
||||||
|
str := make([]byte, ln)
|
||||||
|
for i := 0; i < ln; i++ {
|
||||||
|
str[i] = byte(alphabet[s%len(alphabet)])
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func randByteSlice(ln int, s int) []byte {
|
||||||
|
str := make([]byte, ln)
|
||||||
|
for i := 0; i < ln; i++ {
|
||||||
|
str[i] = byte(s % 256)
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
186
boil/testing_test.go
Normal file
186
boil/testing_test.go
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
package boil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/nullbio/null.v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsZeroValue(t *testing.T) {
|
||||||
|
o := struct {
|
||||||
|
A []byte
|
||||||
|
B time.Time
|
||||||
|
C null.Time
|
||||||
|
D null.Int64
|
||||||
|
E int64
|
||||||
|
}{}
|
||||||
|
|
||||||
|
if errs := IsZeroValue(o, true, "A", "B", "C", "D", "E"); errs != nil {
|
||||||
|
for _, e := range errs {
|
||||||
|
t.Errorf("%s", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
colNames := []string{"A", "B", "C", "D", "E"}
|
||||||
|
for _, c := range colNames {
|
||||||
|
if err := IsZeroValue(o, true, c); err != nil {
|
||||||
|
t.Errorf("Expected %s to be zero value: %s", c, err[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o.A = []byte("asdf")
|
||||||
|
o.B = time.Now()
|
||||||
|
o.C = null.NewTime(time.Now(), false)
|
||||||
|
o.D = null.NewInt64(2, false)
|
||||||
|
o.E = 5
|
||||||
|
|
||||||
|
if errs := IsZeroValue(o, false, "A", "B", "C", "D", "E"); errs != nil {
|
||||||
|
for _, e := range errs {
|
||||||
|
t.Errorf("%s", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range colNames {
|
||||||
|
if err := IsZeroValue(o, false, c); err != nil {
|
||||||
|
t.Errorf("Expected %s to be non-zero value: %s", c, err[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsValueMatch(t *testing.T) {
|
||||||
|
var errs []error
|
||||||
|
var values []interface{}
|
||||||
|
|
||||||
|
o := struct {
|
||||||
|
A []byte
|
||||||
|
B time.Time
|
||||||
|
C null.Time
|
||||||
|
D null.Int64
|
||||||
|
E int64
|
||||||
|
}{}
|
||||||
|
|
||||||
|
values = []interface{}{
|
||||||
|
[]byte(nil),
|
||||||
|
time.Time{},
|
||||||
|
null.Time{},
|
||||||
|
null.Int64{},
|
||||||
|
int64(0),
|
||||||
|
}
|
||||||
|
|
||||||
|
cols := []string{"A", "B", "C", "D", "E"}
|
||||||
|
errs = IsValueMatch(o, cols, values)
|
||||||
|
if errs != nil {
|
||||||
|
for _, e := range errs {
|
||||||
|
t.Errorf("%s", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values = []interface{}{
|
||||||
|
[]byte("hi"),
|
||||||
|
time.Date(2007, 11, 2, 1, 1, 1, 1, time.UTC),
|
||||||
|
null.NewTime(time.Date(2007, 11, 2, 1, 1, 1, 1, time.UTC), true),
|
||||||
|
null.NewInt64(5, false),
|
||||||
|
int64(6),
|
||||||
|
}
|
||||||
|
|
||||||
|
errs = IsValueMatch(o, cols, values)
|
||||||
|
// Expect 6 errors
|
||||||
|
// 5 for each column and an additional 1 for the invalid Valid field match
|
||||||
|
if len(errs) != 6 {
|
||||||
|
t.Errorf("Expected 6 errors, got: %d", len(errs))
|
||||||
|
for _, e := range errs {
|
||||||
|
t.Errorf("%s", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o.A = []byte("hi")
|
||||||
|
o.B = time.Date(2007, 11, 2, 1, 1, 1, 1, time.UTC)
|
||||||
|
o.C = null.NewTime(time.Date(2007, 11, 2, 1, 1, 1, 1, time.UTC), true)
|
||||||
|
o.D = null.NewInt64(5, false)
|
||||||
|
o.E = 6
|
||||||
|
|
||||||
|
errs = IsValueMatch(o, cols, values)
|
||||||
|
if errs != nil {
|
||||||
|
for _, e := range errs {
|
||||||
|
t.Errorf("%s", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o.B = time.Date(2007, 11, 2, 2, 2, 2, 2, time.UTC)
|
||||||
|
errs = IsValueMatch(o, cols, values)
|
||||||
|
if errs != nil {
|
||||||
|
for _, e := range errs {
|
||||||
|
t.Errorf("%s", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandomizeStruct(t *testing.T) {
|
||||||
|
var testStruct = struct {
|
||||||
|
Int int
|
||||||
|
Int64 int64
|
||||||
|
Float64 float64
|
||||||
|
Bool bool
|
||||||
|
Time time.Time
|
||||||
|
String string
|
||||||
|
ByteSlice []byte
|
||||||
|
Interval string
|
||||||
|
|
||||||
|
Ignore int
|
||||||
|
|
||||||
|
NullInt null.Int
|
||||||
|
NullFloat64 null.Float64
|
||||||
|
NullBool null.Bool
|
||||||
|
NullString null.String
|
||||||
|
NullTime null.Time
|
||||||
|
NullInterval null.String
|
||||||
|
}{}
|
||||||
|
|
||||||
|
fieldTypes := map[string]string{
|
||||||
|
"Int": "integer",
|
||||||
|
"Int64": "bigint",
|
||||||
|
"Float64": "decimal",
|
||||||
|
"Bool": "boolean",
|
||||||
|
"Time": "date",
|
||||||
|
"String": "character varying",
|
||||||
|
"ByteSlice": "bytea",
|
||||||
|
"Interval": "interval",
|
||||||
|
"Ignore": "integer",
|
||||||
|
"NullInt": "integer",
|
||||||
|
"NullFloat64": "numeric",
|
||||||
|
"NullBool": "boolean",
|
||||||
|
"NullString": "character",
|
||||||
|
"NullTime": "time",
|
||||||
|
"NullInterval": "interval",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := RandomizeStruct(&testStruct, fieldTypes, "Ignore")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testStruct.Ignore != 0 {
|
||||||
|
t.Error("blacklisted value was filled in:", testStruct.Ignore)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testStruct.Int == 0 &&
|
||||||
|
testStruct.Int64 == 0 &&
|
||||||
|
testStruct.Float64 == 0 &&
|
||||||
|
testStruct.Bool == false &&
|
||||||
|
testStruct.Time.IsZero() &&
|
||||||
|
testStruct.String == "" &&
|
||||||
|
testStruct.Interval == "" &&
|
||||||
|
testStruct.ByteSlice == nil {
|
||||||
|
t.Errorf("the regular values are not being randomized: %#v", testStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testStruct.NullInt.Valid == false &&
|
||||||
|
testStruct.NullFloat64.Valid == false &&
|
||||||
|
testStruct.NullBool.Valid == false &&
|
||||||
|
testStruct.NullString.Valid == false &&
|
||||||
|
testStruct.NullInterval.Valid == false &&
|
||||||
|
testStruct.NullTime.Valid == false {
|
||||||
|
t.Errorf("the null values are not being randomized: %#v", testStruct)
|
||||||
|
}
|
||||||
|
}
|
|
@ -170,6 +170,7 @@ var defaultTestTemplateImports = imports{
|
||||||
`"time"`,
|
`"time"`,
|
||||||
},
|
},
|
||||||
thirdParty: importList{
|
thirdParty: importList{
|
||||||
|
`"gopkg.in/nullbio/null.v4"`,
|
||||||
`"github.com/nullbio/sqlboiler/boil"`,
|
`"github.com/nullbio/sqlboiler/boil"`,
|
||||||
`"github.com/nullbio/sqlboiler/boil/qm"`,
|
`"github.com/nullbio/sqlboiler/boil/qm"`,
|
||||||
},
|
},
|
||||||
|
|
6
main.go
6
main.go
|
@ -119,6 +119,12 @@ func preRun(cmd *cobra.Command, args []string) error {
|
||||||
SSLMode: viper.GetString("postgres.sslmode"),
|
SSLMode: viper.GetString("postgres.sslmode"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the default SSLMode value
|
||||||
|
if cmdConfig.Postgres.SSLMode == "" {
|
||||||
|
viper.Set("postgres.sslmode", "require")
|
||||||
|
cmdConfig.Postgres.SSLMode = viper.GetString("postgres.sslmode")
|
||||||
|
}
|
||||||
|
|
||||||
err = vala.BeginValidation().Validate(
|
err = vala.BeginValidation().Validate(
|
||||||
vala.StringNotEmpty(cmdConfig.Postgres.User, "postgres.user"),
|
vala.StringNotEmpty(cmdConfig.Postgres.User, "postgres.user"),
|
||||||
vala.StringNotEmpty(cmdConfig.Postgres.Pass, "postgres.pass"),
|
vala.StringNotEmpty(cmdConfig.Postgres.Pass, "postgres.pass"),
|
||||||
|
|
|
@ -98,6 +98,17 @@ func CamelCase(name string) string {
|
||||||
return strings.Join(splits, "")
|
return strings.Join(splits, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeStringMap converts a map[string]string into the format:
|
||||||
|
// "key": "value", "key": "value"
|
||||||
|
func MakeStringMap(types map[string]string) string {
|
||||||
|
var typArr []string
|
||||||
|
for k, v := range types {
|
||||||
|
typArr = append(typArr, fmt.Sprintf(`"%s": "%s"`, k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(typArr, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
// StringMap maps a function over a slice of strings.
|
// StringMap maps a function over a slice of strings.
|
||||||
func StringMap(modifier func(string) string, strs []string) []string {
|
func StringMap(modifier func(string) string, strs []string) []string {
|
||||||
ret := make([]string, len(strs))
|
ret := make([]string, len(strs))
|
||||||
|
|
|
@ -124,6 +124,29 @@ func TestCamelCase(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMakeStringMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var m map[string]string
|
||||||
|
r := MakeStringMap(m)
|
||||||
|
|
||||||
|
if r != "" {
|
||||||
|
t.Errorf("Expected empty result, got: %s", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
m = map[string]string{
|
||||||
|
"TestOne": "interval",
|
||||||
|
"TestTwo": "integer",
|
||||||
|
}
|
||||||
|
|
||||||
|
r = MakeStringMap(m)
|
||||||
|
e := `"TestOne": "interval", "TestTwo": "integer"`
|
||||||
|
|
||||||
|
if r != e {
|
||||||
|
t.Errorf("Expected %s, got %s", e, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestStringMap(t *testing.T) {
|
func TestStringMap(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,9 @@ var templateFunctions = template.FuncMap{
|
||||||
"hasElement": strmangle.HasElement,
|
"hasElement": strmangle.HasElement,
|
||||||
"prefixStringSlice": strmangle.PrefixStringSlice,
|
"prefixStringSlice": strmangle.PrefixStringSlice,
|
||||||
|
|
||||||
|
// String Map ops
|
||||||
|
"makeStringMap": strmangle.MakeStringMap,
|
||||||
|
|
||||||
// Database related mangling
|
// Database related mangling
|
||||||
"whereClause": strmangle.WhereClause,
|
"whereClause": strmangle.WhereClause,
|
||||||
|
|
||||||
|
@ -143,6 +146,7 @@ var templateFunctions = template.FuncMap{
|
||||||
"sqlColDefinitions": bdb.SQLColDefinitions,
|
"sqlColDefinitions": bdb.SQLColDefinitions,
|
||||||
"sqlColDefStrings": bdb.SQLColDefStrings,
|
"sqlColDefStrings": bdb.SQLColDefStrings,
|
||||||
"columnNames": bdb.ColumnNames,
|
"columnNames": bdb.ColumnNames,
|
||||||
|
"columnDBTypes": bdb.ColumnDBTypes,
|
||||||
"toManyRelationships": bdb.ToManyRelationships,
|
"toManyRelationships": bdb.ToManyRelationships,
|
||||||
"zeroValue": bdb.ZeroValue,
|
"zeroValue": bdb.ZeroValue,
|
||||||
"defaultValues": bdb.DefaultValues,
|
"defaultValues": bdb.DefaultValues,
|
||||||
|
|
|
@ -1,47 +1,36 @@
|
||||||
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
|
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
|
||||||
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
||||||
// Insert a single record.
|
// Insert a single record.
|
||||||
func (o *{{$tableNameSingular}}) Insert(include ... string) error {
|
func (o *{{$tableNameSingular}}) Insert(whitelist ... string) error {
|
||||||
return o.InsertX(boil.GetDB(), include...)
|
return o.InsertX(boil.GetDB(), whitelist...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertX a single record using an executor.
|
// InsertX a single record using an executor.
|
||||||
func (o *{{$tableNameSingular}}) InsertX(exec boil.Executor, include ... string) error {
|
func (o *{{$tableNameSingular}}) InsertX(exec boil.Executor, whitelist ... string) error {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
return errors.New("{{.PkgName}}: no {{.Table.Name}} provided for insertion")
|
return errors.New("{{.PkgName}}: no {{.Table.Name}} provided for insertion")
|
||||||
}
|
}
|
||||||
|
|
||||||
var includes []string
|
wl, returnColumns := o.generateInsertColumns(whitelist)
|
||||||
|
|
||||||
includes = append(includes, include...)
|
|
||||||
if len(include) == 0 {
|
|
||||||
includes = append(includes, {{$varNameSingular}}ColumnsWithoutDefault...)
|
|
||||||
}
|
|
||||||
|
|
||||||
includes = append(boil.NonZeroDefaultSet({{$varNameSingular}}ColumnsWithDefault, o), includes...)
|
|
||||||
includes = boil.SortByKeys({{$varNameSingular}}Columns, includes)
|
|
||||||
|
|
||||||
// Only return the columns with default values that are not in the insert include
|
|
||||||
returnColumns := boil.SetComplement({{$varNameSingular}}ColumnsWithDefault, includes)
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if err := o.doBeforeCreateHooks(); err != nil {
|
if err := o.doBeforeCreateHooks(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ins := fmt.Sprintf(`INSERT INTO {{.Table.Name}} ("%s") VALUES (%s)`, strings.Join(includes, `","`), boil.GenerateParamFlags(len(includes), 1))
|
ins := fmt.Sprintf(`INSERT INTO {{.Table.Name}} ("%s") VALUES (%s)`, strings.Join(wl, `","`), boil.GenerateParamFlags(len(wl), 1))
|
||||||
|
|
||||||
{{if driverUsesLastInsertID .DriverName}}
|
{{if driverUsesLastInsertID .DriverName}}
|
||||||
if len(returnColumns) != 0 {
|
if len(returnColumns) != 0 {
|
||||||
result, err := exec.Exec(ins, boil.GetStructValues(o, includes...)...)
|
result, err := exec.Exec(ins, boil.GetStructValues(o, wl...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("{{.PkgName}}: unable to insert into {{.Table.Name}}: %s", err)
|
return fmt.Errorf("{{.PkgName}}: unable to insert into {{.Table.Name}}: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lastId, err := result.lastInsertId()
|
lastId, err := result.lastInsertId()
|
||||||
if err != nil || lastId == 0 {
|
if err != nil || lastId == 0 {
|
||||||
sel := fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s`, strings.Join(returnColumns, `","`), boil.WhereClause(includes))
|
sel := fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s`, strings.Join(returnColumns, `","`), boil.WhereClause(wl))
|
||||||
rows, err := exec.Query(sel, boil.GetStructValues(o, includes...)...)
|
rows, err := exec.Query(sel, boil.GetStructValues(o, wl...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("{{.PkgName}}: unable to insert into {{.Table.Name}}: %s", err)
|
return fmt.Errorf("{{.PkgName}}: unable to insert into {{.Table.Name}}: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -59,19 +48,19 @@ func (o *{{$tableNameSingular}}) InsertX(exec boil.Executor, include ... string)
|
||||||
sel := fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s=$1`, strings.Join(returnColumns, ","), {{$varNameSingular}}AutoIncPrimaryKey, lastId)
|
sel := fmt.Sprintf(`SELECT %s FROM {{.Table.Name}} WHERE %s=$1`, strings.Join(returnColumns, ","), {{$varNameSingular}}AutoIncPrimaryKey, lastId)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, err = exec.Exec(ins, boil.GetStructValues(o, includes...)...)
|
_, err = exec.Exec(ins, boil.GetStructValues(o, wl...)...)
|
||||||
}
|
}
|
||||||
{{else}}
|
{{else}}
|
||||||
if len(returnColumns) != 0 {
|
if len(returnColumns) != 0 {
|
||||||
ins = ins + fmt.Sprintf(` RETURNING %s`, strings.Join(returnColumns, ","))
|
ins = ins + fmt.Sprintf(` RETURNING %s`, strings.Join(returnColumns, ","))
|
||||||
err = exec.QueryRow(ins, boil.GetStructValues(o, includes...)...).Scan(boil.GetStructPointers(o, returnColumns...)...)
|
err = exec.QueryRow(ins, boil.GetStructValues(o, wl...)...).Scan(boil.GetStructPointers(o, returnColumns...)...)
|
||||||
} else {
|
} else {
|
||||||
_, err = exec.Exec(ins, {{.Table.Columns | columnNames | stringMap .StringFuncs.titleCase | prefixStringSlice "o." | join ", "}})
|
_, err = exec.Exec(ins, {{.Table.Columns | columnNames | stringMap .StringFuncs.titleCase | prefixStringSlice "o." | join ", "}})
|
||||||
}
|
}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
if boil.DebugMode {
|
if boil.DebugMode {
|
||||||
fmt.Fprintln(boil.DebugWriter, ins, boil.GetStructValues(o, includes...))
|
fmt.Fprintln(boil.DebugWriter, ins, boil.GetStructValues(o, wl...))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -84,3 +73,21 @@ func (o *{{$tableNameSingular}}) InsertX(exec boil.Executor, include ... string)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generateInsertColumns generates the whitelist columns and return columns for an insert statement
|
||||||
|
func (o *{{$tableNameSingular}}) generateInsertColumns(whitelist []string) ([]string, []string) {
|
||||||
|
var wl []string
|
||||||
|
|
||||||
|
wl = append(wl, whitelist...)
|
||||||
|
if len(whitelist) == 0 {
|
||||||
|
wl = append(wl, {{$varNameSingular}}ColumnsWithoutDefault...)
|
||||||
|
}
|
||||||
|
|
||||||
|
wl = append(boil.NonZeroDefaultSet({{$varNameSingular}}ColumnsWithDefault, o), wl...)
|
||||||
|
wl = boil.SortByKeys({{$varNameSingular}}Columns, wl)
|
||||||
|
|
||||||
|
// Only return the columns with default values that are not in the insert whitelist
|
||||||
|
rc := boil.SetComplement({{$varNameSingular}}ColumnsWithDefault, wl)
|
||||||
|
|
||||||
|
return wl, rc
|
||||||
|
}
|
||||||
|
|
|
@ -3,28 +3,6 @@
|
||||||
{{- $tableNamePlural := .Table.Name | plural | titleCase -}}
|
{{- $tableNamePlural := .Table.Name | plural | titleCase -}}
|
||||||
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
|
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
|
||||||
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
||||||
func {{$varNameSingular}}CompareVals(o *{{$tableNameSingular}}, j *{{$tableNameSingular}}, t *testing.T) {
|
|
||||||
{{range $key, $value := .Table.Columns}}
|
|
||||||
{{if eq $value.Type "null.Time"}}
|
|
||||||
if o.{{titleCase $value.Name}}.Time.Format("02/01/2006") != j.{{titleCase $value.Name}}.Time.Format("02/01/2006") {
|
|
||||||
t.Errorf("Expected NullTime {{$value.Name}} column string values to match, got:\nStruct: %#v\nResponse: %#v\n\n", o.{{titleCase $value.Name}}.Time.Format("02/01/2006"), j.{{titleCase $value.Name}}.Time.Format("02/01/2006"))
|
|
||||||
}
|
|
||||||
{{else if eq $value.Type "time.Time"}}
|
|
||||||
if o.{{titleCase $value.Name}}.Format("02/01/2006") != j.{{titleCase $value.Name}}.Format("02/01/2006") {
|
|
||||||
t.Errorf("Expected Time {{$value.Name}} column string values to match, got:\nStruct: %#v\nResponse: %#v\n\n", o.{{titleCase $value.Name}}.Format("02/01/2006"), j.{{titleCase $value.Name}}.Format("02/01/2006"))
|
|
||||||
}
|
|
||||||
{{else if eq $value.Type "[]byte"}}
|
|
||||||
if !byteSliceEqual(o.{{titleCase $value.Name}}, j.{{titleCase $value.Name}}) {
|
|
||||||
t.Errorf("Expected {{$value.Name}} columns to match, got:\nStruct: %#v\nResponse: %#v\n\n", o.{{titleCase $value.Name}}, j.{{titleCase $value.Name}})
|
|
||||||
}
|
|
||||||
{{else}}
|
|
||||||
if j.{{titleCase $value.Name}} != o.{{titleCase $value.Name}} {
|
|
||||||
t.Errorf("Expected {{$value.Name}} columns to match, got:\nStruct: %#v\nResponse: %#v\n\n", o.{{titleCase $value.Name}}, j.{{titleCase $value.Name}})
|
|
||||||
}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test{{$tableNamePlural}}(t *testing.T) {
|
func Test{{$tableNamePlural}}(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -32,11 +10,11 @@ func Test{{$tableNamePlural}}(t *testing.T) {
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
{{$varNamePlural}}DeleteAllRows(t)
|
||||||
|
|
||||||
o := make({{$varNameSingular}}Slice, 2)
|
o := make({{$varNameSingular}}Slice, 2)
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert two random columns to test DeleteAll
|
// insert two random objects to test DeleteAll
|
||||||
for i := 0; i < len(o); i++ {
|
for i := 0; i < len(o); i++ {
|
||||||
err = o[i].Insert()
|
err = o[i].Insert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -59,7 +37,7 @@ func Test{{$tableNamePlural}}(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
o = make({{$varNameSingular}}Slice, 3)
|
o = make({{$varNameSingular}}Slice, 3)
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ func Test{{$tableNamePlural}}QueryDeleteAll(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
o := make({{$varNameSingular}}Slice, 3)
|
o := make({{$varNameSingular}}Slice, 3)
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ func Test{{$tableNamePlural}}SliceDeleteAll(t *testing.T) {
|
||||||
|
|
||||||
// insert random columns to test DeleteAll
|
// insert random columns to test DeleteAll
|
||||||
o := make({{$varNameSingular}}Slice, 3)
|
o := make({{$varNameSingular}}Slice, 3)
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ func Test{{$tableNamePlural}}Delete(t *testing.T) {
|
||||||
|
|
||||||
// insert random columns to test Delete
|
// insert random columns to test Delete
|
||||||
o := make({{$varNameSingular}}Slice, 3)
|
o := make({{$varNameSingular}}Slice, 3)
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ func Test{{$tableNamePlural}}Find(t *testing.T) {
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
{{$varNamePlural}}DeleteAllRows(t)
|
||||||
|
|
||||||
o := make({{$varNameSingular}}Slice, 3)
|
o := make({{$varNameSingular}}Slice, 3)
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ func Test{{$tableNamePlural}}Find(t *testing.T) {
|
||||||
if o[0].{{titleCase $value}} != f.{{titleCase $value}} {
|
if o[0].{{titleCase $value}} != f.{{titleCase $value}} {
|
||||||
t.Errorf("Expected primary key values to match, {{titleCase $value}} did not match")
|
t.Errorf("Expected primary key values to match, {{titleCase $value}} did not match")
|
||||||
}
|
}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
colsWithoutPrimKeys := boil.SetComplement({{$varNameSingular}}Columns, {{$varNameSingular}}PrimaryKeyColumns)
|
colsWithoutPrimKeys := boil.SetComplement({{$varNameSingular}}Columns, {{$varNameSingular}}PrimaryKeyColumns)
|
||||||
fRef := reflect.ValueOf(f).Elem()
|
fRef := reflect.ValueOf(f).Elem()
|
||||||
|
@ -40,5 +41,4 @@ func Test{{$tableNamePlural}}Find(t *testing.T) {
|
||||||
t.Errorf("Expected all other columns to be zero value, but column %s was %#v", v, val.Interface())
|
t.Errorf("Expected all other columns to be zero value, but column %s was %#v", v, val.Interface())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{{end}}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ func Test{{$tableNamePlural}}Bind(t *testing.T) {
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
{{$varNamePlural}}DeleteAllRows(t)
|
||||||
|
|
||||||
o := {{$tableNameSingular}}{}
|
o := {{$tableNameSingular}}{}
|
||||||
if err = boil.RandomizeStruct(&o); err != nil {
|
if err = boil.RandomizeStruct(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ func Test{{$tableNamePlural}}Bind(t *testing.T) {
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
{{$varNamePlural}}DeleteAllRows(t)
|
||||||
|
|
||||||
y := make({{$varNameSingular}}Slice, 3)
|
y := make({{$varNameSingular}}Slice, 3)
|
||||||
if err = boil.RandomizeSlice(&y); err != nil {
|
if err = boil.RandomizeSlice(&y, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ func Test{{$tableNamePlural}}One(t *testing.T) {
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
{{$varNamePlural}}DeleteAllRows(t)
|
||||||
|
|
||||||
o := {{$tableNameSingular}}{}
|
o := {{$tableNameSingular}}{}
|
||||||
if err = boil.RandomizeStruct(&o); err != nil {
|
if err = boil.RandomizeStruct(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ func Test{{$tableNamePlural}}All(t *testing.T) {
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
{{$varNamePlural}}DeleteAllRows(t)
|
||||||
|
|
||||||
o := make({{$varNameSingular}}Slice, 3)
|
o := make({{$varNameSingular}}Slice, 3)
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ func Test{{$tableNamePlural}}Count(t *testing.T) {
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
{{$varNamePlural}}DeleteAllRows(t)
|
||||||
|
|
||||||
o := make({{$varNameSingular}}Slice, 3)
|
o := make({{$varNameSingular}}Slice, 3)
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,36 @@
|
||||||
{{- $tableNamePlural := .Table.Name | plural | titleCase -}}
|
{{- $tableNamePlural := .Table.Name | plural | titleCase -}}
|
||||||
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
|
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
|
||||||
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
||||||
|
var {{$varNameSingular}}DBTypes = map[string]string{{"{"}}{{.Table.Columns | columnDBTypes | makeStringMap}}{{"}"}}
|
||||||
|
|
||||||
|
func {{$varNameSingular}}CompareVals(o *{{$tableNameSingular}}, j *{{$tableNameSingular}}, t *testing.T) {
|
||||||
|
{{range $key, $value := .Table.Columns}}
|
||||||
|
{{if eq $value.Type "null.Time"}}
|
||||||
|
if o.{{titleCase $value.Name}}.Time.Format("02/01/2006") != j.{{titleCase $value.Name}}.Time.Format("02/01/2006") {
|
||||||
|
t.Errorf("Expected NullTime {{$value.Name}} column string values to match, got:\nStruct: %#v\nResponse: %#v\n\n", o.{{titleCase $value.Name}}.Time.Format("02/01/2006"), j.{{titleCase $value.Name}}.Time.Format("02/01/2006"))
|
||||||
|
}
|
||||||
|
{{else if eq $value.Type "time.Time"}}
|
||||||
|
if o.{{titleCase $value.Name}}.Format("02/01/2006") != j.{{titleCase $value.Name}}.Format("02/01/2006") {
|
||||||
|
t.Errorf("Expected Time {{$value.Name}} column string values to match, got:\nStruct: %#v\nResponse: %#v\n\n", o.{{titleCase $value.Name}}.Format("02/01/2006"), j.{{titleCase $value.Name}}.Format("02/01/2006"))
|
||||||
|
}
|
||||||
|
{{else if eq $value.Type "[]byte"}}
|
||||||
|
if !byteSliceEqual(o.{{titleCase $value.Name}}, j.{{titleCase $value.Name}}) {
|
||||||
|
t.Errorf("Expected {{$value.Name}} columns to match, got:\nStruct: %#v\nResponse: %#v\n\n", o.{{titleCase $value.Name}}, j.{{titleCase $value.Name}})
|
||||||
|
}
|
||||||
|
{{else}}
|
||||||
|
if j.{{titleCase $value.Name}} != o.{{titleCase $value.Name}} {
|
||||||
|
t.Errorf("Expected {{$value.Name}} columns to match, got:\nStruct: %#v\nResponse: %#v\n\n", o.{{titleCase $value.Name}}, j.{{titleCase $value.Name}})
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
|
||||||
func Test{{$tableNamePlural}}InPrimaryKeyArgs(t *testing.T) {
|
func Test{{$tableNamePlural}}InPrimaryKeyArgs(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
var o {{$tableNameSingular}}
|
var o {{$tableNameSingular}}
|
||||||
o = {{$tableNameSingular}}{}
|
o = {{$tableNameSingular}}{}
|
||||||
|
|
||||||
if err = boil.RandomizeStruct(&o); err != nil {
|
if err = boil.RandomizeStruct(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Could not randomize struct: %s", err)
|
t.Errorf("Could not randomize struct: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +53,7 @@ func Test{{$tableNamePlural}}SliceInPrimaryKeyArgs(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
o := make({{$varNameSingular}}Slice, 3)
|
o := make({{$varNameSingular}}Slice, 3)
|
||||||
|
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Could not randomize slice: %s", err)
|
t.Errorf("Could not randomize slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,5 +23,5 @@ func Test{{$tableNamePlural}}Hooks(t *testing.T) {
|
||||||
// var err error
|
// var err error
|
||||||
|
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
{{$varNamePlural}}DeleteAllRows(t)
|
||||||
t.Errorf("Hook tests not implemented")
|
t.Skip("Hook tests not implemented")
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,21 @@
|
||||||
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
||||||
{{- $parent := . -}}
|
{{- $parent := . -}}
|
||||||
func Test{{$tableNamePlural}}Insert(t *testing.T) {
|
func Test{{$tableNamePlural}}Insert(t *testing.T) {
|
||||||
t.Skip("don't need this ruining everything")
|
|
||||||
var err error
|
var err error
|
||||||
var errs []error
|
|
||||||
emptyTime := time.Time{}.String()
|
|
||||||
|
|
||||||
|
var errs []error
|
||||||
|
_ = errs
|
||||||
|
|
||||||
|
emptyTime := time.Time{}.String()
|
||||||
|
_ = emptyTime
|
||||||
|
|
||||||
|
nullTime := null.NewTime(time.Time{}, true)
|
||||||
|
_ = nullTime
|
||||||
|
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
{{$varNamePlural}}DeleteAllRows(t)
|
||||||
|
|
||||||
o := make({{$varNameSingular}}Slice, 3)
|
o := make({{$varNameSingular}}Slice, 3)
|
||||||
if err = boil.RandomizeSlice(&o); err != nil {
|
if err = boil.RandomizeSlice(&o, {{$varNameSingular}}DBTypes); err != nil {
|
||||||
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
t.Errorf("Unable to randomize {{$tableNameSingular}} slice: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,41 +76,6 @@ func Test{{$tableNamePlural}}Insert(t *testing.T) {
|
||||||
}
|
}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
||||||
/*{{with .Table.Columns | filterColumnsBySimpleDefault}}
|
|
||||||
// Ensure the default value columns are returned in the object
|
|
||||||
{{range .}}
|
|
||||||
{{$tc := titleCase .Name}}
|
|
||||||
{{$zv := zeroValue .}}
|
|
||||||
{{$dv := "false"}}
|
|
||||||
{{$ty := trimPrefix "null." .Type}}
|
|
||||||
{{if and (ne $ty "[]byte") .Nullable}}
|
|
||||||
if item.{{$tc}}.Valid == false {
|
|
||||||
t.Errorf("Expected the nullable default value column {{$tc}} of {{$tableNameSingular}} to be valid.")
|
|
||||||
}
|
|
||||||
{{if eq .Type "null.Time"}}
|
|
||||||
if (item.{{$tc}}.{{$ty}}.String() == emptyTime && !isZeroTime({{$dv}})) ||
|
|
||||||
(item.{{$tc}}.{{$ty}}.String() > emptyTime && isZeroTime({{$dv}})) {
|
|
||||||
{{else}}
|
|
||||||
if item.{{$tc}}.{{$ty}} != {{$dv}} {
|
|
||||||
{{- end -}}
|
|
||||||
t.Errorf("Expected the nullable default value column {{$tc}} of {{$tableNameSingular}} to match the database default value:\n%#v\n%v\n\n", item.{{$tc}}.{{$ty}}, {{$dv}})
|
|
||||||
}
|
|
||||||
{{else}}
|
|
||||||
{{if eq .Type "[]byte"}}
|
|
||||||
if string(item.{{$tc}}) != string({{$dv}}) {
|
|
||||||
{{else if eq .Type "time.Time"}}
|
|
||||||
if (item.{{$tc}}.String() == emptyTime && !isZeroTime({{$dv}})) ||
|
|
||||||
(item.{{$tc}}.String() > emptyTime && isZeroTime({{$dv}})) {
|
|
||||||
{{else}}
|
|
||||||
if item.{{$tc}} != {{$dv}} {
|
|
||||||
{{- end -}}
|
|
||||||
t.Errorf("Expected the default value column {{$tc}} of {{$tableNameSingular}} to match the database default value:\n%#v\n%v\n\n", item.{{$tc}}, {{$dv}})
|
|
||||||
}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}*/
|
|
||||||
|
|
||||||
{{with .Table.Columns | filterColumnsByAutoIncrement false | filterColumnsByDefault false}}
|
{{with .Table.Columns | filterColumnsByAutoIncrement false | filterColumnsByDefault false}}
|
||||||
// Ensure the non-defaultvalue columns and non-autoincrement columns are stored correctly as zero or null values.
|
// Ensure the non-defaultvalue columns and non-autoincrement columns are stored correctly as zero or null values.
|
||||||
{{range .}}
|
{{range .}}
|
||||||
|
@ -135,59 +106,4 @@ func Test{{$tableNamePlural}}Insert(t *testing.T) {
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
/**
|
|
||||||
* Edge case test for:
|
|
||||||
* No includes specified, all non-zero values.
|
|
||||||
*
|
|
||||||
* Expected result:
|
|
||||||
* Non-zero auto-increment column values ignored by insert helper.
|
|
||||||
* Object updated with correct auto-increment values.
|
|
||||||
* All other column values in object remain.
|
|
||||||
*/
|
|
||||||
|
|
||||||
{{$varNamePlural}}DeleteAllRows(t)
|
|
||||||
|
|
||||||
item = &{{$tableNameSingular}}{}
|
|
||||||
if err = item.Insert(); err != nil {
|
|
||||||
t.Errorf("Unable to insert zero-value item {{$tableNameSingular}}:\n%#v\nErr: %s", item, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edge case test for:
|
|
||||||
* Auto-increment columns and nullable columns includes specified, all zero values.
|
|
||||||
*
|
|
||||||
* Expected result:
|
|
||||||
* Auto-increment value inserted and nullable column values inserted.
|
|
||||||
* Default values for nullable columns should NOT be present in returned object.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edge case test for:
|
|
||||||
* Auto-increment columns and nullable columns includes specified, all non-zero values.
|
|
||||||
*
|
|
||||||
* Expected result:
|
|
||||||
* Auto-increment value inserted and nullable column values inserted.
|
|
||||||
* Default values for nullable columns should NOT be present in returned object.
|
|
||||||
* Should be no zero values anywhere.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edge case test for:
|
|
||||||
* Non-nullable columns includes specified, all zero values.
|
|
||||||
*
|
|
||||||
* Expected result:
|
|
||||||
* Auto-increment values ignored by insert helper.
|
|
||||||
* Object updated with correct auto-increment values.
|
|
||||||
* All non-nullable columns should be returned as zero values, regardless of default values.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edge case test for:
|
|
||||||
* Non-nullable columns includes specified, all non-zero values.
|
|
||||||
*
|
|
||||||
* Expected result:
|
|
||||||
* Auto-increment values ignored by insert helper.
|
|
||||||
* Object updated with correct auto-increment values.
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ func DBConnect(user, pass, dbname, host string, port int, sslmode string) (*sql.
|
||||||
connStr := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%d sslmode=%s",
|
connStr := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%d sslmode=%s",
|
||||||
user, pass, dbname, host, port, sslmode)
|
user, pass, dbname, host, port, sslmode)
|
||||||
|
|
||||||
return sql.Open("postgres", connStr)
|
return sql.Open("postgres", connStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup dumps the database schema and imports it into a temporary randomly
|
// setup dumps the database schema and imports it into a temporary randomly
|
||||||
|
@ -123,6 +123,12 @@ func setup() error {
|
||||||
testCfg.Postgres.DBName = getDBNameHash(viper.GetString("postgres.dbname"))
|
testCfg.Postgres.DBName = getDBNameHash(viper.GetString("postgres.dbname"))
|
||||||
testCfg.Postgres.SSLMode = viper.GetString("postgres.sslmode")
|
testCfg.Postgres.SSLMode = viper.GetString("postgres.sslmode")
|
||||||
|
|
||||||
|
// Set the default SSLMode value
|
||||||
|
if testCfg.Postgres.SSLMode == "" {
|
||||||
|
viper.Set("postgres.sslmode", "require")
|
||||||
|
testCfg.Postgres.SSLMode = viper.GetString("postgres.sslmode")
|
||||||
|
}
|
||||||
|
|
||||||
err = vala.BeginValidation().Validate(
|
err = vala.BeginValidation().Validate(
|
||||||
vala.StringNotEmpty(testCfg.Postgres.User, "postgres.user"),
|
vala.StringNotEmpty(testCfg.Postgres.User, "postgres.user"),
|
||||||
vala.StringNotEmpty(testCfg.Postgres.Pass, "postgres.pass"),
|
vala.StringNotEmpty(testCfg.Postgres.Pass, "postgres.pass"),
|
||||||
|
@ -227,7 +233,6 @@ func setup() error {
|
||||||
testCfg.Postgres.DBName,
|
testCfg.Postgres.DBName,
|
||||||
testCfg.Postgres.User,
|
testCfg.Postgres.User,
|
||||||
testCfg.Postgres.Pass,
|
testCfg.Postgres.Pass,
|
||||||
testCfg.Postgres.SSLMode,
|
|
||||||
))
|
))
|
||||||
|
|
||||||
testPassFilePath := passDir + "/testpwfile"
|
testPassFilePath := passDir + "/testpwfile"
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
|
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
|
||||||
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
||||||
func Test{{$tableNamePlural}}Select(t *testing.T) {
|
func Test{{$tableNamePlural}}Select(t *testing.T) {
|
||||||
t.Errorf("test select not implemented")
|
t.Skip("Test select not implemented")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
|
|
||||||
{{- $dbName := singular .Table.Name -}}
|
|
||||||
{{- $tableNamePlural := .Table.Name | plural | titleCase -}}
|
|
||||||
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
|
|
||||||
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
|
||||||
func Test{{$tableNamePlural}}Struct(t *testing.T) {
|
|
||||||
t.Errorf("test struct not implemented")
|
|
||||||
}
|
|
|
@ -4,5 +4,5 @@
|
||||||
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
|
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
|
||||||
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
|
||||||
func Test{{$tableNamePlural}}Update(t *testing.T) {
|
func Test{{$tableNamePlural}}Update(t *testing.T) {
|
||||||
t.Errorf("test update not implemented")
|
t.Skip("test update not implemented")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue