Create comprehensive documentation for future Claude Code instances working in this repository, including: - Development commands for testing, building, and code quality - Core architecture overview of the SQL query builder system - Directory structure and component explanations - Testing patterns and conventions - Key dependencies and their purposes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1347 lines
37 KiB
Go
1347 lines
37 KiB
Go
package util_test
|
|
|
|
import (
|
|
"database/sql"
|
|
"reflect"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.fsdpf.net/go/db/internal/util"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
var (
|
|
uints = []interface{}{
|
|
uint(10),
|
|
uint8(10),
|
|
uint16(10),
|
|
uint32(10),
|
|
uint64(10),
|
|
}
|
|
ints = []interface{}{
|
|
int(10),
|
|
int8(10),
|
|
int16(10),
|
|
int32(10),
|
|
int64(10),
|
|
}
|
|
floats = []interface{}{
|
|
float32(3.14),
|
|
float64(3.14),
|
|
}
|
|
strs = []interface{}{
|
|
"abc",
|
|
"",
|
|
}
|
|
bools = []interface{}{
|
|
true,
|
|
false,
|
|
}
|
|
structs = []interface{}{
|
|
sql.NullString{},
|
|
}
|
|
invalids = []interface{}{
|
|
nil,
|
|
}
|
|
pointers = []interface{}{
|
|
&sql.NullString{},
|
|
}
|
|
)
|
|
|
|
type (
|
|
TestInterface interface {
|
|
A() string
|
|
}
|
|
TestInterfaceImpl struct {
|
|
str string
|
|
}
|
|
TestStruct struct {
|
|
arr [0]string
|
|
slc []string
|
|
mp map[string]interface{}
|
|
str string
|
|
bl bool
|
|
i int
|
|
i8 int8
|
|
i16 int16
|
|
i32 int32
|
|
i64 int64
|
|
ui uint
|
|
ui8 uint8
|
|
ui16 uint16
|
|
ui32 uint32
|
|
ui64 uint64
|
|
f32 float32
|
|
f64 float64
|
|
intr TestInterface
|
|
ptr *sql.NullString
|
|
}
|
|
)
|
|
|
|
func (t TestInterfaceImpl) A() string {
|
|
return t.str
|
|
}
|
|
|
|
type reflectTest struct {
|
|
suite.Suite
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsUint() {
|
|
for _, v := range uints {
|
|
rt.True(util.IsUint(reflect.ValueOf(v).Kind()))
|
|
}
|
|
|
|
for _, v := range ints {
|
|
rt.False(util.IsUint(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range floats {
|
|
rt.False(util.IsUint(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range strs {
|
|
rt.False(util.IsUint(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range bools {
|
|
rt.False(util.IsUint(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range structs {
|
|
rt.False(util.IsUint(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range invalids {
|
|
rt.False(util.IsUint(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range pointers {
|
|
rt.False(util.IsUint(reflect.ValueOf(v).Kind()))
|
|
}
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsInt() {
|
|
for _, v := range ints {
|
|
rt.True(util.IsInt(reflect.ValueOf(v).Kind()))
|
|
}
|
|
|
|
for _, v := range uints {
|
|
rt.False(util.IsInt(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range floats {
|
|
rt.False(util.IsInt(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range strs {
|
|
rt.False(util.IsInt(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range bools {
|
|
rt.False(util.IsInt(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range structs {
|
|
rt.False(util.IsInt(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range invalids {
|
|
rt.False(util.IsInt(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range pointers {
|
|
rt.False(util.IsInt(reflect.ValueOf(v).Kind()))
|
|
}
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsFloat() {
|
|
for _, v := range floats {
|
|
rt.True(util.IsFloat(reflect.ValueOf(v).Kind()))
|
|
}
|
|
|
|
for _, v := range uints {
|
|
rt.False(util.IsFloat(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range ints {
|
|
rt.False(util.IsFloat(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range strs {
|
|
rt.False(util.IsFloat(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range bools {
|
|
rt.False(util.IsFloat(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range structs {
|
|
rt.False(util.IsFloat(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range invalids {
|
|
rt.False(util.IsFloat(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range pointers {
|
|
rt.False(util.IsFloat(reflect.ValueOf(v).Kind()))
|
|
}
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsString() {
|
|
for _, v := range strs {
|
|
rt.True(util.IsString(reflect.ValueOf(v).Kind()))
|
|
}
|
|
|
|
for _, v := range uints {
|
|
rt.False(util.IsString(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range ints {
|
|
rt.False(util.IsString(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range floats {
|
|
rt.False(util.IsString(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range bools {
|
|
rt.False(util.IsString(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range structs {
|
|
rt.False(util.IsString(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range invalids {
|
|
rt.False(util.IsString(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range pointers {
|
|
rt.False(util.IsString(reflect.ValueOf(v).Kind()))
|
|
}
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsBool() {
|
|
for _, v := range bools {
|
|
rt.True(util.IsBool(reflect.ValueOf(v).Kind()))
|
|
}
|
|
|
|
for _, v := range uints {
|
|
rt.False(util.IsBool(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range ints {
|
|
rt.False(util.IsBool(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range floats {
|
|
rt.False(util.IsBool(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range strs {
|
|
rt.False(util.IsBool(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range structs {
|
|
rt.False(util.IsBool(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range invalids {
|
|
rt.False(util.IsBool(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range pointers {
|
|
rt.False(util.IsBool(reflect.ValueOf(v).Kind()))
|
|
}
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsStruct() {
|
|
for _, v := range structs {
|
|
rt.True(util.IsStruct(reflect.ValueOf(v).Kind()))
|
|
}
|
|
|
|
for _, v := range uints {
|
|
rt.False(util.IsStruct(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range ints {
|
|
rt.False(util.IsStruct(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range floats {
|
|
rt.False(util.IsStruct(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range bools {
|
|
rt.False(util.IsStruct(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range strs {
|
|
rt.False(util.IsStruct(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range invalids {
|
|
rt.False(util.IsStruct(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range pointers {
|
|
rt.False(util.IsStruct(reflect.ValueOf(v).Kind()))
|
|
}
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsSlice() {
|
|
rt.True(util.IsSlice(reflect.ValueOf(uints).Kind()))
|
|
rt.True(util.IsSlice(reflect.ValueOf(ints).Kind()))
|
|
rt.True(util.IsSlice(reflect.ValueOf(floats).Kind()))
|
|
rt.True(util.IsSlice(reflect.ValueOf(structs).Kind()))
|
|
|
|
rt.False(util.IsSlice(reflect.ValueOf(structs[0]).Kind()))
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsInvalid() {
|
|
for _, v := range invalids {
|
|
rt.True(util.IsInvalid(reflect.ValueOf(v).Kind()))
|
|
}
|
|
|
|
for _, v := range uints {
|
|
rt.False(util.IsInvalid(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range ints {
|
|
rt.False(util.IsInvalid(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range floats {
|
|
rt.False(util.IsInvalid(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range bools {
|
|
rt.False(util.IsInvalid(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range strs {
|
|
rt.False(util.IsInvalid(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range structs {
|
|
rt.False(util.IsInvalid(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range pointers {
|
|
rt.False(util.IsInvalid(reflect.ValueOf(v).Kind()))
|
|
}
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsPointer() {
|
|
for _, v := range pointers {
|
|
rt.True(util.IsPointer(reflect.ValueOf(v).Kind()))
|
|
}
|
|
|
|
for _, v := range uints {
|
|
rt.False(util.IsPointer(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range ints {
|
|
rt.False(util.IsPointer(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range floats {
|
|
rt.False(util.IsPointer(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range bools {
|
|
rt.False(util.IsPointer(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range strs {
|
|
rt.False(util.IsPointer(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range structs {
|
|
rt.False(util.IsPointer(reflect.ValueOf(v).Kind()))
|
|
}
|
|
for _, v := range invalids {
|
|
rt.False(util.IsPointer(reflect.ValueOf(v).Kind()))
|
|
}
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsEmptyValue_emptyValues() {
|
|
ts := TestStruct{}
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.arr)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.slc)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.mp)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.str)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.bl)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.i)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.i8)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.i16)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.i32)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.i64)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.ui)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.ui8)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.ui16)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.ui32)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.ui64)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.f32)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.f64)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.intr)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts.ptr)))
|
|
rt.True(util.IsEmptyValue(reflect.ValueOf(ts)))
|
|
rt.True(util.IsNil(reflect.ValueOf(nil)))
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsEmptyValue_validValues() {
|
|
ts := TestStruct{intr: TestInterfaceImpl{"hello"}}
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf([1]string{"a"})))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf([]string{"a"})))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(map[string]interface{}{"a": true})))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf("str")))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(true)))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(int(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(int8(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(int16(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(int32(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(int64(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(uint(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(uint8(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(uint16(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(uint32(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(uint64(1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(float32(0.1))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(float64(0.2))))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(ts.intr)))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(&TestStruct{str: "a"})))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(ts)))
|
|
}
|
|
|
|
func (rt *reflectTest) TestIsNil() {
|
|
ts := TestStruct{}
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.arr)))
|
|
rt.True(util.IsNil(reflect.ValueOf(ts.slc)))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf([]string{"a"})))
|
|
rt.True(util.IsNil(reflect.ValueOf(ts.mp)))
|
|
rt.False(util.IsEmptyValue(reflect.ValueOf(map[string]interface{}{"a": true})))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.str)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.bl)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.i)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.i8)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.i16)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.i32)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.i64)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.ui)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.ui8)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.ui16)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.ui32)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.ui64)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.f32)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts.f64)))
|
|
rt.True(util.IsNil(reflect.ValueOf(ts.intr)))
|
|
rt.True(util.IsNil(reflect.ValueOf(ts.ptr)))
|
|
rt.False(util.IsNil(reflect.ValueOf(ts)))
|
|
rt.True(util.IsNil(reflect.ValueOf(nil)))
|
|
}
|
|
|
|
func (rt *reflectTest) TestColumnRename() {
|
|
// different key names are used each time to circumvent the caching that happens
|
|
// it seems like a solid assumption that when people use this feature,
|
|
// they would simply set a renaming function once at startup,
|
|
// and not change between requests like this
|
|
lowerAnon := struct {
|
|
FirstLower string
|
|
LastLower string
|
|
}{}
|
|
lowerColumnMap, lowerErr := util.GetColumnMap(&lowerAnon)
|
|
rt.NoError(lowerErr)
|
|
|
|
lowerKeys := make([]string, 0, len(lowerColumnMap))
|
|
for key := range lowerColumnMap {
|
|
lowerKeys = append(lowerKeys, key)
|
|
}
|
|
rt.Contains(lowerKeys, "firstlower")
|
|
rt.Contains(lowerKeys, "lastlower")
|
|
|
|
// changing rename function
|
|
util.SetColumnRenameFunction(strings.ToUpper)
|
|
|
|
upperAnon := struct {
|
|
FirstUpper string
|
|
LastUpper string
|
|
}{}
|
|
upperColumnMap, upperErr := util.GetColumnMap(&upperAnon)
|
|
rt.NoError(upperErr)
|
|
|
|
upperKeys := make([]string, 0, len(upperColumnMap))
|
|
for key := range upperColumnMap {
|
|
upperKeys = append(upperKeys, key)
|
|
}
|
|
rt.Contains(upperKeys, "FIRSTUPPER")
|
|
rt.Contains(upperKeys, "LASTUPPER")
|
|
|
|
util.SetColumnRenameFunction(util.DefaultColumnRenameFunction)
|
|
}
|
|
|
|
func (rt *reflectTest) TestParallelGetColumnMap() {
|
|
type item struct {
|
|
id uint
|
|
name string
|
|
}
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
wg.Add(1)
|
|
go func() {
|
|
i := item{id: 1, name: "bob"}
|
|
m, err := util.GetColumnMap(i)
|
|
rt.NoError(err)
|
|
rt.NotNil(m)
|
|
wg.Done()
|
|
}()
|
|
|
|
wg.Add(1)
|
|
go func() {
|
|
i := item{id: 2, name: "sally"}
|
|
m, err := util.GetColumnMap(i)
|
|
rt.NoError(err)
|
|
rt.NotNil(m)
|
|
wg.Done()
|
|
}()
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
func (rt *reflectTest) TestAssignStructVals_withStruct() {
|
|
type TestStruct struct {
|
|
Str string
|
|
Int int64
|
|
Bool bool
|
|
Valuer sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
data := map[string]interface{}{
|
|
"str": "string",
|
|
"int": int64(10),
|
|
"bool": true,
|
|
"valuer": sql.NullString{String: "null_str", Valid: true},
|
|
}
|
|
|
|
util.AssignStructVals(&ts, data, cm)
|
|
rt.Equal(ts, TestStruct{
|
|
Str: "string",
|
|
Int: 10,
|
|
Bool: true,
|
|
Valuer: sql.NullString{String: "null_str", Valid: true},
|
|
})
|
|
}
|
|
|
|
func (rt *reflectTest) TestAssignStructVals_withStructWithPointerVals() {
|
|
type TestStruct struct {
|
|
Str string
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
ns := &sql.NullString{String: "null_str1", Valid: true}
|
|
data := map[string]interface{}{
|
|
"str": "string",
|
|
"int": int64(10),
|
|
"bool": true,
|
|
"valuer": &ns,
|
|
}
|
|
util.AssignStructVals(&ts, data, cm)
|
|
rt.Equal(ts, TestStruct{
|
|
Str: "string",
|
|
Int: 10,
|
|
Bool: true,
|
|
Valuer: ns,
|
|
})
|
|
}
|
|
|
|
func (rt *reflectTest) TestAssignStructVals_withStructWithEmbeddedStruct() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
EmbeddedStruct
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
ns := &sql.NullString{String: "null_str1", Valid: true}
|
|
data := map[string]interface{}{
|
|
"str": "string",
|
|
"int": int64(10),
|
|
"bool": true,
|
|
"valuer": &ns,
|
|
}
|
|
util.AssignStructVals(&ts, data, cm)
|
|
rt.Equal(ts, TestStruct{
|
|
EmbeddedStruct: EmbeddedStruct{Str: "string"},
|
|
Int: 10,
|
|
Bool: true,
|
|
Valuer: ns,
|
|
})
|
|
}
|
|
|
|
func (rt *reflectTest) TestAssignStructVals_withStructWithEmbeddedStructPointer() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
*EmbeddedStruct
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
ns := &sql.NullString{String: "null_str1", Valid: true}
|
|
data := map[string]interface{}{
|
|
"str": "string",
|
|
"int": int64(10),
|
|
"bool": true,
|
|
"valuer": &ns,
|
|
}
|
|
util.AssignStructVals(&ts, data, cm)
|
|
rt.Equal(ts, TestStruct{
|
|
EmbeddedStruct: &EmbeddedStruct{Str: "string"},
|
|
Int: 10,
|
|
Bool: true,
|
|
Valuer: ns,
|
|
})
|
|
}
|
|
|
|
func (rt *reflectTest) TestAssignStructVals_withStructWithTaggedEmbeddedStruct() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
EmbeddedStruct `db:"embedded"`
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
ns := &sql.NullString{String: "null_str1", Valid: true}
|
|
data := map[string]interface{}{
|
|
"embedded.str": "string",
|
|
"int": int64(10),
|
|
"bool": true,
|
|
"valuer": &ns,
|
|
}
|
|
util.AssignStructVals(&ts, data, cm)
|
|
rt.Equal(ts, TestStruct{
|
|
EmbeddedStruct: EmbeddedStruct{Str: "string"},
|
|
Int: 10,
|
|
Bool: true,
|
|
Valuer: ns,
|
|
})
|
|
}
|
|
|
|
func (rt *reflectTest) TestAssignStructVals_withStructWithTaggedEmbeddedPointer() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
*EmbeddedStruct `db:"embedded"`
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
ns := &sql.NullString{String: "null_str1", Valid: true}
|
|
data := map[string]interface{}{
|
|
"embedded.str": "string",
|
|
"int": int64(10),
|
|
"bool": true,
|
|
"valuer": &ns,
|
|
}
|
|
util.AssignStructVals(&ts, data, cm)
|
|
rt.Equal(ts, TestStruct{
|
|
EmbeddedStruct: &EmbeddedStruct{Str: "string"},
|
|
Int: 10,
|
|
Bool: true,
|
|
Valuer: ns,
|
|
})
|
|
}
|
|
|
|
func (rt *reflectTest) TestAssignStructVals_withStructWithTaggedStructField() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
Embedded EmbeddedStruct `db:"embedded"`
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
ns := &sql.NullString{String: "null_str1", Valid: true}
|
|
data := map[string]interface{}{
|
|
"embedded.str": "string",
|
|
"int": int64(10),
|
|
"bool": true,
|
|
"valuer": &ns,
|
|
}
|
|
util.AssignStructVals(&ts, data, cm)
|
|
rt.Equal(ts, TestStruct{
|
|
Embedded: EmbeddedStruct{Str: "string"},
|
|
Int: 10,
|
|
Bool: true,
|
|
Valuer: ns,
|
|
})
|
|
}
|
|
|
|
func (rt *reflectTest) TestAssignStructVals_withStructWithTaggedPointerField() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
Embedded *EmbeddedStruct `db:"embedded"`
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
ns := &sql.NullString{String: "null_str1", Valid: true}
|
|
data := map[string]interface{}{
|
|
"embedded.str": "string",
|
|
"int": int64(10),
|
|
"bool": true,
|
|
"valuer": &ns,
|
|
}
|
|
util.AssignStructVals(&ts, data, cm)
|
|
rt.Equal(ts, TestStruct{
|
|
Embedded: &EmbeddedStruct{Str: "string"},
|
|
Int: 10,
|
|
Bool: true,
|
|
Valuer: ns,
|
|
})
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withStruct() {
|
|
type TestStruct struct {
|
|
Str string
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"str": {ColumnName: "str", FieldIndex: []int{0}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf("")},
|
|
"int": {ColumnName: "int", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
"valuer": {ColumnName: "valuer", FieldIndex: []int{3}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withStructDbv2Tags() {
|
|
type TestStruct struct {
|
|
Str string `ff:"skipinsert,skipupdate"`
|
|
Int int64 `ff:"skipinsert"`
|
|
Bool bool `ff:"skipupdate"`
|
|
Empty bool `ff:"defaultifempty"`
|
|
OmitNil bool `ff:"omitnil"`
|
|
OmitEmpty bool `ff:"omitempty"`
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"str": {ColumnName: "str", FieldIndex: []int{0}, ShouldInsert: false, ShouldUpdate: false, GoType: reflect.TypeOf("")},
|
|
"int": {ColumnName: "int", FieldIndex: []int{1}, ShouldInsert: false, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: false, GoType: reflect.TypeOf(true)},
|
|
"empty": {
|
|
ColumnName: "empty",
|
|
FieldIndex: []int{3},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
DefaultIfEmpty: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"omitnil": {
|
|
ColumnName: "omitnil",
|
|
FieldIndex: []int{4},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
OmitNil: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"omitempty": {
|
|
ColumnName: "omitempty",
|
|
FieldIndex: []int{5},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
OmitEmpty: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"valuer": {ColumnName: "valuer", FieldIndex: []int{6}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withStructWithIgnoreUntagged() {
|
|
defer util.SetIgnoreUntaggedFields(false)
|
|
util.SetIgnoreUntaggedFields(true)
|
|
|
|
type EmbeddedStruct struct {
|
|
Float float64 `db:"f"`
|
|
Rune rune // Ignored
|
|
}
|
|
|
|
type TestStruct struct {
|
|
EmbeddedStruct
|
|
Str string `db:"s"`
|
|
Int int64 `db:"i"`
|
|
Bool bool // Ignored
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"f": {ColumnName: "f", FieldIndex: []int{0, 0}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(float64(1))},
|
|
"s": {ColumnName: "s", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf("")},
|
|
"i": {ColumnName: "i", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withStructWithTag() {
|
|
type TestStruct struct {
|
|
Str string `db:"s"`
|
|
Int int64 `db:"i"`
|
|
Bool bool `db:"b"`
|
|
Valuer *sql.NullString `db:"v"`
|
|
Ignored string `db:"-"`
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"s": {ColumnName: "s", FieldIndex: []int{0}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf("")},
|
|
"i": {ColumnName: "i", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"b": {ColumnName: "b", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
"v": {ColumnName: "v", FieldIndex: []int{3}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withStructWithTagAndDbv2Tag() {
|
|
type TestStruct struct {
|
|
Str string `db:"s" ff:"skipinsert,skipupdate"`
|
|
Int int64 `db:"i" ff:"skipinsert"`
|
|
Bool bool `db:"b" ff:"skipupdate"`
|
|
Valuer *sql.NullString `db:"v"`
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"s": {ColumnName: "s", FieldIndex: []int{0}, ShouldInsert: false, ShouldUpdate: false, GoType: reflect.TypeOf("")},
|
|
"i": {ColumnName: "i", FieldIndex: []int{1}, ShouldInsert: false, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"b": {ColumnName: "b", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: false, GoType: reflect.TypeOf(true)},
|
|
"v": {ColumnName: "v", FieldIndex: []int{3}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withStructWithTransientFields() {
|
|
type TestStruct struct {
|
|
Str string
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString `db:"-"`
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"str": {ColumnName: "str", FieldIndex: []int{0}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf("")},
|
|
"int": {ColumnName: "int", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withSliceOfStructs() {
|
|
type TestStruct struct {
|
|
Str string
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts []TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"str": {ColumnName: "str", FieldIndex: []int{0}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf("")},
|
|
"int": {ColumnName: "int", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
"valuer": {ColumnName: "valuer", FieldIndex: []int{3}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withNonStruct() {
|
|
var v int64
|
|
_, err := util.GetColumnMap(&v)
|
|
rt.EqualError(err, "db: cannot scan into this type: int64")
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withStructWithEmbeddedStruct() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
EmbeddedStruct
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"str": {ColumnName: "str", FieldIndex: []int{0, 0}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf("")},
|
|
"int": {ColumnName: "int", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
"valuer": {ColumnName: "valuer", FieldIndex: []int{3}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withStructWithEmbeddedStructPointer() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
*EmbeddedStruct
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"str": {ColumnName: "str", FieldIndex: []int{0, 0}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf("")},
|
|
"int": {ColumnName: "int", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
"valuer": {ColumnName: "valuer", FieldIndex: []int{3}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withIgnoredEmbeddedStruct() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
EmbeddedStruct `db:"-"`
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"int": {ColumnName: "int", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
"valuer": {ColumnName: "valuer", FieldIndex: []int{3}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withIgnoredEmbeddedPointerStruct() {
|
|
type EmbeddedStruct struct {
|
|
Str string
|
|
}
|
|
type TestStruct struct {
|
|
*EmbeddedStruct `db:"-"`
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"int": {ColumnName: "int", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
"valuer": {ColumnName: "valuer", FieldIndex: []int{3}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withPrivateFields() {
|
|
type TestStruct struct {
|
|
str string //nolint:structcheck,unused // not used directly but needed for test
|
|
Int int64
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"int": {ColumnName: "int", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
"valuer": {ColumnName: "valuer", FieldIndex: []int{3}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withPrivateEmbeddedFields() {
|
|
type TestEmbedded struct {
|
|
str string //nolint:structcheck,unused // not used directly but need for test
|
|
Int int64
|
|
}
|
|
|
|
type TestStruct struct {
|
|
TestEmbedded
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"int": {ColumnName: "int", FieldIndex: []int{0, 1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(int64(1))},
|
|
"bool": {ColumnName: "bool", FieldIndex: []int{1}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(true)},
|
|
"valuer": {ColumnName: "valuer", FieldIndex: []int{2}, ShouldInsert: true, ShouldUpdate: true, GoType: reflect.TypeOf(&sql.NullString{})},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withEmbeddedTaggedStruct() {
|
|
type TestEmbedded struct {
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
|
|
type TestStruct struct {
|
|
TestEmbedded `db:"test_embedded"`
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"test_embedded.bool": {
|
|
ColumnName: "test_embedded.bool",
|
|
FieldIndex: []int{0, 0},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"test_embedded.valuer": {
|
|
ColumnName: "test_embedded.valuer",
|
|
FieldIndex: []int{0, 1},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(&sql.NullString{}),
|
|
},
|
|
"bool": {
|
|
ColumnName: "bool",
|
|
FieldIndex: []int{1},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"valuer": {
|
|
ColumnName: "valuer",
|
|
FieldIndex: []int{2},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(&sql.NullString{}),
|
|
},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withEmbeddedTaggedStructPointer() {
|
|
type TestEmbedded struct {
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
|
|
type TestStruct struct {
|
|
*TestEmbedded `db:"test_embedded"`
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"test_embedded.bool": {
|
|
ColumnName: "test_embedded.bool",
|
|
FieldIndex: []int{0, 0},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"test_embedded.valuer": {
|
|
ColumnName: "test_embedded.valuer",
|
|
FieldIndex: []int{0, 1},
|
|
ShouldInsert: true, ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(&sql.NullString{}),
|
|
},
|
|
"bool": {
|
|
ColumnName: "bool",
|
|
FieldIndex: []int{1},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"valuer": {
|
|
ColumnName: "valuer",
|
|
FieldIndex: []int{2},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(&sql.NullString{}),
|
|
},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withTaggedStructField() {
|
|
type TestEmbedded struct {
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
|
|
type TestStruct struct {
|
|
Embedded TestEmbedded `db:"test_embedded"`
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"test_embedded.bool": {
|
|
ColumnName: "test_embedded.bool",
|
|
FieldIndex: []int{0, 0},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"test_embedded.valuer": {
|
|
ColumnName: "test_embedded.valuer",
|
|
FieldIndex: []int{0, 1},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(&sql.NullString{}),
|
|
},
|
|
"bool": {
|
|
ColumnName: "bool",
|
|
FieldIndex: []int{1},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"valuer": {
|
|
ColumnName: "valuer",
|
|
FieldIndex: []int{2},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(&sql.NullString{}),
|
|
},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetColumnMap_withTaggedStructPointerField() {
|
|
type TestEmbedded struct {
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
|
|
type TestStruct struct {
|
|
Embedded *TestEmbedded `db:"test_embedded"`
|
|
Bool bool
|
|
Valuer *sql.NullString
|
|
}
|
|
var ts TestStruct
|
|
cm, err := util.GetColumnMap(&ts)
|
|
rt.NoError(err)
|
|
rt.Equal(util.ColumnMap{
|
|
"test_embedded.bool": {
|
|
ColumnName: "test_embedded.bool",
|
|
FieldIndex: []int{0, 0},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"test_embedded.valuer": {
|
|
ColumnName: "test_embedded.valuer",
|
|
FieldIndex: []int{0, 1},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(&sql.NullString{}),
|
|
},
|
|
"bool": {
|
|
ColumnName: "bool",
|
|
FieldIndex: []int{1},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(true),
|
|
},
|
|
"valuer": {
|
|
ColumnName: "valuer",
|
|
FieldIndex: []int{2},
|
|
ShouldInsert: true,
|
|
ShouldUpdate: true,
|
|
GoType: reflect.TypeOf(&sql.NullString{}),
|
|
},
|
|
}, cm)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetTypeInfo() {
|
|
var a int64
|
|
var b []int64
|
|
var c []*time.Time
|
|
|
|
t, k := util.GetTypeInfo(&a, reflect.ValueOf(a))
|
|
rt.Equal(reflect.TypeOf(a), t)
|
|
rt.Equal(reflect.Int64, k)
|
|
|
|
t, k = util.GetTypeInfo(&b, reflect.ValueOf(a))
|
|
rt.Equal(reflect.TypeOf(a), t)
|
|
rt.Equal(reflect.Int64, k)
|
|
|
|
t, k = util.GetTypeInfo(c, reflect.ValueOf(c))
|
|
rt.Equal(reflect.TypeOf(time.Time{}), t)
|
|
rt.Equal(reflect.Struct, k)
|
|
}
|
|
|
|
func (rt *reflectTest) TestSafeGetFieldByIndex() {
|
|
type TestEmbedded struct {
|
|
FieldA int
|
|
}
|
|
type TestEmbeddedPointerStruct struct {
|
|
*TestEmbedded
|
|
FieldB string
|
|
}
|
|
type TestEmbeddedStruct struct {
|
|
TestEmbedded
|
|
FieldB string
|
|
}
|
|
v := reflect.ValueOf(TestEmbeddedPointerStruct{})
|
|
f, isAvailable := util.SafeGetFieldByIndex(v, []int{0, 0})
|
|
rt.False(isAvailable)
|
|
rt.False(f.IsValid())
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{1})
|
|
rt.True(isAvailable)
|
|
rt.True(f.IsValid())
|
|
rt.Equal(reflect.String, f.Type().Kind())
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{})
|
|
rt.True(isAvailable)
|
|
rt.Equal(v, f)
|
|
|
|
v = reflect.ValueOf(TestEmbeddedPointerStruct{TestEmbedded: &TestEmbedded{}})
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{0, 0})
|
|
rt.True(isAvailable)
|
|
rt.True(f.IsValid())
|
|
rt.Equal(reflect.Int, f.Type().Kind())
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{1})
|
|
rt.True(isAvailable)
|
|
rt.True(f.IsValid())
|
|
rt.Equal(reflect.String, f.Type().Kind())
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{})
|
|
rt.True(isAvailable)
|
|
rt.Equal(v, f)
|
|
|
|
v = reflect.ValueOf(TestEmbeddedStruct{})
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{0, 0})
|
|
rt.True(isAvailable)
|
|
rt.True(f.IsValid())
|
|
rt.Equal(reflect.Int, f.Type().Kind())
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{1})
|
|
rt.True(isAvailable)
|
|
rt.True(f.IsValid())
|
|
rt.Equal(reflect.String, f.Type().Kind())
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{})
|
|
rt.True(isAvailable)
|
|
rt.Equal(v, f)
|
|
|
|
v = reflect.ValueOf(TestEmbeddedStruct{TestEmbedded: TestEmbedded{}})
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{0, 0})
|
|
rt.True(isAvailable)
|
|
rt.True(f.IsValid())
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{1})
|
|
rt.True(isAvailable)
|
|
rt.True(f.IsValid())
|
|
rt.Equal(reflect.String, f.Type().Kind())
|
|
f, isAvailable = util.SafeGetFieldByIndex(v, []int{})
|
|
rt.True(isAvailable)
|
|
rt.Equal(v, f)
|
|
}
|
|
|
|
func (rt *reflectTest) TestSafeSetFieldByIndex() {
|
|
type TestEmbedded struct {
|
|
FieldA int
|
|
}
|
|
type TestEmbeddedPointerStruct struct {
|
|
*TestEmbedded
|
|
FieldB string
|
|
}
|
|
type TestEmbeddedStruct struct {
|
|
TestEmbedded
|
|
FieldB string
|
|
}
|
|
var teps TestEmbeddedPointerStruct
|
|
v := reflect.ValueOf(&teps)
|
|
f := util.SafeSetFieldByIndex(v, []int{}, nil)
|
|
rt.Equal(TestEmbeddedPointerStruct{}, f.Interface())
|
|
|
|
f = util.SafeSetFieldByIndex(v, []int{0, 0}, 1)
|
|
rt.Equal(TestEmbeddedPointerStruct{
|
|
TestEmbedded: &TestEmbedded{FieldA: 1},
|
|
}, f.Interface())
|
|
|
|
f = util.SafeSetFieldByIndex(v, []int{1}, "hello")
|
|
rt.Equal(TestEmbeddedPointerStruct{
|
|
TestEmbedded: &TestEmbedded{FieldA: 1},
|
|
FieldB: "hello",
|
|
}, f.Interface())
|
|
rt.Equal(TestEmbeddedPointerStruct{
|
|
TestEmbedded: &TestEmbedded{FieldA: 1},
|
|
FieldB: "hello",
|
|
}, teps)
|
|
|
|
var tes TestEmbeddedStruct
|
|
v = reflect.ValueOf(&tes)
|
|
f = util.SafeSetFieldByIndex(v, []int{}, nil)
|
|
rt.Equal(TestEmbeddedStruct{}, f.Interface())
|
|
|
|
f = util.SafeSetFieldByIndex(v, []int{0, 0}, 1)
|
|
rt.Equal(TestEmbeddedStruct{
|
|
TestEmbedded: TestEmbedded{FieldA: 1},
|
|
}, f.Interface())
|
|
|
|
f = util.SafeSetFieldByIndex(v, []int{1}, "hello")
|
|
rt.Equal(TestEmbeddedStruct{
|
|
TestEmbedded: TestEmbedded{FieldA: 1},
|
|
FieldB: "hello",
|
|
}, f.Interface())
|
|
rt.Equal(TestEmbeddedStruct{
|
|
TestEmbedded: TestEmbedded{FieldA: 1},
|
|
FieldB: "hello",
|
|
}, tes)
|
|
}
|
|
|
|
func (rt *reflectTest) TestGetSliceElementType() {
|
|
type MyStruct struct{}
|
|
|
|
tests := []struct {
|
|
slice interface{}
|
|
want reflect.Type
|
|
}{
|
|
{
|
|
slice: []int{},
|
|
want: reflect.TypeOf(1),
|
|
},
|
|
{
|
|
slice: []*int{},
|
|
want: reflect.TypeOf(1),
|
|
},
|
|
{
|
|
slice: []MyStruct{},
|
|
want: reflect.TypeOf(MyStruct{}),
|
|
},
|
|
{
|
|
slice: []*MyStruct{},
|
|
want: reflect.TypeOf(MyStruct{}),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
sliceVal := reflect.ValueOf(tt.slice)
|
|
elementType := util.GetSliceElementType(sliceVal)
|
|
|
|
rt.Equal(tt.want, elementType)
|
|
}
|
|
}
|
|
|
|
func (rt *reflectTest) TestAppendSliceElement() {
|
|
type MyStruct struct{}
|
|
|
|
sliceVal := reflect.Indirect(reflect.ValueOf(&[]MyStruct{}))
|
|
util.AppendSliceElement(sliceVal, reflect.ValueOf(&MyStruct{}))
|
|
|
|
rt.Equal([]MyStruct{{}}, sliceVal.Interface())
|
|
|
|
sliceVal = reflect.Indirect(reflect.ValueOf(&[]*MyStruct{}))
|
|
util.AppendSliceElement(sliceVal, reflect.ValueOf(&MyStruct{}))
|
|
|
|
rt.Equal([]*MyStruct{{}}, sliceVal.Interface())
|
|
}
|
|
|
|
func TestReflectSuite(t *testing.T) {
|
|
suite.Run(t, new(reflectTest))
|
|
}
|