You can use aliases for types provided by sql package such as (NullInt64, NullString etc...). There are two advantages of using that, one you can scan null values and can get in golang structure and second you can marshal that struct in JSON.
Please, look at the sample code:
// NullInt64 is an alias for sql.NullInt64 data type
type NullInt64 sql.NullInt64
// Scan implements the Scanner interface for NullInt64
func (ni *NullInt64) Scan(value interface{}) error {
var i sql.NullInt64
if err := i.Scan(value); err != nil {
return err
}
// if nil the make Valid false
if reflect.TypeOf(value) == nil {
*ni = NullInt64{i.Int64, false}
} else {
*ni = NullInt64{i.Int64, true}
}
return nil
}
// MarshalJSON for NullInt64
func (ni *NullInt64) MarshalJSON() ([]byte, error) {
if !ni.Valid {
return []byte("null"), nil
}
return json.Marshal(ni.Int64)
}
Please, have a look at this article, it would be very helpful about handling null values in golang and how to use it in JSON.
Answer from rsudip90 on Stack OverflowYou can use aliases for types provided by sql package such as (NullInt64, NullString etc...). There are two advantages of using that, one you can scan null values and can get in golang structure and second you can marshal that struct in JSON.
Please, look at the sample code:
// NullInt64 is an alias for sql.NullInt64 data type
type NullInt64 sql.NullInt64
// Scan implements the Scanner interface for NullInt64
func (ni *NullInt64) Scan(value interface{}) error {
var i sql.NullInt64
if err := i.Scan(value); err != nil {
return err
}
// if nil the make Valid false
if reflect.TypeOf(value) == nil {
*ni = NullInt64{i.Int64, false}
} else {
*ni = NullInt64{i.Int64, true}
}
return nil
}
// MarshalJSON for NullInt64
func (ni *NullInt64) MarshalJSON() ([]byte, error) {
if !ni.Valid {
return []byte("null"), nil
}
return json.Marshal(ni.Int64)
}
Please, have a look at this article, it would be very helpful about handling null values in golang and how to use it in JSON.
As an option you can implement your custom data type that would match the JSON Marshaler interface. After that you would be able to marshal your struct using regular tags.
Check the example:
type UserTitleType sql.NullString
func (s UserTitleType) MarshalJSON() ([]byte, error) {
if s.Valid {
return json.Marshal(s.String)
}
return jsonNull, nil
}
type User struct {
Id int64 `json:"id"`
Title UserTitleType `json:"title"`
}
It's quite a common situation when you need to do work with a column that can be null in SQL (PostgreSQL in my case). I wish I could add NOT NULL constraints to every single column but that doesn't always make sense from the domain perspective.
The standard workarounds are to the best of my knowledge: using a pointer (say, *string or *int) to make sure that a potentially NULL value can be safely scanned into this field OR using a nullable SQL type like sql.NullString.
Russ Cox himself, if my memory serves me well, once wrote that effectively those two options can be considered the same. That said, the letter gets marshaled in a peculiar way (with all that Valid stuff), which is fixable but unpleasant to have.
Until recently, my choice was using pointers. The only drawback is the necessity to handle/check for NULLs in code, which is, to be more accurate, related to anything with pointers.
What I thought today is that it probably makes sense to use COALESCE in SQL to guarantee that NULLs can not be returned in the first place thus making zero values somehow useful :)
This solves the scanning issue and using the omitempty tag ensures the JSON output looks good.
One possible caveat I can think of is that there is now no way to tell whether a field is NULL or just an empty string/0 in the table. For strings, I can easily believe that this difference doesn't make a lot of sense. After all, having an empty string is always suspicious. It's different, though, with integers where 0 can be quite a valid value.
What do you think about this COALESCE approach and what is your favorite one to handle NULLs from SQL?
I'm storing possible null values in my DB as pointers in structs in my Go code.
Like in this article: https://iamdual.com/en/posts/handle-sql-null-golang/
Is there a downside to this strategy?
There are two ways how to work with database NULL values in Go:
-
sql.NullString, sql.NullBool, sql.NullInt64
-
*string, *bool, *int64
I have found two different opinions on this topic.
Opinion A, Russ Cox.
Any reason to use sql.NullString rather than *string? - https://groups.google.com/forum/#!topic/golang-nuts/vOTFu2SMNeA
There's no effective difference. We thought people might want to use NullString because it is so common and perhaps expresses the intent more clearly than *string. But either will work.
Opinion B, Arne Hormann.
Consider pointers to string (Int, etc) rather than NullString (Int, etc) - https://github.com/VividCortex/go-database-sql-tutorial/issues/32
*string is stored in an interface, so you have 3 levels of indirection (interface -> pointer to string -> pointer to bytes). NullString only has 2 levels of indirection and takes up less space in memory, which is why it's used in database/sql.
It would be useful for people to find all possible arguments regarding this topic in single place.
Please put your opinons and/or references.
In my code I have a function that converts a string to sql.NullString
func NewNullString(s string) sql.NullString {
if len(s) == 0 {
return sql.NullString{}
}
return sql.NullString{
String: s,
Valid: true,
}
}
Then whenever I am using Exec I wrap my strings that could be NULL in the DB with the NewNullString function.
db.Exec(`
insert into
users first_name, last_name, email
values (?,?,?)`,
firstName,
lastName,
NewNullString(email),
)
The database/sql package has a NullString type (docs) for just this situation.
Basically just use sql.NullString in place of strings where you want them to be nullable in db.
You could also use a *string in your code to the same effect.
The problem in either case is in mapping to/from a nullable string to a non-nullable string. The empty string is technically a value, so you will almost always have to do something like this if you decide empty string should be translated to nil:
nullableS := &s
if s == "" {
nullableS = nil
}
The alternative would be to just use *string instead of string in your models throughout your app.
In databases, I have been taking the approach that empty string and null are equivalent, and just storing empty sting in the db, and making most columns non-nullable.