Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(database/gdb): gdb.Counter not work in OnDuplicate #4073

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions contrib/drivers/mysql/mysql_z_unit_model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2812,6 +2812,28 @@ func Test_Model_OnDuplicate(t *testing.T) {
})
}

func Test_Model_OnDuplicateWithCounter(t *testing.T) {
table := createInitTable()
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
data := g.Map{
"id": 1,
"passport": "pp1",
"password": "pw1",
"nickname": "n1",
"create_time": "2016-06-06",
}
_, err := db.Model(table).OnConflict("id").OnDuplicate(g.Map{
"id": gdb.Counter{Field: "id", Value: 999999},
}).Data(data).Save()
t.AssertNil(err)
one, err := db.Model(table).WherePri(1).One()
t.AssertNil(err)
t.AssertNil(one)
})
}

func Test_Model_OnDuplicateEx(t *testing.T) {
table := createInitTable()
defer dropTable(table)
Expand Down
19 changes: 19 additions & 0 deletions contrib/drivers/pgsql/pgsql_format_upsert.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,25 @@ func (d *Driver) FormatUpsert(columns []string, list gdb.List, option gdb.DoInse
d.Core.QuoteWord(k),
v,
)
case gdb.Counter, *gdb.Counter:
var counter gdb.Counter
switch value := v.(type) {
case gdb.Counter:
counter = value
case *gdb.Counter:
counter = *value
}
operator, columnVal := "+", counter.Value
if columnVal < 0 {
operator, columnVal = "-", -columnVal
}
onDuplicateStr += fmt.Sprintf(
"%s=EXCLUDED.%s%s%s",
d.QuoteWord(k),
d.QuoteWord(counter.Field),
operator,
gconv.String(columnVal),
)
default:
onDuplicateStr += fmt.Sprintf(
"%s=EXCLUDED.%s",
Expand Down
22 changes: 22 additions & 0 deletions contrib/drivers/pgsql/pgsql_z_unit_model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,28 @@ func Test_Model_OnDuplicate(t *testing.T) {
})
}

func Test_Model_OnDuplicateWithCounter(t *testing.T) {
table := createInitTable()
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
data := g.Map{
"id": 1,
"passport": "pp1",
"password": "pw1",
"nickname": "n1",
"create_time": "2016-06-06",
}
_, err := db.Model(table).OnConflict("id").OnDuplicate(g.Map{
"id": gdb.Counter{Field: "id", Value: 999999},
}).Data(data).Save()
t.AssertNil(err)
one, err := db.Model(table).WherePri(1).One()
t.AssertNil(err)
t.AssertNil(one)
})
}

func Test_Model_OnDuplicateEx(t *testing.T) {
table := createInitTable()
defer dropTable(table)
Expand Down
19 changes: 19 additions & 0 deletions contrib/drivers/sqlite/sqlite_format_upsert.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,25 @@ func (d *Driver) FormatUpsert(columns []string, list gdb.List, option gdb.DoInse
d.Core.QuoteWord(k),
v,
)
case gdb.Counter, *gdb.Counter:
cyjaysong marked this conversation as resolved.
Show resolved Hide resolved
var counter gdb.Counter
switch value := v.(type) {
case gdb.Counter:
counter = value
case *gdb.Counter:
counter = *value
}
operator, columnVal := "+", counter.Value
if columnVal < 0 {
operator, columnVal = "-", -columnVal
}
onDuplicateStr += fmt.Sprintf(
"%s=EXCLUDED.%s%s%s",
d.QuoteWord(k),
d.QuoteWord(counter.Field),
operator,
gconv.String(columnVal),
)
cyjaysong marked this conversation as resolved.
Show resolved Hide resolved
default:
onDuplicateStr += fmt.Sprintf(
"%s=EXCLUDED.%s",
Expand Down
22 changes: 22 additions & 0 deletions contrib/drivers/sqlite/sqlite_z_unit_model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4324,3 +4324,25 @@ func Test_OrderRandom(t *testing.T) {
t.Assert(len(result), TableSize)
})
}

