Files
ozon-api-client/core.go
2024-04-30 13:03:08 +03:00

196 lines
3.8 KiB
Go

package core
import (
"fmt"
"net/http"
"reflect"
"strconv"
"strings"
"testing"
"time"
)
type CommonResponse struct {
StatusCode int
Code int `json:"code"`
Details []CommonResponseDetail `json:"details"`
Message string `json:"message"`
}
type CommonResponseDetail struct {
TypeUrl string `json:"typeUrl"`
Value string `json:"value"`
}
type Response struct {
CommonResponse
Data interface{}
}
func (r Response) CopyCommonResponse(rhs *CommonResponse) {
rhs.Code = r.Code
rhs.Details = r.Details
rhs.StatusCode = r.StatusCode
rhs.Message = r.Message
}
func getDefaultValues(v reflect.Value) error {
vValue := v.Elem()
vType := vValue.Type()
for i := 0; i < vType.NumField(); i++ {
field := vType.Field(i)
switch field.Type.Kind() {
case reflect.Slice:
for j := 0; j < vValue.Field(i).Len(); j++ {
// skip if slice type is primitive
if vValue.Field(i).Index(j).Kind() != reflect.Struct {
continue
}
// Attach any slices as query params
err := getDefaultValues(vValue.Field(i).Index(j).Addr())
if err != nil {
return err
}
}
case reflect.String:
isNil, err := isZero(vValue.Field(i).Addr())
if err != nil {
return err
}
if !isNil {
continue
}
defaultValue, ok := field.Tag.Lookup("default")
if !ok {
continue
}
vValue.Field(i).SetString(defaultValue)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
isNil, err := isZero(vValue.Field(i).Addr())
if err != nil {
return err
}
if !isNil {
continue
}
defaultValue, ok := field.Tag.Lookup("default")
if !ok {
continue
}
defaultValueInt, err := strconv.Atoi(defaultValue)
if err != nil {
return err
}
vValue.Field(i).SetInt(int64(defaultValueInt))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
isNil, err := isZero(vValue.Field(i).Addr())
if err != nil {
return err
}
if !isNil {
continue
}
defaultValue, ok := field.Tag.Lookup("default")
if !ok {
continue
}
defaultValueUint, err := strconv.ParseUint(defaultValue, 10, 64)
if err != nil {
return err
}
vValue.Field(i).SetUint(uint64(defaultValueUint))
case reflect.Struct:
err := getDefaultValues(vValue.Field(i).Addr())
if err != nil {
return err
}
case reflect.Ptr:
isNil, err := isZero(vValue.Field(i).Addr())
if err != nil {
return err
}
if isNil {
continue
}
if err := getDefaultValues(vValue.Field(i)); err != nil {
return err
}
default:
continue
}
}
return nil
}
func buildRawQuery(req *http.Request, v interface{}) (string, error) {
query := req.URL.Query()
if v == nil {
return query.Encode(), nil
}
err := getDefaultValues(reflect.ValueOf(v))
if err != nil {
return "", err
}
return query.Encode(), nil
}
func isZero(v reflect.Value) (bool, error) {
t := v.Elem().Type()
if !t.Comparable() {
return false, fmt.Errorf("type is not comparable: %v", t)
}
return reflect.Zero(t).Equal(v.Elem()), nil
}
func TimeFromString(t *testing.T, format, datetime string) time.Time {
dt, err := time.Parse(format, datetime)
if err != nil {
t.Errorf("error when parsing time: %s", err)
}
return dt
}
const LayoutRequestDateDefault = "2006-01-02"
type RequestDate struct {
time.Time
layout string
}
func NewRequestDate(t time.Time, layout string) *RequestDate {
return &RequestDate{
Time: t,
layout: layout,
}
}
func (rd *RequestDate) UnmarshalJSON(b []byte) (err error) {
s := strings.Trim(string(b), `"`) // remove quotes
if s == "null" {
return
}
rd.Time, err = time.Parse(rd.layout, s)
return
}
func (rd *RequestDate) MarshalJSON() ([]byte, error) {
if rd.Time.IsZero() {
return nil, nil
}
return []byte(fmt.Sprintf(`"%s"`, rd.Time.Format(rd.layout))), nil
}