From 52f44287216b47149da9eb3f038408447f0e5981 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Fri, 17 Apr 2026 14:53:52 +0200 Subject: improve test coverage, error reporting for Select() --- errors.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 errors.go (limited to 'errors.go') diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..1e81060 --- /dev/null +++ b/errors.go @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2026 Stefan Majewsky +// SPDX-License-Identifier: Apache-2.0 + +package oblast + +import ( + "fmt" + "reflect" + "strings" +) + +// MissingRecordError is returned by [Store.Update] if one of the rows to be updated does not exist in the DB. +type MissingRecordError[R any] struct { + // The record that was provided to [Store.Update], + // but for which no row with the same primary key values could be located. + Record R + plan plan +} + +// Error implements the builtin/error interface. +func (e MissingRecordError[R]) Error() string { + keyDescs := make([]string, len(e.plan.PrimaryKeyColumnNames)) + v := reflect.ValueOf(e.Record) + for idx, columnName := range e.plan.PrimaryKeyColumnNames { + keyDescs[idx] = fmt.Sprintf("%s = %#v", columnName, v.FieldByIndex(e.plan.IndexByColumnName[columnName])) + } + return "could not UPDATE record that does not exist in the database: " + strings.Join(keyDescs, ", ") +} + +// An error type that optionally contains either one of the following or both: +// - a core error from an IO operation (e.g. a database read) +// - an auxiliary error from closing or otherwise cleaning up the respective IO handle +type ioError struct { + MainError error + CleanupError error + CleanupOperation string +} + +func newIOError(err error, cleanupOperation string, cleanupErr error) error { + if err == nil && cleanupErr == nil { + return nil + } + return ioError{err, cleanupErr, cleanupOperation} +} + +// Error implements the builtin/error interface. +func (e ioError) Error() string { + switch { + case e.CleanupError == nil: + return e.MainError.Error() + case e.MainError == nil: + return fmt.Sprintf("during %s(): %s", e.CleanupOperation, e.CleanupError.Error()) + default: + 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 { + result := make([]error, 0, 2) + if e.MainError != nil { + result = append(result, e.MainError) + } + if e.CleanupError != nil { + result = append(result, e.CleanupError) + } + return result +} -- cgit v1.2.3