db 管理初始化
This commit is contained in:
parent
00f5f1bde7
commit
2f915f225d
|
@ -3,5 +3,5 @@ package common
|
||||||
const (
|
const (
|
||||||
TOKEN_PRE = "player_token_"
|
TOKEN_PRE = "player_token_"
|
||||||
TOKEN_Admin = "Admin_token_"
|
TOKEN_Admin = "Admin_token_"
|
||||||
ADMIN_V1 = "/admin/api/v1"
|
ADMIN_OAUTH_V1 = "/admin/api/oauth/v1"
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package backend
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cron_admin/app/constants/errorcode"
|
||||||
|
"cron_admin/app/http/controllers"
|
||||||
|
"cron_admin/app/http/entities/backend"
|
||||||
|
"cron_admin/app/services/db_service"
|
||||||
|
"cron_admin/app/utils/helper"
|
||||||
|
"cron_admin/app/utils/mapstructure"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DbList(c *gin.Context) {
|
||||||
|
request := controllers.GetRequest(c).(*backend.DbListRequest)
|
||||||
|
count, DbListInfo, err := db_service.DbList(request, request.Page, request.Limit)
|
||||||
|
if err != nil {
|
||||||
|
controllers.HandCodeRes(c, nil, errorcode.ParamError)
|
||||||
|
} else {
|
||||||
|
var DbListResponse []backend.DbListResponse
|
||||||
|
_ = mapstructure.DecodeWithTime(DbListInfo, &DbListResponse, helper.DefaultFormatLayout)
|
||||||
|
controllers.HandRes(c, gin.H{"data": DbListResponse, "count": count}, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DbAdd(c *gin.Context) {
|
||||||
|
request := controllers.GetRequest(c).(*backend.DbAddRequest)
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package backend
|
||||||
|
|
||||||
|
type DbListRequest struct {
|
||||||
|
Page int `json:"page" validate:"required" form:"page" example:"1"`
|
||||||
|
Limit int `json:"limit" validate:"required" form:"limit" example:"10"`
|
||||||
|
DbName string `json:"db_name" form:"db_name" example:""`
|
||||||
|
Status int `json:"status" form:"status" example:"1"`
|
||||||
|
DbType string `json:"db_type" form:"db_type" example:"mysql"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DbListResponse struct {
|
||||||
|
DbId string `json:"db_id"`
|
||||||
|
DbName string `json:"db_name"`
|
||||||
|
DbType string `json:"db_type"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
DbPermission int `json:"db_permission"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
CreateTime string `json:"create_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DbAddRequest struct {
|
||||||
|
}
|
|
@ -1,8 +1,13 @@
|
||||||
package requestmapping
|
package requestmapping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cron_admin/app/constants/common"
|
||||||
|
"cron_admin/app/http/entities/backend"
|
||||||
|
)
|
||||||
|
|
||||||
var BackendRequestMap = map[string]func() interface{}{
|
var BackendRequestMap = map[string]func() interface{}{
|
||||||
|
|
||||||
//common.ADMIN_V1 + "/product/create": func() interface{} {
|
common.ADMIN_OAUTH_V1 + "/sql/list": func() interface{} {
|
||||||
// return new(backend.ProductCreateRequest)
|
return new(backend.DbListRequest)
|
||||||
//},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ func RegisterAdminRoute(router *gin.Engine) {
|
||||||
//数据库管理
|
//数据库管理
|
||||||
sql := v1.Group("/sql")
|
sql := v1.Group("/sql")
|
||||||
{
|
{
|
||||||
sql.GET("/list", backend.Empty)
|
sql.POST("/list", backend.DbList)
|
||||||
}
|
}
|
||||||
//任务
|
//任务
|
||||||
cmd := v1.Group("/cmd")
|
cmd := v1.Group("/cmd")
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package db_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cron_admin/app/http/entities/backend"
|
||||||
|
"cron_admin/app/models/crondbmodel"
|
||||||
|
"xorm.io/builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DbList(request *backend.DbListRequest, page int, limit int) (count int64, DbListInfo []crondbmodel.CronDb, err error) {
|
||||||
|
conn := builder.NewCond()
|
||||||
|
if request.DbName != "" {
|
||||||
|
conn = conn.And(builder.Like{"DbName", request.DbName})
|
||||||
|
}
|
||||||
|
if request.DbType != "" {
|
||||||
|
conn = conn.And(builder.Like{"DbType", request.DbType})
|
||||||
|
}
|
||||||
|
if request.Status != 0 {
|
||||||
|
conn = conn.And(builder.Eq{"Status": request.Status})
|
||||||
|
}
|
||||||
|
session := crondbmodel.GetInstance().GetDb().Where(conn)
|
||||||
|
if page != 0 && limit != 0 {
|
||||||
|
session = session.Limit(limit, (page-1)*limit)
|
||||||
|
}
|
||||||
|
count, err = session.FindAndCount(&DbListInfo)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import "github.com/duke-git/lancet/v2/slice"
|
||||||
|
|
||||||
|
func SliceConvertSlice[O int | int32 | int64 | int8, T int | int32 | int64 | int8](inputSlice []T) []O {
|
||||||
|
output := slice.Map(inputSlice, func(_ int, item T) O {
|
||||||
|
return O(item)
|
||||||
|
})
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeInt64Slices 合并两个 []O 切片为一个新的 []O 切片
|
||||||
|
func MergeInt64Slices[O int | int32 | int64 | int8](a, b []O) []O {
|
||||||
|
length := len(a) + len(b)
|
||||||
|
merged := make([]O, length)
|
||||||
|
copy(merged, a)
|
||||||
|
copy(merged[len(a):], b)
|
||||||
|
return merged
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMergeInt64Slices(t *testing.T) {
|
||||||
|
v1 := []int64{1, 2}
|
||||||
|
v2 := []int64{4, 3}
|
||||||
|
v := MergeInt64Slices(v1, v2)
|
||||||
|
fmt.Printf("%v", v)
|
||||||
|
vv := append(v1, v2...)
|
||||||
|
fmt.Printf("%v", vv)
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultParseFormatLayout = "2006-1-02 15:04:05" // 默认解析时间格式
|
||||||
|
DefaultFormatLayout = "2006-01-02 15:04:05" // 默认时间格式
|
||||||
|
MicroFormatLayout = "2006-01-02 15:04:05.000000" // 微秒时间格式
|
||||||
|
FormatLayout = "20060102150405" // 导出时间格式
|
||||||
|
)
|
||||||
|
|
||||||
|
func AfterMinutesUnix(minutes int64) int64 {
|
||||||
|
// 获取当前时间
|
||||||
|
currentTime := time.Now()
|
||||||
|
// 将当前时间增加5分钟
|
||||||
|
currentTime = currentTime.Add(time.Duration(minutes) * time.Minute)
|
||||||
|
// 转换为Unix时间戳(秒)
|
||||||
|
return currentTime.Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
func DateStringToTime(localTimeStr string) (time.Time, error) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
LogErr(errors.New("时间转换错误:" + localTimeStr))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if localTimeStr == "" {
|
||||||
|
return time.Time{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
layouts := []string{
|
||||||
|
DefaultParseFormatLayout,
|
||||||
|
DefaultFormatLayout,
|
||||||
|
"2006-01-02 15:04",
|
||||||
|
"2006-1-02 15:04",
|
||||||
|
"2006-01-02",
|
||||||
|
"2006-1-02",
|
||||||
|
time.RFC3339Nano,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
localTime time.Time
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
loc, _ := time.LoadLocation(GetTimeZone())
|
||||||
|
for _, layout := range layouts {
|
||||||
|
localTime, err = time.ParseInLocation(layout, localTimeStr, loc)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, errors.Errorf("解析时间错误: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return localTime, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeFormat 时间戳转时间格式
|
||||||
|
func TimeFormat(inTime *time.Time, layout ...string) string {
|
||||||
|
if inTime == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(layout) == 0 {
|
||||||
|
layout = []string{DefaultFormatLayout}
|
||||||
|
}
|
||||||
|
return inTime.Format(layout[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeStampFormat 时间戳转时间格式
|
||||||
|
func TimeStampFormat(timestamp int64, layout ...string) string {
|
||||||
|
if timestamp == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(layout) == 0 {
|
||||||
|
layout = []string{DefaultFormatLayout}
|
||||||
|
}
|
||||||
|
return time.Unix(timestamp, 0).Format(layout[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32TimeStampFormat int32类型时间戳转时间格式
|
||||||
|
func Int32TimeStampFormat(timestamp int32, layout ...string) string {
|
||||||
|
return TimeStampFormat(int64(timestamp), layout...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsoDateStringToTimeStamp iso格式字符串转时间戳
|
||||||
|
func IsoDateStringToTimeStamp(isoTimeStr string) (int64, error) {
|
||||||
|
isoTime, err := time.ParseInLocation(time.RFC3339Nano, isoTimeStr, time.Local)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return isoTime.Unix(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LayOutDateStringToTimeStamp layout格式字符串转时间戳
|
||||||
|
func LayOutDateStringToTimeStamp(localTimeStr string) (int64, error) {
|
||||||
|
localTime, err := time.ParseInLocation(DefaultFormatLayout, localTimeStr, time.Local)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return localTime.Unix(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DateStringToTimeStamp 字符串转时间戳(兼容格式)
|
||||||
|
func DateStringToTimeStamp(date string) (int64, error) {
|
||||||
|
u, err := IsoDateStringToTimeStamp(date)
|
||||||
|
if err != nil {
|
||||||
|
u, err = LayOutDateStringToTimeStamp(date)
|
||||||
|
}
|
||||||
|
return u, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DateStringToTimeStampInt32 字符串转时间戳(兼容格式)
|
||||||
|
func DateStringToTimeStampInt32(date string) (int32, error) {
|
||||||
|
u, err := DateStringToTimeStamp(date)
|
||||||
|
return int32(u), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchDateStringToTimeStampInt32 批量字符串转时间戳
|
||||||
|
func BatchDateStringToTimeStampInt32(dates []string) ([]int32, error) {
|
||||||
|
res := make([]int32, 0, len(dates))
|
||||||
|
for _, date := range dates {
|
||||||
|
u, err := DateStringToTimeStampInt32(date)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res = append(res, u)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoogleTimeToString google proto时间转字符串
|
||||||
|
func GoogleTimeToString(date *timestamppb.Timestamp) string {
|
||||||
|
loc, _ := time.LoadLocation(GetTimeZone())
|
||||||
|
return date.AsTime().In(loc).Format(DefaultFormatLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoogleTimeToMicroString google proto时间转字符串
|
||||||
|
func GoogleTimeToMicroString(date *timestamppb.Timestamp) string {
|
||||||
|
loc, _ := time.LoadLocation(GetTimeZone())
|
||||||
|
return date.AsTime().In(loc).Format(MicroFormatLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DateStringToTimeStampV2(localTimeStr string) (int64, error) {
|
||||||
|
if localTimeStr == "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
layouts := []string{
|
||||||
|
DefaultParseFormatLayout,
|
||||||
|
DefaultFormatLayout,
|
||||||
|
"2006-01-02 15:04",
|
||||||
|
"2006-1-02 15:04",
|
||||||
|
"2006-01-02",
|
||||||
|
"2006-1-02",
|
||||||
|
time.RFC3339Nano,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
localTime time.Time
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
loc, _ := time.LoadLocation(GetTimeZone())
|
||||||
|
for _, layout := range layouts {
|
||||||
|
localTime, err = time.ParseInLocation(layout, localTimeStr, loc)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Errorf("解析时间错误: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return localTime.Unix(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTimeStrBefore 时间比较 格式:2006-01-02 15:04:05
|
||||||
|
func IsTimeStrBefore(beforeTime, afterTime string) bool {
|
||||||
|
time1, _ := time.Parse(DefaultFormatLayout, beforeTime)
|
||||||
|
time2, _ := time.Parse(DefaultFormatLayout, afterTime)
|
||||||
|
if time1.Before(time2) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTimeBefore 时间比较 格式:2006-01-02 15:04:05
|
||||||
|
func IsTimeBefore(beforeTime, afterTime time.Time) bool {
|
||||||
|
if beforeTime.Before(afterTime) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDateStringToTime(t *testing.T) {
|
||||||
|
got, err := DateStringToTime("2024-01-01 00:00:00")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("DateStringToTime() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Log(got)
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultTimeZone = "Asia/Shanghai" // 时区
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetEnv(name string) string {
|
||||||
|
return os.Getenv(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetEnvWithDefault(name string, defaultValue string) string {
|
||||||
|
value := GetEnv(name)
|
||||||
|
if value == "" {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTimeZone() string {
|
||||||
|
return GetEnvWithDefault("TZ", DefaultTimeZone)
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/go-kratos/kratos/v2/transport/http"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/xuri/excelize/v2"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ImportFile(ctx http.Context) (map[string][]int32, error) {
|
||||||
|
// 获取上传的文件
|
||||||
|
file, _, err := ctx.Request().FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get form file: %w", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 解析Excel文件
|
||||||
|
f, err := excelize.OpenReader(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to open excel file: %w", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// 获取第一个工作表的名称
|
||||||
|
sheetNames := f.GetSheetList()
|
||||||
|
|
||||||
|
if len(sheetNames) == 0 {
|
||||||
|
return nil, fmt.Errorf("无效的excel,未获取到对应的sheet")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有行
|
||||||
|
rows, err := f.GetRows(sheetNames[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get rows from Excel sheet: %w", err)
|
||||||
|
}
|
||||||
|
if len(rows) == 0 {
|
||||||
|
return nil, fmt.Errorf("无效的excel,未获取到对应的记录数据")
|
||||||
|
}
|
||||||
|
|
||||||
|
actualHeaders := rows[0] // 获取第一行作为表头
|
||||||
|
var key int
|
||||||
|
for i, v := range actualHeaders {
|
||||||
|
if v == "ID" {
|
||||||
|
key = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个map来存储订单ID到SendInfo的映射
|
||||||
|
var ids []int32
|
||||||
|
// 遍历行并处理数据
|
||||||
|
for i, row := range rows {
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
continue // 跳过头栏
|
||||||
|
}
|
||||||
|
if row[key] != "" {
|
||||||
|
id, _ := strconv.Atoi(row[key])
|
||||||
|
ids = append(ids, int32(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return nil, errors.New("未获取到数据")
|
||||||
|
}
|
||||||
|
idsPb := map[string][]int32{"ids": ids}
|
||||||
|
|
||||||
|
return idsPb, nil
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/go-kratos/kratos/v2/transport/http"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetHeaderRealIP 获取header头中的真实IP
|
||||||
|
func GetHeaderRealIP(ctx context.Context) string {
|
||||||
|
serverContext, isOk := http.RequestFromServerContext(ctx)
|
||||||
|
if isOk {
|
||||||
|
return serverContext.Header.Get("X-Real-Ip")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClientIP 获取客户端IP
|
||||||
|
func GetClientIP(r *http.Request) string {
|
||||||
|
xForwardedFor := r.Header.Get("X-Forwarded-For")
|
||||||
|
ip := strings.TrimSpace(strings.Split(xForwardedFor, ",")[0])
|
||||||
|
if ip != "" {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))
|
||||||
|
if ip != "" {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPString2Long 把ip字符串转为数值(ipv4)
|
||||||
|
func IPString2Long(ip string) uint {
|
||||||
|
b := net.ParseIP(ip).To4()
|
||||||
|
if b == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/snowflake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateIDString() (string, error) {
|
||||||
|
node, err := snowflake.NewNode(time.Now().UnixMilli() % 1023)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return strconv.FormatInt(node.Generate().Int64(), 36), nil
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateIDString(t *testing.T) {
|
||||||
|
s, err := GenerateIDString()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Log(s)
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StringToInt64(s string) int64 {
|
||||||
|
i, _ := strconv.ParseInt(s, 10, 64)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringToInt32(s string) int32 {
|
||||||
|
i, _ := strconv.ParseInt(s, 10, 64)
|
||||||
|
return int32(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToInt32WithError 将字符串转换为int32
|
||||||
|
func StringToInt32WithError(s string) (int32, error) {
|
||||||
|
i, err := strconv.ParseInt(s, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int32(i), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToAsterisk 替换密钥中间字符为 *
|
||||||
|
func StringToAsterisk(value string) string {
|
||||||
|
length := len(value)
|
||||||
|
if length == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
asterisk := "*"
|
||||||
|
if length < 4 {
|
||||||
|
asterisk = strings.Repeat(asterisk, length)
|
||||||
|
return strings.Replace(value, value, asterisk, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := length / 4
|
||||||
|
asterisk = strings.Repeat(asterisk, length-offset*2)
|
||||||
|
return value[:offset] + asterisk + value[length-offset:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func StrSuffixNumSort(in []string) []string {
|
||||||
|
sort.Slice(in, func(i, j int) bool {
|
||||||
|
return getSuffixNumber(in[i]) < getSuffixNumber(in[j])
|
||||||
|
})
|
||||||
|
var result []string
|
||||||
|
for _, str := range in {
|
||||||
|
result = append(result, str)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取字符串中最后面的后缀数字
|
||||||
|
func getSuffixNumber(s string) int {
|
||||||
|
parts := strings.Split(s, "_")
|
||||||
|
lastPart := parts[len(parts)-1] // 获取最后一个部分
|
||||||
|
numStr := ""
|
||||||
|
for i := len(lastPart) - 1; i >= 0; i-- {
|
||||||
|
if _, err := strconv.Atoi(string(lastPart[i])); err == nil {
|
||||||
|
numStr = string(lastPart[i]) + numStr
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num, _ := strconv.Atoi(numStr)
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRandomStr(length int) string {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
// 去掉容易搞错的字符,例如0,1,l,L,0,O,o,I,i
|
||||||
|
const charset = "abcdefghjklmnpqrstuvwxyzABCDEFGHIJKMNPQRSTUVWXYZ123456789"
|
||||||
|
password := make([]byte, length)
|
||||||
|
for i := range password {
|
||||||
|
password[i] = charset[rand.Intn(len(charset))]
|
||||||
|
}
|
||||||
|
return string(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToTitleFirst(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
runes := []rune(s)
|
||||||
|
runes[0] = unicode.ToUpper(runes[0])
|
||||||
|
return string(runes)
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 测试 StringToInt32方法
|
||||||
|
func TestStringToInt32(t *testing.T) {
|
||||||
|
// 测试用例
|
||||||
|
type args struct {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want int32
|
||||||
|
}{
|
||||||
|
{name: "测试1", args: args{s: "123"}, want: 123},
|
||||||
|
{name: "测试2", args: args{s: "123.123"}, want: 0},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
// 调用方法
|
||||||
|
if got := StringToInt32(tt.args.s); got != tt.want {
|
||||||
|
// 判断结果
|
||||||
|
t.Errorf("StringToInt32() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReplaceStar(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
secretKey string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{name: "测试1", args: args{secretKey: "123456789"}, want: "12******89"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := StringToAsterisk(tt.args.secretKey)
|
||||||
|
t.Logf("StringToAsterisk() = %v, want %v \n", got, tt.want)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("StringToAsterisk() = %v, want %v \n", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandomPassword(t *testing.T) {
|
||||||
|
password := GetRandomStr(6)
|
||||||
|
fmt.Println("生成的随机密码为:", password)
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Log(name string, msg ...interface{}) {
|
||||||
|
_, file, line, _ := runtime.Caller(1)
|
||||||
|
timeLayout := "2006-01-01 03:04:05" //转化所需模板
|
||||||
|
var datetime = time.Unix(time.Now().Unix(), 0).Format(timeLayout)
|
||||||
|
fmt.Println(name, msg, file, line, datetime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogErr(err error) {
|
||||||
|
if err != nil {
|
||||||
|
Log("err", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Path(path string) (string, error) {
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
if err := os.MkdirAll(path, 0777); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FileExists(filePath string) bool {
|
||||||
|
_, err := os.Stat(filePath)
|
||||||
|
return err == nil || os.IsExist(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackTime 运行时间 defer TrackTime()()
|
||||||
|
func TrackTime() func() {
|
||||||
|
pre := time.Now()
|
||||||
|
return func() {
|
||||||
|
elapsed := time.Since(pre)
|
||||||
|
fmt.Println("elapsed:", elapsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ter 三目运算 Ter(true, 1, 2)
|
||||||
|
func Ter[T any](cond bool, a, b T) T {
|
||||||
|
if cond {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// get参转结构体
|
||||||
|
func ParseQueryStringToStruct(query string, target interface{}) error {
|
||||||
|
// 解析查询字符串
|
||||||
|
values, err := url.ParseQuery(query)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取目标结构体的反射值
|
||||||
|
rv := reflect.ValueOf(target).Elem()
|
||||||
|
|
||||||
|
// 遍历查询字符串中的每个键值对
|
||||||
|
for key, values := range values {
|
||||||
|
// 假设每个查询参数只传递一个值(如果有多个值,这里只取第一个)
|
||||||
|
value := values[0]
|
||||||
|
|
||||||
|
// 查找目标结构体中对应的字段
|
||||||
|
field := rv.FieldByName(strings.Title(key)) // 假设字段名与查询参数名相同,但首字母大写
|
||||||
|
if !field.IsValid() || !field.CanSet() {
|
||||||
|
// 如果找不到对应的字段,或者字段不可设置,则跳过
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据字段类型设置值
|
||||||
|
switch field.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
field.SetString(value)
|
||||||
|
case reflect.Int:
|
||||||
|
intValue, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
field.SetInt(int64(intValue))
|
||||||
|
// 可以根据需要添加更多类型处理
|
||||||
|
default:
|
||||||
|
// 不支持的类型,可以选择跳过或返回错误
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateMD5Hash 生成 MD5 的函数,接收一个实现了 proto.Message 接口的结构体
|
||||||
|
func GenerateMD5Hash(msg proto.Message) (string, error) {
|
||||||
|
// 使用 proto.Marshal 序列化结构体,proto.Marshal 接受任何实现 proto.Message 接口的结构体
|
||||||
|
data, err := proto.Marshal(msg)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to serialize message: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算 MD5
|
||||||
|
hash := md5.New()
|
||||||
|
hash.Write(data)
|
||||||
|
hashBytes := hash.Sum(nil)
|
||||||
|
|
||||||
|
// 返回 MD5 值的十六进制字符串
|
||||||
|
return fmt.Sprintf("%x", hashBytes), nil
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
|
// chineseMobileFormMatcher 手机号格式正则匹配器
|
||||||
|
var chineseMobileFormMatcher = regexp.MustCompile(`^1\d{10}$`)
|
||||||
|
|
||||||
|
// IsMobileForm 手机号格式,不严谨的验证
|
||||||
|
func IsMobileForm(mobile string) bool {
|
||||||
|
return chineseMobileFormMatcher.MatchString(mobile)
|
||||||
|
}
|
|
@ -0,0 +1,279 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns
|
||||||
|
// it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
|
||||||
|
func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
|
||||||
|
// Create variables here so we can reference them with the reflect pkg
|
||||||
|
var f1 DecodeHookFuncType
|
||||||
|
var f2 DecodeHookFuncKind
|
||||||
|
var f3 DecodeHookFuncValue
|
||||||
|
|
||||||
|
// Fill in the variables into this interface and the rest is done
|
||||||
|
// automatically using the reflect package.
|
||||||
|
potential := []interface{}{f1, f2, f3}
|
||||||
|
|
||||||
|
v := reflect.ValueOf(h)
|
||||||
|
vt := v.Type()
|
||||||
|
for _, raw := range potential {
|
||||||
|
pt := reflect.ValueOf(raw).Type()
|
||||||
|
if vt.ConvertibleTo(pt) {
|
||||||
|
return v.Convert(pt).Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeHookExec executes the given decode hook. This should be used
|
||||||
|
// since it'll naturally degrade to the older backwards compatible DecodeHookFunc
|
||||||
|
// that took reflect.Kind instead of reflect.Type.
|
||||||
|
func DecodeHookExec(
|
||||||
|
raw DecodeHookFunc,
|
||||||
|
from reflect.Value, to reflect.Value) (interface{}, error) {
|
||||||
|
|
||||||
|
switch f := typedDecodeHook(raw).(type) {
|
||||||
|
case DecodeHookFuncType:
|
||||||
|
return f(from.Type(), to.Type(), from.Interface())
|
||||||
|
case DecodeHookFuncKind:
|
||||||
|
return f(from.Kind(), to.Kind(), from.Interface())
|
||||||
|
case DecodeHookFuncValue:
|
||||||
|
return f(from, to)
|
||||||
|
default:
|
||||||
|
return nil, errors.New("invalid decode hook signature")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComposeDecodeHookFunc creates a single DecodeHookFunc that
|
||||||
|
// automatically composes multiple DecodeHookFuncs.
|
||||||
|
//
|
||||||
|
// The composed funcs are called in order, with the result of the
|
||||||
|
// previous transformation.
|
||||||
|
func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
|
||||||
|
return func(f reflect.Value, t reflect.Value) (interface{}, error) {
|
||||||
|
var err error
|
||||||
|
data := f.Interface()
|
||||||
|
|
||||||
|
newFrom := f
|
||||||
|
for _, f1 := range fs {
|
||||||
|
data, err = DecodeHookExec(f1, newFrom, t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newFrom = reflect.ValueOf(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
|
||||||
|
// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
|
||||||
|
func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {
|
||||||
|
return func(a, b reflect.Value) (interface{}, error) {
|
||||||
|
var allErrs string
|
||||||
|
var out interface{}
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for _, f := range ff {
|
||||||
|
out, err = DecodeHookExec(f, a, b)
|
||||||
|
if err != nil {
|
||||||
|
allErrs += err.Error() + "\n"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New(allErrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToSliceHookFunc returns a DecodeHookFunc that converts
|
||||||
|
// string to []string by splitting on the given sep.
|
||||||
|
func StringToSliceHookFunc(sep string) DecodeHookFunc {
|
||||||
|
return func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
if f != reflect.String || t != reflect.Slice {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
raw := data.(string)
|
||||||
|
if raw == "" {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Split(raw, sep), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
|
||||||
|
// strings to time.Duration.
|
||||||
|
func StringToTimeDurationHookFunc() DecodeHookFunc {
|
||||||
|
return func(
|
||||||
|
f reflect.Type,
|
||||||
|
t reflect.Type,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
if f.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
if t != reflect.TypeOf(time.Duration(5)) {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert it by parsing
|
||||||
|
return time.ParseDuration(data.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToIPHookFunc returns a DecodeHookFunc that converts
|
||||||
|
// strings to net.IP
|
||||||
|
func StringToIPHookFunc() DecodeHookFunc {
|
||||||
|
return func(
|
||||||
|
f reflect.Type,
|
||||||
|
t reflect.Type,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
if f.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
if t != reflect.TypeOf(net.IP{}) {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert it by parsing
|
||||||
|
ip := net.ParseIP(data.(string))
|
||||||
|
if ip == nil {
|
||||||
|
return net.IP{}, fmt.Errorf("failed parsing ip %v", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToIPNetHookFunc returns a DecodeHookFunc that converts
|
||||||
|
// strings to net.IPNet
|
||||||
|
func StringToIPNetHookFunc() DecodeHookFunc {
|
||||||
|
return func(
|
||||||
|
f reflect.Type,
|
||||||
|
t reflect.Type,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
if f.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
if t != reflect.TypeOf(net.IPNet{}) {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert it by parsing
|
||||||
|
_, net, err := net.ParseCIDR(data.(string))
|
||||||
|
return net, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToTimeHookFunc returns a DecodeHookFunc that converts
|
||||||
|
// strings to time.Time.
|
||||||
|
func StringToTimeHookFunc(layout string) DecodeHookFunc {
|
||||||
|
return func(
|
||||||
|
f reflect.Type,
|
||||||
|
t reflect.Type,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
if f.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
if t != reflect.TypeOf(time.Time{}) {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert it by parsing
|
||||||
|
return time.Parse(layout, data.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
|
||||||
|
// the decoder.
|
||||||
|
//
|
||||||
|
// Note that this is significantly different from the WeaklyTypedInput option
|
||||||
|
// of the DecoderConfig.
|
||||||
|
func WeaklyTypedHook(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
dataVal := reflect.ValueOf(data)
|
||||||
|
switch t {
|
||||||
|
case reflect.String:
|
||||||
|
switch f {
|
||||||
|
case reflect.Bool:
|
||||||
|
if dataVal.Bool() {
|
||||||
|
return "1", nil
|
||||||
|
}
|
||||||
|
return "0", nil
|
||||||
|
case reflect.Float32:
|
||||||
|
return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
|
||||||
|
case reflect.Int:
|
||||||
|
return strconv.FormatInt(dataVal.Int(), 10), nil
|
||||||
|
case reflect.Slice:
|
||||||
|
dataType := dataVal.Type()
|
||||||
|
elemKind := dataType.Elem().Kind()
|
||||||
|
if elemKind == reflect.Uint8 {
|
||||||
|
return string(dataVal.Interface().([]uint8)), nil
|
||||||
|
}
|
||||||
|
case reflect.Uint:
|
||||||
|
return strconv.FormatUint(dataVal.Uint(), 10), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecursiveStructToMapHookFunc() DecodeHookFunc {
|
||||||
|
return func(f reflect.Value, t reflect.Value) (interface{}, error) {
|
||||||
|
if f.Kind() != reflect.Struct {
|
||||||
|
return f.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var i interface{} = struct{}{}
|
||||||
|
if t.Type() != reflect.TypeOf(&i).Elem() {
|
||||||
|
return f.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
t.Set(reflect.ValueOf(m))
|
||||||
|
|
||||||
|
return f.Interface(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TextUnmarshallerHookFunc returns a DecodeHookFunc that applies
|
||||||
|
// strings to the UnmarshalText function, when the target type
|
||||||
|
// implements the encoding.TextUnmarshaler interface
|
||||||
|
func TextUnmarshallerHookFunc() DecodeHookFuncType {
|
||||||
|
return func(
|
||||||
|
f reflect.Type,
|
||||||
|
t reflect.Type,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
if f.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
result := reflect.New(t).Interface()
|
||||||
|
unmarshaller, ok := result.(encoding.TextUnmarshaler)
|
||||||
|
if !ok {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
if err := unmarshaller.UnmarshalText([]byte(data.(string))); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,567 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestComposeDecodeHookFunc(t *testing.T) {
|
||||||
|
f1 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return data.(string) + "foo", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return data.(string) + "bar", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f := ComposeDecodeHookFunc(f1, f2)
|
||||||
|
|
||||||
|
result, err := DecodeHookExec(
|
||||||
|
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bad: %s", err)
|
||||||
|
}
|
||||||
|
if result.(string) != "foobar" {
|
||||||
|
t.Fatalf("bad: %#v", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComposeDecodeHookFunc_err(t *testing.T) {
|
||||||
|
f1 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
|
||||||
|
return nil, errors.New("foo")
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
|
||||||
|
panic("NOPE")
|
||||||
|
}
|
||||||
|
|
||||||
|
f := ComposeDecodeHookFunc(f1, f2)
|
||||||
|
|
||||||
|
_, err := DecodeHookExec(
|
||||||
|
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
|
||||||
|
if err.Error() != "foo" {
|
||||||
|
t.Fatalf("bad: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComposeDecodeHookFunc_kinds(t *testing.T) {
|
||||||
|
var f2From reflect.Kind
|
||||||
|
|
||||||
|
f1 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return int(42), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
f2From = f
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f := ComposeDecodeHookFunc(f1, f2)
|
||||||
|
|
||||||
|
_, err := DecodeHookExec(
|
||||||
|
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bad: %s", err)
|
||||||
|
}
|
||||||
|
if f2From != reflect.Int {
|
||||||
|
t.Fatalf("bad: %#v", f2From)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrComposeDecodeHookFunc(t *testing.T) {
|
||||||
|
f1 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return data.(string) + "foo", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return data.(string) + "bar", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f := OrComposeDecodeHookFunc(f1, f2)
|
||||||
|
|
||||||
|
result, err := DecodeHookExec(
|
||||||
|
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bad: %s", err)
|
||||||
|
}
|
||||||
|
if result.(string) != "foo" {
|
||||||
|
t.Fatalf("bad: %#v", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrComposeDecodeHookFunc_correctValueIsLast(t *testing.T) {
|
||||||
|
f1 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return nil, errors.New("f1 error")
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return nil, errors.New("f2 error")
|
||||||
|
}
|
||||||
|
|
||||||
|
f3 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return data.(string) + "bar", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f := OrComposeDecodeHookFunc(f1, f2, f3)
|
||||||
|
|
||||||
|
result, err := DecodeHookExec(
|
||||||
|
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bad: %s", err)
|
||||||
|
}
|
||||||
|
if result.(string) != "bar" {
|
||||||
|
t.Fatalf("bad: %#v", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOrComposeDecodeHookFunc_err(t *testing.T) {
|
||||||
|
f1 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return nil, errors.New("f1 error")
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 := func(
|
||||||
|
f reflect.Kind,
|
||||||
|
t reflect.Kind,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
return nil, errors.New("f2 error")
|
||||||
|
}
|
||||||
|
|
||||||
|
f := OrComposeDecodeHookFunc(f1, f2)
|
||||||
|
|
||||||
|
_, err := DecodeHookExec(
|
||||||
|
f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("bad: should return an error")
|
||||||
|
}
|
||||||
|
if err.Error() != "f1 error\nf2 error\n" {
|
||||||
|
t.Fatalf("bad: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComposeDecodeHookFunc_safe_nofuncs(t *testing.T) {
|
||||||
|
f := ComposeDecodeHookFunc()
|
||||||
|
type myStruct2 struct {
|
||||||
|
MyInt int
|
||||||
|
}
|
||||||
|
|
||||||
|
type myStruct1 struct {
|
||||||
|
Blah map[string]myStruct2
|
||||||
|
}
|
||||||
|
|
||||||
|
src := &myStruct1{Blah: map[string]myStruct2{
|
||||||
|
"test": {
|
||||||
|
MyInt: 1,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
dst := &myStruct1{}
|
||||||
|
dConf := &DecoderConfig{
|
||||||
|
Result: dst,
|
||||||
|
ErrorUnused: true,
|
||||||
|
DecodeHook: f,
|
||||||
|
}
|
||||||
|
d, err := NewDecoder(dConf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = d.Decode(src)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringToSliceHookFunc(t *testing.T) {
|
||||||
|
f := StringToSliceHookFunc(",")
|
||||||
|
|
||||||
|
strValue := reflect.ValueOf("42")
|
||||||
|
sliceValue := reflect.ValueOf([]byte("42"))
|
||||||
|
cases := []struct {
|
||||||
|
f, t reflect.Value
|
||||||
|
result interface{}
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{sliceValue, sliceValue, []byte("42"), false},
|
||||||
|
{strValue, strValue, "42", false},
|
||||||
|
{
|
||||||
|
reflect.ValueOf("foo,bar,baz"),
|
||||||
|
sliceValue,
|
||||||
|
[]string{"foo", "bar", "baz"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reflect.ValueOf(""),
|
||||||
|
sliceValue,
|
||||||
|
[]string{},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
||||||
|
if tc.err != (err != nil) {
|
||||||
|
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actual, tc.result) {
|
||||||
|
t.Fatalf(
|
||||||
|
"case %d: expected %#v, got %#v",
|
||||||
|
i, tc.result, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringToTimeDurationHookFunc(t *testing.T) {
|
||||||
|
f := StringToTimeDurationHookFunc()
|
||||||
|
|
||||||
|
timeValue := reflect.ValueOf(time.Duration(5))
|
||||||
|
strValue := reflect.ValueOf("")
|
||||||
|
cases := []struct {
|
||||||
|
f, t reflect.Value
|
||||||
|
result interface{}
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{reflect.ValueOf("5s"), timeValue, 5 * time.Second, false},
|
||||||
|
{reflect.ValueOf("5"), timeValue, time.Duration(0), true},
|
||||||
|
{reflect.ValueOf("5"), strValue, "5", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
||||||
|
if tc.err != (err != nil) {
|
||||||
|
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actual, tc.result) {
|
||||||
|
t.Fatalf(
|
||||||
|
"case %d: expected %#v, got %#v",
|
||||||
|
i, tc.result, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringToTimeHookFunc(t *testing.T) {
|
||||||
|
strValue := reflect.ValueOf("5")
|
||||||
|
timeValue := reflect.ValueOf(time.Time{})
|
||||||
|
cases := []struct {
|
||||||
|
f, t reflect.Value
|
||||||
|
layout string
|
||||||
|
result interface{}
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{reflect.ValueOf("2006-01-02T15:04:05Z"), timeValue, time.RFC3339,
|
||||||
|
time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC), false},
|
||||||
|
{strValue, timeValue, time.RFC3339, time.Time{}, true},
|
||||||
|
{strValue, strValue, time.RFC3339, "5", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
f := StringToTimeHookFunc(tc.layout)
|
||||||
|
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
||||||
|
if tc.err != (err != nil) {
|
||||||
|
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actual, tc.result) {
|
||||||
|
t.Fatalf(
|
||||||
|
"case %d: expected %#v, got %#v",
|
||||||
|
i, tc.result, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringToIPHookFunc(t *testing.T) {
|
||||||
|
strValue := reflect.ValueOf("5")
|
||||||
|
ipValue := reflect.ValueOf(net.IP{})
|
||||||
|
cases := []struct {
|
||||||
|
f, t reflect.Value
|
||||||
|
result interface{}
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{reflect.ValueOf("1.2.3.4"), ipValue,
|
||||||
|
net.IPv4(0x01, 0x02, 0x03, 0x04), false},
|
||||||
|
{strValue, ipValue, net.IP{}, true},
|
||||||
|
{strValue, strValue, "5", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
f := StringToIPHookFunc()
|
||||||
|
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
||||||
|
if tc.err != (err != nil) {
|
||||||
|
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actual, tc.result) {
|
||||||
|
t.Fatalf(
|
||||||
|
"case %d: expected %#v, got %#v",
|
||||||
|
i, tc.result, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringToIPNetHookFunc(t *testing.T) {
|
||||||
|
strValue := reflect.ValueOf("5")
|
||||||
|
ipNetValue := reflect.ValueOf(net.IPNet{})
|
||||||
|
var nilNet *net.IPNet = nil
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
f, t reflect.Value
|
||||||
|
result interface{}
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{reflect.ValueOf("1.2.3.4/24"), ipNetValue,
|
||||||
|
&net.IPNet{
|
||||||
|
IP: net.IP{0x01, 0x02, 0x03, 0x00},
|
||||||
|
Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00),
|
||||||
|
}, false},
|
||||||
|
{strValue, ipNetValue, nilNet, true},
|
||||||
|
{strValue, strValue, "5", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
f := StringToIPNetHookFunc()
|
||||||
|
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
||||||
|
if tc.err != (err != nil) {
|
||||||
|
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actual, tc.result) {
|
||||||
|
t.Fatalf(
|
||||||
|
"case %d: expected %#v, got %#v",
|
||||||
|
i, tc.result, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWeaklyTypedHook(t *testing.T) {
|
||||||
|
var f DecodeHookFunc = WeaklyTypedHook
|
||||||
|
|
||||||
|
strValue := reflect.ValueOf("")
|
||||||
|
cases := []struct {
|
||||||
|
f, t reflect.Value
|
||||||
|
result interface{}
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
// TO STRING
|
||||||
|
{
|
||||||
|
reflect.ValueOf(false),
|
||||||
|
strValue,
|
||||||
|
"0",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
reflect.ValueOf(true),
|
||||||
|
strValue,
|
||||||
|
"1",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
reflect.ValueOf(float32(7)),
|
||||||
|
strValue,
|
||||||
|
"7",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
reflect.ValueOf(int(7)),
|
||||||
|
strValue,
|
||||||
|
"7",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
reflect.ValueOf([]uint8("foo")),
|
||||||
|
strValue,
|
||||||
|
"foo",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
reflect.ValueOf(uint(7)),
|
||||||
|
strValue,
|
||||||
|
"7",
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
||||||
|
if tc.err != (err != nil) {
|
||||||
|
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actual, tc.result) {
|
||||||
|
t.Fatalf(
|
||||||
|
"case %d: expected %#v, got %#v",
|
||||||
|
i, tc.result, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStructToMapHookFuncTabled(t *testing.T) {
|
||||||
|
var f DecodeHookFunc = RecursiveStructToMapHookFunc()
|
||||||
|
|
||||||
|
type b struct {
|
||||||
|
TestKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
type a struct {
|
||||||
|
Sub b
|
||||||
|
}
|
||||||
|
|
||||||
|
testStruct := a{
|
||||||
|
Sub: b{
|
||||||
|
TestKey: "testval",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testMap := map[string]interface{}{
|
||||||
|
"Sub": map[string]interface{}{
|
||||||
|
"TestKey": "testval",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
receiver interface{}
|
||||||
|
input interface{}
|
||||||
|
expected interface{}
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"map receiver",
|
||||||
|
func() interface{} {
|
||||||
|
var res map[string]interface{}
|
||||||
|
return &res
|
||||||
|
}(),
|
||||||
|
testStruct,
|
||||||
|
&testMap,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"interface receiver",
|
||||||
|
func() interface{} {
|
||||||
|
var res interface{}
|
||||||
|
return &res
|
||||||
|
}(),
|
||||||
|
testStruct,
|
||||||
|
func() interface{} {
|
||||||
|
var exp interface{} = testMap
|
||||||
|
return &exp
|
||||||
|
}(),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slice receiver errors",
|
||||||
|
func() interface{} {
|
||||||
|
var res []string
|
||||||
|
return &res
|
||||||
|
}(),
|
||||||
|
testStruct,
|
||||||
|
new([]string),
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"slice to slice - no change",
|
||||||
|
func() interface{} {
|
||||||
|
var res []string
|
||||||
|
return &res
|
||||||
|
}(),
|
||||||
|
[]string{"a", "b"},
|
||||||
|
&[]string{"a", "b"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"string to string - no change",
|
||||||
|
func() interface{} {
|
||||||
|
var res string
|
||||||
|
return &res
|
||||||
|
}(),
|
||||||
|
"test",
|
||||||
|
func() *string {
|
||||||
|
s := "test"
|
||||||
|
return &s
|
||||||
|
}(),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
cfg := &DecoderConfig{
|
||||||
|
DecodeHook: f,
|
||||||
|
Result: tc.receiver,
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := NewDecoder(cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = d.Decode(tc.input)
|
||||||
|
if tc.err != (err != nil) {
|
||||||
|
t.Fatalf("expected err %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(tc.expected, tc.receiver) {
|
||||||
|
t.Fatalf("expected %#v, got %#v",
|
||||||
|
tc.expected, tc.receiver)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTextUnmarshallerHookFunc(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
f, t reflect.Value
|
||||||
|
result interface{}
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{reflect.ValueOf("42"), reflect.ValueOf(big.Int{}), big.NewInt(42), false},
|
||||||
|
{reflect.ValueOf("invalid"), reflect.ValueOf(big.Int{}), nil, true},
|
||||||
|
{reflect.ValueOf("5"), reflect.ValueOf("5"), "5", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range cases {
|
||||||
|
f := TextUnmarshallerHookFunc()
|
||||||
|
actual, err := DecodeHookExec(f, tc.f, tc.t)
|
||||||
|
if tc.err != (err != nil) {
|
||||||
|
t.Fatalf("case %d: expected err %#v", i, tc.err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actual, tc.result) {
|
||||||
|
t.Fatalf(
|
||||||
|
"case %d: expected %#v, got %#v",
|
||||||
|
i, tc.result, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error implements the error interface and can represents multiple
|
||||||
|
// errors that occur in the course of a single decode.
|
||||||
|
type Error struct {
|
||||||
|
Errors []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
points := make([]string, len(e.Errors))
|
||||||
|
for i, err := range e.Errors {
|
||||||
|
points[i] = fmt.Sprintf("* %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(points)
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%d error(s) decoding:\n\n%s",
|
||||||
|
len(e.Errors), strings.Join(points, "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrappedErrors implements the errwrap.Wrapper interface to make this
|
||||||
|
// return value more useful with the errwrap and go-multierror libraries.
|
||||||
|
func (e *Error) WrappedErrors() []error {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]error, len(e.Errors))
|
||||||
|
for i, e := range e.Errors {
|
||||||
|
result[i] = errors.New(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendErrors(errors []string, err error) []string {
|
||||||
|
switch e := err.(type) {
|
||||||
|
case *Error:
|
||||||
|
return append(errors, e.Errors...)
|
||||||
|
default:
|
||||||
|
return append(errors, e.Error())
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,285 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
Emails []string
|
||||||
|
Extra map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_Decode(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": "Mitchell",
|
||||||
|
"age": 91,
|
||||||
|
"emails": []string{"one", "two", "three"},
|
||||||
|
"extra": map[string]string{
|
||||||
|
"twitter": "mitchellh",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Decode(input, &result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeViaJSON takes the map data and passes it through encoding/json to convert it into the
|
||||||
|
// given Go native structure pointed to by v. v must be a pointer to a struct.
|
||||||
|
func decodeViaJSON(data interface{}, v interface{}) error {
|
||||||
|
// Perform the task by simply marshalling the input into JSON,
|
||||||
|
// then unmarshalling it into target native Go struct.
|
||||||
|
b, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return json.Unmarshal(b, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeViaJSON(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": "Mitchell",
|
||||||
|
"age": 91,
|
||||||
|
"emails": []string{"one", "two", "three"},
|
||||||
|
"extra": map[string]string{
|
||||||
|
"twitter": "mitchellh",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
decodeViaJSON(input, &result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_JSONUnmarshal(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": "Mitchell",
|
||||||
|
"age": 91,
|
||||||
|
"emails": []string{"one", "two", "three"},
|
||||||
|
"extra": map[string]string{
|
||||||
|
"twitter": "mitchellh",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
inputB, err := json.Marshal(input)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal("Failed to marshal test input:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
json.Unmarshal(inputB, &result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeBasic(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vstring": "foo",
|
||||||
|
"vint": 42,
|
||||||
|
"Vuint": 42,
|
||||||
|
"vbool": true,
|
||||||
|
"Vfloat": 42.42,
|
||||||
|
"vsilent": true,
|
||||||
|
"vdata": 42,
|
||||||
|
"vjsonInt": json.Number("1234"),
|
||||||
|
"vjsonFloat": json.Number("1234.5"),
|
||||||
|
"vjsonNumber": json.Number("1234.5"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
var result Basic
|
||||||
|
Decode(input, &result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeEmbedded(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vstring": "foo",
|
||||||
|
"Basic": map[string]interface{}{
|
||||||
|
"vstring": "innerfoo",
|
||||||
|
},
|
||||||
|
"vunique": "bar",
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Embedded
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Decode(input, &result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeTypeConversion(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"IntToFloat": 42,
|
||||||
|
"IntToUint": 42,
|
||||||
|
"IntToBool": 1,
|
||||||
|
"IntToString": 42,
|
||||||
|
"UintToInt": 42,
|
||||||
|
"UintToFloat": 42,
|
||||||
|
"UintToBool": 42,
|
||||||
|
"UintToString": 42,
|
||||||
|
"BoolToInt": true,
|
||||||
|
"BoolToUint": true,
|
||||||
|
"BoolToFloat": true,
|
||||||
|
"BoolToString": true,
|
||||||
|
"FloatToInt": 42.42,
|
||||||
|
"FloatToUint": 42.42,
|
||||||
|
"FloatToBool": 42.42,
|
||||||
|
"FloatToString": 42.42,
|
||||||
|
"StringToInt": "42",
|
||||||
|
"StringToUint": "42",
|
||||||
|
"StringToBool": "1",
|
||||||
|
"StringToFloat": "42.42",
|
||||||
|
"SliceToMap": []interface{}{},
|
||||||
|
"MapToSlice": map[string]interface{}{},
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultStrict TypeConversionResult
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Decode(input, &resultStrict)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeMap(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vfoo": "foo",
|
||||||
|
"vother": map[interface{}]interface{}{
|
||||||
|
"foo": "foo",
|
||||||
|
"bar": "bar",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Map
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Decode(input, &result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeMapOfStruct(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"value": map[string]interface{}{
|
||||||
|
"foo": map[string]string{"vstring": "one"},
|
||||||
|
"bar": map[string]string{"vstring": "two"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var result MapOfStruct
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Decode(input, &result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeSlice(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vfoo": "foo",
|
||||||
|
"vbar": []string{"foo", "bar", "baz"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Slice
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Decode(input, &result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeSliceOfStruct(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"value": []map[string]interface{}{
|
||||||
|
{"vstring": "one"},
|
||||||
|
{"vstring": "two"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var result SliceOfStruct
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Decode(input, &result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeWeaklyTypedInput(b *testing.B) {
|
||||||
|
// This input can come from anywhere, but typically comes from
|
||||||
|
// something like decoding JSON, generated by a weakly typed language
|
||||||
|
// such as PHP.
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": 123, // number => string
|
||||||
|
"age": "42", // string => number
|
||||||
|
"emails": map[string]interface{}{}, // empty map => empty array
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
config := &DecoderConfig{
|
||||||
|
WeaklyTypedInput: true,
|
||||||
|
Result: &result,
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(config)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
decoder.Decode(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeMetadata(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": "Mitchell",
|
||||||
|
"age": 91,
|
||||||
|
"email": "foo@bar.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
var md Metadata
|
||||||
|
var result Person
|
||||||
|
config := &DecoderConfig{
|
||||||
|
Metadata: &md,
|
||||||
|
Result: &result,
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(config)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
decoder.Decode(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeMetadataEmbedded(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vstring": "foo",
|
||||||
|
"vunique": "bar",
|
||||||
|
}
|
||||||
|
|
||||||
|
var md Metadata
|
||||||
|
var result EmbeddedSquash
|
||||||
|
config := &DecoderConfig{
|
||||||
|
Metadata: &md,
|
||||||
|
Result: &result,
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(config)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
decoder.Decode(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Benchmark_DecodeTagged(b *testing.B) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
"bar": "value",
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Tagged
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Decode(input, &result)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,627 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GH-1, GH-10, GH-96
|
||||||
|
func TestDecode_NilValue(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
in interface{}
|
||||||
|
target interface{}
|
||||||
|
out interface{}
|
||||||
|
metaKeys []string
|
||||||
|
metaUnused []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"all nil",
|
||||||
|
&map[string]interface{}{
|
||||||
|
"vfoo": nil,
|
||||||
|
"vother": nil,
|
||||||
|
},
|
||||||
|
&Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
|
||||||
|
&Map{Vfoo: "", Vother: nil},
|
||||||
|
[]string{"Vfoo", "Vother"},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partial nil",
|
||||||
|
&map[string]interface{}{
|
||||||
|
"vfoo": "baz",
|
||||||
|
"vother": nil,
|
||||||
|
},
|
||||||
|
&Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
|
||||||
|
&Map{Vfoo: "baz", Vother: nil},
|
||||||
|
[]string{"Vfoo", "Vother"},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"partial decode",
|
||||||
|
&map[string]interface{}{
|
||||||
|
"vother": nil,
|
||||||
|
},
|
||||||
|
&Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
|
||||||
|
&Map{Vfoo: "foo", Vother: nil},
|
||||||
|
[]string{"Vother"},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unused values",
|
||||||
|
&map[string]interface{}{
|
||||||
|
"vbar": "bar",
|
||||||
|
"vfoo": nil,
|
||||||
|
"vother": nil,
|
||||||
|
},
|
||||||
|
&Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
|
||||||
|
&Map{Vfoo: "", Vother: nil},
|
||||||
|
[]string{"Vfoo", "Vother"},
|
||||||
|
[]string{"vbar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map interface all nil",
|
||||||
|
&map[interface{}]interface{}{
|
||||||
|
"vfoo": nil,
|
||||||
|
"vother": nil,
|
||||||
|
},
|
||||||
|
&Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
|
||||||
|
&Map{Vfoo: "", Vother: nil},
|
||||||
|
[]string{"Vfoo", "Vother"},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map interface partial nil",
|
||||||
|
&map[interface{}]interface{}{
|
||||||
|
"vfoo": "baz",
|
||||||
|
"vother": nil,
|
||||||
|
},
|
||||||
|
&Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
|
||||||
|
&Map{Vfoo: "baz", Vother: nil},
|
||||||
|
[]string{"Vfoo", "Vother"},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map interface partial decode",
|
||||||
|
&map[interface{}]interface{}{
|
||||||
|
"vother": nil,
|
||||||
|
},
|
||||||
|
&Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
|
||||||
|
&Map{Vfoo: "foo", Vother: nil},
|
||||||
|
[]string{"Vother"},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map interface unused values",
|
||||||
|
&map[interface{}]interface{}{
|
||||||
|
"vbar": "bar",
|
||||||
|
"vfoo": nil,
|
||||||
|
"vother": nil,
|
||||||
|
},
|
||||||
|
&Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
|
||||||
|
&Map{Vfoo: "", Vother: nil},
|
||||||
|
[]string{"Vfoo", "Vother"},
|
||||||
|
[]string{"vbar"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
config := &DecoderConfig{
|
||||||
|
Metadata: new(Metadata),
|
||||||
|
Result: tc.target,
|
||||||
|
ZeroFields: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("should not error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = decoder.Decode(tc.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("should not error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(tc.out, tc.target) {
|
||||||
|
t.Fatalf("%q: TestDecode_NilValue() expected: %#v, got: %#v", tc.name, tc.out, tc.target)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(tc.metaKeys, config.Metadata.Keys) {
|
||||||
|
t.Fatalf("%q: Metadata.Keys mismatch expected: %#v, got: %#v", tc.name, tc.metaKeys, config.Metadata.Keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(tc.metaUnused, config.Metadata.Unused) {
|
||||||
|
t.Fatalf("%q: Metadata.Unused mismatch expected: %#v, got: %#v", tc.name, tc.metaUnused, config.Metadata.Unused)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #48
|
||||||
|
func TestNestedTypePointerWithDefaults(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vfoo": "foo",
|
||||||
|
"vbar": map[string]interface{}{
|
||||||
|
"vstring": "foo",
|
||||||
|
"vint": 42,
|
||||||
|
"vbool": true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := NestedPointer{
|
||||||
|
Vbar: &Basic{
|
||||||
|
Vuint: 42,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := Decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got an err: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vfoo != "foo" {
|
||||||
|
t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vbar.Vstring != "foo" {
|
||||||
|
t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vbar.Vint != 42 {
|
||||||
|
t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vbar.Vbool != true {
|
||||||
|
t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vbar.Vextra != "" {
|
||||||
|
t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the error
|
||||||
|
if result.Vbar.Vuint != 42 {
|
||||||
|
t.Errorf("vuint value should be 42: %#v", result.Vbar.Vuint)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type NestedSlice struct {
|
||||||
|
Vfoo string
|
||||||
|
Vbars []Basic
|
||||||
|
Vempty []Basic
|
||||||
|
}
|
||||||
|
|
||||||
|
// #48
|
||||||
|
func TestNestedTypeSliceWithDefaults(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vfoo": "foo",
|
||||||
|
"vbars": []map[string]interface{}{
|
||||||
|
{"vstring": "foo", "vint": 42, "vbool": true},
|
||||||
|
{"vint": 42, "vbool": true},
|
||||||
|
},
|
||||||
|
"vempty": []map[string]interface{}{
|
||||||
|
{"vstring": "foo", "vint": 42, "vbool": true},
|
||||||
|
{"vint": 42, "vbool": true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := NestedSlice{
|
||||||
|
Vbars: []Basic{
|
||||||
|
{Vuint: 42},
|
||||||
|
{Vstring: "foo"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := Decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got an err: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vfoo != "foo" {
|
||||||
|
t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vbars[0].Vstring != "foo" {
|
||||||
|
t.Errorf("vstring value should be 'foo': %#v", result.Vbars[0].Vstring)
|
||||||
|
}
|
||||||
|
// this is the error
|
||||||
|
if result.Vbars[0].Vuint != 42 {
|
||||||
|
t.Errorf("vuint value should be 42: %#v", result.Vbars[0].Vuint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #48 workaround
|
||||||
|
func TestNestedTypeWithDefaults(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vfoo": "foo",
|
||||||
|
"vbar": map[string]interface{}{
|
||||||
|
"vstring": "foo",
|
||||||
|
"vint": 42,
|
||||||
|
"vbool": true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := Nested{
|
||||||
|
Vbar: Basic{
|
||||||
|
Vuint: 42,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := Decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got an err: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vfoo != "foo" {
|
||||||
|
t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vbar.Vstring != "foo" {
|
||||||
|
t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vbar.Vint != 42 {
|
||||||
|
t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vbar.Vbool != true {
|
||||||
|
t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Vbar.Vextra != "" {
|
||||||
|
t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the error
|
||||||
|
if result.Vbar.Vuint != 42 {
|
||||||
|
t.Errorf("vuint value should be 42: %#v", result.Vbar.Vuint)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// #67 panic() on extending slices (decodeSlice with disabled ZeroValues)
|
||||||
|
func TestDecodeSliceToEmptySliceWOZeroing(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type TestStruct struct {
|
||||||
|
Vfoo []string
|
||||||
|
}
|
||||||
|
|
||||||
|
decode := func(m interface{}, rawVal interface{}) error {
|
||||||
|
config := &DecoderConfig{
|
||||||
|
Metadata: nil,
|
||||||
|
Result: rawVal,
|
||||||
|
ZeroFields: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return decoder.Decode(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vfoo": []string{"1"},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &TestStruct{}
|
||||||
|
|
||||||
|
err := decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got an err: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vfoo": []string{"1"},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &TestStruct{
|
||||||
|
Vfoo: []string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got an err: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"vfoo": []string{"2", "3"},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &TestStruct{
|
||||||
|
Vfoo: []string{"1"},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got an err: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #70
|
||||||
|
func TestNextSquashMapstructure(t *testing.T) {
|
||||||
|
data := &struct {
|
||||||
|
Level1 struct {
|
||||||
|
Level2 struct {
|
||||||
|
Foo string
|
||||||
|
} `mapstructure:",squash"`
|
||||||
|
} `mapstructure:",squash"`
|
||||||
|
}{}
|
||||||
|
err := Decode(map[interface{}]interface{}{"foo": "baz"}, &data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("should not error: %s", err)
|
||||||
|
}
|
||||||
|
if data.Level1.Level2.Foo != "baz" {
|
||||||
|
t.Fatal("value should be baz")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImplementsInterfacePointerReceiver struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ImplementsInterfacePointerReceiver) DoStuff() {}
|
||||||
|
|
||||||
|
type ImplementsInterfaceValueReceiver string
|
||||||
|
|
||||||
|
func (i ImplementsInterfaceValueReceiver) DoStuff() {}
|
||||||
|
|
||||||
|
// GH-140 Type error when using DecodeHook to decode into interface
|
||||||
|
func TestDecode_DecodeHookInterface(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type Interface interface {
|
||||||
|
DoStuff()
|
||||||
|
}
|
||||||
|
type DecodeIntoInterface struct {
|
||||||
|
Test Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
testData := map[string]string{"test": "test"}
|
||||||
|
|
||||||
|
stringToPointerInterfaceDecodeHook := func(from, to reflect.Type, data interface{}) (interface{}, error) {
|
||||||
|
if from.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if to != reflect.TypeOf((*Interface)(nil)).Elem() {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
// Ensure interface is satisfied
|
||||||
|
var impl Interface = &ImplementsInterfacePointerReceiver{data.(string)}
|
||||||
|
return impl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
stringToValueInterfaceDecodeHook := func(from, to reflect.Type, data interface{}) (interface{}, error) {
|
||||||
|
if from.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if to != reflect.TypeOf((*Interface)(nil)).Elem() {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
// Ensure interface is satisfied
|
||||||
|
var impl Interface = ImplementsInterfaceValueReceiver(data.(string))
|
||||||
|
return impl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
decodeInto := new(DecodeIntoInterface)
|
||||||
|
|
||||||
|
decoder, _ := NewDecoder(&DecoderConfig{
|
||||||
|
DecodeHook: stringToPointerInterfaceDecodeHook,
|
||||||
|
Result: decodeInto,
|
||||||
|
})
|
||||||
|
|
||||||
|
err := decoder.Decode(testData)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Decode returned error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := &ImplementsInterfacePointerReceiver{"test"}
|
||||||
|
if !reflect.DeepEqual(decodeInto.Test, expected) {
|
||||||
|
t.Fatalf("expected: %#v (%T), got: %#v (%T)", decodeInto.Test, decodeInto.Test, expected, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
decodeInto := new(DecodeIntoInterface)
|
||||||
|
|
||||||
|
decoder, _ := NewDecoder(&DecoderConfig{
|
||||||
|
DecodeHook: stringToValueInterfaceDecodeHook,
|
||||||
|
Result: decodeInto,
|
||||||
|
})
|
||||||
|
|
||||||
|
err := decoder.Decode(testData)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Decode returned error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := ImplementsInterfaceValueReceiver("test")
|
||||||
|
if !reflect.DeepEqual(decodeInto.Test, expected) {
|
||||||
|
t.Fatalf("expected: %#v (%T), got: %#v (%T)", decodeInto.Test, decodeInto.Test, expected, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #103 Check for data type before trying to access its composants prevent a panic error
|
||||||
|
// in decodeSlice
|
||||||
|
func TestDecodeBadDataTypeInSlice(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"Toto": "titi",
|
||||||
|
}
|
||||||
|
result := []struct {
|
||||||
|
Toto string
|
||||||
|
}{}
|
||||||
|
|
||||||
|
if err := Decode(input, &result); err == nil {
|
||||||
|
t.Error("An error was expected, got nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #202 Ensure that intermediate maps in the struct -> struct decode process are settable
|
||||||
|
// and not just the elements within them.
|
||||||
|
func TestDecodeIntermediateMapsSettable(t *testing.T) {
|
||||||
|
type Timestamp struct {
|
||||||
|
Seconds int64
|
||||||
|
Nanos int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type TsWrapper struct {
|
||||||
|
Timestamp *Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimeWrapper struct {
|
||||||
|
Timestamp time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
input := TimeWrapper{
|
||||||
|
Timestamp: time.Unix(123456789, 987654),
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := TsWrapper{
|
||||||
|
Timestamp: &Timestamp{
|
||||||
|
Seconds: 123456789,
|
||||||
|
Nanos: 987654,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
timePtrType := reflect.TypeOf((*time.Time)(nil))
|
||||||
|
mapStrInfType := reflect.TypeOf((map[string]interface{})(nil))
|
||||||
|
|
||||||
|
var actual TsWrapper
|
||||||
|
decoder, err := NewDecoder(&DecoderConfig{
|
||||||
|
Result: &actual,
|
||||||
|
DecodeHook: func(from, to reflect.Type, data interface{}) (interface{}, error) {
|
||||||
|
if from == timePtrType && to == mapStrInfType {
|
||||||
|
ts := data.(*time.Time)
|
||||||
|
nanos := ts.UnixNano()
|
||||||
|
|
||||||
|
seconds := nanos / 1000000000
|
||||||
|
nanos = nanos % 1000000000
|
||||||
|
|
||||||
|
return &map[string]interface{}{
|
||||||
|
"Seconds": seconds,
|
||||||
|
"Nanos": int32(nanos),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create decoder: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := decoder.Decode(&input); err != nil {
|
||||||
|
t.Fatalf("failed to decode input: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
|
t.Fatalf("expected: %#[1]v (%[1]T), got: %#[2]v (%[2]T)", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GH-206: decodeInt throws an error for an empty string
|
||||||
|
func TestDecode_weakEmptyStringToInt(t *testing.T) {
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"StringToInt": "",
|
||||||
|
"StringToUint": "",
|
||||||
|
"StringToBool": "",
|
||||||
|
"StringToFloat": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedResultWeak := TypeConversionResult{
|
||||||
|
StringToInt: 0,
|
||||||
|
StringToUint: 0,
|
||||||
|
StringToBool: false,
|
||||||
|
StringToFloat: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test weak type conversion
|
||||||
|
var resultWeak TypeConversionResult
|
||||||
|
err := WeakDecode(input, &resultWeak)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got an err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(resultWeak, expectedResultWeak) {
|
||||||
|
t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GH-228: Squash cause *time.Time set to zero
|
||||||
|
func TestMapSquash(t *testing.T) {
|
||||||
|
type AA struct {
|
||||||
|
T *time.Time
|
||||||
|
}
|
||||||
|
type A struct {
|
||||||
|
AA
|
||||||
|
}
|
||||||
|
|
||||||
|
v := time.Now()
|
||||||
|
in := &AA{
|
||||||
|
T: &v,
|
||||||
|
}
|
||||||
|
out := &A{}
|
||||||
|
d, err := NewDecoder(&DecoderConfig{
|
||||||
|
Squash: true,
|
||||||
|
Result: out,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
if err := d.Decode(in); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// these failed
|
||||||
|
if !v.Equal(*out.T) {
|
||||||
|
t.Fatal("expected equal")
|
||||||
|
}
|
||||||
|
if out.T.IsZero() {
|
||||||
|
t.Fatal("expected false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GH-238: Empty key name when decoding map from struct with only omitempty flag
|
||||||
|
func TestMapOmitEmptyWithEmptyFieldnameInTag(t *testing.T) {
|
||||||
|
type Struct struct {
|
||||||
|
Username string `mapstructure:",omitempty"`
|
||||||
|
Age int `mapstructure:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
s := Struct{
|
||||||
|
Username: "Joe",
|
||||||
|
}
|
||||||
|
var m map[string]interface{}
|
||||||
|
|
||||||
|
if err := Decode(s, &m); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m) != 1 {
|
||||||
|
t.Fatalf("fail: %#v", m)
|
||||||
|
}
|
||||||
|
if m["Username"] != "Joe" {
|
||||||
|
t.Fatalf("fail: %#v", m)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,256 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleDecode() {
|
||||||
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
Emails []string
|
||||||
|
Extra map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// This input can come from anywhere, but typically comes from
|
||||||
|
// something like decoding JSON where we're not quite sure of the
|
||||||
|
// struct initially.
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": "Mitchell",
|
||||||
|
"age": 91,
|
||||||
|
"emails": []string{"one", "two", "three"},
|
||||||
|
"extra": map[string]string{
|
||||||
|
"twitter": "mitchellh",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
err := Decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%#v", result)
|
||||||
|
// Output:
|
||||||
|
// mapstructure.Person{Name:"Mitchell", Age:91, Emails:[]string{"one", "two", "three"}, Extra:map[string]string{"twitter":"mitchellh"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDecode_errors() {
|
||||||
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
Emails []string
|
||||||
|
Extra map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// This input can come from anywhere, but typically comes from
|
||||||
|
// something like decoding JSON where we're not quite sure of the
|
||||||
|
// struct initially.
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": 123,
|
||||||
|
"age": "bad value",
|
||||||
|
"emails": []int{1, 2, 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
err := Decode(input, &result)
|
||||||
|
if err == nil {
|
||||||
|
panic("should have an error")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
// Output:
|
||||||
|
// 5 error(s) decoding:
|
||||||
|
//
|
||||||
|
// * 'Age' expected type 'int', got unconvertible type 'string', value: 'bad value'
|
||||||
|
// * 'Emails[0]' expected type 'string', got unconvertible type 'int', value: '1'
|
||||||
|
// * 'Emails[1]' expected type 'string', got unconvertible type 'int', value: '2'
|
||||||
|
// * 'Emails[2]' expected type 'string', got unconvertible type 'int', value: '3'
|
||||||
|
// * 'Name' expected type 'string', got unconvertible type 'int', value: '123'
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDecode_metadata() {
|
||||||
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
|
||||||
|
// This input can come from anywhere, but typically comes from
|
||||||
|
// something like decoding JSON where we're not quite sure of the
|
||||||
|
// struct initially.
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": "Mitchell",
|
||||||
|
"age": 91,
|
||||||
|
"email": "foo@bar.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
// For metadata, we make a more advanced DecoderConfig so we can
|
||||||
|
// more finely configure the decoder that is used. In this case, we
|
||||||
|
// just tell the decoder we want to track metadata.
|
||||||
|
var md Metadata
|
||||||
|
var result Person
|
||||||
|
config := &DecoderConfig{
|
||||||
|
Metadata: &md,
|
||||||
|
Result: &result,
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(config)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := decoder.Decode(input); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Unused keys: %#v", md.Unused)
|
||||||
|
// Output:
|
||||||
|
// Unused keys: []string{"email"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDecode_weaklyTypedInput() {
|
||||||
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
Emails []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// This input can come from anywhere, but typically comes from
|
||||||
|
// something like decoding JSON, generated by a weakly typed language
|
||||||
|
// such as PHP.
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": 123, // number => string
|
||||||
|
"age": "42", // string => number
|
||||||
|
"emails": map[string]interface{}{}, // empty map => empty array
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
config := &DecoderConfig{
|
||||||
|
WeaklyTypedInput: true,
|
||||||
|
Result: &result,
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(config)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = decoder.Decode(input)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%#v", result)
|
||||||
|
// Output: mapstructure.Person{Name:"123", Age:42, Emails:[]string{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDecode_tags() {
|
||||||
|
// Note that the mapstructure tags defined in the struct type
|
||||||
|
// can indicate which fields the values are mapped to.
|
||||||
|
type Person struct {
|
||||||
|
Name string `mapstructure:"person_name"`
|
||||||
|
Age int `mapstructure:"person_age"`
|
||||||
|
}
|
||||||
|
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"person_name": "Mitchell",
|
||||||
|
"person_age": 91,
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
err := Decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%#v", result)
|
||||||
|
// Output:
|
||||||
|
// mapstructure.Person{Name:"Mitchell", Age:91}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDecode_embeddedStruct() {
|
||||||
|
// Squashing multiple embedded structs is allowed using the squash tag.
|
||||||
|
// This is demonstrated by creating a composite struct of multiple types
|
||||||
|
// and decoding into it. In this case, a person can carry with it both
|
||||||
|
// a Family and a Location, as well as their own FirstName.
|
||||||
|
type Family struct {
|
||||||
|
LastName string
|
||||||
|
}
|
||||||
|
type Location struct {
|
||||||
|
City string
|
||||||
|
}
|
||||||
|
type Person struct {
|
||||||
|
Family `mapstructure:",squash"`
|
||||||
|
Location `mapstructure:",squash"`
|
||||||
|
FirstName string
|
||||||
|
}
|
||||||
|
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"FirstName": "Mitchell",
|
||||||
|
"LastName": "Hashimoto",
|
||||||
|
"City": "San Francisco",
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
err := Decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s %s, %s", result.FirstName, result.LastName, result.City)
|
||||||
|
// Output:
|
||||||
|
// Mitchell Hashimoto, San Francisco
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDecode_remainingData() {
|
||||||
|
// Note that the mapstructure tags defined in the struct type
|
||||||
|
// can indicate which fields the values are mapped to.
|
||||||
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
Other map[string]interface{} `mapstructure:",remain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
input := map[string]interface{}{
|
||||||
|
"name": "Mitchell",
|
||||||
|
"age": 91,
|
||||||
|
"email": "mitchell@example.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
var result Person
|
||||||
|
err := Decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%#v", result)
|
||||||
|
// Output:
|
||||||
|
// mapstructure.Person{Name:"Mitchell", Age:91, Other:map[string]interface {}{"email":"mitchell@example.com"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleDecode_omitempty() {
|
||||||
|
// Add omitempty annotation to avoid map keys for empty values
|
||||||
|
type Family struct {
|
||||||
|
LastName string
|
||||||
|
}
|
||||||
|
type Location struct {
|
||||||
|
City string
|
||||||
|
}
|
||||||
|
type Person struct {
|
||||||
|
*Family `mapstructure:",omitempty"`
|
||||||
|
*Location `mapstructure:",omitempty"`
|
||||||
|
Age int
|
||||||
|
FirstName string
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &map[string]interface{}{}
|
||||||
|
input := Person{FirstName: "Somebody"}
|
||||||
|
err := Decode(input, &result)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%+v", result)
|
||||||
|
// Output:
|
||||||
|
// &map[Age:0 FirstName:Somebody]
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDecode_Ptr(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type G struct {
|
||||||
|
Id int
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type X struct {
|
||||||
|
Id int
|
||||||
|
Name int
|
||||||
|
}
|
||||||
|
|
||||||
|
type AG struct {
|
||||||
|
List []*G
|
||||||
|
}
|
||||||
|
|
||||||
|
type AX struct {
|
||||||
|
List []*X
|
||||||
|
}
|
||||||
|
|
||||||
|
g2 := &AG{
|
||||||
|
List: []*G{
|
||||||
|
{
|
||||||
|
Id: 11,
|
||||||
|
Name: "gg",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
x2 := AX{}
|
||||||
|
|
||||||
|
// 报错但还是会转换成功,转换后值为目标类型的 0 值
|
||||||
|
err := Decode(g2, &x2)
|
||||||
|
|
||||||
|
res := AX{
|
||||||
|
List: []*X{
|
||||||
|
{
|
||||||
|
Id: 11,
|
||||||
|
Name: 0, // 这个类型的 0 值
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Decode_Ptr err should not be 'nil': %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(res, x2) {
|
||||||
|
t.Errorf("result should be %#v: got %#v", res, x2)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,26 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// DecodeWithTime 支持时间转字符串
|
||||||
|
// 支持
|
||||||
|
// 1. *Time.time 转 string/*string
|
||||||
|
// 2. *Time.time 转 uint/uint32/uint64/int/int32/int64,支持带指针
|
||||||
|
// 不能用 Time.time 转,它会在上层认为是一个结构体数据而直接转成map,再到hook方法
|
||||||
|
func DecodeWithTime(input, output interface{}, layout string) error {
|
||||||
|
if layout == "" {
|
||||||
|
layout = time.DateTime
|
||||||
|
}
|
||||||
|
config := &DecoderConfig{
|
||||||
|
Metadata: nil,
|
||||||
|
Result: output,
|
||||||
|
DecodeHook: ComposeDecodeHookFunc(TimeToStringHook(layout), TimeToUnixIntHook()),
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := NewDecoder(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return decoder.Decode(input)
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TimeToStringHook 时间转字符串
|
||||||
|
// 支持 *Time.time 转 string/*string
|
||||||
|
// 不能用 Time.time 转,它会在上层认为是一个结构体数据而直接转成map,再到hook方法
|
||||||
|
func TimeToStringHook(layout string) DecodeHookFunc {
|
||||||
|
return func(
|
||||||
|
f reflect.Type,
|
||||||
|
t reflect.Type,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
// 判断目标类型是否为字符串
|
||||||
|
var strType string
|
||||||
|
var isStrPointer *bool // 要转换的目标类型是否为指针字符串
|
||||||
|
if t == reflect.TypeOf(strType) {
|
||||||
|
isStrPointer = new(bool)
|
||||||
|
} else if t == reflect.TypeOf(&strType) {
|
||||||
|
isStrPointer = new(bool)
|
||||||
|
*isStrPointer = true
|
||||||
|
}
|
||||||
|
if isStrPointer == nil {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断类型是否为时间
|
||||||
|
timeType := time.Time{}
|
||||||
|
if f != reflect.TypeOf(timeType) && f != reflect.TypeOf(&timeType) {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将时间转换为字符串
|
||||||
|
var output string
|
||||||
|
switch v := data.(type) {
|
||||||
|
case *time.Time:
|
||||||
|
output = v.Format(layout)
|
||||||
|
case time.Time:
|
||||||
|
output = v.Format(layout)
|
||||||
|
default:
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if *isStrPointer {
|
||||||
|
return &output, nil
|
||||||
|
}
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeToUnixIntHook 时间转时间戳
|
||||||
|
// 支持 *Time.time 转 uint/uint32/uint64/int/int32/int64,支持带指针
|
||||||
|
// 不能用 Time.time 转,它会在上层认为是一个结构体数据而直接转成map,再到hook方法
|
||||||
|
func TimeToUnixIntHook() DecodeHookFunc {
|
||||||
|
return func(
|
||||||
|
f reflect.Type,
|
||||||
|
t reflect.Type,
|
||||||
|
data interface{}) (interface{}, error) {
|
||||||
|
|
||||||
|
tkd := t.Kind()
|
||||||
|
if tkd != reflect.Int && tkd != reflect.Int32 && tkd != reflect.Int64 &&
|
||||||
|
tkd != reflect.Uint && tkd != reflect.Uint32 && tkd != reflect.Uint64 {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断类型是否为时间
|
||||||
|
timeType := time.Time{}
|
||||||
|
if f != reflect.TypeOf(timeType) && f != reflect.TypeOf(&timeType) {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将时间转换为字符串
|
||||||
|
var output int64
|
||||||
|
switch v := data.(type) {
|
||||||
|
case *time.Time:
|
||||||
|
output = v.Unix()
|
||||||
|
case time.Time:
|
||||||
|
output = v.Unix()
|
||||||
|
default:
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
switch tkd {
|
||||||
|
case reflect.Int:
|
||||||
|
return int(output), nil
|
||||||
|
case reflect.Int32:
|
||||||
|
return int32(output), nil
|
||||||
|
case reflect.Int64:
|
||||||
|
return output, nil
|
||||||
|
case reflect.Uint:
|
||||||
|
return uint(output), nil
|
||||||
|
case reflect.Uint32:
|
||||||
|
return uint32(output), nil
|
||||||
|
case reflect.Uint64:
|
||||||
|
return uint64(output), nil
|
||||||
|
default:
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,274 @@
|
||||||
|
package mapstructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_TimeToStringHook(t *testing.T) {
|
||||||
|
type Input struct {
|
||||||
|
Time time.Time
|
||||||
|
Id int
|
||||||
|
}
|
||||||
|
|
||||||
|
type InputTPointer struct {
|
||||||
|
Time *time.Time
|
||||||
|
Id int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Output struct {
|
||||||
|
Time string
|
||||||
|
Id int
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutputTPointer struct {
|
||||||
|
Time *string
|
||||||
|
Id int
|
||||||
|
}
|
||||||
|
now := time.Now()
|
||||||
|
target := now.Format("2006-01-02 15:04:05")
|
||||||
|
idValue := 1
|
||||||
|
tests := []struct {
|
||||||
|
input any
|
||||||
|
output any
|
||||||
|
name string
|
||||||
|
layout string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "测试Time.time转string",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: Output{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "测试*Time.time转*string",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: OutputTPointer{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
decoder, err := NewDecoder(&DecoderConfig{
|
||||||
|
DecodeHook: TimeToStringHook(tt.layout),
|
||||||
|
Result: &tt.output,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("NewDecoder() err = %v,want nil", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if i, isOk := tt.input.(Input); isOk {
|
||||||
|
err = decoder.Decode(i)
|
||||||
|
}
|
||||||
|
if i, isOk := tt.input.(InputTPointer); isOk {
|
||||||
|
err = decoder.Decode(&i)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Decode err = %v,want nil", err)
|
||||||
|
}
|
||||||
|
//验证测试值
|
||||||
|
if output, isOk := tt.output.(OutputTPointer); isOk {
|
||||||
|
if *output.Time != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", *output.Time, target)
|
||||||
|
}
|
||||||
|
if output.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", output.Id, idValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if output, isOk := tt.output.(Output); isOk {
|
||||||
|
if output.Time != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", output.Time, target)
|
||||||
|
}
|
||||||
|
if output.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", output.Id, idValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_TimeToUnixIntHook(t *testing.T) {
|
||||||
|
type InputTPointer struct {
|
||||||
|
Time *time.Time
|
||||||
|
Id int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Output[T int | *int | int32 | *int32 | int64 | *int64 | uint | *uint] struct {
|
||||||
|
Time T
|
||||||
|
Id int
|
||||||
|
}
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
input any
|
||||||
|
output any
|
||||||
|
name string
|
||||||
|
layout string
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
target := now.Unix()
|
||||||
|
idValue := 1
|
||||||
|
tests := []test{
|
||||||
|
{
|
||||||
|
name: "测试Time.time转int",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: Output[int]{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "测试Time.time转*int",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: Output[*int]{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "测试Time.time转int32",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: Output[int32]{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "测试Time.time转*int32",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: Output[*int32]{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "测试Time.time转int64",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: Output[int64]{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "测试Time.time转*int64",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: Output[*int64]{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "测试Time.time转uint",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: Output[uint]{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "测试Time.time转*uint",
|
||||||
|
layout: "2006-01-02 15:04:05",
|
||||||
|
input: InputTPointer{
|
||||||
|
Time: &now,
|
||||||
|
Id: idValue,
|
||||||
|
},
|
||||||
|
output: Output[*uint]{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
decoder, err := NewDecoder(&DecoderConfig{
|
||||||
|
DecodeHook: TimeToUnixIntHook(),
|
||||||
|
Result: &tt.output,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("NewDecoder() err = %v,want nil", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if i, isOk := tt.input.(InputTPointer); isOk {
|
||||||
|
err = decoder.Decode(i)
|
||||||
|
}
|
||||||
|
if i, isOk := tt.input.(InputTPointer); isOk {
|
||||||
|
err = decoder.Decode(&i)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Decode err = %v,want nil", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证测试值
|
||||||
|
switch v := tt.output.(type) {
|
||||||
|
case Output[int]:
|
||||||
|
if int64(v.Time) != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", v.Time, target)
|
||||||
|
}
|
||||||
|
if v.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", v.Id, idValue)
|
||||||
|
}
|
||||||
|
case Output[*int]:
|
||||||
|
if int64(*v.Time) != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", v.Time, target)
|
||||||
|
}
|
||||||
|
if v.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", v.Id, idValue)
|
||||||
|
}
|
||||||
|
case Output[int32]:
|
||||||
|
if int64(v.Time) != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", v.Time, target)
|
||||||
|
}
|
||||||
|
if v.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", v.Id, idValue)
|
||||||
|
}
|
||||||
|
case Output[*int32]:
|
||||||
|
if int64(*v.Time) != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", v.Time, target)
|
||||||
|
}
|
||||||
|
if v.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", v.Id, idValue)
|
||||||
|
}
|
||||||
|
case Output[int64]:
|
||||||
|
if int64(v.Time) != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", v.Time, target)
|
||||||
|
}
|
||||||
|
if v.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", v.Id, idValue)
|
||||||
|
}
|
||||||
|
case Output[*int64]:
|
||||||
|
if int64(*v.Time) != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", v.Time, target)
|
||||||
|
}
|
||||||
|
if v.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", v.Id, idValue)
|
||||||
|
}
|
||||||
|
case Output[uint]:
|
||||||
|
if int64(v.Time) != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", v.Time, target)
|
||||||
|
}
|
||||||
|
if v.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", v.Id, idValue)
|
||||||
|
}
|
||||||
|
case Output[*uint]:
|
||||||
|
if int64(*v.Time) != target {
|
||||||
|
t.Errorf("Decode output time = %v,want %v", v.Time, target)
|
||||||
|
}
|
||||||
|
if v.Id != idValue {
|
||||||
|
t.Errorf("Decode output id = %v,want %v", v.Id, idValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ func Bootstrap(conf *config.Config) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
db.GetDb().ShowSQL(true)
|
||||||
//注册redis服务
|
//注册redis服务
|
||||||
err = redis.Pr.Register(redis.SingletonMain, conf.Redis)
|
err = redis.Pr.Register(redis.SingletonMain, conf.Redis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
36
go.mod
36
go.mod
|
@ -8,12 +8,16 @@ require (
|
||||||
github.com/Shopify/sarama v1.19.0
|
github.com/Shopify/sarama v1.19.0
|
||||||
github.com/ahmetb/go-linq/v3 v3.2.0
|
github.com/ahmetb/go-linq/v3 v3.2.0
|
||||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||||
|
github.com/bwmarrin/snowflake v0.3.0
|
||||||
|
github.com/duke-git/lancet/v2 v2.3.3
|
||||||
github.com/forgoer/openssl v1.6.0
|
github.com/forgoer/openssl v1.6.0
|
||||||
github.com/gin-gonic/gin v1.7.7
|
github.com/gin-gonic/gin v1.7.7
|
||||||
|
github.com/go-kratos/kratos/v2 v2.8.2
|
||||||
github.com/go-playground/locales v0.14.0
|
github.com/go-playground/locales v0.14.0
|
||||||
github.com/go-playground/universal-translator v0.18.0
|
github.com/go-playground/universal-translator v0.18.0
|
||||||
github.com/go-sql-driver/mysql v1.6.0
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
|
github.com/golang/protobuf v1.5.4
|
||||||
github.com/nacos-group/nacos-sdk-go/v2 v2.2.5
|
github.com/nacos-group/nacos-sdk-go/v2 v2.2.5
|
||||||
github.com/nats-io/nats.go v1.9.1
|
github.com/nats-io/nats.go v1.9.1
|
||||||
github.com/openzipkin/zipkin-go v0.2.2
|
github.com/openzipkin/zipkin-go v0.2.2
|
||||||
|
@ -27,8 +31,9 @@ require (
|
||||||
github.com/swaggo/swag v1.7.9
|
github.com/swaggo/swag v1.7.9
|
||||||
github.com/tjfoc/gmsm v1.4.1
|
github.com/tjfoc/gmsm v1.4.1
|
||||||
github.com/valyala/fasthttp v1.31.0
|
github.com/valyala/fasthttp v1.31.0
|
||||||
google.golang.org/grpc v1.56.3
|
github.com/xuri/excelize/v2 v2.9.0
|
||||||
google.golang.org/protobuf v1.30.0
|
google.golang.org/grpc v1.61.1
|
||||||
|
google.golang.org/protobuf v1.33.0
|
||||||
gopkg.in/go-playground/validator.v9 v9.31.0
|
gopkg.in/go-playground/validator.v9 v9.31.0
|
||||||
xorm.io/builder v0.3.9
|
xorm.io/builder v0.3.9
|
||||||
xorm.io/xorm v1.2.5
|
xorm.io/xorm v1.2.5
|
||||||
|
@ -57,17 +62,19 @@ require (
|
||||||
github.com/emirpasic/gods v1.12.0 // indirect
|
github.com/emirpasic/gods v1.12.0 // indirect
|
||||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 // indirect
|
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-kratos/aegis v0.2.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||||
github.com/go-openapi/spec v0.20.4 // indirect
|
github.com/go-openapi/spec v0.20.4 // indirect
|
||||||
github.com/go-openapi/swag v0.19.15 // indirect
|
github.com/go-openapi/swag v0.19.15 // indirect
|
||||||
|
github.com/go-playground/form/v4 v4.2.0 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.9.0 // indirect
|
github.com/go-playground/validator/v10 v10.9.0 // indirect
|
||||||
github.com/go-redis/redis/v8 v8.11.4 // indirect
|
github.com/go-redis/redis/v8 v8.11.4 // indirect
|
||||||
github.com/goccy/go-json v0.8.1 // indirect
|
github.com/goccy/go-json v0.8.1 // indirect
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.4.0 // indirect
|
||||||
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/hetiansu5/accesslog v1.0.0 // indirect
|
github.com/hetiansu5/accesslog v1.0.0 // indirect
|
||||||
github.com/hetiansu5/cores v1.0.0 // indirect
|
github.com/hetiansu5/cores v1.0.0 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
||||||
|
@ -82,6 +89,7 @@ require (
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||||
github.com/nats-io/jwt v0.3.2 // indirect
|
github.com/nats-io/jwt v0.3.2 // indirect
|
||||||
github.com/nats-io/nkeys v0.1.3 // indirect
|
github.com/nats-io/nkeys v0.1.3 // indirect
|
||||||
github.com/nats-io/nuid v1.0.1 // indirect
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
|
@ -90,6 +98,8 @@ require (
|
||||||
github.com/prometheus/common v0.32.1 // indirect
|
github.com/prometheus/common v0.32.1 // indirect
|
||||||
github.com/prometheus/procfs v0.7.3 // indirect
|
github.com/prometheus/procfs v0.7.3 // indirect
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
|
||||||
|
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||||
|
github.com/richardlehane/msoleps v1.0.4 // indirect
|
||||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||||
|
@ -99,20 +109,24 @@ require (
|
||||||
github.com/ugorji/go/codec v1.2.6 // indirect
|
github.com/ugorji/go/codec v1.2.6 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||||
|
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect
|
||||||
|
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect
|
||||||
go.uber.org/atomic v1.9.0 // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
go.uber.org/zap v1.21.0 // indirect
|
go.uber.org/zap v1.21.0 // indirect
|
||||||
golang.org/x/crypto v0.17.0 // indirect
|
golang.org/x/crypto v0.28.0 // indirect
|
||||||
golang.org/x/net v0.17.0 // indirect
|
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a // indirect
|
||||||
golang.org/x/sync v0.1.0 // indirect
|
golang.org/x/net v0.30.0 // indirect
|
||||||
golang.org/x/sys v0.15.0 // indirect
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/sys v0.26.0 // indirect
|
||||||
|
golang.org/x/text v0.19.0 // indirect
|
||||||
golang.org/x/time v0.1.0 // indirect
|
golang.org/x/time v0.1.0 // indirect
|
||||||
golang.org/x/tools v0.6.0 // indirect
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
stathat.com/c/consistent v1.0.0 // indirect
|
stathat.com/c/consistent v1.0.0 // indirect
|
||||||
xorm.io/core v0.7.3 // indirect
|
xorm.io/core v0.7.3 // indirect
|
||||||
)
|
)
|
||||||
|
|
94
go.sum
94
go.sum
|
@ -110,6 +110,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
||||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
|
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||||
|
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
||||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
@ -146,6 +148,8 @@ github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/duke-git/lancet/v2 v2.3.3 h1:OhqzNzkbJBS9ZlWLo/C7g+WSAOAAyNj7p9CAiEHurUc=
|
||||||
|
github.com/duke-git/lancet/v2 v2.3.3/go.mod h1:zGa2R4xswg6EG9I6WnyubDbFO/+A/RROxIbXcwryTsc=
|
||||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
|
github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU=
|
||||||
|
@ -173,8 +177,9 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB
|
||||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
|
||||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||||
|
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||||
|
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc=
|
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc=
|
||||||
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg=
|
github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
@ -195,6 +200,10 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||||
|
github.com/go-kratos/aegis v0.2.0 h1:dObzCDWn3XVjUkgxyBp6ZeWtx/do0DPZ7LY3yNSJLUQ=
|
||||||
|
github.com/go-kratos/aegis v0.2.0/go.mod h1:v0R2m73WgEEYB3XYu6aE2WcMwsZkJ/Rzuf5eVccm7bI=
|
||||||
|
github.com/go-kratos/kratos/v2 v2.8.2 h1:EsEA7AmPQ2YQQ0FZrDWO2HgBNqeWM8z/mWKzS5UkQaQ=
|
||||||
|
github.com/go-kratos/kratos/v2 v2.8.2/go.mod h1:+Vfe3FzF0d+BfMdajA11jT0rAyJWublRE/seZQNZVxE=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
|
@ -213,6 +222,8 @@ github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyr
|
||||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/form/v4 v4.2.0 h1:N1wh+Goz61e6w66vo8vJkQt+uwZSoLz50kZPJWR8eic=
|
||||||
|
github.com/go-playground/form/v4 v4.2.0/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U=
|
||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||||
|
@ -280,8 +291,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
@ -300,8 +311,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
@ -321,8 +332,9 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||||
|
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
@ -330,8 +342,9 @@ github.com/gopherjs/gopherjs v0.0.0-20211111143520-d0d5ecc1a356 h1:d3wWSjdOuGrMH
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20211111143520-d0d5ecc1a356/go.mod h1:cz9oNYuRUWGdHmLF2IodMLkAhcPtXeULvcBNagUrxTI=
|
github.com/gopherjs/gopherjs v0.0.0-20211111143520-d0d5ecc1a356/go.mod h1:cz9oNYuRUWGdHmLF2IodMLkAhcPtXeULvcBNagUrxTI=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
|
@ -455,8 +468,9 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
@ -522,6 +536,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||||
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/nacos-group/nacos-sdk-go/v2 v2.2.5 h1:r0wwT7PayEjvEHzWXwr1ROi/JSqzujM4w+1L5ikThzQ=
|
github.com/nacos-group/nacos-sdk-go/v2 v2.2.5 h1:r0wwT7PayEjvEHzWXwr1ROi/JSqzujM4w+1L5ikThzQ=
|
||||||
|
@ -627,6 +643,11 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhD
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
|
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
|
||||||
|
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
|
||||||
|
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||||
|
github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00=
|
||||||
|
github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
|
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
|
||||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
|
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
|
||||||
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
|
||||||
|
@ -635,8 +656,9 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||||
|
@ -690,8 +712,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
||||||
github.com/swaggo/gin-swagger v1.3.3 h1:XHyYmeNVFG5PbyWHG4jXtxOm2P4kiZapDCWsyDDiQ/I=
|
github.com/swaggo/gin-swagger v1.3.3 h1:XHyYmeNVFG5PbyWHG4jXtxOm2P4kiZapDCWsyDDiQ/I=
|
||||||
|
@ -731,6 +753,12 @@ github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52
|
||||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
|
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7psK/lVsjIS2otl+1WyRyY=
|
||||||
|
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||||
|
github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQE=
|
||||||
|
github.com/xuri/excelize/v2 v2.9.0/go.mod h1:uqey4QBZ9gdMeWApPLdhm9x+9o2lq4iVmjiLfBS5hdE=
|
||||||
|
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A=
|
||||||
|
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
@ -796,8 +824,8 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -808,8 +836,12 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
|
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||||
|
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
|
||||||
|
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
@ -834,8 +866,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
@ -888,8 +920,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -914,8 +946,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
@ -990,8 +1022,8 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -1003,8 +1035,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -1074,8 +1106,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -1156,8 +1188,8 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
|
||||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
|
||||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||||
|
@ -1183,8 +1215,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
|
google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
|
||||||
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
@ -1198,8 +1230,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|
Loading…
Reference in New Issue