func Test_Model_OnDuplicateWithCounter(t *testing.T) {
table := createInitTable()
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
data := g.Map{
"id": 1,
"passport": "pp1",
"password": "pw1",
"nickname": "n1",
"create_time": "2016-06-06",
}
_, err := db.Model(table).OnConflict("id").OnDuplicate(g.Map{
"id": gdb.Counter{Field: "id", Value: 999999},
}).Data(data).Save()
t.AssertNil(err)
one, err := db.Model(table).WherePri(1).One()
t.AssertNil(err)
t.AssertNil(one)
})
}
90 changes: 90 additions & 0 deletions contrib/drivers/sqlitecgo/sqlite_format_upsert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package sqlitecgo

import (
"fmt"

"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)

// FormatUpsert returns SQL clause of type upsert for SQLite.
// For example: ON CONFLICT (id) DO UPDATE SET ...
func (d *Driver) FormatUpsert(columns []string, list gdb.List, option gdb.DoInsertOption) (string, error) {
if len(option.OnConflict) == 0 {
return "", gerror.NewCode(
gcode.CodeMissingParameter, `Please specify conflict columns`,
)
}

var onDuplicateStr string
if option.OnDuplicateStr != "" {
onDuplicateStr = option.OnDuplicateStr
} else if len(option.OnDuplicateMap) > 0 {
for k, v := range option.OnDuplicateMap {
if len(onDuplicateStr) > 0 {
onDuplicateStr += ","
}
switch v.(type) {
case gdb.Raw, *gdb.Raw:
onDuplicateStr += fmt.Sprintf(
"%s=%s",
d.Core.QuoteWord(k),
v,
)
case gdb.Counter, *gdb.Counter:
var counter gdb.Counter
switch value := v.(type) {
case gdb.Counter:
counter = value
case *gdb.Counter:
counter = *value
}
operator, columnVal := "+", counter.Value
if columnVal < 0 {
operator, columnVal = "-", -columnVal
}
onDuplicateStr += fmt.Sprintf(
"%s=EXCLUDED.%s%s%s",
d.QuoteWord(k),
d.QuoteWord(counter.Field),
operator,
gconv.String(columnVal),
)
default:
onDuplicateStr += fmt.Sprintf(
"%s=EXCLUDED.%s",
d.Core.QuoteWord(k),
d.Core.QuoteWord(gconv.String(v)),
)
}
}
} else {
for _, column := range columns {
// If it's SAVE operation, do not automatically update the creating time.
if d.Core.IsSoftCreatedFieldName(column) {
continue
}
if len(onDuplicateStr) > 0 {
onDuplicateStr += ","
}
onDuplicateStr += fmt.Sprintf(
"%s=EXCLUDED.%s",
d.Core.QuoteWord(column),
d.Core.QuoteWord(column),
)
}
}

conflictKeys := gstr.Join(option.OnConflict, ",")

return fmt.Sprintf("ON CONFLICT (%s) DO UPDATE SET ", conflictKeys) + onDuplicateStr, nil
}
10 changes: 0 additions & 10 deletions contrib/drivers/sqlitecgo/sqlitecgo_do_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import (
"context"

"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/text/gstr"
)

Expand All @@ -26,14 +24,6 @@ func (d *Driver) DoFilter(

case gstr.HasPrefix(sql, gdb.InsertOperationReplace):
sql = "INSERT OR REPLACE" + sql[len(gdb.InsertOperationReplace):]

default:
if gstr.Contains(sql, gdb.InsertOnDuplicateKeyUpdate) {
return sql, args, gerror.NewCode(
gcode.CodeNotSupported,
`Save operation is not supported by sqlite driver`,
)
}
}
return d.Core.DoFilter(ctx, link, sql, args)
}
10 changes: 5 additions & 5 deletions contrib/drivers/sqlitecgo/sqlitecgo_tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import (
"github.com/gogf/gf/v2/database/gdb"
)

const (
tablesSqlTmp = `SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`
)

// Tables retrieves and returns the tables of current schema.
// It's mainly used in cli tool chain for automatically generating the models.
func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {
Expand All @@ -21,11 +25,7 @@ func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string,
return nil, err
}

