Home  >  Article  >  Backend Development  >  Gorm returns scanner error on custom string type

Gorm returns scanner error on custom string type

王林
王林forward
2024-02-11 18:21:211137browse

Gorm 在自定义字符串类型上返回扫描仪错误

php editor banana introduction: In Gorm, when you try to perform a scan operation on a custom string type, you may encounter errors. This issue may cause the scanner to fail to parse the string correctly, resulting in program errors. This is because Gorm uses the `Scan` method by default to scan string type fields, but for custom string types, the `Scan` method may not handle it correctly. The solution to this problem is to use the `Value` method to manually parse the string to ensure that the program executes correctly. This way you can avoid running into problems with scanner errors when using Gorm.

Question content

I wrote the following entities:

type datacategory string

const (
    datacategory1 datacategory = "category1"
    datacategory2 datacategory = "category2"
)

type data struct {
    name            string         `json:"name"`
    categories      []datacategory `json:"category" gorm:"type:text[]"`
}

I manually created a row in the database and filled the categories array type with category1 and category2.

But the following error occurs when reading data:

sql: scan error on column index 19, name "category": unsupported scan, storing driver.value type string into type *[]datacategory

Example value method:

func (s DataCategorySlice) Value() (driver.Value, error) {
    if s == nil {
        return nil, nil
    }
    if len(s) == 0 {
        return "{}", nil
    }

    v := []string{}
    for _, dc := range s {
        v = append(v, string(dc))
    }
    result := fmt.Sprintf("{%s}", strings.Join(v, ","))
    return result, nil
}

Workaround

The following example assumes you are using postgresql as the rdbms and the datacategory value does not contain commas or unescaped single quotes.

// declare the custom type
type datacategoryslice []datacategory
// implement driver.valuer to encode the value into the
// correct format that is accepted by the target rdbms
func (s datacategoryslice) value() (driver.value, error) {
    if s == nil {
        return nil, nil
    }
    if len(s) == 0 {
        return []byte(`{}`), nil
    }

    v := []byte(`{`)
    for i := range s {
        v = append(v, s[i]...)
        v = append(v, ',')
    }
    v[len(v)-1] = '}' // replace last comma with closing brace
    return v, nil
}
// implement scanner to decode the raw source
// value as retrieved from the database
func (s *datacategoryslice) scan(src any) error {
    var data []byte
    switch v := src.(type) {
    case []byte:
        data = v
    case string:
        data = []byte(v)
    case nil:
        return nil
    default:
        return fmt.errorf("unsupported type: %t", src)
    }
    if len(data) == 0 {
        return nil
    }
    data = data[1:len(data)-1] // remove surrounding braces
    for _, v := range bytes.split(data, []byte{','}) {
        *s = append(*s, datacategory(v))
    }
    return nil
}

Alternatively, if returning []byte<code> from value() (driver.value, error) does not work, e.g. it results in "Error: malformed array literal: 077f02b2b848485c344b9727eb929650 (sqlstate 22p02)", then you can try using string as the return type.

Example from @kozhioyrin

// implement driver.Valuer to encode the value into the
// correct format that is accepted by the target RDBMS
func (s DataCategorySlice) Value() (driver.Value, error) {
    if s == nil {
        return nil, nil
    }
    if len(s) == 0 {
        return "{}", nil
    }

    v := []string{}
    for _, dc := range s {
        v = append(v, string(dc))
    }
    result := fmt.Sprintf("{%s}", strings.Join(v, ","))
    return result, nil
}

The above is the detailed content of Gorm returns scanner error on custom string type. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete