2 回答

TA貢獻(xiàn)1840條經(jīng)驗(yàn) 獲得超5個(gè)贊
我認(rèn)為較小查詢(xún)的合理解決方案是動(dòng)態(tài)構(gòu)建UPDATE查詢(xún)和綁定參數(shù)列表,同時(shí)使用識(shí)別更新內(nèi)容和留空內(nèi)容的邏輯處理有效負(fù)載。
根據(jù)我自己的經(jīng)驗(yàn),這是清晰易讀的(如果重復(fù),您始終可以迭代共享相同邏輯或使用反射并查看結(jié)構(gòu)標(biāo)記提示等的結(jié)構(gòu)成員)。每次(我)為此編寫(xiě)通用解決方案的嘗試都以非常復(fù)雜的矯枉過(guò)正,支持各種極端情況和端點(diǎn)之間的行為差異。
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"})
}
編輯:如果""是修補(bǔ)的有效值,那么它需要與默認(rèn)的空值區(qū)分開(kāi)來(lái)。解決字符串問(wèn)題的一種方法是使用指針,nil如果有效載荷中不存在值,則默認(rèn)為:
type Sample struct {
ID int `json:"id"`
StringA *string `json:"stringA"`
StringB *string `json:"stringB"`
}
然后修改條件以檢查字段是否像這樣發(fā)送:
if s.StringA != nil {
query.WriteString(" stringA = ?")
params = append(params, *s.StringA)
}
在操場(chǎng)上查看完整示例:https ://go.dev/play/p/RI7OsNEYrk6

TA貢獻(xiàn)1844條經(jīng)驗(yàn) 獲得超8個(gè)贊
對(duì)于它的價(jià)值,我通過(guò)以下方式解決了這個(gè)問(wèn)題:
將請(qǐng)求有效負(fù)載轉(zhuǎn)換為通用
map[string]interface{}
.實(shí)現(xiàn)一個(gè)查詢(xún)構(gòu)建器,該構(gòu)建器循環(huán)遍歷地圖的鍵以創(chuàng)建查詢(xún)。
我走這條路的部分原因是它符合我的所有要求,而且我不是特別喜歡有*string
s 或*int
s 躺在那里。
以下是查詢(xún)構(gòu)建器的樣子:
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
}
}
請(qǐng)注意,我使用的是 PostgreSQL,所以我需要為查詢(xún)提供編號(hào)參數(shù),例如$1,這是params用于的。它也是從函數(shù)返回的,因此可以按如下方式使用:
// 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 關(guān)注
- 143 瀏覽
添加回答
舉報(bào)