result, err = d.DoSelect(
ctx,
link,
`SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`,
)
result, err = d.DoSelect(ctx, link, tablesSqlTmp)
if err != nil {
return
}
Expand Down
5 changes: 0 additions & 5 deletions contrib/drivers/sqlitecgo/sqlitecgo_z_unit_init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (

"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gfile"
Expand All @@ -27,9 +25,6 @@ var (
configNode gdb.ConfigNode
dbDir = gfile.Temp("sqlite")
ctx = gctx.New()

// Error
ErrorSave = gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by sqlite driver`)
)

const (
Expand Down
24 changes: 23 additions & 1 deletion contrib/drivers/sqlitecgo/sqlitecgo_z_unit_model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ func Test_Model_Save(t *testing.T) {
"nickname": "oldme",
"create_time": CreateTime,
}).OnConflict("id").Save()
t.Assert(err, ErrorSave)
t.AssertNil(err)
})
}

Expand Down Expand Up @@ -4361,3 +4361,25 @@ func TestResult_Structs1(t *testing.T) {
t.Assert(array[1].Name, "smith")
})
}

func Test_Model_OnDuplicateWithCounter(t *testing.T) {
table := createInitTable()
defer dropTable(table)

gtest.C(t, func(t *gtest.T) {
data := g.Map{
"id": 1,
"passport": "pp1",
"password": "pw1",
"nickname": "n1",
"create_time": "2016-06-06",
}
_, err := db.Model(table).OnConflict("id").OnDuplicate(g.Map{
"id": gdb.Counter{Field: "id", Value: 999999},
}).Data(data).Save()
t.AssertNil(err)
one, err := db.Model(table).WherePri(1).One()
t.AssertNil(err)
t.AssertNil(one)
})
}
51 changes: 26 additions & 25 deletions database/gdb/gdb_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,24 +583,8 @@ func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data inter
switch kind {
case reflect.Map, reflect.Struct:
var (
fields []string
dataMap map[string]interface{}
counterHandler = func(column string, counter Counter) {
if counter.Value != 0 {
column = c.QuoteWord(column)
var (
columnRef = c.QuoteWord(counter.Field)
columnVal = counter.Value
operator = "+"
)
if columnVal < 0 {
operator = "-"
columnVal = -columnVal
}
fields = append(fields, fmt.Sprintf("%s=%s%s?", column, columnRef, operator))
params = append(params, columnVal)
}
}
fields []string
dataMap map[string]interface{}
)
dataMap, err = c.ConvertDataForRecord(ctx, data, table)
if err != nil {
Expand All @@ -620,13 +604,21 @@ func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data inter
}
for _, k := range keysInSequence {
v := dataMap[k]
switch value := v.(type) {
case *Counter:
counterHandler(k, *value)

case Counter:
counterHandler(k, value)

switch v.(type) {
case Counter, *Counter:
var counter Counter
switch value := v.(type) {
case Counter:
counter = value
case *Counter:
counter = *value
}
if counter.Value == 0 {
continue
}
operator, columnVal := c.getCounterAlter(counter)
fields = append(fields, fmt.Sprintf("%s=%s%s?", c.QuoteWord(k), c.QuoteWord(counter.Field), operator))
params = append(params, columnVal)
default:
if s, ok := v.(Raw); ok {
fields = append(fields, c.QuoteWord(k)+"="+gconv.String(s))
Expand Down Expand Up @@ -796,3 +788,12 @@ func (c *Core) IsSoftCreatedFieldName(fieldName string) bool {
func (c *Core) FormatSqlBeforeExecuting(sql string, args []interface{}) (newSql string, newArgs []interface{}) {
return handleSliceAndStructArgsForSql(sql, args)
}

// getCounterAlter
func (c *Core) getCounterAlter(counter Counter) (operator string, columnVal float64) {
operator, columnVal = "+", counter.Value
if columnVal < 0 {
operator, columnVal = "-", -columnVal
}
return
}
Loading
Loading