web-dev-qa-db-fra.com

Comment puis-je travailler avec les valeurs SQL NULL et JSON dans Golang dans le bon sens?

Allez des types comme Int64 et String ne peuvent pas stocker de valeurs nulles, j'ai donc trouvé que je pouvais utiliser sql.NullInt64 et sql.NullString pour cela.

Mais lorsque je les utilise dans un Struct et que je génère du JSON à partir du Struct avec le package json , le format est différent de celui que j'utilise régulièrement Int64 et String types.

Le JSON a un niveau supplémentaire car le sql.Null *** est également un Struct.

Existe-t-il une bonne solution de contournement pour cela, ou dois-je ne pas utiliser de valeurs NULL dans ma base de données SQL?

31
Alex

Des types comme sql.NullInt64 n'implémente pas de gestion spéciale pour le marshaling ou le démarshaling JSON, donc les règles par défaut s'appliquent. Étant donné que le type est une structure, il est rassemblé en tant qu'objet avec ses champs en tant qu'attributs.

Une façon de contourner ce problème consiste à créer votre propre type qui implémente le json.Marshaller/json.Unmarshaler interfaces. En intégrant le sql.NullInt64 type, nous obtenons gratuitement les méthodes SQL. Quelque chose comme ça:

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
}

Si vous utilisez ce type à la place de sql.NullInt64, il doit être encodé comme prévu.

Vous pouvez tester cet exemple ici: http://play.golang.org/p/zFESxLcd-c

48
James Henstridge

Si vous utilisez le package null.v , vous n'aurez pas besoin d'implémenter les méthodes marshal ou unmarshal. C'est un surensemble des structures sql.Null et c'est probablement ce que vous voulez.

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
}

Si vous souhaitez voir un serveur Web Golang complet qui utilise sqlite, nulls et json, vous pouvez consulter this Gist .

8
Stephen Wood