Golang works effectively with Null * types

If you are working with a database, the Null* type is useful for most scenarios, since usually a β€œnull” value is not required, you want the NOT NULL constraints, etc. were picked up and reminded you that you did not pass all the necessary data.

So, you create a structure similar to the following:

 type Role struct { Id sql.NullInt64 Code sql.NullString } 

This is great, but now you can’t directly access properties and use Role.Id.Value to get and install, it will become quite old in a large application when you have to have an extra step every time you want to access properties.

It would be nice if you could assign directly, for example. Role.Code = "Fsfs" , and be able to do something like Role.Code.IsNull when you are interested in checking for zero. Is it possible?

+8
go
source share
3 answers

Does the value of the intermediate pointer (s) use the option?

 package main import "fmt" type tmp struct { Value int } func getInt() *int { i := 123 return &i } func main() { // Re var v *int v = nil fmt.Printf("%T / %v\n", v, v) if v == nil { println("nil...") } v = getInt() fmt.Printf("%T / %v\n", v, *v) if v != nil { println("not nil...") } s := tmp{*v} fmt.Printf("%T / %v\n", s, s) } 

http://play.golang.org/p/lBrwTKh6-v

+1
source share

You can access Role.Code as follows:

 var r *Role r.Code = *code 

You can check the null value as follows:

 fmt.Println(r.Code, r.Code.Valid) 

If you change the r.Code value manually without using sql.Scanner, then Setter might be useful:

 func (r *Role) SetCode(code string) { r.Code.String = code r.Code.Valid = true } func main() { var r *Role r.SetCode("mi") if r.Code.Valid { fmt.Println(r.Code) } 

I tried this here: https://play.golang.org/p/faxQUm-2lr

+1
source share

Save application and database code separately.

 // Role belongs to app code, no compromises. type Role struct { Id int64 Code string } 

Database model.

 // Database has tables with columns. type Table struct { Name string Columns []string } var RoleTable = Table{ Name: "roles", Columns: []string{ "id", "code", }, } 

Enter the code once to convert between the model and the database row.

 // Database package needs to make it work. // Write a model to database row. type Writer struct { Role } func (w *Writer) Write() []interface{} { return []interface{}{ w.Role.Id, sql.NullString{ Valid: len(w.Role.Code) > 0, String: w.Role.String, }, } } // Read a database row into model. type Reader struct { Id int64 Code sql.NullString } func (r *Reader) Scan(row *sql.Row) error { return row.Scan( &r.Id, &r.Code, ) } func (r *Reader) Read() Role { return Role{ Id: r.Id, Code: r.Code.String, } } 

Your schema is separate from the application model. When saving or loading, you can smooth out structures such as user contact information.

 // Nested struct in app code. type User struct { TwitterProfile struct { Id string ScreenName string } } // Database row is normalized flat. var UserTable = Table{ Name: "users", Columns: []string{ "twitter_id", "twitter_screen_name", }, } 

He is flexible. You can even scan join strings without intermediate structures.

 type RowMux struct { vs []interface{} } func (mux *RowMux) Scan(vs ...interface{}) error { mux.vs = append(mux.vs, vs...) return nil } func (mux *RowMux) Mux(row *sql.Row) error { return row.Scan(mux.vs...) } // Scan join rows! row := db.QueryRow(` SELECT users.*, roles.* FROM users JOIN roles ON users.id = roles.user_id WHERE users.twitter_id = "123" `) mux := &RowMux{} userReader := &UserReader{} userReader.Scan(mux) roleReader := &RoleReader{} roleReader.Scan(mux) if err := mux.Mux(row); err != nil { panic(err) } user := userReader.Read() role := roleReader.Read() 
+1
source share

All Articles