1

我有一个名为http_requests. 我已经建模了以下结构来表示该表中的行。

type Map map[string]interface{}

type HTTPRequest struct {
   ID              int64     `json:"id" gorm:"id"`
   RequestURL      string    `json:"request_url,omitempty" gorm:"request_url"`
   RequestParams   *RequestParams  `json:"request_params,omitempty" gorm:"request_params"`
}


// RequestParams is another struct that holds params from body and URL query
type RequestParams struct {
    FromBody  Map `json:"body,omitempty"`
    FromQuery Map `json:"query,omitempty"`
}

保存 HTTPRequest 的代码:

request  := &HTTPRequest{
        RequestURL:      "dummy/url",
        RequestParams:   &RequestParams{FromBody: Map{"param1": "value1"}},
}

if err := gorm.DB.Create(request).Error; err != nil {
        return err
}

当我尝试保存此 HTTPRequest 时,会导致错误:

sql: Scan error on column index 9, name "request_params": unsupported Scan, storing driver.Value type []uint8 into type *RequestParams 

我希望有这样的request_params列来存储 JSON:

{"body":{"param1":"value1"}, "query": {"param2" : "value2"} }
or
{"body":{"param1":"value1"}}
or
{"query": {"param2" : "value2"} }

从数据库读取时,这应该被解析为 RequestParams 结构。

4

1 回答 1

0

正如@mkopriva 所建议的,我为我的 RequestParams 类型实现了 Scan() 和 Value() 方法。请参阅下面的代码。


import (
    "database/sql/driver"
    "encoding/json"
    "strings"
)

// Value converts RequestParams to a map
func (reqParams RequestParams) Value() (driver.Value, error) {
    reqMap, err := reqParams.ToMap()

    if err != nil {
        return nil, err
    }

    return reqMap.ForceJSON(), nil
}

// Scan converts value to RequestParams
func (reqParams *RequestParams) Scan(value interface{}) error {
    // set empty struct by default
    *reqParams = RequestParams{}

    if value == nil {
        return nil
    }

    if s, ok := value.([]byte); ok {
        d := json.NewDecoder(strings.NewReader(string(s)))
        d.UseNumber()

        rp := &RequestParams{}
        if err := d.Decode(rp); err == nil {
            *reqParams = *rp
        }
    }

    return nil
}

于 2019-09-08T06:52:01.177 回答