Как мне хорошо работать со значениями SQL NULL и JSON в Golang?

Go типа как Int64 а также String не может хранить нулевые значения, поэтому я обнаружил, что могу использовать sql.NullInt64 и sql.NullString для этого.

Но когда я использую их в Struct и генерирую JSON из Struct с помощью пакета json, формат отличается от того, когда я использую обычный Int64 а также String типы.

JSON имеет дополнительный уровень, потому что sql.Null*** также является Struct.

Есть хороший обходной путь для этого, или я не должен использовать NULL в моей базе данных SQL?

2 ответа

Решение

Типы как sql.NullInt64 не реализуйте никакой специальной обработки для маршалинга или демаршалинга JSON, поэтому применяются правила по умолчанию. Поскольку тип является структурой, он маршалируется как объект с его полями в качестве атрибутов.

Одним из способов обойти это является создание собственного типа, который реализует json.Marshaller / json.Unmarshaler интерфейсы. Встраивая sql.NullInt64 типа, мы получаем методы SQL бесплатно. Что-то вроде этого:

type JsonNullInt64 struct {
    sql.NullInt64
}

func (v JsonNullInt64) MarshalJSON() ([]byte, error) {
    if v.Valid {
        return json.Marshal(v.Int64)
    } else {
        return json.Marshal(nil)
    }
}

func (v *JsonNullInt64) UnmarshalJSON(data []byte) error {
    // Unmarshalling into a pointer will let us detect null
    var x *int64
    if err := json.Unmarshal(data, &x); err != nil {
        return err
    }
    if x != nil {
        v.Valid = true
        v.Int64 = *x
    } else {
        v.Valid = false
    }
    return nil
}

Если вы используете этот тип вместо sql.NullInt64, это должно быть закодировано, как вы ожидаете.

Вы можете проверить этот пример здесь: http://play.golang.org/p/zFESxLcd-c

Если вы используете пакет null.v3, вам не нужно реализовывать какие-либо методы маршала или демаршала. Это надмножество структур sql.Null и, вероятно, то, что вы хотите.

package main

import "gopkg.in/guregu/null.v3"

type Person struct {
    Name     string      `json:"id"`
    Age      int         `json:"age"`
    NickName null.String `json:"nickname"` // Optional
}

Если вы хотите увидеть полноценный веб-сервер Golang, который использует sqlite, nulls и json, вы можете обратиться к этой сути.

Другие вопросы по тегам