This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
package sq
|
||||
|
||||
import (
|
||||
"git.blackforestbytes.com/BlackForestBytes/goext/tst"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuildInsertStatementBasic(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
sqlstr, pp, err := BuildInsertStatement(q, "users", r{ID: "1", Name: "alice"})
|
||||
tst.AssertNoErr(t, err)
|
||||
|
||||
tst.AssertTrue(t, strings.HasPrefix(sqlstr, "INSERT INTO users ("))
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, "id"))
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, "name"))
|
||||
tst.AssertEqual(t, 2, len(pp))
|
||||
|
||||
values := []any{}
|
||||
for _, v := range pp {
|
||||
values = append(values, v)
|
||||
}
|
||||
|
||||
hasID, hasName := false, false
|
||||
for _, v := range values {
|
||||
if vs, ok := v.(string); ok {
|
||||
if vs == "1" {
|
||||
hasID = true
|
||||
}
|
||||
if vs == "alice" {
|
||||
hasName = true
|
||||
}
|
||||
}
|
||||
}
|
||||
tst.AssertTrue(t, hasID)
|
||||
tst.AssertTrue(t, hasName)
|
||||
}
|
||||
|
||||
func TestBuildInsertStatementSkipsUnexported(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
hidden string `db:"hidden"` //nolint:unused
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
sqlstr, pp, err := BuildInsertStatement(q, "users", r{ID: "1"})
|
||||
tst.AssertNoErr(t, err)
|
||||
tst.AssertEqual(t, 1, len(pp))
|
||||
tst.AssertTrue(t, !strings.Contains(sqlstr, "hidden"))
|
||||
}
|
||||
|
||||
func TestBuildInsertStatementSkipsNoTagAndDash(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
Skip1 string `db:"-"`
|
||||
Skip2 string
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
sqlstr, pp, err := BuildInsertStatement(q, "users", r{ID: "1", Skip1: "x", Skip2: "y"})
|
||||
tst.AssertNoErr(t, err)
|
||||
tst.AssertEqual(t, 1, len(pp))
|
||||
tst.AssertTrue(t, !strings.Contains(sqlstr, "Skip"))
|
||||
}
|
||||
|
||||
func TestBuildInsertStatementNoFields(t *testing.T) {
|
||||
type r struct {
|
||||
Skip string
|
||||
}
|
||||
q := fakeQueryable{}
|
||||
_, _, err := BuildInsertStatement(q, "x", r{})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for no usable fields")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildInsertStatementNilPointer(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
Note *string `db:"note"`
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
sqlstr, pp, err := BuildInsertStatement(q, "users", r{ID: "1", Note: nil})
|
||||
tst.AssertNoErr(t, err)
|
||||
|
||||
// Only id is parameterized; nil pointer becomes literal NULL
|
||||
tst.AssertEqual(t, 1, len(pp))
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, "NULL"))
|
||||
}
|
||||
|
||||
func TestBuildInsertStatementWithConverter(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
Flag bool `db:"flag"`
|
||||
}
|
||||
|
||||
q := fakeQueryable{converters: []DBTypeConverter{ConverterBoolToBit}}
|
||||
_, pp, err := BuildInsertStatement(q, "users", r{ID: "1", Flag: true})
|
||||
tst.AssertNoErr(t, err)
|
||||
tst.AssertEqual(t, 2, len(pp))
|
||||
|
||||
foundOne := false
|
||||
for _, v := range pp {
|
||||
if vi, ok := v.(int64); ok && vi == 1 {
|
||||
foundOne = true
|
||||
}
|
||||
}
|
||||
tst.AssertTrue(t, foundOne)
|
||||
}
|
||||
|
||||
func TestBuildUpdateStatementBasic(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
sqlstr, pp, err := BuildUpdateStatement(q, "users", r{ID: "1", Name: "alice"}, "id")
|
||||
tst.AssertNoErr(t, err)
|
||||
|
||||
tst.AssertTrue(t, strings.HasPrefix(sqlstr, "UPDATE users SET "))
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, "name = :"))
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, "(id = :"))
|
||||
tst.AssertEqual(t, 2, len(pp))
|
||||
}
|
||||
|
||||
func TestBuildUpdateStatementMissingID(t *testing.T) {
|
||||
type r struct {
|
||||
Name string `db:"name"`
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
_, _, err := BuildUpdateStatement(q, "users", r{Name: "alice"}, "id")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for missing id column")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildUpdateStatementOnlyID(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
_, _, err := BuildUpdateStatement(q, "users", r{ID: "1"}, "id")
|
||||
if err == nil {
|
||||
t.Fatal("expected error when no SET clauses")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildUpdateStatementNilPointer(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
Note *string `db:"note"`
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
sqlstr, _, err := BuildUpdateStatement(q, "users", r{ID: "1", Note: nil}, "id")
|
||||
tst.AssertNoErr(t, err)
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, "note = NULL"))
|
||||
}
|
||||
|
||||
func TestBuildInsertMultipleStatementBasic(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
sqlstr, pp, err := BuildInsertMultipleStatement(q, "users", []r{
|
||||
{ID: "1", Name: "alice"},
|
||||
{ID: "2", Name: "bob"},
|
||||
})
|
||||
tst.AssertNoErr(t, err)
|
||||
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, `INSERT INTO "users"`))
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, `"id"`))
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, `"name"`))
|
||||
// 2 rows × 2 fields = 4 placeholders
|
||||
tst.AssertEqual(t, 4, len(pp))
|
||||
|
||||
// Two value tuples should appear -> exactly one "), (" separator
|
||||
tst.AssertEqual(t, 1, strings.Count(sqlstr, "), ("))
|
||||
}
|
||||
|
||||
func TestBuildInsertMultipleStatementEmpty(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
}
|
||||
q := fakeQueryable{}
|
||||
_, _, err := BuildInsertMultipleStatement(q, "x", []r{})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for empty input")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildInsertMultipleStatementNilPointer(t *testing.T) {
|
||||
type r struct {
|
||||
ID string `db:"id"`
|
||||
Note *string `db:"note"`
|
||||
}
|
||||
|
||||
q := fakeQueryable{}
|
||||
sqlstr, _, err := BuildInsertMultipleStatement(q, "users", []r{{ID: "1", Note: nil}})
|
||||
tst.AssertNoErr(t, err)
|
||||
tst.AssertTrue(t, strings.Contains(sqlstr, "NULL"))
|
||||
}
|
||||
Reference in New Issue
Block a user