fork github.com/doug-martin

This commit is contained in:
2025-03-22 23:02:05 +08:00
commit f14642a736
131 changed files with 34555 additions and 0 deletions
+527
View File
@@ -0,0 +1,527 @@
package db_test
import (
"testing"
dbv2 "git.fsdpf.net/go/db/v2"
"git.fsdpf.net/go/db/v2/exp"
"git.fsdpf.net/go/db/v2/internal/errors"
"git.fsdpf.net/go/db/v2/internal/sb"
"git.fsdpf.net/go/db/v2/mocks"
"github.com/DATA-DOG/go-sqlmock"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
)
type (
updateTestCase struct {
ds *dbv2.UpdateDataset
clauses exp.UpdateClauses
}
updateDatasetSuite struct {
suite.Suite
}
)
func (uds *updateDatasetSuite) assertCases(cases ...updateTestCase) {
for _, s := range cases {
uds.Equal(s.clauses, s.ds.GetClauses())
}
}
func (uds *updateDatasetSuite) TestUpdate() {
ds := dbv2.Update("test")
uds.IsType(&dbv2.UpdateDataset{}, ds)
uds.Implements((*exp.Expression)(nil), ds)
uds.Implements((*exp.AppendableExpression)(nil), ds)
}
func (uds *updateDatasetSuite) TestClone() {
ds := dbv2.Update("test")
uds.Equal(ds, ds.Clone())
}
func (uds *updateDatasetSuite) TestExpression() {
ds := dbv2.Update("test")
uds.Equal(ds, ds.Expression())
}
func (uds *updateDatasetSuite) TestDialect() {
ds := dbv2.Update("test")
uds.NotNil(ds.Dialect())
}
func (uds *updateDatasetSuite) TestWithDialect() {
ds := dbv2.Update("test")
md := new(mocks.SQLDialect)
ds = ds.SetDialect(md)
dialect := dbv2.GetDialect("default")
dialectDs := ds.WithDialect("default")
uds.Equal(md, ds.Dialect())
uds.Equal(dialect, dialectDs.Dialect())
}
func (uds *updateDatasetSuite) TestPrepared() {
ds := dbv2.Update("test")
preparedDs := ds.Prepared(true)
uds.True(preparedDs.IsPrepared())
uds.False(ds.IsPrepared())
// should apply the prepared to any datasets created from the root
uds.True(preparedDs.Where(dbv2.Ex{"a": 1}).IsPrepared())
defer dbv2.SetDefaultPrepared(false)
dbv2.SetDefaultPrepared(true)
// should be prepared by default
ds = dbv2.Update("test")
uds.True(ds.IsPrepared())
}
func (uds *updateDatasetSuite) TestGetClauses() {
ds := dbv2.Update("test")
ce := exp.NewUpdateClauses().SetTable(dbv2.I("test"))
uds.Equal(ce, ds.GetClauses())
}
func (uds *updateDatasetSuite) TestWith() {
from := dbv2.Update("cte")
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.With("test-cte", from),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
CommonTablesAppend(exp.NewCommonTableExpression(false, "test-cte", from)),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
)
}
func (uds *updateDatasetSuite) TestWithRecursive() {
from := dbv2.Update("cte")
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.WithRecursive("test-cte", from),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
CommonTablesAppend(exp.NewCommonTableExpression(true, "test-cte", from)),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
)
}
func (uds *updateDatasetSuite) TestTable() {
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.Table("items2"),
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items2")),
},
updateTestCase{
ds: bd.Table(dbv2.L("literal_table")),
clauses: exp.NewUpdateClauses().SetTable(dbv2.L("literal_table")),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
)
uds.PanicsWithValue(dbv2.ErrUnsupportedUpdateTableType, func() {
bd.Table(true)
})
}
func (uds *updateDatasetSuite) TestSet() {
type item struct {
Address string `db:"address"`
Name string `db:"name"`
}
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.Set(item{Name: "Test", Address: "111 Test Addr"}),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
SetSetValues(item{Name: "Test", Address: "111 Test Addr"}),
},
updateTestCase{
ds: bd.Set(dbv2.Record{"name": "Test", "address": "111 Test Addr"}),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
SetSetValues(dbv2.Record{"name": "Test", "address": "111 Test Addr"}),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")),
},
updateTestCase{
ds: bd.Set([]exp.UpdateExpression{
dbv2.C("name").Set("Test"),
dbv2.C("address").Set("111 Test Addr"),
}),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
SetSetValues([]exp.UpdateExpression{
dbv2.C("name").Set("Test"),
dbv2.C("address").Set("111 Test Addr"),
}),
},
)
}
func (uds *updateDatasetSuite) TestFrom() {
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.From("other"),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
SetFrom(exp.NewColumnListExpression("other")),
},
updateTestCase{
ds: bd.From("other").From("other2"),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
SetFrom(exp.NewColumnListExpression("other2")),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")),
},
)
}
func (uds *updateDatasetSuite) TestWhere() {
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.Where(dbv2.Ex{"a": 1}),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
WhereAppend(dbv2.Ex{"a": 1}),
},
updateTestCase{
ds: bd.Where(dbv2.Ex{"a": 1}).Where(dbv2.C("b").Eq("c")),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
WhereAppend(dbv2.Ex{"a": 1}).WhereAppend(dbv2.C("b").Eq("c")),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")),
},
)
}
func (uds *updateDatasetSuite) TestClearWhere() {
bd := dbv2.Update("items").Where(dbv2.Ex{"a": 1})
uds.assertCases(
updateTestCase{
ds: bd.ClearWhere(),
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
WhereAppend(dbv2.Ex{"a": 1}),
},
)
}
func (uds *updateDatasetSuite) TestOrder() {
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.Order(dbv2.C("a").Desc()),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).OrderAppend(dbv2.C("a").Desc()),
},
updateTestCase{
ds: bd.Order(dbv2.C("a").Desc()).Order(dbv2.C("b").Asc()),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
OrderAppend(dbv2.C("b").Asc()),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
)
}
func (uds *updateDatasetSuite) TestOrderAppend() {
bd := dbv2.Update("items").Order(dbv2.C("a").Desc())
uds.assertCases(
updateTestCase{
ds: bd.OrderAppend(dbv2.C("b").Asc()),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
OrderAppend(dbv2.C("a").Desc()).
OrderAppend(dbv2.C("b").Asc()),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
OrderAppend(dbv2.C("a").Desc()),
},
)
}
func (uds *updateDatasetSuite) TestOrderPrepend() {
bd := dbv2.Update("items").Order(dbv2.C("a").Desc())
uds.assertCases(
updateTestCase{
ds: bd.OrderPrepend(dbv2.C("b").Asc()),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
OrderAppend(dbv2.C("b").Asc()).
OrderAppend(dbv2.C("a").Desc()),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
OrderAppend(dbv2.C("a").Desc()),
},
)
}
func (uds *updateDatasetSuite) TestClearOrder() {
bd := dbv2.Update("items").Order(dbv2.C("a").Desc())
uds.assertCases(
updateTestCase{
ds: bd.ClearOrder(),
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
OrderAppend(dbv2.C("a").Desc()),
},
)
}
func (uds *updateDatasetSuite) TestLimit() {
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.Limit(10),
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")).SetLimit(uint(10)),
},
updateTestCase{
ds: bd.Limit(0),
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
)
}
func (uds *updateDatasetSuite) TestLimitAll() {
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.LimitAll(),
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")).SetLimit(dbv2.L("ALL")),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
)
}
func (uds *updateDatasetSuite) TestClearLimit() {
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.LimitAll().ClearLimit(),
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
updateTestCase{
ds: bd.Limit(10).ClearLimit(),
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
)
}
func (uds *updateDatasetSuite) TestReturning() {
bd := dbv2.Update("items")
uds.assertCases(
updateTestCase{
ds: bd.Returning("a", "b"),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
SetReturning(exp.NewColumnListExpression("a", "b")),
},
updateTestCase{
ds: bd.Returning(),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
SetReturning(exp.NewColumnListExpression()),
},
updateTestCase{
ds: bd.Returning(nil),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
SetReturning(exp.NewColumnListExpression()),
},
updateTestCase{
ds: bd.Returning("a", "b").Returning("c"),
clauses: exp.NewUpdateClauses().
SetTable(dbv2.C("items")).
SetReturning(exp.NewColumnListExpression("c")),
},
updateTestCase{
ds: bd,
clauses: exp.NewUpdateClauses().SetTable(dbv2.C("items")),
},
)
}
func (uds *updateDatasetSuite) TestReturnsColumns() {
ds := dbv2.Update("test")
uds.False(ds.ReturnsColumns())
uds.True(ds.Returning("foo", "bar").ReturnsColumns())
}
func (uds *updateDatasetSuite) TestToSQL() {
md := new(mocks.SQLDialect)
ds := dbv2.Update("test").SetDialect(md)
r := dbv2.Record{"c": "a"}
c := ds.GetClauses().SetSetValues(r)
sqlB := sb.NewSQLBuilder(false)
md.On("ToUpdateSQL", sqlB, c).Return(nil).Once()
updateSQL, args, err := ds.Set(r).ToSQL()
uds.Empty(updateSQL)
uds.Empty(args)
uds.Nil(err)
md.AssertExpectations(uds.T())
}
func (uds *updateDatasetSuite) TestToSQL_Prepared() {
md := new(mocks.SQLDialect)
ds := dbv2.Update("test").Prepared(true).SetDialect(md)
r := dbv2.Record{"c": "a"}
c := ds.GetClauses().SetSetValues(r)
sqlB := sb.NewSQLBuilder(true)
md.On("ToUpdateSQL", sqlB, c).Return(nil).Once()
updateSQL, args, err := ds.Set(dbv2.Record{"c": "a"}).ToSQL()
uds.Empty(updateSQL)
uds.Empty(args)
uds.Nil(err)
md.AssertExpectations(uds.T())
}
func (uds *updateDatasetSuite) TestToSQL_WithError() {
md := new(mocks.SQLDialect)
ds := dbv2.Update("test").SetDialect(md)
r := dbv2.Record{"c": "a"}
c := ds.GetClauses().SetSetValues(r)
sqlB := sb.NewSQLBuilder(false)
ee := errors.New("expected error")
md.On("ToUpdateSQL", sqlB, c).Run(func(args mock.Arguments) {
args.Get(0).(sb.SQLBuilder).SetError(ee)
}).Once()
updateSQL, args, err := ds.Set(dbv2.Record{"c": "a"}).ToSQL()
uds.Empty(updateSQL)
uds.Empty(args)
uds.Equal(ee, err)
md.AssertExpectations(uds.T())
}
func (uds *updateDatasetSuite) TestExecutor() {
mDB, _, err := sqlmock.New()
uds.NoError(err)
ds := dbv2.New("mock", mDB).
Update("items").
Set(dbv2.Record{"address": "111 Test Addr", "name": "Test1"}).
Where(dbv2.C("name").IsNull())
updateSQL, args, err := ds.Executor().ToSQL()
uds.NoError(err)
uds.Empty(args)
uds.Equal(`UPDATE "items" SET "address"='111 Test Addr',"name"='Test1' WHERE ("name" IS NULL)`, updateSQL)
updateSQL, args, err = ds.Prepared(true).Executor().ToSQL()
uds.NoError(err)
uds.Equal([]interface{}{"111 Test Addr", "Test1"}, args)
uds.Equal(`UPDATE "items" SET "address"=?,"name"=? WHERE ("name" IS NULL)`, updateSQL)
defer dbv2.SetDefaultPrepared(false)
dbv2.SetDefaultPrepared(true)
updateSQL, args, err = ds.Executor().ToSQL()
uds.NoError(err)
uds.Equal([]interface{}{"111 Test Addr", "Test1"}, args)
uds.Equal(`UPDATE "items" SET "address"=?,"name"=? WHERE ("name" IS NULL)`, updateSQL)
}
func (uds *updateDatasetSuite) TestSetError() {
err1 := errors.New("error #1")
err2 := errors.New("error #2")
err3 := errors.New("error #3")
// Verify initial error set/get works properly
md := new(mocks.SQLDialect)
ds := dbv2.Update("test").SetDialect(md)
ds = ds.SetError(err1)
uds.Equal(err1, ds.Error())
sql, args, err := ds.ToSQL()
uds.Empty(sql)
uds.Empty(args)
uds.Equal(err1, err)
// Repeated SetError calls on Dataset should not overwrite the original error
ds = ds.SetError(err2)
uds.Equal(err1, ds.Error())
sql, args, err = ds.ToSQL()
uds.Empty(sql)
uds.Empty(args)
uds.Equal(err1, err)
// Builder functions should not lose the error
ds = ds.ClearLimit()
uds.Equal(err1, ds.Error())
sql, args, err = ds.ToSQL()
uds.Empty(sql)
uds.Empty(args)
uds.Equal(err1, err)
// Deeper errors inside SQL generation should still return original error
c := ds.GetClauses()
sqlB := sb.NewSQLBuilder(false)
md.On("ToUpdateSQL", sqlB, c).Run(func(args mock.Arguments) {
args.Get(0).(sb.SQLBuilder).SetError(err3)
}).Once()
sql, args, err = ds.ToSQL()
uds.Empty(sql)
uds.Empty(args)
uds.Equal(err1, err)
}
func TestUpdateDataset(t *testing.T) {
suite.Run(t, new(updateDatasetSuite))
}