Add ON DUPLICATE KEY UPDATE support (MySQL).

This commit is contained in:
go-jet 2020-05-03 20:46:21 +02:00
parent 30284af33e
commit 980b9b6aac
18 changed files with 388 additions and 109 deletions

View file

@ -13,13 +13,15 @@ type InsertStatement interface {
MODEL(data interface{}) InsertStatement
MODELS(data interface{}) InsertStatement
ON_DUPLICATE_KEY_UPDATE(assigments ...ColumnAssigment) InsertStatement
QUERY(selectStatement SelectStatement) InsertStatement
}
func newInsertStatement(table Table, columns []jet.Column) InsertStatement {
newInsert := &insertStatementImpl{}
newInsert.SerializerStatement = jet.NewStatementImpl(Dialect, jet.InsertStatementType, newInsert,
&newInsert.Insert, &newInsert.ValuesQuery)
&newInsert.Insert, &newInsert.ValuesQuery, &newInsert.OnDuplicateKey)
newInsert.Insert.Table = table
newInsert.Insert.Columns = columns
@ -30,26 +32,55 @@ func newInsertStatement(table Table, columns []jet.Column) InsertStatement {
type insertStatementImpl struct {
jet.SerializerStatement
Insert jet.ClauseInsert
ValuesQuery jet.ClauseValuesQuery
Insert jet.ClauseInsert
ValuesQuery jet.ClauseValuesQuery
OnDuplicateKey onDuplicateKeyUpdateClause
}
func (i *insertStatementImpl) VALUES(value interface{}, values ...interface{}) InsertStatement {
i.ValuesQuery.Rows = append(i.ValuesQuery.Rows, jet.UnwindRowFromValues(value, values))
return i
func (is *insertStatementImpl) VALUES(value interface{}, values ...interface{}) InsertStatement {
is.ValuesQuery.Rows = append(is.ValuesQuery.Rows, jet.UnwindRowFromValues(value, values))
return is
}
func (i *insertStatementImpl) MODEL(data interface{}) InsertStatement {
i.ValuesQuery.Rows = append(i.ValuesQuery.Rows, jet.UnwindRowFromModel(i.Insert.GetColumns(), data))
return i
func (is *insertStatementImpl) MODEL(data interface{}) InsertStatement {
is.ValuesQuery.Rows = append(is.ValuesQuery.Rows, jet.UnwindRowFromModel(is.Insert.GetColumns(), data))
return is
}
func (i *insertStatementImpl) MODELS(data interface{}) InsertStatement {
i.ValuesQuery.Rows = append(i.ValuesQuery.Rows, jet.UnwindRowsFromModels(i.Insert.GetColumns(), data)...)
return i
func (is *insertStatementImpl) MODELS(data interface{}) InsertStatement {
is.ValuesQuery.Rows = append(is.ValuesQuery.Rows, jet.UnwindRowsFromModels(is.Insert.GetColumns(), data)...)
return is
}
func (i *insertStatementImpl) QUERY(selectStatement SelectStatement) InsertStatement {
i.ValuesQuery.Query = selectStatement
return i
func (is *insertStatementImpl) ON_DUPLICATE_KEY_UPDATE(assigments ...ColumnAssigment) InsertStatement {
is.OnDuplicateKey = assigments
return is
}
func (is *insertStatementImpl) QUERY(selectStatement SelectStatement) InsertStatement {
is.ValuesQuery.Query = selectStatement
return is
}
type onDuplicateKeyUpdateClause []jet.ColumnAssigment
// Serialize for SetClause
func (s onDuplicateKeyUpdateClause) Serialize(statementType jet.StatementType, out *jet.SQLBuilder, options ...jet.SerializeOption) {
if len(s) == 0 {
return
}
out.NewLine()
out.WriteString("ON DUPLICATE KEY UPDATE")
out.IncreaseIdent(24)
for i, assigment := range s {
if i > 0 {
out.WriteString(",")
out.NewLine()
}
jet.Serialize(assigment, statementType, out, jet.ShortName.WithFallTrough(options)...)
}
out.DecreaseIdent(24)
}

View file

@ -133,3 +133,50 @@ VALUES (DEFAULT, ?);
assertStatementSql(t, stmt, expectedSQL, "two")
}
func TestInsertOnDuplicateKeyUpdate(t *testing.T) {
stmt := func() InsertStatement {
return table1.INSERT(table1Col1, table1ColFloat).
VALUES(DEFAULT, "two")
}
t.Run("empty list", func(t *testing.T) {
stmt := stmt().ON_DUPLICATE_KEY_UPDATE()
assertStatementSql(t, stmt, `
INSERT INTO db.table1 (col1, col_float)
VALUES (DEFAULT, ?);
`, "two")
})
t.Run("one set", func(t *testing.T) {
stmt := stmt().ON_DUPLICATE_KEY_UPDATE(table1ColFloat.SET(Float(11.1)))
assertStatementSql(t, stmt, `
INSERT INTO db.table1 (col1, col_float)
VALUES (DEFAULT, ?)
ON DUPLICATE KEY UPDATE col_float = ?;
`, "two", 11.1)
})
t.Run("all types set", func(t *testing.T) {
stmt := stmt().ON_DUPLICATE_KEY_UPDATE(
table1ColBool.SET(Bool(true)),
table1ColInt.SET(Int(11)),
table1ColFloat.SET(Float(11.1)),
table1ColString.SET(String("str")),
table1ColTime.SET(Time(11, 23, 11)),
table1ColTimestamp.SET(Timestamp(2020, 1, 22, 3, 4, 5)),
table1ColDate.SET(Date(2020, 12, 1)),
)
assertStatementSql(t, stmt, `
INSERT INTO db.table1 (col1, col_float)
VALUES (DEFAULT, ?)
ON DUPLICATE KEY UPDATE col_bool = ?,
col_int = ?,
col_float = ?,
col_string = ?,
col_time = CAST(? AS TIME),
col_timestamp = TIMESTAMP(?),
col_date = CAST(? AS DATE);
`, "two", true, int64(11), 11.1, "str", "11:23:11", "2020-01-22 03:04:05", "2020-12-01")
})
}

View file

@ -10,3 +10,6 @@ type Projection = jet.Projection
// ProjectionList can be used to create conditional constructed projection list.
type ProjectionList = jet.ProjectionList
// ColumnAssigment is interface wrapper around column assigment
type ColumnAssigment = jet.ColumnAssigment

View file

@ -7,12 +7,14 @@ import (
)
var table1Col1 = IntegerColumn("col1")
var table1ColBool = BoolColumn("col_bool")
var table1ColInt = IntegerColumn("col_int")
var table1ColFloat = FloatColumn("col_float")
var table1ColString = StringColumn("col_string")
var table1Col3 = IntegerColumn("col3")
var table1ColTimestamp = TimestampColumn("col_timestamp")
var table1ColBool = BoolColumn("col_bool")
var table1ColDate = DateColumn("col_date")
var table1ColTime = TimeColumn("col_time")
var table1 = NewTable(
"db",
@ -20,10 +22,12 @@ var table1 = NewTable(
table1Col1,
table1ColInt,
table1ColFloat,
table1ColString,
table1Col3,
table1ColBool,
table1ColDate,
table1ColTimestamp,
table1ColTime,
)
var table2Col3 = IntegerColumn("col3")