Proposal Details

I really appreciate the implementation of #60370. The sql.Null[T] type improves the visibility for the explicit absence of a certain value and its mapping to the db greatly.

However, I've come to notice that sql.Null[T] behaves somewhat counterintuitive when JSON (un)marhsalling. I guess, it's pretty easy to see, even without an example. Still, as visible in this playground a null-value marshalls into: "baz":{"V":"","Valid":false}, and a non-null-value into: "bar":{"V":"bar some value","Valid":true}.

At the same time, a valid not-null JSON unmarshalls into Bar:{V: Valid:false} anyway.

I'd appreciate, if sql.Null[T] marshalls into the value of T and null respectively, and null unmarshalls into a zero T and Valid:false (of course "some value", unmarshalls into V:"some value" and Valid:true).

Since I have implemented something like this for an sql.Null[T] wrapper type myself already, I would assume this feature should be pretty straightforward.

Possible MarshalJSON/UnmarshalJSON

func (n Null[T]) MarshalJSON() ([]byte, error) {
    if n.Valid {
        return json.Marshal(n.V)
    }

    return json.Marshal(nil)
}

func (n *Null[T]) UnmarshalJSON(data []byte) error {
    if string(data) == "null" {
        n.Valid = false
        return nil
    }

    n.Valid = true
    return json.Unmarshal(data, &n.V)
}

Thanks for your attention, have a lovely day! :)

Comment From: gabyhelp

Related Issues and Documentation

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: seankhliao

See https://pkg.go.dev/encoding

Adding encoding/decoding methods to existing types may constitute a breaking change, as they can be used for serialization in communicating with programs written with different library versions. The policy for packages maintained by the Go project is to only allow the addition of marshaling functions if no existing, reasonable marshaling exists.

Closing as infeasible.