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
+496
View File
@@ -0,0 +1,496 @@
package db_test
import (
"context"
"fmt"
"strings"
"testing"
"time"
dbv2 "git.fsdpf.net/go/db/v2"
"git.fsdpf.net/go/db/v2/exp"
"github.com/DATA-DOG/go-sqlmock"
"github.com/stretchr/testify/suite"
)
type githubIssuesSuite struct {
suite.Suite
}
func (gis *githubIssuesSuite) AfterTest(_, _ string) {
dbv2.SetColumnRenameFunction(strings.ToLower)
}
// Test for https://github.com/doug-martin/dbv2/issues/49
func (gis *githubIssuesSuite) TestIssue49() {
dialect := dbv2.Dialect("default")
filters := dbv2.Or()
sql, args, err := dialect.From("table").Where(filters).ToSQL()
gis.NoError(err)
gis.Empty(args)
gis.Equal(`SELECT * FROM "table"`, sql)
sql, args, err = dialect.From("table").Where(dbv2.Ex{}).ToSQL()
gis.NoError(err)
gis.Empty(args)
gis.Equal(`SELECT * FROM "table"`, sql)
sql, args, err = dialect.From("table").Where(dbv2.ExOr{}).ToSQL()
gis.NoError(err)
gis.Empty(args)
gis.Equal(`SELECT * FROM "table"`, sql)
}
// Test for https://github.com/doug-martin/dbv2/issues/115
func (gis *githubIssuesSuite) TestIssue115() {
type TestStruct struct {
Field string
}
dbv2.SetColumnRenameFunction(func(col string) string {
return ""
})
_, _, err := dbv2.Insert("test").Rows(TestStruct{Field: "hello"}).ToSQL()
gis.EqualError(err, `db: a empty identifier was encountered, please specify a "schema", "table" or "column"`)
}
// Test for https://github.com/doug-martin/dbv2/issues/118
func (gis *githubIssuesSuite) TestIssue118_withEmbeddedStructWithoutExportedFields() {
// struct is in a custom package
type SimpleRole struct {
permissions []string //nolint:structcheck,unused //needed for test
}
// .....
type Role struct {
*SimpleRole
ID string `json:"id" db:"id" ff:"skipinsert"`
Key string `json:"key" db:"key"`
Name string `json:"name" db:"name"`
CreatedAt time.Time `json:"-" db:"created_at" ff:"skipinsert"`
}
rUser := &Role{
Key: `user`,
Name: `User role`,
}
sql, arg, err := dbv2.Insert(`rbac_roles`).
Returning(dbv2.C(`id`)).
Rows(rUser).
ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(`INSERT INTO "rbac_roles" ("key", "name") VALUES ('user', 'User role') RETURNING "id"`, sql)
sql, arg, err = dbv2.Update(`rbac_roles`).
Returning(dbv2.C(`id`)).
Set(rUser).
ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(
`UPDATE "rbac_roles" SET "created_at"='0001-01-01T00:00:00Z',"id"='',"key"='user',"name"='User role' RETURNING "id"`,
sql,
)
rUser = &Role{
SimpleRole: &SimpleRole{},
Key: `user`,
Name: `User role`,
}
sql, arg, err = dbv2.Insert(`rbac_roles`).
Returning(dbv2.C(`id`)).
Rows(rUser).
ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(`INSERT INTO "rbac_roles" ("key", "name") VALUES ('user', 'User role') RETURNING "id"`, sql)
sql, arg, err = dbv2.Update(`rbac_roles`).
Returning(dbv2.C(`id`)).
Set(rUser).
ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(
`UPDATE "rbac_roles" SET `+
`"created_at"='0001-01-01T00:00:00Z',"id"='',"key"='user',"name"='User role' RETURNING "id"`,
sql,
)
}
// Test for https://github.com/doug-martin/dbv2/issues/118
func (gis *githubIssuesSuite) TestIssue118_withNilEmbeddedStructWithExportedFields() {
// struct is in a custom package
type SimpleRole struct {
permissions []string //nolint:structcheck,unused // needed for test
IDStr string
}
// .....
type Role struct {
*SimpleRole
ID string `json:"id" db:"id" ff:"skipinsert"`
Key string `json:"key" db:"key"`
Name string `json:"name" db:"name"`
CreatedAt time.Time `json:"-" db:"created_at" ff:"skipinsert"`
}
rUser := &Role{
Key: `user`,
Name: `User role`,
}
sql, arg, err := dbv2.Insert(`rbac_roles`).
Returning(dbv2.C(`id`)).
Rows(rUser).
ToSQL()
gis.NoError(err)
gis.Empty(arg)
// it should not insert fields on nil embedded pointers
gis.Equal(`INSERT INTO "rbac_roles" ("key", "name") VALUES ('user', 'User role') RETURNING "id"`, sql)
sql, arg, err = dbv2.Update(`rbac_roles`).
Returning(dbv2.C(`id`)).
Set(rUser).
ToSQL()
gis.NoError(err)
gis.Empty(arg)
// it should not insert fields on nil embedded pointers
gis.Equal(
`UPDATE "rbac_roles" SET "created_at"='0001-01-01T00:00:00Z',"id"='',"key"='user',"name"='User role' RETURNING "id"`,
sql,
)
rUser = &Role{
SimpleRole: &SimpleRole{},
Key: `user`,
Name: `User role`,
}
sql, arg, err = dbv2.Insert(`rbac_roles`).
Returning(dbv2.C(`id`)).
Rows(rUser).
ToSQL()
gis.NoError(err)
gis.Empty(arg)
// it should not insert fields on nil embedded pointers
gis.Equal(
`INSERT INTO "rbac_roles" ("idstr", "key", "name") VALUES ('', 'user', 'User role') RETURNING "id"`,
sql,
)
sql, arg, err = dbv2.Update(`rbac_roles`).
Returning(dbv2.C(`id`)).
Set(rUser).
ToSQL()
gis.NoError(err)
gis.Empty(arg)
// it should not insert fields on nil embedded pointers
gis.Equal(
`UPDATE "rbac_roles" SET `+
`"created_at"='0001-01-01T00:00:00Z',"id"='',"idstr"='',"key"='user',"name"='User role' RETURNING "id"`,
sql,
)
}
// Test for https://github.com/doug-martin/dbv2/issues/118
func (gis *githubIssuesSuite) TestIssue140() {
sql, arg, err := dbv2.Insert(`test`).Returning().ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(`INSERT INTO "test" DEFAULT VALUES`, sql)
sql, arg, err = dbv2.Update(`test`).Set(dbv2.Record{"a": "b"}).Returning().ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(
`UPDATE "test" SET "a"='b'`,
sql,
)
sql, arg, err = dbv2.Delete(`test`).Returning().ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(
`DELETE FROM "test"`,
sql,
)
sql, arg, err = dbv2.Insert(`test`).Returning(nil).ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(`INSERT INTO "test" DEFAULT VALUES`, sql)
sql, arg, err = dbv2.Update(`test`).Set(dbv2.Record{"a": "b"}).Returning(nil).ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(
`UPDATE "test" SET "a"='b'`,
sql,
)
sql, arg, err = dbv2.Delete(`test`).Returning(nil).ToSQL()
gis.NoError(err)
gis.Empty(arg)
gis.Equal(
`DELETE FROM "test"`,
sql,
)
}
// Test for https://github.com/doug-martin/dbv2/issues/164
func (gis *githubIssuesSuite) TestIssue164() {
insertDs := dbv2.Insert("foo").Rows(dbv2.Record{"user_id": 10}).Returning("id")
ds := dbv2.From("bar").
With("ins", insertDs).
Select("bar_name").
Where(dbv2.Ex{"bar.user_id": dbv2.I("ins.user_id")})
sql, args, err := ds.ToSQL()
gis.NoError(err)
gis.Empty(args)
gis.Equal(
`WITH ins AS (INSERT INTO "foo" ("user_id") VALUES (10) RETURNING "id") `+
`SELECT "bar_name" FROM "bar" WHERE ("bar"."user_id" = "ins"."user_id")`,
sql,
)
sql, args, err = ds.Prepared(true).ToSQL()
gis.NoError(err)
gis.Equal([]interface{}{int64(10)}, args)
gis.Equal(
`WITH ins AS (INSERT INTO "foo" ("user_id") VALUES (?) RETURNING "id")`+
` SELECT "bar_name" FROM "bar" WHERE ("bar"."user_id" = "ins"."user_id")`,
sql,
)
updateDs := dbv2.Update("foo").Set(dbv2.Record{"bar": "baz"}).Returning("id")
ds = dbv2.From("bar").
With("upd", updateDs).
Select("bar_name").
Where(dbv2.Ex{"bar.user_id": dbv2.I("upd.user_id")})
sql, args, err = ds.ToSQL()
gis.NoError(err)
gis.Empty(args)
gis.Equal(
`WITH upd AS (UPDATE "foo" SET "bar"='baz' RETURNING "id") SELECT "bar_name" FROM "bar" WHERE ("bar"."user_id" = "upd"."user_id")`,
sql,
)
sql, args, err = ds.Prepared(true).ToSQL()
gis.NoError(err)
gis.Equal([]interface{}{"baz"}, args)
gis.Equal(
`WITH upd AS (UPDATE "foo" SET "bar"=? RETURNING "id") SELECT "bar_name" FROM "bar" WHERE ("bar"."user_id" = "upd"."user_id")`,
sql,
)
deleteDs := dbv2.Delete("foo").Where(dbv2.Ex{"bar": "baz"}).Returning("id")
ds = dbv2.From("bar").
With("del", deleteDs).
Select("bar_name").
Where(dbv2.Ex{"bar.user_id": dbv2.I("del.user_id")})
sql, args, err = ds.ToSQL()
gis.NoError(err)
gis.Empty(args)
gis.Equal(
`WITH del AS (DELETE FROM "foo" WHERE ("bar" = 'baz') RETURNING "id")`+
` SELECT "bar_name" FROM "bar" WHERE ("bar"."user_id" = "del"."user_id")`,
sql,
)
sql, args, err = ds.Prepared(true).ToSQL()
gis.NoError(err)
gis.Equal([]interface{}{"baz"}, args)
gis.Equal(
`WITH del AS (DELETE FROM "foo" WHERE ("bar" = ?) RETURNING "id")`+
` SELECT "bar_name" FROM "bar" WHERE ("bar"."user_id" = "del"."user_id")`,
sql,
)
}
// Test for https://github.com/doug-martin/dbv2/issues/177
func (gis *githubIssuesSuite) TestIssue177() {
ds := dbv2.Dialect("postgres").
From("ins1").
With("ins1",
dbv2.Dialect("postgres").
Insert("account").
Rows(dbv2.Record{"email": "email@email.com", "status": "active", "uuid": "XXX-XXX-XXXX"}).
Returning("*"),
).
With("ins2",
dbv2.Dialect("postgres").
Insert("account_user").
Cols("account_id", "user_id").
FromQuery(dbv2.Dialect("postgres").
From("ins1").
Select(
"id",
dbv2.V(1001),
),
),
).
Select("*")
sql, args, err := ds.ToSQL()
gis.NoError(err)
gis.Equal(`WITH ins1 AS (`+
`INSERT INTO "account" ("email", "status", "uuid") VALUES ('email@email.com', 'active', 'XXX-XXX-XXXX') RETURNING *),`+
` ins2 AS (INSERT INTO "account_user" ("account_id", "user_id") SELECT "id", 1001 FROM "ins1")`+
` SELECT * FROM "ins1"`, sql)
gis.Len(args, 0)
sql, args, err = ds.Prepared(true).ToSQL()
gis.NoError(err)
gis.Equal(`WITH ins1 AS (INSERT INTO "account" ("email", "status", "uuid") VALUES ($1, $2, $3) RETURNING *), ins2`+
` AS (INSERT INTO "account_user" ("account_id", "user_id") SELECT "id", $4 FROM "ins1") SELECT * FROM "ins1"`, sql)
gis.Equal(args, []interface{}{"email@email.com", "active", "XXX-XXX-XXXX", int64(1001)})
}
// Test for https://github.com/doug-martin/dbv2/issues/183
func (gis *githubIssuesSuite) TestIssue184() {
expectedErr := fmt.Errorf("an error")
testCases := []struct {
ds exp.AppendableExpression
}{
{ds: dbv2.From("test").As("t").SetError(expectedErr)},
{ds: dbv2.Insert("test").Rows(dbv2.Record{"foo": "bar"}).Returning("foo").SetError(expectedErr)},
{ds: dbv2.Update("test").Set(dbv2.Record{"foo": "bar"}).Returning("foo").SetError(expectedErr)},
{ds: dbv2.Update("test").Set(dbv2.Record{"foo": "bar"}).Returning("foo").SetError(expectedErr)},
{ds: dbv2.Delete("test").Returning("foo").SetError(expectedErr)},
}
for _, tc := range testCases {
ds := dbv2.From(tc.ds)
sql, args, err := ds.ToSQL()
gis.Equal(expectedErr, err)
gis.Empty(sql)
gis.Empty(args)
sql, args, err = ds.Prepared(true).ToSQL()
gis.Equal(expectedErr, err)
gis.Empty(sql)
gis.Empty(args)
ds = dbv2.From("test2").Where(dbv2.Ex{"foo": tc.ds})
sql, args, err = ds.ToSQL()
gis.Equal(expectedErr, err)
gis.Empty(sql)
gis.Empty(args)
sql, args, err = ds.Prepared(true).ToSQL()
gis.Equal(expectedErr, err)
gis.Empty(sql)
gis.Empty(args)
}
}
// Test for https://github.com/doug-martin/dbv2/issues/185
func (gis *githubIssuesSuite) TestIssue185() {
mDB, sqlMock, err := sqlmock.New()
gis.NoError(err)
sqlMock.ExpectQuery(
`SELECT \* FROM \(SELECT "id" FROM "table" ORDER BY "id" ASC\) AS "t1" UNION
\(SELECT \* FROM \(SELECT "id" FROM "table" ORDER BY "id" ASC\) AS "t1"\)`,
).
WillReturnRows(sqlmock.NewRows([]string{"id"}).FromCSVString("1\n2\n3\n4\n"))
db := dbv2.New("mock", mDB)
ds := db.Select("id").From("table").Order(dbv2.C("id").Asc()).
Union(
db.Select("id").From("table").Order(dbv2.C("id").Asc()),
)
ctx := context.Background()
var i []int
gis.NoError(ds.ScanValsContext(ctx, &i))
gis.Equal([]int{1, 2, 3, 4}, i)
}
// Test for https://github.com/doug-martin/dbv2/issues/203
func (gis *githubIssuesSuite) TestIssue203() {
// Schema definitions.
authSchema := dbv2.S("company_auth")
// Table definitions
usersTable := authSchema.Table("users")
u := usersTable.As("u")
ds := dbv2.From(u).Select(
u.Col("id"),
u.Col("name"),
u.Col("created_at"),
u.Col("updated_at"),
)
sql, args, err := ds.ToSQL()
gis.NoError(err)
gis.Equal(`SELECT "u"."id", "u"."name", "u"."created_at", "u"."updated_at" FROM "company_auth"."users" AS "u"`, sql)
gis.Empty(args, []interface{}{})
sql, args, err = ds.Prepared(true).ToSQL()
gis.NoError(err)
gis.Equal(`SELECT "u"."id", "u"."name", "u"."created_at", "u"."updated_at" FROM "company_auth"."users" AS "u"`, sql)
gis.Empty(args, []interface{}{})
}
func (gis *githubIssuesSuite) TestIssue290() {
type OcomModel struct {
ID uint `json:"id" db:"id" ff:"skipinsert"`
CreatedDate time.Time `json:"created_date" db:"created_date" ff:"skipupdate"`
ModifiedDate time.Time `json:"modified_date" db:"modified_date"`
}
type ActiveModel struct {
OcomModel
ActiveStartDate time.Time `json:"active_start_date" db:"active_start_date"`
ActiveEndDate *time.Time `json:"active_end_date" db:"active_end_date"`
}
type CodeModel struct {
ActiveModel
Code string `json:"code" db:"code"`
Description string `json:"description" binding:"required" db:"description"`
}
type CodeExample struct {
CodeModel
}
var item CodeExample
item.Code = "Code"
item.Description = "Description"
item.ID = 1 // Value set HERE!
item.CreatedDate = time.Date(
2021, 1, 1, 1, 1, 1, 1, time.UTC)
item.ModifiedDate = time.Date(
2021, 2, 2, 2, 2, 2, 2, time.UTC) // The Value we Get!
item.ActiveStartDate = time.Date(
2021, 3, 3, 3, 3, 3, 3, time.UTC)
updateQuery := dbv2.From("example").Update().Set(item).Where(dbv2.C("id").Eq(1))
sql, params, err := updateQuery.ToSQL()
gis.NoError(err)
gis.Empty(params)
gis.Equal(`UPDATE "example" SET "active_end_date"=NULL,"active_start_date"='2021-03-03T03:03:03.000000003Z',"code"='Code',"description"='Description',"id"=1,"modified_date"='2021-02-02T02:02:02.000000002Z' WHERE ("id" = 1)`, sql) //nolint:lll
}
func TestGithubIssuesSuite(t *testing.T) {
suite.Run(t, new(githubIssuesSuite))
}