From de42c4248128a43d771458112887572e802e030f Mon Sep 17 00:00:00 2001 From: future-taga Date: Tue, 28 Jun 2022 18:09:54 +0900 Subject: [PATCH 1/2] add embedded struct time.Time support. --- eval.go | 26 ++++++++++++++++++++------ eval_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/eval.go b/eval.go index 75fbd33..521e476 100644 --- a/eval.go +++ b/eval.go @@ -186,7 +186,7 @@ func encode(dest map[string]interface{}, src interface{}) error { } // tagscanner does not support nest struct type. - encodeNestStructTyp(src, dest, tags) + encodeStructField(src, dest, tags) return nil } @@ -201,21 +201,35 @@ func convertToMapStringAny(mp reflect.Value, dest map[string]interface{}) bool { return true } -func encodeNestStructTyp(src interface{}, dest map[string]interface{}, tags []string) { - srcFieldTyps := reflect.ValueOf(src).Type().Elem() - srcFieldValues := reflect.ValueOf(src).Elem() +func encodeStructField(src interface{}, dest map[string]interface{}, tags []string) { + srcFieldValues := reflect.ValueOf(src) + srcFieldTyps := srcFieldValues.Type() + if srcFieldTyps.Kind() == reflect.Pointer { + srcFieldTyps = srcFieldTyps.Elem() + srcFieldValues = srcFieldValues.Elem() + } for i := 0; i < srcFieldTyps.NumField(); i++ { srcFieldTyp := srcFieldTyps.Field(i) + srcFieldValue := srcFieldValues.Field(i) + tagValue := getTagValue(srcFieldTyp.Tag, tags) - if tagValue == "" { + + if srcFieldTyp.Type.Kind() != reflect.Struct { continue } - srcFieldValue := srcFieldValues.Field(i) switch srcFieldTyp.Type.PkgPath() { case "database/sql": + if tagValue == "" { + continue + } encodeSQLNullTyp(srcFieldValue, dest, tagValue) case "time": + if tagValue == "" { + continue + } encodeTimeTyp(srcFieldValue, dest, tagValue) + default: + encodeStructField(srcFieldValue.Interface(), dest, tags) } } } diff --git a/eval_test.go b/eval_test.go index 6d6f9a9..6d5a7e6 100644 --- a/eval_test.go +++ b/eval_test.go @@ -1122,6 +1122,17 @@ func TestEvalWithMap(t *testing.T) { } func TestEval_NestStructTyp(t *testing.T) { + type Embed struct { + EmbedNullString sql.NullString `db:"embed_null_string"` + EmbedTime time.Time `db:"embed_time"` + EmbedPtrTime *time.Time `db:"embed_ptr_time"` + + Skip string + Nest struct { + ID string + } + } + type SQLTypInfo struct { NullBool sql.NullBool `db:"null_bool"` NullFloat64 sql.NullFloat64 `db:"null_float_64"` @@ -1131,6 +1142,8 @@ func TestEval_NestStructTyp(t *testing.T) { NullString sql.NullString `db:"null_string"` NullTime sql.NullTime `db:"null_time"` Time time.Time `db:"time"` + + Embed Embed } tests := []struct { @@ -1222,6 +1235,36 @@ func TestEval_NestStructTyp(t *testing.T) { wantQuery: `SELECT * FROM person WHERE value = ?/*null_string*/`, wantParams: []interface{}{nil}, }, + { + name: "bind embed time.Time", + input: `SELECT * FROM person WHERE value = /*embed_time*/'2022-01-01 10:00:00'`, + inputParams: SQLTypInfo{ + Embed: Embed{EmbedTime: time.Date(2022, 7, 1, 12, 30, 30, 0, time.UTC)}, + }, + wantQuery: `SELECT * FROM person WHERE value = ?/*embed_time*/`, + wantParams: []interface{}{time.Date(2022, 7, 1, 12, 30, 30, 0, time.UTC)}, + }, + { + name: "bind embed ptr time.Time", + input: `SELECT * FROM person WHERE value = /*embed_ptr_time*/'2022-01-01 10:00:00'`, + inputParams: SQLTypInfo{ + Embed: Embed{EmbedPtrTime: func() *time.Time { + d := time.Date(2022, 7, 1, 12, 30, 30, 0, time.UTC) + return &d + }()}, + }, + wantQuery: `SELECT * FROM person WHERE value = ?/*embed_ptr_time*/`, + wantParams: []interface{}{time.Date(2022, 7, 1, 12, 30, 30, 0, time.UTC)}, + }, + { + name: "bind embed sql.NullString", + input: `SELECT * FROM person WHERE value = /*embed_null_string*/'embed_null_string'`, + inputParams: SQLTypInfo{ + Embed: Embed{EmbedNullString: sql.NullString{String: "value", Valid: true}}, + }, + wantQuery: `SELECT * FROM person WHERE value = ?/*embed_null_string*/`, + wantParams: []interface{}{"value"}, + }, { name: "bind invalid", input: `SELECT * FROM person WHERE value = /*null_string*/'hoge'`, From 17371e962c59977384e8e08d74c34e2ce757eaf4 Mon Sep 17 00:00:00 2001 From: future-taga Date: Tue, 28 Jun 2022 18:12:42 +0900 Subject: [PATCH 2/2] add ptr time.Time encode test case. --- eval_test.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/eval_test.go b/eval_test.go index 6d5a7e6..08970ca 100644 --- a/eval_test.go +++ b/eval_test.go @@ -1126,11 +1126,6 @@ func TestEval_NestStructTyp(t *testing.T) { EmbedNullString sql.NullString `db:"embed_null_string"` EmbedTime time.Time `db:"embed_time"` EmbedPtrTime *time.Time `db:"embed_ptr_time"` - - Skip string - Nest struct { - ID string - } } type SQLTypInfo struct { @@ -1142,6 +1137,7 @@ func TestEval_NestStructTyp(t *testing.T) { NullString sql.NullString `db:"null_string"` NullTime sql.NullTime `db:"null_time"` Time time.Time `db:"time"` + PtrTime *time.Time `db:"ptr_time"` Embed Embed } @@ -1228,6 +1224,18 @@ func TestEval_NestStructTyp(t *testing.T) { wantQuery: `SELECT * FROM person WHERE value = ?/*time*/`, wantParams: []interface{}{time.Date(2022, 7, 1, 12, 30, 30, 0, time.UTC)}, }, + { + name: "bind ptr time.Time", + input: `SELECT * FROM person WHERE value = /*ptr_time*/'2022-01-01 10:00:00'`, + inputParams: SQLTypInfo{ + PtrTime: func() *time.Time { + d := time.Date(2022, 7, 1, 12, 30, 30, 0, time.UTC) + return &d + }(), + }, + wantQuery: `SELECT * FROM person WHERE value = ?/*ptr_time*/`, + wantParams: []interface{}{time.Date(2022, 7, 1, 12, 30, 30, 0, time.UTC)}, + }, { name: "bind initial", input: `SELECT * FROM person WHERE value = /*null_string*/'hoge'`,