summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2026-07-31 23:34:43 +0200
committerStefan Majewsky <majewsky@gmx.net>2026-07-31 23:34:43 +0200
commita2f8d7a68f324d5b4086148571f990409425e22a (patch)
treef2756c205ad8bd897b48460c12191df8e2aa2cd6
parent4e00aa81308e3f71c0c665ada873127dd1530480 (diff)
downloadgo-oblast-a2f8d7a68f324d5b4086148571f990409425e22a.tar.gz
replace ioError with gg/errext.WithCleanup
-rw-r--r--benchmark/go.mod2
-rw-r--r--benchmark/go.sum4
-rw-r--r--errors.go37
-rw-r--r--errors_test.go40
-rw-r--r--go.mod2
-rw-r--r--go.work.sum2
-rw-r--r--query.go26
-rw-r--r--select.go11
8 files changed, 26 insertions, 98 deletions
diff --git a/benchmark/go.mod b/benchmark/go.mod
index 48ee3a3..8aaed53 100644
--- a/benchmark/go.mod
+++ b/benchmark/go.mod
@@ -7,7 +7,7 @@ require (
github.com/jackc/pgx/v5 v5.10.0
github.com/lib/pq v1.12.3
github.com/mattn/go-sqlite3 v1.14.48
- go.xyrillian.de/gg v1.11.1
+ go.xyrillian.de/gg v1.12.0
go.xyrillian.de/oblast v0.11.0
gorm.io/driver/sqlite v1.6.0
gorm.io/gorm v1.31.2
diff --git a/benchmark/go.sum b/benchmark/go.sum
index 89eb327..1122ecf 100644
--- a/benchmark/go.sum
+++ b/benchmark/go.sum
@@ -30,8 +30,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
-go.xyrillian.de/gg v1.11.1 h1:7P3kDFkTmR7jx2riYi0GwX5uhgrsL37QSrN16xH/n8E=
-go.xyrillian.de/gg v1.11.1/go.mod h1:DoO4fQSWIrBRlNlCjVyrYM0kAEBt/Jg2GkMH+cGRZ0k=
+go.xyrillian.de/gg v1.12.0 h1:oW9S91y36lS72D3p9a4axqjkD9zkkjkNZ12+PaZHpos=
+go.xyrillian.de/gg v1.12.0/go.mod h1:DoO4fQSWIrBRlNlCjVyrYM0kAEBt/Jg2GkMH+cGRZ0k=
go.xyrillian.de/oblast v0.11.0 h1:ZqHsxoQW/LPgtQ/jXlG1X3DLTYkgxf9zzrDYyykXJG4=
go.xyrillian.de/oblast v0.11.0/go.mod h1:sYCzxyVFzzL43EglZJn7Vtd8kfHYBwKff/Us4yF8k+Q=
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
diff --git a/errors.go b/errors.go
index 4002f58..0a58340 100644
--- a/errors.go
+++ b/errors.go
@@ -26,40 +26,3 @@ func (e MissingRecordError[R]) Error() string {
}
return "could not UPDATE record that does not exist in the database: " + strings.Join(keyDescs, ", ")
}
-
-// ioError is an error type that contains:
-// - (optionally) a main error from an IO operation (e.g. a database read)
-// - an auxiliary error from closing or otherwise cleaning up the respective IO handle
-//
-// This is only used when there is a cleanup error.
-// Otherwise, the main error will be returned without being wrapped in this type.
-type ioError struct {
- MainError error
- CleanupError error
- CleanupOperation string
-}
-
-func newIOError(err error, cleanupOperation string, cleanupErr error) error {
- if cleanupErr == nil {
- return err
- }
- return ioError{err, cleanupErr, cleanupOperation}
-}
-
-// Error implements the builtin/error interface.
-func (e ioError) Error() string {
- if e.MainError == nil {
- return fmt.Sprintf("during %s(): %s", e.CleanupOperation, e.CleanupError.Error())
- } else {
- return fmt.Sprintf("%s (additional error during %s(): %s)", e.MainError.Error(), e.CleanupOperation, e.CleanupError.Error())
- }
-}
-
-// Unwrap implements the interface implied by the documentation of package errors.
-func (e ioError) Unwrap() []error {
- if e.MainError == nil {
- return []error{e.CleanupError}
- } else {
- return []error{e.MainError, e.CleanupError}
- }
-}
diff --git a/errors_test.go b/errors_test.go
deleted file mode 100644
index bec0650..0000000
--- a/errors_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net>
-// SPDX-License-Identifier: Apache-2.0
-
-package oblast
-
-import (
- "errors"
- "testing"
-
- "go.xyrillian.de/gg/assert"
-)
-
-type fooError struct{}
-type barError struct{}
-type bazError struct{}
-
-func (fooError) Error() string { return "foo" }
-func (barError) Error() string { return "bar" }
-func (bazError) Error() string { return "baz" }
-
-func TestIOError(t *testing.T) {
- err := newIOError(nil, "File.Close", nil)
- assert.Equal(t, err == nil, true)
-
- err = newIOError(fooError{}, "File.Close", nil)
- assert.ErrEqual(t, err, "foo")
- assert.Equal(t, err, error(fooError{})) // check for no wrapping in type ioError without cleanup error
-
- err = newIOError(nil, "File.Close", barError{})
- assert.ErrEqual(t, err, "during File.Close(): bar")
- assert.Equal(t, errors.Is(err, fooError{}), false)
- assert.Equal(t, errors.Is(err, barError{}), true)
- assert.Equal(t, errors.Is(err, bazError{}), false)
-
- err = newIOError(fooError{}, "File.Close", barError{})
- assert.ErrEqual(t, err, "foo (additional error during File.Close(): bar)")
- assert.Equal(t, errors.Is(err, fooError{}), true)
- assert.Equal(t, errors.Is(err, barError{}), true)
- assert.Equal(t, errors.Is(err, bazError{}), false)
-}
diff --git a/go.mod b/go.mod
index fe35b3e..9b7bb5d 100644
--- a/go.mod
+++ b/go.mod
@@ -2,4 +2,4 @@ module go.xyrillian.de/oblast
go 1.26
-require go.xyrillian.de/gg v1.11.1
+require go.xyrillian.de/gg v1.12.0
diff --git a/go.work.sum b/go.work.sum
index 7486d21..5f01129 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -5,6 +5,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/nelsam/hel/v2 v2.3.3/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+go.xyrillian.de/gg v1.12.0 h1:oW9S91y36lS72D3p9a4axqjkD9zkkjkNZ12+PaZHpos=
+go.xyrillian.de/gg v1.12.0/go.mod h1:DoO4fQSWIrBRlNlCjVyrYM0kAEBt/Jg2GkMH+cGRZ0k=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
diff --git a/query.go b/query.go
index 605dac4..b92106a 100644
--- a/query.go
+++ b/query.go
@@ -9,6 +9,8 @@ import (
"fmt"
"reflect"
+ "go.xyrillian.de/gg/errext"
+
"go.xyrillian.de/oblast/handle"
)
@@ -72,15 +74,15 @@ func (s Store[R]) insertUsing(ctx context.Context, stmt handle.Statement, db Han
v := reflect.ValueOf(r).Elem()
err := checkTransparentPointerStructFieldsInitialized("INSERT", idx, v, s.plan, false)
if err != nil {
- return newIOError(err, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(err, "Stmt.Close", stmt.Close())
}
err = insertRecord(ctx, s.plan, v, idx, stmt, argumentIndexes, argumentSlots, scanIndexes, scanSlots)
if err != nil {
- return newIOError(err, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(err, "Stmt.Close", stmt.Close())
}
}
- return newIOError(nil, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(nil, "Stmt.Close", stmt.Close())
}
func insertRecord(ctx context.Context, plan plan, v reflect.Value, recordIndex int, stmt handle.Statement, argumentIndexes [][]int, argumentSlots []any, scanIndexes [][]int, scanSlots []any) error {
@@ -172,17 +174,17 @@ func (s Store[R]) Update(ctx context.Context, db Handle, records ...R) error {
v := reflect.ValueOf(&records[idx]).Elem()
err := checkTransparentPointerStructFieldsInitialized("UPDATE", idx, v, s.plan, false)
if err != nil {
- return newIOError(err, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(err, "Stmt.Close", stmt.Close())
}
rowsAffected, err := updateRecord(ctx, v, idx, stmt, argumentIndexes, argumentSlots)
if err == nil && rowsAffected == 0 {
err = MissingRecordError[R]{records[idx], s.plan}
}
if err != nil {
- return newIOError(err, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(err, "Stmt.Close", stmt.Close())
}
}
- return newIOError(nil, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(nil, "Stmt.Close", stmt.Close())
}
func updateRecord(ctx context.Context, v reflect.Value, recordIndex int, stmt handle.Statement, argumentIndexes [][]int, argumentSlots []any) (int64, error) {
@@ -221,17 +223,17 @@ func (s Store[R]) Delete(ctx context.Context, db Handle, records ...R) error {
v := reflect.ValueOf(&records[idx]).Elem()
err := deleteRecord(ctx, s.plan, v, idx, stmt, argumentIndexes, argumentSlots)
if err != nil {
- return newIOError(err, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(err, "Stmt.Close", stmt.Close())
}
}
- return newIOError(nil, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(nil, "Stmt.Close", stmt.Close())
}
func deleteRecord(ctx context.Context, plan plan, v reflect.Value, recordIndex int, stmt handle.Statement, argumentIndexes [][]int, argumentSlots []any) error {
err := checkTransparentPointerStructFieldsInitialized("DELETE", recordIndex, v, plan, true)
if err != nil {
- return newIOError(err, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(err, "Stmt.Close", stmt.Close())
}
for idx, index := range argumentIndexes {
argumentSlots[idx] = v.FieldByIndex(index).Interface()
@@ -270,12 +272,12 @@ func (s Store[R]) Upsert(ctx context.Context, db Handle, records ...*R) error {
}
updateStmt, err := prepare(ctx, db, s.plan.Update.Query, "Update", 0)
if err != nil {
- return newIOError(err, "InsertStmt.Close", insertStmt.Close())
+ return errext.WithCleanup(err, "InsertStmt.Close", insertStmt.Close())
}
err = s.doUpsert(ctx, db, insertStmt, updateStmt, records)
- err = newIOError(err, "InsertStmt.Close", insertStmt.Close())
- err = newIOError(err, "UpdateStmt.Close", updateStmt.Close())
+ err = errext.WithCleanup(err, "InsertStmt.Close", insertStmt.Close())
+ err = errext.WithCleanup(err, "UpdateStmt.Close", updateStmt.Close())
return err
}
diff --git a/select.go b/select.go
index d3a2195..37edb92 100644
--- a/select.go
+++ b/select.go
@@ -10,6 +10,7 @@ import (
"fmt"
"reflect"
+ "go.xyrillian.de/gg/errext"
. "go.xyrillian.de/gg/option"
"go.xyrillian.de/oblast/handle"
)
@@ -56,7 +57,7 @@ func startSelectQuery(ctx context.Context, db Handle, plan plan, query string, a
columnNames, err := rows.Columns()
if err != nil {
err = fmt.Errorf("during rows.Columns(): %w", err)
- return selection{Err: newIOError(err, "Rows.Close", rows.Close())}
+ return selection{Err: errext.WithCleanup(err, "Rows.Close", rows.Close())}
}
indexes := make([][]int, len(columnNames))
for idx, columnName := range columnNames {
@@ -67,7 +68,7 @@ func startSelectQuery(ctx context.Context, db Handle, plan plan, query string, a
"result has column %q in position %d, but no field in type %s has `db:%[1]q`",
columnName, idx, plan.TypeName,
)
- return selection{Err: newIOError(err, "Rows.Close", rows.Close())}
+ return selection{Err: errext.WithCleanup(err, "Rows.Close", rows.Close())}
}
}
@@ -167,7 +168,7 @@ func selectOne(ctx context.Context, db Handle, plan plan, v reflect.Value, query
return err
}
err = stmt.QueryRow(ctx, args, slots)
- return newIOError(err, "Stmt.Close", stmt.Close())
+ return errext.WithCleanup(err, "Stmt.Close", stmt.Close())
}
func noRowsToNone[R any](record R, err error) (Option[R], error) {
@@ -271,7 +272,7 @@ func (s selection) collectRow(v reflect.Value, slots []any) error {
}
err := s.Rows.Scan(slots...)
if err != nil {
- return newIOError(err, "Rows.Close", s.Rows.Close())
+ return errext.WithCleanup(err, "Rows.Close", s.Rows.Close())
}
return nil
}
@@ -350,7 +351,7 @@ func (s Selection[R]) Foreach(action func(R) error) error {
}
err = action(record)
if err != nil {
- return newIOError(err, "Rows.Close", s.Rows.Close())
+ return errext.WithCleanup(err, "Rows.Close", s.Rows.Close())
}
}
return nil