MySQL update statement tests.
This commit is contained in:
parent
a46e8c1c51
commit
7660bdd8b5
12 changed files with 406 additions and 115 deletions
|
|
@ -131,7 +131,7 @@ func (q *sqlBuilder) writeReturning(statement statementType, returning []project
|
||||||
}
|
}
|
||||||
|
|
||||||
if !q.dialect.SupportsReturning {
|
if !q.dialect.SupportsReturning {
|
||||||
panic(q.dialect.Name + " dialect does not support RETURNING.")
|
panic("jet: " + q.dialect.Name + " dialect does not support RETURNING.")
|
||||||
}
|
}
|
||||||
|
|
||||||
q.newLine()
|
q.newLine()
|
||||||
|
|
|
||||||
60
dialects.go
60
dialects.go
|
|
@ -21,6 +21,7 @@ func newPostgresDialect() Dialect {
|
||||||
return "$" + strconv.Itoa(ord)
|
return "$" + strconv.Itoa(ord)
|
||||||
}
|
}
|
||||||
postgresDialect.SupportsReturning = true
|
postgresDialect.SupportsReturning = true
|
||||||
|
postgresDialect.UpdateAssigment = postgresUpdateAssigment
|
||||||
|
|
||||||
return postgresDialect
|
return postgresDialect
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +41,7 @@ func newMySQLDialect() Dialect {
|
||||||
}
|
}
|
||||||
|
|
||||||
mySQLDialect.SupportsReturning = false
|
mySQLDialect.SupportsReturning = false
|
||||||
|
mySQLDialect.UpdateAssigment = mysqlUpdateAssigment
|
||||||
|
|
||||||
return mySQLDialect
|
return mySQLDialect
|
||||||
}
|
}
|
||||||
|
|
@ -52,6 +54,7 @@ type Dialect struct {
|
||||||
AliasQuoteChar byte
|
AliasQuoteChar byte
|
||||||
IdentifierQuoteChar byte
|
IdentifierQuoteChar byte
|
||||||
ArgumentPlaceholder queryPlaceholderFunc
|
ArgumentPlaceholder queryPlaceholderFunc
|
||||||
|
UpdateAssigment func(columns []column, values []clause, out *sqlBuilder) (err error)
|
||||||
|
|
||||||
SupportsReturning bool
|
SupportsReturning bool
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +63,63 @@ func (d *Dialect) serializeOverride(operator string) serializeOverride {
|
||||||
return d.SerializeOverrides[operator]
|
return d.SerializeOverrides[operator]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mysqlUpdateAssigment(columns []column, values []clause, out *sqlBuilder) (err error) {
|
||||||
|
|
||||||
|
if len(columns) != len(values) {
|
||||||
|
return errors.New("jet: mismatch in numers of columns and values")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, column := range columns {
|
||||||
|
if i > 0 {
|
||||||
|
out.writeString(", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
out.writeString(column.Name())
|
||||||
|
|
||||||
|
out.writeString(" = ")
|
||||||
|
|
||||||
|
if err = values[i].serialize(updateStatement, out); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func postgresUpdateAssigment(columns []column, values []clause, out *sqlBuilder) (err error) {
|
||||||
|
if len(columns) > 1 {
|
||||||
|
out.writeString("(")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = serializeColumnNames(columns, out)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(columns) > 1 {
|
||||||
|
out.writeString(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
out.writeString("=")
|
||||||
|
|
||||||
|
if len(values) > 1 {
|
||||||
|
out.writeString("(")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = serializeClauseList(updateStatement, values, out)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(values) > 1 {
|
||||||
|
out.writeString(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type queryPlaceholderFunc func(ord int) string
|
type queryPlaceholderFunc func(ord int) string
|
||||||
|
|
||||||
func newDialect(name, packageName string) Dialect {
|
func newDialect(name, packageName string) Dialect {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-jet/jet"
|
"github.com/go-jet/jet"
|
||||||
|
"github.com/go-jet/jet/execution"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
@ -28,6 +29,24 @@ func JsonSave(v interface{}, path string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AssertExec(t *testing.T, stmt jet.Statement, db execution.DB, rowsAffected ...int64) {
|
||||||
|
res, err := stmt.Exec(db)
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
rows, err := res.RowsAffected()
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
if len(rowsAffected) > 0 {
|
||||||
|
assert.Equal(t, rows, rowsAffected[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AssertExecErr(t *testing.T, stmt jet.Statement, db execution.DB, errorStr string) {
|
||||||
|
_, err := stmt.Exec(db)
|
||||||
|
|
||||||
|
assert.Error(t, err, errorStr)
|
||||||
|
}
|
||||||
|
|
||||||
func AssertJSON(t *testing.T, expectedJSON string, data interface{}) {
|
func AssertJSON(t *testing.T, expectedJSON string, data interface{}) {
|
||||||
jsonData, err := json.MarshalIndent(data, "", "\t")
|
jsonData, err := json.MarshalIndent(data, "", "\t")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
@ -46,8 +65,8 @@ func AssertJSONFile(t *testing.T, data interface{}, jsonFilePath string) {
|
||||||
jsonData, err := json.MarshalIndent(data, "", "\t")
|
jsonData, err := json.MarshalIndent(data, "", "\t")
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
//assert.Assert(t, string(fileJSONData) == string(jsonData))
|
assert.Assert(t, string(fileJSONData) == string(jsonData))
|
||||||
assert.DeepEqual(t, string(fileJSONData), string(jsonData))
|
//assert.DeepEqual(t, string(fileJSONData), string(jsonData))
|
||||||
}
|
}
|
||||||
|
|
||||||
func AssertStatementSql(t *testing.T, query jet.Statement, expectedQuery string, expectedArgs ...interface{}) {
|
func AssertStatementSql(t *testing.T, query jet.Statement, expectedQuery string, expectedArgs ...interface{}) {
|
||||||
|
|
|
||||||
|
|
@ -138,4 +138,18 @@ CREATE TABLE IF NOT EXISTS test_sample.link (
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO test_sample.link (ID, url, name, description) VALUES
|
INSERT INTO test_sample.link (ID, url, name, description) VALUES
|
||||||
|
(0, 'http://www.youtube.com', 'Youtube' , '');
|
||||||
|
|
||||||
|
-- Link2 table --------------------
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS test_sample.link2;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS test_sample.link2 (
|
||||||
|
id int PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
url VARCHAR (255) NOT NULL,
|
||||||
|
name VARCHAR (255) NOT NULL,
|
||||||
|
description VARCHAR (255)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO test_sample.link2 (ID, url, name, description) VALUES
|
||||||
(0, 'http://www.youtube.com', 'Youtube' , '');
|
(0, 'http://www.youtube.com', 'Youtube' , '');
|
||||||
|
|
@ -13,7 +13,7 @@ func TestCast(t *testing.T) {
|
||||||
|
|
||||||
query := SELECT(
|
query := SELECT(
|
||||||
CAST(String("test")).AS("CHAR CHARACTER SET utf8").AS("result.AS1"),
|
CAST(String("test")).AS("CHAR CHARACTER SET utf8").AS("result.AS1"),
|
||||||
CAST(String("2011-02-02")).AS_DATE().AS("result.date"),
|
CAST(String("2011-02-02")).AS_DATE().AS("result.date1"),
|
||||||
CAST(String("14:06:10")).AS_TIME().AS("result.time"),
|
CAST(String("14:06:10")).AS_TIME().AS("result.time"),
|
||||||
CAST(String("2011-02-02 14:06:10")).AS_DATETIME().AS("result.datetime"),
|
CAST(String("2011-02-02 14:06:10")).AS_DATETIME().AS("result.datetime"),
|
||||||
|
|
||||||
|
|
@ -27,7 +27,7 @@ func TestCast(t *testing.T) {
|
||||||
|
|
||||||
testutils.AssertStatementSql(t, query, `
|
testutils.AssertStatementSql(t, query, `
|
||||||
SELECT CAST(? AS CHAR CHARACTER SET utf8) AS "result.AS1",
|
SELECT CAST(? AS CHAR CHARACTER SET utf8) AS "result.AS1",
|
||||||
CAST(? AS DATE) AS "result.date",
|
CAST(? AS DATE) AS "result.date1",
|
||||||
CAST(? AS TIME) AS "result.time",
|
CAST(? AS TIME) AS "result.time",
|
||||||
CAST(? AS DATETIME) AS "result.datetime",
|
CAST(? AS DATETIME) AS "result.datetime",
|
||||||
CAST(? AS CHAR) AS "result.char1",
|
CAST(? AS CHAR) AS "result.char1",
|
||||||
|
|
@ -41,7 +41,7 @@ FROM test_sample.all_types;
|
||||||
|
|
||||||
type Result struct {
|
type Result struct {
|
||||||
As1 string
|
As1 string
|
||||||
Date time.Time
|
Date1 time.Time
|
||||||
Time time.Time
|
Time time.Time
|
||||||
DateTime time.Time
|
DateTime time.Time
|
||||||
Char1 string
|
Char1 string
|
||||||
|
|
@ -59,7 +59,7 @@ FROM test_sample.all_types;
|
||||||
|
|
||||||
assert.DeepEqual(t, dest, Result{
|
assert.DeepEqual(t, dest, Result{
|
||||||
As1: "test",
|
As1: "test",
|
||||||
Date: *testutils.Date("2011-02-02"),
|
Date1: *testutils.Date("2011-02-02"),
|
||||||
Time: *testutils.TimeWithoutTimeZone("14:06:10"),
|
Time: *testutils.TimeWithoutTimeZone("14:06:10"),
|
||||||
DateTime: *testutils.TimestampWithoutTimeZone("2011-02-02 14:06:10", 0),
|
DateTime: *testutils.TimestampWithoutTimeZone("2011-02-02 14:06:10", 0),
|
||||||
Char1: "150",
|
Char1: "150",
|
||||||
|
|
|
||||||
|
|
@ -137,69 +137,6 @@ ORDER BY payment.customer_id, SUM(payment.amount) ASC;
|
||||||
testutils.AssertJSONFile(t, dest, "mysql/testdata/customer_payment_sum.json")
|
testutils.AssertJSONFile(t, dest, "mysql/testdata/customer_payment_sum.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRowLockTestData() map[SelectLock]string {
|
|
||||||
return map[SelectLock]string{
|
|
||||||
UPDATE(): "UPDATE",
|
|
||||||
SHARE(): "SHARE",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRowLock(t *testing.T) {
|
|
||||||
expectedSQL := `
|
|
||||||
SELECT *
|
|
||||||
FROM dvds.address
|
|
||||||
LIMIT 3
|
|
||||||
OFFSET 1
|
|
||||||
FOR`
|
|
||||||
query := Address.
|
|
||||||
SELECT(STAR).
|
|
||||||
LIMIT(3).
|
|
||||||
OFFSET(1)
|
|
||||||
|
|
||||||
for lockType, lockTypeStr := range getRowLockTestData() {
|
|
||||||
query.FOR(lockType)
|
|
||||||
|
|
||||||
expectedQuery := expectedSQL + " " + lockTypeStr + ";\n"
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedQuery, int64(3), int64(1))
|
|
||||||
|
|
||||||
tx, _ := db.Begin()
|
|
||||||
|
|
||||||
_, err := query.Exec(tx)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
err = tx.Rollback()
|
|
||||||
assert.NilError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for lockType, lockTypeStr := range getRowLockTestData() {
|
|
||||||
query.FOR(lockType.NOWAIT())
|
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL+" "+lockTypeStr+" NOWAIT;\n", int64(3), int64(1))
|
|
||||||
|
|
||||||
tx, _ := db.Begin()
|
|
||||||
|
|
||||||
_, err := query.Exec(tx)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
err = tx.Rollback()
|
|
||||||
assert.NilError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for lockType, lockTypeStr := range getRowLockTestData() {
|
|
||||||
query.FOR(lockType.SKIP_LOCKED())
|
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL+" "+lockTypeStr+" SKIP LOCKED;\n", int64(3), int64(1))
|
|
||||||
|
|
||||||
tx, _ := db.Begin()
|
|
||||||
|
|
||||||
_, err := query.Exec(tx)
|
|
||||||
assert.NilError(t, err)
|
|
||||||
|
|
||||||
err = tx.Rollback()
|
|
||||||
assert.NilError(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSubQuery(t *testing.T) {
|
func TestSubQuery(t *testing.T) {
|
||||||
|
|
||||||
rRatingFilms := Film.
|
rRatingFilms := Film.
|
||||||
|
|
@ -385,3 +322,66 @@ LIMIT ?;
|
||||||
testutils.AssertJSONFile(t, dest, "./mysql/testdata/lang_film_actor_inventory_rental.json")
|
testutils.AssertJSONFile(t, dest, "./mysql/testdata/lang_film_actor_inventory_rental.json")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRowLockTestData() map[SelectLock]string {
|
||||||
|
return map[SelectLock]string{
|
||||||
|
UPDATE(): "UPDATE",
|
||||||
|
SHARE(): "SHARE",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRowLock(t *testing.T) {
|
||||||
|
expectedSQL := `
|
||||||
|
SELECT *
|
||||||
|
FROM dvds.address
|
||||||
|
LIMIT 3
|
||||||
|
OFFSET 1
|
||||||
|
FOR`
|
||||||
|
query := Address.
|
||||||
|
SELECT(STAR).
|
||||||
|
LIMIT(3).
|
||||||
|
OFFSET(1)
|
||||||
|
|
||||||
|
for lockType, lockTypeStr := range getRowLockTestData() {
|
||||||
|
query.FOR(lockType)
|
||||||
|
|
||||||
|
expectedQuery := expectedSQL + " " + lockTypeStr + ";\n"
|
||||||
|
testutils.AssertDebugStatementSql(t, query, expectedQuery, int64(3), int64(1))
|
||||||
|
|
||||||
|
tx, _ := db.Begin()
|
||||||
|
|
||||||
|
_, err := query.Exec(tx)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
err = tx.Rollback()
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for lockType, lockTypeStr := range getRowLockTestData() {
|
||||||
|
query.FOR(lockType.NOWAIT())
|
||||||
|
|
||||||
|
testutils.AssertDebugStatementSql(t, query, expectedSQL+" "+lockTypeStr+" NOWAIT;\n", int64(3), int64(1))
|
||||||
|
|
||||||
|
tx, _ := db.Begin()
|
||||||
|
|
||||||
|
_, err := query.Exec(tx)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
err = tx.Rollback()
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for lockType, lockTypeStr := range getRowLockTestData() {
|
||||||
|
query.FOR(lockType.SKIP_LOCKED())
|
||||||
|
|
||||||
|
testutils.AssertDebugStatementSql(t, query, expectedSQL+" "+lockTypeStr+" SKIP LOCKED;\n", int64(3), int64(1))
|
||||||
|
|
||||||
|
tx, _ := db.Begin()
|
||||||
|
|
||||||
|
_, err := query.Exec(tx)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
err = tx.Rollback()
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
224
tests/mysql/update_test.go
Normal file
224
tests/mysql/update_test.go
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
package mysql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
. "github.com/go-jet/jet"
|
||||||
|
"github.com/go-jet/jet/internal/testutils"
|
||||||
|
"github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/model"
|
||||||
|
. "github.com/go-jet/jet/tests/.gentestdata/mysql/test_sample/table"
|
||||||
|
"gotest.tools/assert"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUpdateValues(t *testing.T) {
|
||||||
|
setupLinkTableForUpdateTest(t)
|
||||||
|
|
||||||
|
query := Link.
|
||||||
|
UPDATE(Link.Name, Link.URL).
|
||||||
|
SET("Bong", "http://bong.com").
|
||||||
|
WHERE(Link.Name.EQ(String("Bing")))
|
||||||
|
|
||||||
|
var expectedSQL = `
|
||||||
|
UPDATE test_sample.link
|
||||||
|
SET name = 'Bong', url = 'http://bong.com'
|
||||||
|
WHERE link.name = 'Bing';
|
||||||
|
`
|
||||||
|
|
||||||
|
testutils.AssertDebugStatementSql(t, query, expectedSQL, "Bong", "http://bong.com", "Bing")
|
||||||
|
|
||||||
|
testutils.AssertExec(t, query, db)
|
||||||
|
|
||||||
|
links := []model.Link{}
|
||||||
|
|
||||||
|
err := Link.
|
||||||
|
SELECT(Link.AllColumns).
|
||||||
|
WHERE(Link.Name.EQ(String("Bong"))).
|
||||||
|
Query(db, &links)
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, len(links), 1)
|
||||||
|
assert.DeepEqual(t, links[0], model.Link{
|
||||||
|
ID: 204,
|
||||||
|
URL: "http://bong.com",
|
||||||
|
Name: "Bong",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateWithSubQueries(t *testing.T) {
|
||||||
|
setupLinkTableForUpdateTest(t)
|
||||||
|
|
||||||
|
query := Link.
|
||||||
|
UPDATE(Link.Name, Link.URL).
|
||||||
|
SET(
|
||||||
|
SELECT(String("Bong")),
|
||||||
|
SELECT(Link2.URL).
|
||||||
|
FROM(Link2).
|
||||||
|
WHERE(Link2.Name.EQ(String("Youtube"))),
|
||||||
|
).
|
||||||
|
WHERE(Link.Name.EQ(String("Bing")))
|
||||||
|
|
||||||
|
expectedSQL := `
|
||||||
|
UPDATE test_sample.link
|
||||||
|
SET name = (
|
||||||
|
SELECT ?
|
||||||
|
), url = (
|
||||||
|
SELECT link2.url AS "link2.url"
|
||||||
|
FROM test_sample.link2
|
||||||
|
WHERE link2.name = ?
|
||||||
|
)
|
||||||
|
WHERE link.name = ?;
|
||||||
|
`
|
||||||
|
testutils.AssertStatementSql(t, query, expectedSQL, "Bong", "Youtube", "Bing")
|
||||||
|
|
||||||
|
testutils.AssertExec(t, query, db)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateAndReturning(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
assert.Equal(t, r, "jet: MySQL dialect does not support RETURNING.")
|
||||||
|
}()
|
||||||
|
|
||||||
|
stmt := Link.
|
||||||
|
UPDATE(Link.Name, Link.URL).
|
||||||
|
SET("DuckDuckGo", "http://www.duckduckgo.com").
|
||||||
|
WHERE(Link.Name.EQ(String("Ask"))).
|
||||||
|
RETURNING(Link.AllColumns)
|
||||||
|
|
||||||
|
stmt.Query(db, &struct{}{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateWithModelData(t *testing.T) {
|
||||||
|
setupLinkTableForUpdateTest(t)
|
||||||
|
|
||||||
|
link := model.Link{
|
||||||
|
ID: 201,
|
||||||
|
URL: "http://www.duckduckgo.com",
|
||||||
|
Name: "DuckDuckGo",
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt := Link.
|
||||||
|
UPDATE(Link.AllColumns).
|
||||||
|
MODEL(link).
|
||||||
|
WHERE(Link.ID.EQ(Int(int64(link.ID))))
|
||||||
|
|
||||||
|
expectedSQL := `
|
||||||
|
UPDATE test_sample.link
|
||||||
|
SET id = ?, url = ?, name = ?, description = ?
|
||||||
|
WHERE link.id = ?;
|
||||||
|
`
|
||||||
|
testutils.AssertStatementSql(t, stmt, expectedSQL, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201))
|
||||||
|
|
||||||
|
testutils.AssertExec(t, stmt, db)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateWithModelDataAndPredefinedColumnList(t *testing.T) {
|
||||||
|
|
||||||
|
setupLinkTableForUpdateTest(t)
|
||||||
|
|
||||||
|
link := model.Link{
|
||||||
|
ID: 201,
|
||||||
|
URL: "http://www.duckduckgo.com",
|
||||||
|
Name: "DuckDuckGo",
|
||||||
|
}
|
||||||
|
|
||||||
|
updateColumnList := ColumnList{Link.Description, Link.Name, Link.URL}
|
||||||
|
|
||||||
|
stmt := Link.
|
||||||
|
UPDATE(updateColumnList).
|
||||||
|
MODEL(link).
|
||||||
|
WHERE(Link.ID.EQ(Int(int64(link.ID))))
|
||||||
|
|
||||||
|
var expectedSQL = `
|
||||||
|
UPDATE test_sample.link
|
||||||
|
SET description = NULL, name = 'DuckDuckGo', url = 'http://www.duckduckgo.com'
|
||||||
|
WHERE link.id = 201;
|
||||||
|
`
|
||||||
|
//fmt.Println(stmt.DebugSql())
|
||||||
|
|
||||||
|
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int64(201))
|
||||||
|
|
||||||
|
testutils.AssertExec(t, stmt, db)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateWithInvalidModelData(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
|
||||||
|
assert.Equal(t, r, "missing struct field for column : id")
|
||||||
|
}()
|
||||||
|
|
||||||
|
setupLinkTableForUpdateTest(t)
|
||||||
|
|
||||||
|
link := struct {
|
||||||
|
Ident int
|
||||||
|
URL string
|
||||||
|
Name string
|
||||||
|
Description *string
|
||||||
|
Rel *string
|
||||||
|
}{
|
||||||
|
Ident: 201,
|
||||||
|
URL: "http://www.duckduckgo.com",
|
||||||
|
Name: "DuckDuckGo",
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt := Link.
|
||||||
|
UPDATE(Link.AllColumns).
|
||||||
|
MODEL(link).
|
||||||
|
WHERE(Link.ID.EQ(Int(int64(link.Ident))))
|
||||||
|
|
||||||
|
stmt.Sql()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateQueryContext(t *testing.T) {
|
||||||
|
setupLinkTableForUpdateTest(t)
|
||||||
|
|
||||||
|
updateStmt := Link.
|
||||||
|
UPDATE(Link.Name, Link.URL).
|
||||||
|
SET("Bong", "http://bong.com").
|
||||||
|
WHERE(Link.Name.EQ(String("Bing")))
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|
||||||
|
dest := []model.Link{}
|
||||||
|
err := updateStmt.QueryContext(ctx, db, &dest)
|
||||||
|
|
||||||
|
assert.Error(t, err, "context deadline exceeded")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateExecContext(t *testing.T) {
|
||||||
|
setupLinkTableForUpdateTest(t)
|
||||||
|
|
||||||
|
updateStmt := Link.
|
||||||
|
UPDATE(Link.Name, Link.URL).
|
||||||
|
SET("Bong", "http://bong.com").
|
||||||
|
WHERE(Link.Name.EQ(String("Bing")))
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|
||||||
|
_, err := updateStmt.ExecContext(ctx, db)
|
||||||
|
|
||||||
|
assert.Error(t, err, "context deadline exceeded")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupLinkTableForUpdateTest(t *testing.T) {
|
||||||
|
|
||||||
|
cleanUpLinkTable(t)
|
||||||
|
|
||||||
|
_, err := Link.INSERT(Link.ID, Link.URL, Link.Name, Link.Description).
|
||||||
|
VALUES(200, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT).
|
||||||
|
VALUES(201, "http://www.ask.com", "Ask", DEFAULT).
|
||||||
|
VALUES(202, "http://www.ask.com", "Ask", DEFAULT).
|
||||||
|
VALUES(203, "http://www.yahoo.com", "Yahoo", DEFAULT).
|
||||||
|
VALUES(204, "http://www.bing.com", "Bing", DEFAULT).
|
||||||
|
Exec(db)
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,7 @@ WHERE link.name IN ('Gmail', 'Outlook');
|
||||||
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
|
WHERE(Link.Name.IN(String("Gmail"), String("Outlook")))
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, deleteStmt, expectedSQL, "Gmail", "Outlook")
|
testutils.AssertDebugStatementSql(t, deleteStmt, expectedSQL, "Gmail", "Outlook")
|
||||||
assertExec(t, deleteStmt, 2)
|
AssertExec(t, deleteStmt, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteWithWhereAndReturning(t *testing.T) {
|
func TestDeleteWithWhereAndReturning(t *testing.T) {
|
||||||
|
|
@ -61,7 +61,7 @@ func initForDeleteTest(t *testing.T) {
|
||||||
VALUES("www.gmail.com", "Gmail", "Email service developed by Google").
|
VALUES("www.gmail.com", "Gmail", "Email service developed by Google").
|
||||||
VALUES("www.outlook.live.com", "Outlook", "Email service developed by Microsoft")
|
VALUES("www.outlook.live.com", "Outlook", "Email service developed by Microsoft")
|
||||||
|
|
||||||
assertExec(t, stmt, 2)
|
AssertExec(t, stmt, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteQueryContext(t *testing.T) {
|
func TestDeleteQueryContext(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ INSERT INTO test_sample.link VALUES
|
||||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL,
|
testutils.AssertDebugStatementSql(t, stmt, expectedSQL,
|
||||||
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial")
|
100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial")
|
||||||
|
|
||||||
assertExec(t, stmt, 1)
|
AssertExec(t, stmt, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertModelObject(t *testing.T) {
|
func TestInsertModelObject(t *testing.T) {
|
||||||
|
|
@ -109,7 +109,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, "http://www.duckduckgo.com", "Duck Duck go")
|
testutils.AssertDebugStatementSql(t, query, expectedSQL, "http://www.duckduckgo.com", "Duck Duck go")
|
||||||
|
|
||||||
assertExec(t, query, 1)
|
AssertExec(t, query, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertModelObjectEmptyColumnList(t *testing.T) {
|
func TestInsertModelObjectEmptyColumnList(t *testing.T) {
|
||||||
|
|
@ -131,7 +131,7 @@ INSERT INTO test_sample.link VALUES
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, int32(1000), "http://www.duckduckgo.com", "Duck Duck go", nil)
|
testutils.AssertDebugStatementSql(t, query, expectedSQL, int32(1000), "http://www.duckduckgo.com", "Duck Duck go", nil)
|
||||||
|
|
||||||
assertExec(t, query, 1)
|
AssertExec(t, query, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertModelsObject(t *testing.T) {
|
func TestInsertModelsObject(t *testing.T) {
|
||||||
|
|
@ -166,7 +166,7 @@ INSERT INTO test_sample.link (url, name) VALUES
|
||||||
"http://www.google.com", "Google",
|
"http://www.google.com", "Google",
|
||||||
"http://www.yahoo.com", "Yahoo")
|
"http://www.yahoo.com", "Yahoo")
|
||||||
|
|
||||||
assertExec(t, stmt, 3)
|
AssertExec(t, stmt, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertUsingMutableColumns(t *testing.T) {
|
func TestInsertUsingMutableColumns(t *testing.T) {
|
||||||
|
|
@ -200,7 +200,7 @@ INSERT INTO test_sample.link (url, name, description) VALUES
|
||||||
"http://www.google.com", "Google", nil,
|
"http://www.google.com", "Google", nil,
|
||||||
"http://www.yahoo.com", "Yahoo", nil)
|
"http://www.yahoo.com", "Yahoo", nil)
|
||||||
|
|
||||||
assertExec(t, stmt, 4)
|
AssertExec(t, stmt, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertQuery(t *testing.T) {
|
func TestInsertQuery(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ WHERE link.name = 'Bing';
|
||||||
`
|
`
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, "Bong", "http://bong.com", "Bing")
|
testutils.AssertDebugStatementSql(t, query, expectedSQL, "Bong", "http://bong.com", "Bing")
|
||||||
|
|
||||||
assertExec(t, query, 1)
|
AssertExec(t, query, 1)
|
||||||
|
|
||||||
links := []model.Link{}
|
links := []model.Link{}
|
||||||
|
|
||||||
|
|
@ -71,7 +71,7 @@ WHERE link.name = 'Bing';
|
||||||
|
|
||||||
testutils.AssertDebugStatementSql(t, query, expectedSQL, "Bong", "Bing", "Bing")
|
testutils.AssertDebugStatementSql(t, query, expectedSQL, "Bong", "Bing", "Bing")
|
||||||
|
|
||||||
assertExec(t, query, 1)
|
AssertExec(t, query, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateAndReturning(t *testing.T) {
|
func TestUpdateAndReturning(t *testing.T) {
|
||||||
|
|
@ -129,7 +129,7 @@ WHERE link.id = 0;
|
||||||
`
|
`
|
||||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, int64(0), int64(0))
|
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, int64(0), int64(0))
|
||||||
|
|
||||||
assertExec(t, stmt, 1)
|
AssertExec(t, stmt, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateWithInvalidSelect(t *testing.T) {
|
func TestUpdateWithInvalidSelect(t *testing.T) {
|
||||||
|
|
@ -178,7 +178,7 @@ WHERE link.id = 201;
|
||||||
`
|
`
|
||||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201))
|
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201))
|
||||||
|
|
||||||
assertExec(t, stmt, 1)
|
AssertExec(t, stmt, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateWithModelDataAndPredefinedColumnList(t *testing.T) {
|
func TestUpdateWithModelDataAndPredefinedColumnList(t *testing.T) {
|
||||||
|
|
@ -205,7 +205,7 @@ WHERE link.id = 201;
|
||||||
`
|
`
|
||||||
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int64(201))
|
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int64(201))
|
||||||
|
|
||||||
assertExec(t, stmt, 1)
|
AssertExec(t, stmt, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateWithInvalidModelData(t *testing.T) {
|
func TestUpdateWithInvalidModelData(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func assertExec(t *testing.T, stmt jet.Statement, rowsAffected int64) {
|
func AssertExec(t *testing.T, stmt jet.Statement, rowsAffected int64) {
|
||||||
res, err := stmt.Exec(db)
|
res, err := stmt.Exec(db)
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
|
||||||
|
|
@ -23,26 +23,26 @@ func newUpdateStatement(table WritableTable, columns []column) UpdateStatement {
|
||||||
return &updateStatementImpl{
|
return &updateStatementImpl{
|
||||||
table: table,
|
table: table,
|
||||||
columns: columns,
|
columns: columns,
|
||||||
row: make([]clause, 0, len(columns)),
|
values: make([]clause, 0, len(columns)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateStatementImpl struct {
|
type updateStatementImpl struct {
|
||||||
table WritableTable
|
table WritableTable
|
||||||
columns []column
|
columns []column
|
||||||
row []clause
|
values []clause
|
||||||
where BoolExpression
|
where BoolExpression
|
||||||
returning []projection
|
returning []projection
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *updateStatementImpl) SET(value interface{}, values ...interface{}) UpdateStatement {
|
func (u *updateStatementImpl) SET(value interface{}, values ...interface{}) UpdateStatement {
|
||||||
u.row = unwindRowFromValues(value, values)
|
u.values = unwindRowFromValues(value, values)
|
||||||
|
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *updateStatementImpl) MODEL(data interface{}) UpdateStatement {
|
func (u *updateStatementImpl) MODEL(data interface{}) UpdateStatement {
|
||||||
u.row = unwindRowFromModel(u.columns, data)
|
u.values = unwindRowFromModel(u.columns, data)
|
||||||
|
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
@ -82,43 +82,17 @@ func (u *updateStatementImpl) Sql(dialect ...Dialect) (query string, args []inte
|
||||||
return "", nil, errors.New("jet: no columns selected")
|
return "", nil, errors.New("jet: no columns selected")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(u.row) == 0 {
|
if len(u.values) == 0 {
|
||||||
return "", nil, errors.New("jet: no values to updated")
|
return "", nil, errors.New("jet: no values to updated")
|
||||||
}
|
}
|
||||||
|
|
||||||
out.newLine()
|
out.newLine()
|
||||||
out.writeString("SET")
|
out.writeString("SET")
|
||||||
|
|
||||||
if len(u.columns) > 1 {
|
if err = out.dialect.UpdateAssigment(u.columns, u.values, out); err != nil {
|
||||||
out.writeString("(")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = serializeColumnNames(u.columns, out)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(u.columns) > 1 {
|
|
||||||
out.writeString(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
out.writeString("=")
|
|
||||||
|
|
||||||
if len(u.row) > 1 {
|
|
||||||
out.writeString("(")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = serializeClauseList(updateStatement, u.row, out)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(u.row) > 1 {
|
|
||||||
out.writeString(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
if u.where == nil {
|
if u.where == nil {
|
||||||
return "", nil, errors.New("jet: WHERE clause not set")
|
return "", nil, errors.New("jet: WHERE clause not set")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue