Skip to content
This repository has been archived by the owner on Nov 6, 2021. It is now read-only.

Working with database nullable fields

B1nj0y edited this page Apr 3, 2018 · 18 revisions

Rails is easy with database nullable fields, it return a nil if the column value is NULL. It's idiomatic and transparent for us developers.

But Go is a strict typed language, if you set a struct attribute as string, then you can't evaluate it as nil. Here's is a post for the situation: working-with-db-nulls.

Zero values

Go hasn't a nil for its basic types, but it provides zero values for them:

string:     ""
int:        0
bool:       false
float:      0.0
time.Time:  '0001-01-01 00:00:00','+00:00','UTC'

So for the database nullable field, if a string typed field value is NULL, we can set it as "" to make it consistent with Go's zero value specification.

COALESCE function

I hope go-on-rails can work with the nullable fields like Rails does, so I searched the web and found the COALESCE, a function available in most popular databases, here is the spark of inspiration: https://github.com/go-sql-driver/mysql/issues/34#issuecomment-158391340.

Its basic usage is like this:

 COALESCE(column_a, [column_b, "default_string"]) AS an_alias_for_column_a

Here it means that if column_a is NULL, we return one of its parameter in turn from the second ones which maybe is a column_b for query or simply a same typed value for return.

So we can take the zero values for the COALESCE's second parameter, it'll be returned if the nullable field is NULL.

That's it!

Then go-on-rails v0.1.11 is released with the feature built in. All the functions generated by go-on-rails with a SELECT query is enhanced with the COALESCE.

A Go package for it

And I write a Go package as a helper for you to write your own SQL clause that's also safe with nullable fields: zero.

For example, we has a struct:

type Person struct {
    Name string    // Not NULL
    Age  int       // Nullable field in database  
    Address        // Nullable field in database
}

we write a select clause for it with zero and then use the go-on-rails generated FindPersonsBySql() function to execute the query:

import (
    "fmt"

    "github.com/railstack/zero"
    // here we import the models in a relative path, 
    // we assume it is in the up folder of the current "controllers" folder 
    m "../models"
)

sql := fmt.Sprintf("SELECT id, name, %v, %v FROM persons", zero.Int("age"), zero.String("address"))

ps, err := m.FindPersonsBySql(sql)
if err != nil {
    /* ... */
}
fmt.Printf("Persons: %+v", ps)
Clone this wiki locally