aboutsummaryrefslogtreecommitdiff
path: root/select_test.go
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2026-04-14 00:41:25 +0200
committerStefan Majewsky <majewsky@gmx.net>2026-04-14 00:41:25 +0200
commit9191e018ff90deb99f3881966a5d356a05027e0f (patch)
treec36880ed2c0755132306141e61c8073d2926b0de /select_test.go
parent49a52b73afac2c97a8f3b7cffd434b29e6f30fcf (diff)
downloadgo-oblast-9191e018ff90deb99f3881966a5d356a05027e0f.tar.gz
initial test coverage for Store.Select functions
Diffstat (limited to 'select_test.go')
-rw-r--r--select_test.go222
1 files changed, 222 insertions, 0 deletions
diff --git a/select_test.go b/select_test.go
new file mode 100644
index 0000000..d678aa2
--- /dev/null
+++ b/select_test.go
@@ -0,0 +1,222 @@
+// SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net>
+// SPDX-License-Identifier: Apache-2.0
+
+package oblast_test
+
+import (
+ "database/sql"
+ "testing"
+ "time"
+
+ "go.xyrillian.de/oblast"
+ "go.xyrillian.de/oblast/internal/assert"
+ "go.xyrillian.de/oblast/internal/mock"
+ "go.xyrillian.de/oblast/internal/must"
+)
+
+func TestSelectReturningSomeRecords(t *testing.T) {
+ md := mock.NewDriver()
+ db := sql.OpenDB(md)
+
+ type basicRecord struct {
+ ID int64 `db:"id"`
+ Name string `db:"name"`
+ }
+ store := must.Return(oblast.NewStore[basicRecord](
+ oblast.SqliteDialect(),
+ oblast.TableNameIs("basic_records"),
+ oblast.PrimaryKeyIs("id"),
+ ))(t)
+
+ t.Run("using Store.Select", func(t *testing.T) {
+ md.ForQuery(`SELECT * FROM basic_records WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("name", "id").
+ WithRow("foo", 1).
+ WithRow("bar", 2)
+ records := must.Return(store.Select(db, `SELECT * FROM basic_records WHERE id < ?`, 3))(t)
+ assert.SliceEqual(t, records,
+ basicRecord{1, "foo"},
+ basicRecord{2, "bar"},
+ )
+ })
+
+ t.Run("using Store.SelectWhere", func(t *testing.T) {
+ md.ForQuery(`SELECT "id", "name" FROM "basic_records" WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("id", "name").
+ WithRow(1, "ffoo").
+ WithRow(2, "bbar")
+ records := must.Return(store.SelectWhere(db, `id < ?`, 3))(t)
+ assert.SliceEqual(t, records,
+ basicRecord{1, "ffoo"},
+ basicRecord{2, "bbar"},
+ )
+ })
+
+ t.Run("using Store.SelectOne", func(t *testing.T) {
+ md.ForQuery(`SELECT * FROM basic_records WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("name", "id").
+ WithRow("fffoo", 1).
+ WithRow("bbbar", 2)
+ record := must.Return(store.SelectOne(db, `SELECT * FROM basic_records WHERE id < ?`, 3))(t)
+ assert.Equal(t, record, basicRecord{1, "fffoo"})
+ })
+
+ t.Run("using Store.SelectOneWhere", func(t *testing.T) {
+ md.ForQuery(`SELECT "id", "name" FROM "basic_records" WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("id", "name").
+ WithRow(1, "ffffoo").
+ WithRow(2, "bbbbar")
+ record := must.Return(store.SelectOneWhere(db, `id < ?`, 3))(t)
+ assert.Equal(t, record, basicRecord{1, "ffffoo"})
+ })
+}
+
+func TestSelectReturningNoRecords(t *testing.T) {
+ md := mock.NewDriver()
+ db := sql.OpenDB(md)
+
+ type basicRecord struct {
+ ID int64 `db:"id"`
+ Name string `db:"name"`
+ }
+ store := must.Return(oblast.NewStore[basicRecord](
+ oblast.SqliteDialect(),
+ oblast.TableNameIs("basic_records"),
+ oblast.PrimaryKeyIs("id"),
+ ))(t)
+
+ t.Run("using Store.Select", func(t *testing.T) {
+ md.ForQuery(`SELECT * FROM basic_records WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("name", "id")
+ records := must.Return(store.Select(db, `SELECT * FROM basic_records WHERE id < ?`, 3))(t)
+ assert.SliceEqual(t, records, nil...)
+ })
+
+ t.Run("using Store.SelectWhere", func(t *testing.T) {
+ md.ForQuery(`SELECT "id", "name" FROM "basic_records" WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("id", "name")
+ records := must.Return(store.SelectWhere(db, `id < ?`, 3))(t)
+ assert.SliceEqual(t, records, nil...)
+ })
+
+ t.Run("using Store.SelectOne", func(t *testing.T) {
+ md.ForQuery(`SELECT * FROM basic_records WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("name", "id")
+ _, err := store.SelectOne(db, `SELECT * FROM basic_records WHERE id < ?`, 3)
+ assert.Equal(t, err.Error(), sql.ErrNoRows.Error())
+ })
+
+ t.Run("using Store.SelectOneWhere", func(t *testing.T) {
+ md.ForQuery(`SELECT "id", "name" FROM "basic_records" WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("id", "name")
+ _, err := store.SelectOneWhere(db, `id < ?`, 3)
+ assert.Equal(t, err.Error(), sql.ErrNoRows.Error())
+ })
+}
+
+func TestSelectIntoUnexpectedField(t *testing.T) {
+ md := mock.NewDriver()
+ db := sql.OpenDB(md)
+
+ type basicRecord struct {
+ ID int64 `db:"id"`
+ Description string `db:"desc"` // but DB knows only the field "name"!
+ }
+ store := must.Return(oblast.NewStore[basicRecord](
+ oblast.SqliteDialect(),
+ oblast.TableNameIs("basic_records"),
+ oblast.PrimaryKeyIs("id"),
+ ))(t)
+
+ expectedError := "result has column \"name\" in position 0, but no field in type basicRecord has `db:\"name\"`"
+
+ // NOTE: This problem cannot occur with SelectWhere() and SelectOneWhere() because of their use of query generation.
+
+ t.Run("using Store.Select", func(t *testing.T) {
+ md.ForQuery(`SELECT * FROM basic_records WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("name", "id").
+ WithRow("foo", 1).
+ WithRow("bar", 2)
+ _, err := store.Select(db, `SELECT * FROM basic_records WHERE id < ?`, 3)
+ assert.Equal(t, err.Error(), expectedError)
+ })
+
+ t.Run("using Store.SelectOne", func(t *testing.T) {
+ md.ForQuery(`SELECT * FROM basic_records WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("name", "id").
+ WithRow("ffoo", 1).
+ WithRow("bbar", 2)
+ _, err := store.SelectOne(db, `SELECT * FROM basic_records WHERE id < ?`, 3)
+ assert.Equal(t, err.Error(), expectedError)
+ })
+}
+
+func TestSelectWithScanError(t *testing.T) {
+ md := mock.NewDriver()
+ db := sql.OpenDB(md)
+
+ type basicRecord struct {
+ ID int64 `db:"id"`
+ CreatedAt time.Time `db:"created_at"` // but the DB will give us strings that are not timestamps
+ }
+ store := must.Return(oblast.NewStore[basicRecord](
+ oblast.SqliteDialect(),
+ oblast.TableNameIs("basic_records"),
+ oblast.PrimaryKeyIs("id"),
+ ))(t)
+
+ expectedError := `sql: Scan error on column index 1, name "created_at": unsupported Scan, storing driver.Value type string into type *time.Time`
+
+ t.Run("using Store.Select", func(t *testing.T) {
+ md.ForQuery(`SELECT * FROM basic_records WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("id", "created_at").
+ WithRow(1, "foo").
+ WithRow(2, "bar")
+ _, err := store.Select(db, `SELECT * FROM basic_records WHERE id < ?`, 3)
+ assert.Equal(t, err.Error(), expectedError)
+ })
+
+ t.Run("using Store.SelectWhere", func(t *testing.T) {
+ md.ForQuery(`SELECT "id", "created_at" FROM "basic_records" WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("id", "created_at").
+ WithRow(1, "ffoo").
+ WithRow(2, "bbar")
+ _, err := store.SelectWhere(db, `id < ?`, 3)
+ assert.Equal(t, err.Error(), expectedError)
+ })
+
+ t.Run("using Store.SelectOne", func(t *testing.T) {
+ md.ForQuery(`SELECT * FROM basic_records WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("id", "created_at").
+ WithRow(1, "fffoo").
+ WithRow(2, "bbbar")
+ _, err := store.SelectOne(db, `SELECT * FROM basic_records WHERE id < ?`, 3)
+ assert.Equal(t, err.Error(), expectedError)
+ })
+
+ t.Run("using Store.SelectOneWhere", func(t *testing.T) {
+ md.ForQuery(`SELECT "id", "created_at" FROM "basic_records" WHERE id < ?`).
+ ExpectQueryWithArgs(3).
+ AndReturnColumns("id", "created_at").
+ WithRow(1, "ffffoo").
+ WithRow(2, "bbbbar")
+ _, err := store.SelectOneWhere(db, `id < ?`, 3)
+ assert.Equal(t, err.Error(), expectedError)
+ })
+}
+
+// TODO: test error capture during Rows.Close()
+// TODO: check for maximum test coverage in select.go