diff options
| -rw-r--r-- | benchmark/go.mod | 2 | ||||
| -rw-r--r-- | benchmark/go.sum | 4 | ||||
| -rw-r--r-- | errors.go | 37 | ||||
| -rw-r--r-- | errors_test.go | 40 | ||||
| -rw-r--r-- | go.mod | 2 | ||||
| -rw-r--r-- | go.work.sum | 2 | ||||
| -rw-r--r-- | query.go | 26 | ||||
| -rw-r--r-- | select.go | 11 |
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= @@ -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) -} @@ -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= @@ -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 } @@ -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 |
