2 回答
TA贡献1840条经验 获得超5个赞
我认为较小查询的合理解决方案是动态构建UPDATE查询和绑定参数列表,同时使用识别更新内容和留空内容的逻辑处理有效负载。
根据我自己的经验,这是清晰易读的(如果重复,您始终可以迭代共享相同逻辑或使用反射并查看结构标记提示等的结构成员)。每次(我)为此编写通用解决方案的尝试都以非常复杂的矫枉过正,支持各种极端情况和端点之间的行为差异。
func patchSample(s Sample) {
var query strings.Builder
params := make([]interface{}, 0, 2)
// TODO Check if patch makes sense (e.g. id is non-zero, at least one patched value provided, etc.
query.WriteString("UPDATE sample SET")
if s.StringA != "" {
query.WriteString(" stringA = ?")
params = append(params, s.StringA)
}
if s.StringB != "" {
query.WriteString(" stringB = ?")
params = append(params, s.StringB)
}
query.WriteString(" WHERE id = ?")
params = append(params, s.ID)
fmt.Println(query.String(), params)
//_, err := db.Exec(query.String(), params...)
}
func main() {
patchSample(Sample{1, "Foo", ""})
patchSample(Sample{2, "", "Bar"})
patchSample(Sample{3, "Foo", "Bar"})
}
编辑:如果""是修补的有效值,那么它需要与默认的空值区分开来。解决字符串问题的一种方法是使用指针,nil如果有效载荷中不存在值,则默认为:
type Sample struct {
ID int `json:"id"`
StringA *string `json:"stringA"`
StringB *string `json:"stringB"`
}
然后修改条件以检查字段是否像这样发送:
if s.StringA != nil {
query.WriteString(" stringA = ?")
params = append(params, *s.StringA)
}
在操场上查看完整示例:https ://go.dev/play/p/RI7OsNEYrk6
TA贡献1844条经验 获得超8个赞
对于它的价值,我通过以下方式解决了这个问题:
将请求有效负载转换为通用
map[string]interface{}.实现一个查询构建器,该构建器循环遍历地图的键以创建查询。
我走这条路的部分原因是它符合我的所有要求,而且我不是特别喜欢有*strings 或*ints 躺在那里。
以下是查询构建器的样子:
func patchQueryBuilder(id string, patch map[string]interface{}) (string, []interface{}, error) {
var query strings.Builder
params := make([]interface{}, 0)
query.WriteString("UPDATE some_table SET")
for k, v := range patch {
switch k {
case "someString":
if someString, ok := v.(string); ok {
query.WriteString(fmt.Sprintf(" some_string=$%d,", len(params)+1))
params = append(params, someString)
} else {
return "", []interface{}{}, fmt.Errorf("could not process some_string")
}
case "someBool":
if someBool, ok := v.(bool); ok {
query.WriteString(fmt.Sprintf(" some_bool=$%d,", len(params)+1))
params = append(params, someBool)
} else {
return "", []interface{}{}, fmt.Errorf("could not process some_bool")
}
}
}
if len(params) > 0 {
// Remove trailing comma to avoid syntax errors
queryString := fmt.Sprintf("%s WHERE id=$%d RETURNING *", strings.TrimSuffix(query.String(), ","), len(params)+1)
params = append(params, id)
return queryString, params, nil
} else {
return "", []interface{}{}, nil
}
}
请注意,我使用的是 PostgreSQL,所以我需要为查询提供编号参数,例如$1,这是params用于的。它也是从函数返回的,因此可以按如下方式使用:
// Build the patch query based on the payload
query, params, err := patchQueryBuilder(id, patch)
if err != nil {
return nil, err
}
// Use the query/params and get output
row := tx.QueryRowContext(ctx, query, params...)
- 2 回答
- 0 关注
- 167 浏览
添加回答
举报
