Build and unpack pointer values

Signed-off-by: Jingwen Peng <pengsrc@yunify.com>
This commit is contained in:
Jingwen Peng 2017-01-05 22:04:11 +08:00 committed by Aspire
parent a675c48f6c
commit ee0075ad77
4 changed files with 134 additions and 112 deletions

View File

@ -92,11 +92,14 @@ func (b *Builder) parseRequestProperties() error {
fields := reflect.ValueOf(b.operation.Properties).Elem()
for i := 0; i < fields.NumField(); i++ {
switch value := fields.Field(i).Interface().(type) {
case string:
propertiesMap[fields.Type().Field(i).Tag.Get("name")] = value
case int:
numberString := strconv.Itoa(int(value))
propertiesMap[fields.Type().Field(i).Tag.Get("name")] = numberString
case *string:
if value != nil {
propertiesMap[fields.Type().Field(i).Tag.Get("name")] = *value
}
case *int:
if value != nil {
propertiesMap[fields.Type().Field(i).Tag.Get("name")] = strconv.Itoa(int(*value))
}
}
}
@ -128,57 +131,47 @@ func (b *Builder) parseRequestParams() error {
tagDefault := b.input.Elem().Type().Field(i).Tag.Get("default")
if tagName != "" && tagLocation != "" && requestParams != nil {
switch value := b.input.Elem().Field(i).Interface().(type) {
case string:
if value != "" {
requestParams[tagName] = value
case *string:
if tagDefault != "" {
requestParams[tagName] = tagDefault
}
case int:
numberString := strconv.Itoa(int(value))
if numberString == "0" {
numberString = ""
if tagDefault != "" {
numberString = tagDefault
}
if value != nil {
requestParams[tagName] = *value
}
if numberString != "" {
requestParams[tagName] = numberString
case *int:
if tagDefault != "" {
requestParams[tagName] = tagDefault
}
case bool:
case time.Time:
zero := time.Time{}
if value != zero {
var timeString string
if value != nil {
requestParams[tagName] = strconv.Itoa(int(*value))
}
case *bool:
case *time.Time:
if tagDefault != "" {
requestParams[tagName] = tagDefault
}
if value != nil {
format := b.input.Elem().Type().Field(i).Tag.Get("format")
timeString = utils.TimeToString(value, format)
if timeString != "" {
requestParams[tagName] = timeString
requestParams[tagName] = utils.TimeToString(*value, format)
}
case []*string:
for index, item := range value {
key := tagName + "." + strconv.Itoa(index+1)
if tagDefault != "" {
requestParams[tagName] = tagDefault
}
if item != nil {
requestParams[key] = *item
}
}
case []string:
if len(value) > 0 {
for index, item := range value {
key := tagName + "." + strconv.Itoa(index+1)
requestParams[key] = item
case []*int:
for index, item := range value {
key := tagName + "." + strconv.Itoa(index+1)
if tagDefault != "" {
requestParams[tagName] = tagDefault
}
}
case []int:
if len(value) > 0 {
numbersString := []string{}
for _, number := range value {
numberString := strconv.Itoa(int(number))
if numberString == "0" {
numberString = ""
if tagDefault != "" {
numberString = tagDefault
}
}
if numberString != "" {
numbersString = append(numbersString, numberString)
}
}
for index, item := range numbersString {
requestParams[tagName+"."+strconv.Itoa(index+1)] = item
if item != nil {
requestParams[key] = strconv.Itoa(int(*item))
}
}
default:
@ -197,20 +190,13 @@ func (b *Builder) parseRequestParams() error {
tagKey := tagName + "." + strconv.Itoa(i+1) + "." + fieldTagName
switch fieldValue := item.Field(j).Interface().(type) {
case int:
numberString := strconv.Itoa(int(fieldValue))
if numberString == "0" {
numberString = ""
if tagDefault != "" {
numberString = tagDefault
}
case *int:
if fieldValue != nil {
requestParams[tagKey] = strconv.Itoa(int(*fieldValue))
}
if numberString != "" {
requestParams[tagKey] = numberString
}
case string:
if fieldValue != "" {
requestParams[tagKey] = fieldValue
case *string:
if fieldValue != nil {
requestParams[tagKey] = *fieldValue
}
}
}

View File

@ -27,25 +27,42 @@ import (
)
type InstanceServiceProperties struct {
Zone string `json:"zone" name:"zone"` // Required
Zone *string `json:"zone" name:"zone"` // Required
}
type DescribeInstancesInput struct {
ImageID []string `json:"image_id" name:"image_id" location:"params"`
InstanceClass int `json:"instance_class" name:"instance_class" location:"params" default:"0"` // Available values: 0, 1
InstanceType []string `json:"instance_type" name:"instance_type" location:"params"`
Instances []string `json:"instances" name:"instances" location:"params"`
Limit int `json:"limit" name:"limit" omitEmpty:"true" location:"params"`
Offset int `json:"offset" name:"offset" location:"params"`
SearchWord string `json:"search_word" name:"search_word" location:"params"`
Status []string `json:"status" name:"status" location:"params"` // Available values: pending, running, stopped, suspended, terminated, ceased
Tags []string `json:"tags" name:"tags" location:"params"`
Verbose int `json:"verbose" name:"verbose" location:"params"` // Available values: 0, 1
ImageID []*string `json:"image_id" name:"image_id" location:"params"`
InstanceClass *int `json:"instance_class" name:"instance_class" location:"params" default:"0"` // Available values: 0, 1
InstanceType []*string `json:"instance_type" name:"instance_type" location:"params"`
Instances []*string `json:"instances" name:"instances" location:"params"`
Limit *int `json:"limit" name:"limit" location:"params"`
Offset *int `json:"offset" name:"offset" location:"params"`
SearchWord *string `json:"search_word" name:"search_word" location:"params"`
Status []*string `json:"status" name:"status" location:"params"` // Available values: pending, running, stopped, suspended, terminated, ceased
Tags []*string `json:"tags" name:"tags" location:"params"`
Verbose *int `json:"verbose" name:"verbose" location:"params"` // Available values: 0, 1
}
func (i *DescribeInstancesInput) Validate() error {
return nil
}
func String(v string) *string {
return &v
}
func StringSlice(src []string) []*string {
dst := make([]*string, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
func Int(v int) *int {
return &v
}
func TestBuilder(t *testing.T) {
conf, err := config.NewDefault()
@ -56,7 +73,7 @@ func TestBuilder(t *testing.T) {
operation := &data.Operation{
Config: conf,
Properties: &InstanceServiceProperties{
Zone: "beta",
Zone: String("beta"),
},
APIName: "DescribeInstances",
ServiceName: "Instance",
@ -67,16 +84,14 @@ func TestBuilder(t *testing.T) {
},
}
inputValue := reflect.ValueOf(&DescribeInstancesInput{
ImageID: []string{"img-xxxxxxxx", "img-zzzzzzzz"},
InstanceClass: 0,
InstanceType: []string{"type1", "type2"},
Instances: []string{"i-xxxxxxxx", "i-zzzzzzzz"},
Limit: 0,
Offset: 0,
SearchWord: "search_word",
Status: []string{"running"},
Tags: []string{"tag1", "tag2"},
Verbose: 1,
ImageID: StringSlice([]string{"img-xxxxxxxx", "img-zzzzzzzz"}),
InstanceClass: Int(0),
InstanceType: StringSlice([]string{"type1", "type2"}),
Instances: StringSlice([]string{"i-xxxxxxxx", "i-zzzzzzzz"}),
SearchWord: String("search_word"),
Status: StringSlice([]string{"running"}),
Tags: StringSlice([]string{"tag1", "tag2"}),
Verbose: Int(1),
})
httpRequest, err := builder.BuildHTTPRequest(operation, &inputValue)
assert.Nil(t, err)

View File

@ -122,13 +122,13 @@ func (u *Unpacker) parseError() error {
retCodeValue := u.output.Elem().FieldByName("RetCode")
messageValue := u.output.Elem().FieldByName("Message")
if retCodeValue.IsValid() && retCodeValue.Type().String() == "int" &&
messageValue.IsValid() && messageValue.Type().String() == "string" &&
retCodeValue.Int() != 0 {
if retCodeValue.IsValid() && retCodeValue.Type().String() == "*int" &&
messageValue.IsValid() && messageValue.Type().String() == "*string" &&
retCodeValue.Elem().Int() != 0 {
return &errors.QingCloudError{
RetCode: int(retCodeValue.Int()),
Message: messageValue.String(),
RetCode: int(retCodeValue.Elem().Int()),
Message: messageValue.Elem().String(),
}
}

View File

@ -30,33 +30,54 @@ import (
"github.com/yunify/qingcloud-sdk-go/request/errors"
)
func StringValue(v *string) string {
if v != nil {
return *v
}
return ""
}
func IntValue(v *int) int {
if v != nil {
return *v
}
return 0
}
func TimeValue(v *time.Time) time.Time {
if v != nil {
return *v
}
return time.Time{}
}
func TestUnpackerUnpackHTTPRequest(t *testing.T) {
type Instance struct {
Device string `json:"device" name:"device"`
InstanceID string `json:"instance_id" name:"instance_id"`
InstanceName string `json:"instance_name" name:"instance_name"`
Device *string `json:"device" name:"device"`
InstanceID *string `json:"instance_id" name:"instance_id"`
InstanceName *string `json:"instance_name" name:"instance_name"`
}
type Volume struct {
CreateTime time.Time `json:"create_time" name:"create_time" format:"ISO 8601"`
Description string `json:"description" name:"description"`
Instance *Instance `json:"instance" name:"instance"`
Size int `json:"size" name:"size"`
Status string `json:"status" name:"status"`
StatusTime time.Time `json:"status_time" name:"status_time" format:"ISO 8601"`
SubCode int `json:"sub_code" name:"sub_code"`
TransitionStatus string `json:"transition_status" name:"transition_status"`
VolumeID string `json:"volume_id" name:"volume_id"`
VolumeName string `json:"volume_name" name:"volume_name"`
CreateTime *time.Time `json:"create_time" name:"create_time" format:"ISO 8601"`
Description *string `json:"description" name:"description"`
Instance *Instance `json:"instance" name:"instance"`
Size *int `json:"size" name:"size"`
Status *string `json:"status" name:"status"`
StatusTime *time.Time `json:"status_time" name:"status_time" format:"ISO 8601"`
SubCode *int `json:"sub_code" name:"sub_code"`
TransitionStatus *string `json:"transition_status" name:"transition_status"`
VolumeID *string `json:"volume_id" name:"volume_id"`
VolumeName *string `json:"volume_name" name:"volume_name"`
}
type DescribeVolumesOutput struct {
StatusCode int `location:"statusCode"`
Error *errors.QingCloudError
Action string `json:"action" name:"action"`
RetCode int `json:"ret_code" name:"ret_code"`
TotalCount int `json:"total_count" name:"total_count"`
Action *string `json:"action" name:"action"`
RetCode *int `json:"ret_code" name:"ret_code"`
TotalCount *int `json:"total_count" name:"total_count"`
VolumeSet []*Volume `json:"volume_set" name:"volume_set"`
}
@ -94,18 +115,18 @@ func TestUnpackerUnpackHTTPRequest(t *testing.T) {
unpacker := Unpacker{}
err := unpacker.UnpackHTTPRequest(&data.Operation{}, httpResponse, &outputValue)
assert.Nil(t, err)
assert.Equal(t, "i-xxxxxxxx", output.VolumeSet[0].Instance.InstanceID)
assert.Equal(t, "vol-xxxxxxxx", output.VolumeSet[0].VolumeID)
assert.Equal(t, "vol name", output.VolumeSet[0].VolumeName)
assert.Equal(t, 1024, output.TotalCount)
assert.Equal(t, "i-xxxxxxxx", StringValue(output.VolumeSet[0].Instance.InstanceID))
assert.Equal(t, "vol-xxxxxxxx", StringValue(output.VolumeSet[0].VolumeID))
assert.Equal(t, "vol name", StringValue(output.VolumeSet[0].VolumeName))
assert.Equal(t, 1024, IntValue(output.TotalCount))
statusTime := time.Date(2013, 8, 30, 5, 13, 32, 0, time.UTC)
assert.Equal(t, statusTime, output.VolumeSet[0].StatusTime)
assert.Equal(t, statusTime, TimeValue(output.VolumeSet[0].StatusTime))
}
func TestUnpacker_UnpackHTTPRequestWithError(t *testing.T) {
type DescribeInstanceTypesOutput struct {
RetCode int `json:"ret_code" name:"ret_code"`
Message string `json:"message" name:"message"`
RetCode *int `json:"ret_code" name:"ret_code"`
Message *string `json:"message" name:"message"`
}
httpResponse := &http.Response{Header: http.Header{}}