您如何编组 sql.NullString 以便输出被展平以仅给出 go 中的值?
How do you marshal a sql.NullString such that the output is flattened to give just the value in go?
给定一个 go 结构
type Company struct {
ID int `json:"id"`
Abn sql.NullString `json:"abn,string"`
}
当用这样的东西编组时
company := &Company{}
company.ID = 68
company.Abn = "SomeABN"
result, err := json.Marshal(company)
结果是
{
"id": "68",
"abn": {
"String": "SomeABN",
"Valid": true
}
}
想要的结果是
{
"id": "68",
"abn": "SomeABN"
}
我试过明确说明 Abn 是一个字符串。
Abn sql.NullString `json:"abn,string"`
没有改变结果。
如何编组 sql.NullString 以便输出被展平以仅给出 go 中的值?
编辑
我在阅读 https://whosebug.com/users/8256506/nilsocket and https://whosebug.com/users/965900/mkopriva
的答案后得出的结论
package main
import (
"database/sql"
"encoding/json"
"reflect"
//"github.com/lib/pq"
)
/*
https://medium.com/aubergine-solutions/how-i-handled-null-possible-values-from-database-rows-in-golang-521fb0ee267
*/
type NullString sql.NullString
func (x *NullString) MarshalJSON() ([]byte, error) {
if !x.Valid {
x.Valid = true
x.String = ""
//return []byte("null"), nil
}
return json.Marshal(x.String)
}
// Scan implements the Scanner interface for NullString
func (ns *NullString) Scan(value interface{}) error {
var s sql.NullString
if err := s.Scan(value); err != nil {
return err
}
// if nil then make Valid false
if reflect.TypeOf(value) == nil {
*ns = NullString{s.String, false}
} else {
*ns = NullString{s.String, true}
}
return nil
}
type Company struct {
ID int `json:"id"`
Abn NullString `json:"abn"`
}
你不能,至少不能只使用 sql.NullString
和 encoding/json
。
您可以做的是声明一个嵌入 sql.NullString
的自定义类型,并让该自定义类型实现 json.Marshaler
接口。
type MyNullString struct {
sql.NullString
}
func (s MyNullString) MarshalJSON() ([]byte, error) {
if s.Valid {
return json.Marshal(s.String)
}
return []byte(`null`), nil
}
type Company struct {
ID int `json:"id"`
Abn MyNullString `json:"abn,string"`
}
这是代码,
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
)
//Company details
type Company struct {
ID int `json:"id"`
Abn NullString `json:"abn"`
}
//NullString is a wrapper around sql.NullString
type NullString sql.NullString
//MarshalJSON method is called by json.Marshal,
//whenever it is of type NullString
func (x *NullString) MarshalJSON() ([]byte, error) {
if !x.Valid {
return []byte("null"), nil
}
return json.Marshal(x.String)
}
func main() {
company := &Company{}
company.ID = 68
//create new NullString value
nStr := sql.NullString{String: "hello", Valid: true}
//cast it
company.Abn = NullString(nStr)
result, err := json.Marshal(company)
if err != nil {
log.Println(err)
}
fmt.Println(string(result))
}
Here 是博客 post 里面解释得很详细。
问题表明您希望将数据库结构公开为 JSON(大概是 REST-ish)API。除非项目的生命周期很短或者逻辑层很简单,否则这种方法被认为是一种反模式。内部结构(数据库结构)与外部接口耦合 (API),可能导致更改成本很高。
我附上了一些读物,因为 Google 有很多关于如何做相反操作的教程:
给定一个 go 结构
type Company struct {
ID int `json:"id"`
Abn sql.NullString `json:"abn,string"`
}
当用这样的东西编组时
company := &Company{}
company.ID = 68
company.Abn = "SomeABN"
result, err := json.Marshal(company)
结果是
{
"id": "68",
"abn": {
"String": "SomeABN",
"Valid": true
}
}
想要的结果是
{
"id": "68",
"abn": "SomeABN"
}
我试过明确说明 Abn 是一个字符串。
Abn sql.NullString `json:"abn,string"`
没有改变结果。
如何编组 sql.NullString 以便输出被展平以仅给出 go 中的值?
编辑
我在阅读 https://whosebug.com/users/8256506/nilsocket and https://whosebug.com/users/965900/mkopriva
的答案后得出的结论package main
import (
"database/sql"
"encoding/json"
"reflect"
//"github.com/lib/pq"
)
/*
https://medium.com/aubergine-solutions/how-i-handled-null-possible-values-from-database-rows-in-golang-521fb0ee267
*/
type NullString sql.NullString
func (x *NullString) MarshalJSON() ([]byte, error) {
if !x.Valid {
x.Valid = true
x.String = ""
//return []byte("null"), nil
}
return json.Marshal(x.String)
}
// Scan implements the Scanner interface for NullString
func (ns *NullString) Scan(value interface{}) error {
var s sql.NullString
if err := s.Scan(value); err != nil {
return err
}
// if nil then make Valid false
if reflect.TypeOf(value) == nil {
*ns = NullString{s.String, false}
} else {
*ns = NullString{s.String, true}
}
return nil
}
type Company struct {
ID int `json:"id"`
Abn NullString `json:"abn"`
}
你不能,至少不能只使用 sql.NullString
和 encoding/json
。
您可以做的是声明一个嵌入 sql.NullString
的自定义类型,并让该自定义类型实现 json.Marshaler
接口。
type MyNullString struct {
sql.NullString
}
func (s MyNullString) MarshalJSON() ([]byte, error) {
if s.Valid {
return json.Marshal(s.String)
}
return []byte(`null`), nil
}
type Company struct {
ID int `json:"id"`
Abn MyNullString `json:"abn,string"`
}
这是代码,
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
)
//Company details
type Company struct {
ID int `json:"id"`
Abn NullString `json:"abn"`
}
//NullString is a wrapper around sql.NullString
type NullString sql.NullString
//MarshalJSON method is called by json.Marshal,
//whenever it is of type NullString
func (x *NullString) MarshalJSON() ([]byte, error) {
if !x.Valid {
return []byte("null"), nil
}
return json.Marshal(x.String)
}
func main() {
company := &Company{}
company.ID = 68
//create new NullString value
nStr := sql.NullString{String: "hello", Valid: true}
//cast it
company.Abn = NullString(nStr)
result, err := json.Marshal(company)
if err != nil {
log.Println(err)
}
fmt.Println(string(result))
}
Here 是博客 post 里面解释得很详细。
问题表明您希望将数据库结构公开为 JSON(大概是 REST-ish)API。除非项目的生命周期很短或者逻辑层很简单,否则这种方法被认为是一种反模式。内部结构(数据库结构)与外部接口耦合 (API),可能导致更改成本很高。
我附上了一些读物,因为 Google 有很多关于如何做相反操作的教程: