Commit adae708a authored by endk-mirror-svc's avatar endk-mirror-svc

Added a few functions to encode an options struct to URL parameters

parent 2f832905
Pipeline #24629854 passed with stages
in 1 minute 40 seconds
package eds
import (
"context"
"net/url"
"time"
)
......@@ -47,3 +48,31 @@ type Dataset struct {
RevisionID *string `json:"revision_id,omitempty"`
Resolution *string `json:"resolution,omitempty"`
}
// DatasetListOptions specifies a list of optional options to the
// DatasetService.List method.
type DatasetListOptions struct {
// Limits the list of datasets to this many datasets.
Limit int64 `url:"limit,omitempty"`
// The offset to start returning datasets from.
Offset int64 `url:"offset,omitempty"`
}
// List returns a list of datasets available from Energi Data Service
func (s *DatasetService) List(ctx context.Context, opt *DatasetListOptions) ([]*Dataset, error) {
action := "package_list"
//TODO: Add function (Preferably to eds.go so it can be reused) that takes
// a URL/string and a struct of options and converts those to query string.
req, err := s.client.NewRequest("GET", action, nil)
if err != nil {
return nil, err
}
var data APIResponse
_, err = s.client.Do(ctx, req, &data)
if err != nil {
return nil, err
}
//Placeholder
return nil, nil
}
package eds
import (
"fmt"
"net/url"
"reflect"
"strings"
)
// isEmptyValue determines if a value is to be considered empty when also
// considering the "omitempty" option.
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.String:
return v.String() == ""
case reflect.Interface, reflect.Ptr:
return v.IsNil()
}
return false
}
// containsOption determines if the tag options contain a given option.
func containsOption(tagOpts []string, option string) bool {
for _, e := range tagOpts {
if e == option {
return true
}
}
return false
}
// parseOptions expects to be passed a struct and encode it into a URL
// query string.
//
// opts is encoded using the following rules:
//
// Boolean values is encoded to the strings "true" or "false".
//
// String, int and uint values are encoded using their default string representation.
//
// Non-nil pointers encode to the value pointed to.
//
// No other types are supported.
//
// Each exported field is encoded as a URL parameter unless
//
// - the field's tag is "-", or
// - the field is empty and its tag specifies the "omitempty" option
//
// The empty values are false, 0, any nil pointer or interface value.
//
// The URL parameter name defaults to the struct field name but can be
// specified in the struct field's tag value. The "url" key in the struct
// field's tag value is the key name, followed by an optional comma and
// options. For example:
//
// // Field is ignored by this package.
// Field int `url:"-"`
//
// // Field appears as URL parameter "myName".
// Field int `url:"myName"`
//
// // Field appears as URL parameter "myName" and the field is omitted if
// // its value is empty
// Field int `url:"myName,omitempty"`
//
// // Field appears as URL parameter "Field" (the default), but the field
// // is skipped if empty. Note the leading comma.
// Field int `url:",omitempty"`
func parseOptions(opts interface{}) (string, error) {
v := reflect.ValueOf(opts)
if v.Kind() != reflect.Struct {
return "", fmt.Errorf("Expected struct input. Got %v", v.Kind())
}
uv := url.Values{}
typ := v.Type()
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i).Name
value := fmt.Sprint(v.Field(i))
tagString := strings.Split(typ.Field(i).Tag.Get("url"), ",")
tagOpts := tagString[1:]
tag := tagString[0]
if containsOption(tagOpts, "omitempty") && isEmptyValue(v.Field(i)) {
continue
}
if tag == "-" {
continue
}
if tag == "" {
tag = field
}
uv.Add(tag, value)
}
return uv.Encode(), nil
}
package eds
import (
"testing"
)
func TestContainsOptions(t *testing.T) {
testObj := struct {
Male bool `url:"Male,omitempty"`
Female bool `url:"female"`
Name string `url:"name"`
Age int `url:"age"`
FieldOne string `url:"-"`
FieldTwo string `url:",omitempty"`
FieldThree string `url:",omitempty"`
FieldFour uint `url:"fieldFour"`
FieldFive float32
}{
false,
true,
"Dolores",
25,
"I should be ignored",
"",
"Keep Me",
10,
11.0,
}
s, err := parseOptions(testObj)
if err != nil {
t.Error(err)
}
if s != "FieldFive=11&FieldThree=Keep+Me&age=25&female=true&fieldFour=10&name=Dolores" {
t.Errorf("Query String does not match expected. Got %s\n", s)
}
_, err = parseOptions("not")
if err == nil {
t.Error("Expected function to return error, got nil")
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment