go-gorm postgres 方言:管理 jsonb 插入和查找的结构以正确使用 json 标签
go-gorm postgres dialect: managing structs for jsonb insert and find to properly use json tags
进行了大量搜索,虽然我可以找到一堆解释如何直接使用 pq 包的好文章。我在 go-gorm 和 postgresql 方言的上下文中不知所措。
如果在 checks.go 中我使用 ChecksMap 它不允许我插入但会让我找到。如果我使用 postgres.jsonb 它允许我插入和查询,但找到的记录将是 jsonb.
Gorm 使用指针的结构来确定数据库 table 和模式。这在使用 return 是来自 API 的 json 响应的通用 searchHandler 实用程序时会引起头痛。对于任何非 jsonb 类型,gorm 使用适当的结构并使用 json 标签,但对于 jsonb,因为它没有对 jsonb 的引用"struct" 它不能使用 json 标签。这导致 return API json 具有大写键。
{
results: {
id: "123",
someId: "456",
results: [
{
Description: "foobar"
}
]
}
}
是否有一种优雅的方法来处理此类事情,以便 jsonb 结果列具有正确的结构并使用小写的 json 标签?我只是想做一些在 go-gorm 环境下不应该做的事情吗?
POSTGRESQL DDL
CREATE TABLE checks (
id text,
some_id text,
results jsonb
);
checks.go
type CheckRules struct {
Description string `json:"description"`
}
type ChecksMap map[string]CheckRules
type Checks struct {
ID string `gorm: "primary_key", json:"id"`
SomeID *string `json:"someId"`
Results postgres.jsonb `json:"results"` // <-- this
// results ChecksMap `gorm:"type:jsonb" json:"results"` // <-- or this
}
// func (cm *ChecksMap) Value() (driver.Value, error) {...}
// func (cm *ChecksMap) Scan(val interface{}) error {...}
insertChecks.go
var resultsVal = getResultsValue() // simplified
resJson, _ := json.Marshal(resultsVal)
checks := Checks{
SomeID: "123",
Results: postgres.Jsonb{ RawMessage: json.RawMessage(resJson) }
}
err := db.Create(&checks).Error
// ... some error handling
getChecks.go
var checks Checks
err := db.Find(&checks).Error
// ... some error handling
searchHandler.go
func SearchHandler(db *gorm.DB, model, results interface{}) func(c echo.Context) error {
return func(c echo.Context) error {
err := db.Find(results).Error
// ... some error handling
jsnRes, _ := json.Marshal(results) // <-- uppercase "keys"
return c.JSON(http.StatusOK, struct {
Results interface{} `json:"results"`
}{
Results: string(jsnRes),
})
}
}
您可以使用自定义 ChecksMap
类型,但在其 值接收器 而不是指针接收器上实现 driver.Valuer
接口。
所以,而不是:
func (cm *ChecksMap) Value() (driver.Value, error) { ...
你会这样写:
func (cm ChecksMap) Value() (driver.Value, error) {
if cm == nil {
return nil, nil
}
return json.Marshal(cm)
}
或者,您可以使它与指针实现一起使用,但是您必须将字段转换为指针,例如:
type Checks struct {
ID string `gorm: "primary_key", json:"id"`
SomeID *string `json:"someId"`
Results *ChecksMap `json:"results"`
}
(虽然我没有测试过所以我不是 100% 确定 gorm 将如何处理这种情况)
进行了大量搜索,虽然我可以找到一堆解释如何直接使用 pq 包的好文章。我在 go-gorm 和 postgresql 方言的上下文中不知所措。
如果在 checks.go 中我使用 ChecksMap 它不允许我插入但会让我找到。如果我使用 postgres.jsonb 它允许我插入和查询,但找到的记录将是 jsonb.
Gorm 使用指针的结构来确定数据库 table 和模式。这在使用 return 是来自 API 的 json 响应的通用 searchHandler 实用程序时会引起头痛。对于任何非 jsonb 类型,gorm 使用适当的结构并使用 json 标签,但对于 jsonb,因为它没有对 jsonb 的引用"struct" 它不能使用 json 标签。这导致 return API json 具有大写键。
{
results: {
id: "123",
someId: "456",
results: [
{
Description: "foobar"
}
]
}
}
是否有一种优雅的方法来处理此类事情,以便 jsonb 结果列具有正确的结构并使用小写的 json 标签?我只是想做一些在 go-gorm 环境下不应该做的事情吗?
POSTGRESQL DDL
CREATE TABLE checks (
id text,
some_id text,
results jsonb
);
checks.go
type CheckRules struct {
Description string `json:"description"`
}
type ChecksMap map[string]CheckRules
type Checks struct {
ID string `gorm: "primary_key", json:"id"`
SomeID *string `json:"someId"`
Results postgres.jsonb `json:"results"` // <-- this
// results ChecksMap `gorm:"type:jsonb" json:"results"` // <-- or this
}
// func (cm *ChecksMap) Value() (driver.Value, error) {...}
// func (cm *ChecksMap) Scan(val interface{}) error {...}
insertChecks.go
var resultsVal = getResultsValue() // simplified
resJson, _ := json.Marshal(resultsVal)
checks := Checks{
SomeID: "123",
Results: postgres.Jsonb{ RawMessage: json.RawMessage(resJson) }
}
err := db.Create(&checks).Error
// ... some error handling
getChecks.go
var checks Checks
err := db.Find(&checks).Error
// ... some error handling
searchHandler.go
func SearchHandler(db *gorm.DB, model, results interface{}) func(c echo.Context) error {
return func(c echo.Context) error {
err := db.Find(results).Error
// ... some error handling
jsnRes, _ := json.Marshal(results) // <-- uppercase "keys"
return c.JSON(http.StatusOK, struct {
Results interface{} `json:"results"`
}{
Results: string(jsnRes),
})
}
}
您可以使用自定义 ChecksMap
类型,但在其 值接收器 而不是指针接收器上实现 driver.Valuer
接口。
所以,而不是:
func (cm *ChecksMap) Value() (driver.Value, error) { ...
你会这样写:
func (cm ChecksMap) Value() (driver.Value, error) {
if cm == nil {
return nil, nil
}
return json.Marshal(cm)
}
或者,您可以使它与指针实现一起使用,但是您必须将字段转换为指针,例如:
type Checks struct {
ID string `gorm: "primary_key", json:"id"`
SomeID *string `json:"someId"`
Results *ChecksMap `json:"results"`
}
(虽然我没有测试过所以我不是 100% 确定 gorm 将如何处理这种情况)