Repository: caicloud/nirvana
Pull request #353 (2020-08-25 06:54:10)

[release-0.2] feat(time): support convert to time
This is an automated cherry-pick of #352

/assign whalecold

caicloud-bot: @caicloud-bot: Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our [release note process](https://git.k8s.io/community/contributors/guide/release-notes.md) to remove it.

<details>

Instructions for interacting with me using PR comments are available [here](https://github.com/caicloud/engineering/blob/master/guidelines/caicloud_bot.md).  If you have questions or suggestions related to my behavior, please file an issue against the [caicloud/tools](https://github.com/caicloud/tools/issues/new?title=Prow%20issue:) repository.
</details>
caicloud-bot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: 
To fully approve this pull request, please assign additional approvers.
We suggest the following additional approver: **supereagle**

Assign the PR to them by writing `/assign @supereagle` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://github.com/caicloud/engineering/blob/master/guidelines/caicloud_bot.md#bot-commands).

The pull request process is described [here](https://github.com/caicloud/engineering/blob/master/guidelines/caicloud_bot.md#typical-workflow)

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/caicloud/nirvana/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["supereagle"]} -->
iawia002: /release-note-none
/lgtm
caicloud-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/caicloud/nirvana/pull/353#issuecomment-679841031" title="LGTM">iawia002</a>*

The full list of commands accepted by this bot can be found [here](https://github.com/caicloud/engineering/blob/master/guidelines/caicloud_bot.md#bot-commands).

The pull request process is described [here](https://github.com/caicloud/engineering/blob/master/guidelines/caicloud_bot.md#typical-workflow)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/caicloud/nirvana/blob/master/OWNERS)~~ [iawia002]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/service/content.go b/service/content.go
index 9c80e49..5b47344 100644
--- a/service/content.go
+++ b/service/content.go
@@ -25,6 +25,7 @@ import (
 	"io/ioutil"
 	"reflect"
 	"strconv"
+	"time"
 
 	"github.com/caicloud/nirvana/definition"
 )
@@ -370,38 +371,40 @@ func (p *ContextPrefab) Make(ctx context.Context) (interface{}, error) {
 type Converter func(ctx context.Context, data []string) (interface{}, error)
 
 var converters = map[reflect.Type]Converter{
-	reflect.TypeOf(bool(false)):  ConvertToBool,
-	reflect.TypeOf(int(0)):       ConvertToInt,
-	reflect.TypeOf(int8(0)):      ConvertToInt8,
-	reflect.TypeOf(int16(0)):     ConvertToInt16,
-	reflect.TypeOf(int32(0)):     ConvertToInt32,
-	reflect.TypeOf(int64(0)):     ConvertToInt64,
-	reflect.TypeOf(uint(0)):      ConvertToUint,
-	reflect.TypeOf(uint8(0)):     ConvertToUint8,
-	reflect.TypeOf(uint16(0)):    ConvertToUint16,
-	reflect.TypeOf(uint32(0)):    ConvertToUint32,
-	reflect.TypeOf(uint64(0)):    ConvertToUint64,
-	reflect.TypeOf(float32(0)):   ConvertToFloat32,
-	reflect.TypeOf(float64(0)):   ConvertToFloat64,
-	reflect.TypeOf(string("")):   ConvertToString,
-	reflect.TypeOf(new(bool)):    ConvertToBoolP,
-	reflect.TypeOf(new(int)):     ConvertToIntP,
-	reflect.TypeOf(new(int8)):    ConvertToInt8P,
-	reflect.TypeOf(new(int16)):   ConvertToInt16P,
-	reflect.TypeOf(new(int32)):   ConvertToInt32P,
-	reflect.TypeOf(new(int64)):   ConvertToInt64P,
-	reflect.TypeOf(new(uint)):    ConvertToUintP,
-	reflect.TypeOf(new(uint8)):   ConvertToUint8P,
-	reflect.TypeOf(new(uint16)):  ConvertToUint16P,
-	reflect.TypeOf(new(uint32)):  ConvertToUint32P,
-	reflect.TypeOf(new(uint64)):  ConvertToUint64P,
-	reflect.TypeOf(new(float32)): ConvertToFloat32P,
-	reflect.TypeOf(new(float64)): ConvertToFloat64P,
-	reflect.TypeOf(new(string)):  ConvertToStringP,
-	reflect.TypeOf([]bool{}):     ConvertToBoolSlice,
-	reflect.TypeOf([]int{}):      ConvertToIntSlice,
-	reflect.TypeOf([]float64{}):  ConvertToFloat64Slice,
-	reflect.TypeOf([]string{}):   ConvertToStringSlice,
+	reflect.TypeOf(false):          ConvertToBool,
+	reflect.TypeOf(0):              ConvertToInt,
+	reflect.TypeOf(int8(0)):        ConvertToInt8,
+	reflect.TypeOf(int16(0)):       ConvertToInt16,
+	reflect.TypeOf(int32(0)):       ConvertToInt32,
+	reflect.TypeOf(int64(0)):       ConvertToInt64,
+	reflect.TypeOf(uint(0)):        ConvertToUint,
+	reflect.TypeOf(uint8(0)):       ConvertToUint8,
+	reflect.TypeOf(uint16(0)):      ConvertToUint16,
+	reflect.TypeOf(uint32(0)):      ConvertToUint32,
+	reflect.TypeOf(uint64(0)):      ConvertToUint64,
+	reflect.TypeOf(float32(0)):     ConvertToFloat32,
+	reflect.TypeOf(float64(0)):     ConvertToFloat64,
+	reflect.TypeOf(""):             ConvertToString,
+	reflect.TypeOf(time.Time{}):    ConvertToTime,
+	reflect.TypeOf(new(bool)):      ConvertToBoolP,
+	reflect.TypeOf(new(int)):       ConvertToIntP,
+	reflect.TypeOf(new(int8)):      ConvertToInt8P,
+	reflect.TypeOf(new(int16)):     ConvertToInt16P,
+	reflect.TypeOf(new(int32)):     ConvertToInt32P,
+	reflect.TypeOf(new(int64)):     ConvertToInt64P,
+	reflect.TypeOf(new(uint)):      ConvertToUintP,
+	reflect.TypeOf(new(uint8)):     ConvertToUint8P,
+	reflect.TypeOf(new(uint16)):    ConvertToUint16P,
+	reflect.TypeOf(new(uint32)):    ConvertToUint32P,
+	reflect.TypeOf(new(uint64)):    ConvertToUint64P,
+	reflect.TypeOf(new(float32)):   ConvertToFloat32P,
+	reflect.TypeOf(new(float64)):   ConvertToFloat64P,
+	reflect.TypeOf(new(string)):    ConvertToStringP,
+	reflect.TypeOf(new(time.Time)): ConvertToTimeP,
+	reflect.TypeOf([]bool{}):       ConvertToBoolSlice,
+	reflect.TypeOf([]int{}):        ConvertToIntSlice,
+	reflect.TypeOf([]float64{}):    ConvertToFloat64Slice,
+	reflect.TypeOf([]string{}):     ConvertToStringSlice,
 }
 
 // ConverterFor gets converter for specified type.
@@ -665,6 +668,16 @@ func ConvertToFloat64(ctx context.Context, data []string) (interface{}, error) {
 	return target, nil
 }
 
+// ConvertToTime converts []string to time.Time. Only the first data is used.
+func ConvertToTime(ctx context.Context, data []string) (interface{}, error) {
+	origin := data[0]
+	target, err := time.Parse(time.RFC3339, origin)
+	if err != nil {
+		return nil, invalidConversion.Error(origin, "time")
+	}
+	return target, nil
+}
+
 // ConvertToFloat64P converts []string to *float64. Only the first data is used.
 func ConvertToFloat64P(ctx context.Context, data []string) (interface{}, error) {
 	ret, err := ConvertToFloat64(ctx, data)
@@ -685,6 +698,16 @@ func ConvertToStringP(ctx context.Context, data []string) (interface{}, error) {
 	return &data[0], nil
 }
 
+// ConvertToTimeP return the first element's pointer in []string.
+func ConvertToTimeP(ctx context.Context, data []string) (interface{}, error) {
+	ret, err := ConvertToTime(ctx, data)
+	if err != nil {
+		return nil, err
+	}
+	value := ret.(time.Time)
+	return &value, nil
+}
+
 // ConvertToBoolSlice converts all elements in data to bool, and return []bool
 func ConvertToBoolSlice(ctx context.Context, data []string) (interface{}, error) {
 	ret := make([]bool, len(data))
diff --git a/utils/generators/swagger/generator.go b/utils/generators/swagger/generator.go
index 35e6a23..dba97ca 100644
--- a/utils/generators/swagger/generator.go
+++ b/utils/generators/swagger/generator.go
@@ -490,38 +490,40 @@ func (g *Generator) generateAutoParameter(typ api.TypeName) []spec.Parameter {
 }
 
 var converters = map[string]service.Converter{
-	"bool":      service.ConvertToBool,
-	"int":       service.ConvertToInt,
-	"int8":      service.ConvertToInt8,
-	"int16":     service.ConvertToInt16,
-	"int32":     service.ConvertToInt32,
-	"int64":     service.ConvertToInt64,
-	"uint":      service.ConvertToUint,
-	"uint8":     service.ConvertToUint8,
-	"uint16":    service.ConvertToUint16,
-	"uint32":    service.ConvertToUint32,
-	"uint64":    service.ConvertToUint64,
-	"float32":   service.ConvertToFloat32,
-	"float64":   service.ConvertToFloat64,
-	"string":    service.ConvertToString,
-	"*bool":     service.ConvertToBoolP,
-	"*int":      service.ConvertToIntP,
-	"*int8":     service.ConvertToInt8P,
-	"*int16":    service.ConvertToInt16P,
-	"*int32":    service.ConvertToInt32P,
-	"*int64":    service.ConvertToInt64P,
-	"*uint":     service.ConvertToUintP,
-	"*uint8":    service.ConvertToUint8P,
-	"*uint16":   service.ConvertToUint16P,
-	"*uint32":   service.ConvertToUint32P,
-	"*uint64":   service.ConvertToUint64P,
-	"*float32":  service.ConvertToFloat32P,
-	"*float64":  service.ConvertToFloat64P,
-	"*string":   service.ConvertToStringP,
-	"[]bool":    service.ConvertToBoolSlice,
-	"[]int":     service.ConvertToIntSlice,
-	"[]float64": service.ConvertToFloat64Slice,
-	"[]string":  service.ConvertToStringSlice,
+	"bool":       service.ConvertToBool,
+	"int":        service.ConvertToInt,
+	"int8":       service.ConvertToInt8,
+	"int16":      service.ConvertToInt16,
+	"int32":      service.ConvertToInt32,
+	"int64":      service.ConvertToInt64,
+	"uint":       service.ConvertToUint,
+	"uint8":      service.ConvertToUint8,
+	"uint16":     service.ConvertToUint16,
+	"uint32":     service.ConvertToUint32,
+	"uint64":     service.ConvertToUint64,
+	"float32":    service.ConvertToFloat32,
+	"float64":    service.ConvertToFloat64,
+	"string":     service.ConvertToString,
+	"time.Time":  service.ConvertToTime,
+	"*bool":      service.ConvertToBoolP,
+	"*int":       service.ConvertToIntP,
+	"*int8":      service.ConvertToInt8P,
+	"*int16":     service.ConvertToInt16P,
+	"*int32":     service.ConvertToInt32P,
+	"*int64":     service.ConvertToInt64P,
+	"*uint":      service.ConvertToUintP,
+	"*uint8":     service.ConvertToUint8P,
+	"*uint16":    service.ConvertToUint16P,
+	"*uint32":    service.ConvertToUint32P,
+	"*uint64":    service.ConvertToUint64P,
+	"*float32":   service.ConvertToFloat32P,
+	"*float64":   service.ConvertToFloat64P,
+	"*string":    service.ConvertToStringP,
+	"*time.Time": service.ConvertToTimeP,
+	"[]bool":     service.ConvertToBoolSlice,
+	"[]int":      service.ConvertToIntSlice,
+	"[]float64":  service.ConvertToFloat64Slice,
+	"[]string":   service.ConvertToStringSlice,
 }
 
 func (g *Generator) enum(typ *api.Type) []spec.Parameter {


Test patch:
diff --git a/service/content_test.go b/service/content_test.go
index a906da1..4167f66 100644
--- a/service/content_test.go
+++ b/service/content_test.go
@@ -22,6 +22,7 @@ import (
 	"io"
 	"reflect"
 	"testing"
+	"time"
 
 	"github.com/caicloud/nirvana/definition"
 )
@@ -119,6 +120,7 @@ func TestProducer(t *testing.T) {
 }
 
 func TestConverterFor(t *testing.T) {
+	wantTime, _ := time.Parse(time.RFC3339, "2020-08-25T05:12:18Z")
 	tests := []struct {
 		tpy     reflect.Type
 		data    []string
@@ -126,13 +128,13 @@ func TestConverterFor(t *testing.T) {
 		pointer bool
 	}{
 		{
-			reflect.TypeOf(bool(false)),
+			reflect.TypeOf(false),
 			[]string{"true", "false"},
 			true,
 			false,
 		},
 		{
-			reflect.TypeOf(int(0)),
+			reflect.TypeOf(0),
 			[]string{"1", "2"},
 			1,
 			false,
@@ -192,11 +194,17 @@ func TestConverterFor(t *testing.T) {
 			false,
 		},
 		{
-			reflect.TypeOf(string("")),
+			reflect.TypeOf(""),
 			[]string{"1", "2"},
 			"1",
 			false,
 		},
+		{
+			reflect.TypeOf(time.Time{}),
+			[]string{"2020-08-25T05:12:18Z", "2020-08-25T05:12:18Z"},
+			wantTime,
+			false,
+		},
 		{
 			reflect.TypeOf(new(bool)),
 			[]string{"true", "2"},
@@ -284,6 +292,12 @@ func TestConverterFor(t *testing.T) {
 			"1.2",
 			true,
 		},
+		{
+			reflect.TypeOf(new(time.Time)),
+			[]string{"2020-08-25T05:12:18Z", "2020-08-25T05:12:18Z"},
+			wantTime,
+			true,
+		},
 		{
 			reflect.TypeOf([]bool{}),
 			[]string{"true", "false"},