finish get_rcs_list.go
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
)
|
||||
|
||||
// MarshalQueryParams 基于 struct 字段的 json tag 自动构建 URL 查询参数 map。
|
||||
//
|
||||
// 规则:
|
||||
// - 字段必须有 json tag,tag 名(逗号前的部分)作为参数 key
|
||||
// - 指针字段为 nil 时跳过(对应 optional 语义);非 nil 时解引用处理
|
||||
// - 基础类型(string / int / uint / float / bool)转为字符串
|
||||
// - 复杂类型(struct / map / slice 等)自动 marshal 为 JSON 字符串
|
||||
// - 无 json tag 或 tag 为 "-" 的字段被忽略
|
||||
func MarshalQueryParams(v any) (map[string]string, error) {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
if rv.IsNil() {
|
||||
return nil, nil
|
||||
}
|
||||
rv = rv.Elem()
|
||||
}
|
||||
if rv.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("MarshalQueryParams: 期望 struct,实际 %s", rv.Kind())
|
||||
}
|
||||
|
||||
rst := make(map[string]string)
|
||||
rt := rv.Type()
|
||||
for i := 0; i < rt.NumField(); i++ {
|
||||
field := rt.Field(i)
|
||||
tag := field.Tag.Get("json")
|
||||
if tag == "" || tag == "-" {
|
||||
continue
|
||||
}
|
||||
name, _, _ := strings.Cut(tag, ",")
|
||||
|
||||
fv := rv.Field(i)
|
||||
if fv.Kind() == reflect.Ptr {
|
||||
if fv.IsNil() {
|
||||
continue
|
||||
}
|
||||
fv = fv.Elem()
|
||||
}
|
||||
|
||||
val, err := queryValue(fv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("MarshalQueryParams: 字段 %s: %w", field.Name, err)
|
||||
}
|
||||
rst[name] = val
|
||||
}
|
||||
return rst, nil
|
||||
}
|
||||
|
||||
func queryValue(v reflect.Value) (string, error) {
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
return v.String(), nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(v.Int(), 10), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(v.Uint(), 10), nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil
|
||||
case reflect.Bool:
|
||||
return strconv.FormatBool(v.Bool()), nil
|
||||
default:
|
||||
if !v.CanInterface() {
|
||||
return "", fmt.Errorf("无法读取未导出字段")
|
||||
}
|
||||
b, err := sonic.Marshal(v.Interface())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type queryParamsSample struct {
|
||||
IsRGpu *bool `json:"is_rgpu"`
|
||||
Limit int `json:"limit"`
|
||||
Name string `json:"name"`
|
||||
Options StandQueryParameters `json:"options"`
|
||||
Tags []string `json:"tags"`
|
||||
Skip string `json:"-"`
|
||||
NoTag string
|
||||
}
|
||||
|
||||
func TestMarshalQueryParams(t *testing.T) {
|
||||
isGPU := true
|
||||
s := &queryParamsSample{
|
||||
IsRGpu: &isGPU,
|
||||
Limit: 10,
|
||||
Name: "hello",
|
||||
Options: StandQueryParameters{
|
||||
Page: 2,
|
||||
PerPage: 20,
|
||||
},
|
||||
Tags: []string{"a", "b"},
|
||||
}
|
||||
|
||||
m, err := MarshalQueryParams(s)
|
||||
if err != nil {
|
||||
t.Fatalf("MarshalQueryParams() error = %v", err)
|
||||
}
|
||||
|
||||
want := map[string]string{
|
||||
"is_rgpu": "true",
|
||||
"limit": "10",
|
||||
"name": "hello",
|
||||
"options": `{"columnFilters":{},"sort":null,"page":2,"perPage":20}`,
|
||||
"tags": `["a","b"]`,
|
||||
}
|
||||
if !reflect.DeepEqual(m, want) {
|
||||
t.Errorf("MarshalQueryParams() = %v, want %v", m, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalQueryParamsNilPtr(t *testing.T) {
|
||||
s := &queryParamsSample{} // IsRGpu 为 nil
|
||||
m, err := MarshalQueryParams(s)
|
||||
if err != nil {
|
||||
t.Fatalf("MarshalQueryParams() error = %v", err)
|
||||
}
|
||||
|
||||
// nil 指针跳过,无 json tag 和 "-" 的字段跳过
|
||||
if _, ok := m["is_rgpu"]; ok {
|
||||
t.Errorf("nil 指针字段 is_rgpu 不应输出")
|
||||
}
|
||||
if _, ok := m["Skip"]; ok {
|
||||
t.Errorf("tag 为 '-' 的字段不应输出")
|
||||
}
|
||||
if _, ok := m["NoTag"]; ok {
|
||||
t.Errorf("无 json tag 的字段不应输出")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalQueryParamsNonStruct(t *testing.T) {
|
||||
_, err := MarshalQueryParams(42)
|
||||
if err == nil {
|
||||
t.Errorf("非 struct 入参应返回错误")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user