From 47b22f059022f7a230ecdf4e64cf140a1491c4fe Mon Sep 17 00:00:00 2001 From: WeizhongTu Date: Tue, 26 Sep 2023 20:38:49 +0800 Subject: [PATCH] feat: build delete support limit (#148) * feat: build delete support limit * feat: build delete support limit * feat: build delete support limit * feat: build delete support limit --- builder/builder.go | 22 +++++++++++++++++----- builder/builder_test.go | 7 ++++--- builder/dao.go | 6 +++++- builder/dao_test.go | 8 +++++--- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/builder/builder.go b/builder/builder.go index a11b304..5f25222 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -21,7 +21,7 @@ var ( errHavingUnsupportedOperator = errors.New(`[builder] "_having" contains unsupported operator`) errLockModeValueType = errors.New(`[builder] the value of "_lockMode" must be of string type`) errNotAllowedLockMode = errors.New(`[builder] the value of "_lockMode" is not allowed`) - errUpdateLimitType = errors.New(`[builder] the value of "_limit" in update query must be one of int,uint,int64,uint64`) + errLimitType = errors.New(`[builder] the value of "_limit" must be one of int,uint,int64,uint64`) errWhereInterfaceSliceType = `[builder] the value of "xxx %s" must be of []interface{} type` errEmptySliceCondition = `[builder] the value of "%s" must contain at least one element` @@ -170,8 +170,7 @@ func resolveHaving(having interface{}) (map[string]interface{}, error) { return copiedMap, nil } -// BuildUpdate work as its name says -func BuildUpdate(table string, where map[string]interface{}, update map[string]interface{}) (string, []interface{}, error) { +func getLimit(where map[string]interface{}) (uint, error) { var limit uint if v, ok := where["_limit"]; ok { switch val := v.(type) { @@ -184,9 +183,18 @@ func BuildUpdate(table string, where map[string]interface{}, update map[string]i case uint64: limit = uint(val) default: - return "", nil, errUpdateLimitType + return 0, errLimitType } } + return limit, nil +} + +// BuildUpdate work as its name says +func BuildUpdate(table string, where map[string]interface{}, update map[string]interface{}) (string, []interface{}, error) { + limit, err := getLimit(where) + if err != nil { + return "", nil, err + } conditions, err := getWhereConditions(where, defaultIgnoreKeys) if nil != err { return "", nil, err @@ -196,11 +204,15 @@ func BuildUpdate(table string, where map[string]interface{}, update map[string]i // BuildDelete work as its name says func BuildDelete(table string, where map[string]interface{}) (string, []interface{}, error) { + limit, err := getLimit(where) + if err != nil { + return "", nil, err + } conditions, err := getWhereConditions(where, defaultIgnoreKeys) if nil != err { return "", nil, err } - return buildDelete(table, conditions...) + return buildDelete(table, limit, conditions...) } // BuildInsert work as its name says diff --git a/builder/builder_test.go b/builder/builder_test.go index c4032f2..b120f3c 100644 --- a/builder/builder_test.go +++ b/builder/builder_test.go @@ -388,11 +388,12 @@ func Test_BuildDelete(t *testing.T) { "age >=": 21, "sex in": []interface{}{"male", "female"}, "hobby in": []interface{}{"soccer", "basketball", "tenis"}, + "_limit": 10, }, }, out: outStruct{ - cond: "DELETE FROM tb WHERE (hobby IN (?,?,?) AND sex IN (?,?) AND age>=?)", - vals: []interface{}{"soccer", "basketball", "tenis", "male", "female", 21}, + cond: "DELETE FROM tb WHERE (hobby IN (?,?,?) AND sex IN (?,?) AND age>=?) LIMIT ?", + vals: []interface{}{"soccer", "basketball", "tenis", "male", "female", 21, 10}, err: nil, }, }, @@ -486,7 +487,7 @@ func Test_BuildUpdate(t *testing.T) { out: outStruct{ cond: "", vals: nil, - err: errUpdateLimitType, + err: errLimitType, }, }, } diff --git a/builder/dao.go b/builder/dao.go index cc8a65c..c2092d6 100644 --- a/builder/dao.go +++ b/builder/dao.go @@ -439,7 +439,7 @@ func buildUpdate(table string, update map[string]interface{}, limit uint, condit return cond, vals, nil } -func buildDelete(table string, conditions ...Comparable) (string, []interface{}, error) { +func buildDelete(table string, limit uint, conditions ...Comparable) (string, []interface{}, error) { whereString, vals := whereConnector("AND", conditions...) if "" == whereString { return fmt.Sprintf("DELETE FROM %s", table), nil, nil @@ -447,6 +447,10 @@ func buildDelete(table string, conditions ...Comparable) (string, []interface{}, format := "DELETE FROM %s WHERE %s" cond := fmt.Sprintf(format, quoteField(table), whereString) + if limit > 0 { + cond += " LIMIT ?" + vals = append(vals, int(limit)) + } return cond, vals, nil } diff --git a/builder/dao_test.go b/builder/dao_test.go index f6a0ea2..4b9aef1 100644 --- a/builder/dao_test.go +++ b/builder/dao_test.go @@ -363,6 +363,7 @@ func TestBuildUpdate(t *testing.T) { func TestBuildDelete(t *testing.T) { var data = []struct { table string + limit uint where []Comparable outStr string outVals []interface{} @@ -370,6 +371,7 @@ func TestBuildDelete(t *testing.T) { }{ { table: "tb", + limit: 5, where: []Comparable{ Eq(map[string]interface{}{ "foo": 1, @@ -378,14 +380,14 @@ func TestBuildDelete(t *testing.T) { "gmt_create": Raw("gmt_modified"), }), }, - outStr: "DELETE FROM tb WHERE (bar=? AND baz=? AND foo=? AND gmt_create=gmt_modified)", - outVals: []interface{}{2, "tt", 1}, + outStr: "DELETE FROM tb WHERE (bar=? AND baz=? AND foo=? AND gmt_create=gmt_modified) LIMIT ?", + outVals: []interface{}{2, "tt", 1, 5}, outErr: nil, }, } ass := assert.New(t) for _, tc := range data { - actualStr, actualVals, err := buildDelete(tc.table, tc.where...) + actualStr, actualVals, err := buildDelete(tc.table, tc.limit, tc.where...) ass.Equal(tc.outErr, err) ass.Equal(tc.outStr, actualStr) ass.Equal(tc.outVals, actualVals)