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

View File

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

View File

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

View File

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