github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/datastore/errors.go (about)

     1  package datastore
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/rs/zerolog"
     8  )
     9  
    10  // ErrNotFound is a shared interface for not found errors.
    11  type ErrNotFound interface {
    12  	IsNotFoundError() bool
    13  }
    14  
    15  // ErrNamespaceNotFound occurs when a namespace was not found.
    16  type ErrNamespaceNotFound struct {
    17  	error
    18  	namespaceName string
    19  }
    20  
    21  var _ ErrNotFound = ErrNamespaceNotFound{}
    22  
    23  func (err ErrNamespaceNotFound) IsNotFoundError() bool {
    24  	return true
    25  }
    26  
    27  // NotFoundNamespaceName is the name of the namespace not found.
    28  func (err ErrNamespaceNotFound) NotFoundNamespaceName() string {
    29  	return err.namespaceName
    30  }
    31  
    32  // MarshalZerologObject implements zerolog object marshalling.
    33  func (err ErrNamespaceNotFound) MarshalZerologObject(e *zerolog.Event) {
    34  	e.Err(err.error).Str("namespace", err.namespaceName)
    35  }
    36  
    37  // DetailsMetadata returns the metadata for details for this error.
    38  func (err ErrNamespaceNotFound) DetailsMetadata() map[string]string {
    39  	return map[string]string{
    40  		"definition_name": err.namespaceName,
    41  	}
    42  }
    43  
    44  // ErrWatchDisconnected occurs when a watch has fallen too far behind and was forcibly disconnected
    45  // as a result.
    46  type ErrWatchDisconnected struct{ error }
    47  
    48  // ErrWatchCanceled occurs when a watch was canceled by the caller.
    49  type ErrWatchCanceled struct{ error }
    50  
    51  // ErrWatchDisabled occurs when watch is disabled by being unsupported by the datastore.
    52  type ErrWatchDisabled struct{ error }
    53  
    54  // ErrReadOnly is returned when the operation cannot be completed because the datastore is in
    55  // read-only mode.
    56  type ErrReadOnly struct{ error }
    57  
    58  // ErrWatchRetryable is returned when a transient/temporary error occurred in watch and indicates that
    59  // the caller *may* retry the watch after some backoff time.
    60  type ErrWatchRetryable struct{ error }
    61  
    62  // InvalidRevisionReason is the reason the revision could not be used.
    63  type InvalidRevisionReason int
    64  
    65  const (
    66  	// RevisionStale is the reason returned when a revision is outside the window of
    67  	// validity by being too old.
    68  	RevisionStale InvalidRevisionReason = iota
    69  
    70  	// CouldNotDetermineRevision is the reason returned when a revision for a
    71  	// request could not be determined.
    72  	CouldNotDetermineRevision
    73  )
    74  
    75  // ErrInvalidRevision occurs when a revision specified to a call was invalid.
    76  type ErrInvalidRevision struct {
    77  	error
    78  	revision Revision
    79  	reason   InvalidRevisionReason
    80  }
    81  
    82  // InvalidRevision is the revision that failed.
    83  func (err ErrInvalidRevision) InvalidRevision() Revision {
    84  	return err.revision
    85  }
    86  
    87  // Reason is the reason the revision failed.
    88  func (err ErrInvalidRevision) Reason() InvalidRevisionReason {
    89  	return err.reason
    90  }
    91  
    92  // MarshalZerologObject implements zerolog object marshalling.
    93  func (err ErrInvalidRevision) MarshalZerologObject(e *zerolog.Event) {
    94  	switch err.reason {
    95  	case RevisionStale:
    96  		e.Err(err.error).Str("reason", "stale")
    97  	case CouldNotDetermineRevision:
    98  		e.Err(err.error).Str("reason", "indeterminate")
    99  	default:
   100  		e.Err(err.error).Str("reason", "unknown")
   101  	}
   102  }
   103  
   104  // NewNamespaceNotFoundErr constructs a new namespace not found error.
   105  func NewNamespaceNotFoundErr(nsName string) error {
   106  	return ErrNamespaceNotFound{
   107  		error:         fmt.Errorf("object definition `%s` not found", nsName),
   108  		namespaceName: nsName,
   109  	}
   110  }
   111  
   112  // NewWatchDisconnectedErr constructs a new watch was disconnected error.
   113  func NewWatchDisconnectedErr() error {
   114  	return ErrWatchDisconnected{
   115  		error: fmt.Errorf("watch fell too far behind and was disconnected; consider increasing watch buffer size via the flag --datastore-watch-buffer-length"),
   116  	}
   117  }
   118  
   119  // NewWatchCanceledErr constructs a new watch was canceled error.
   120  func NewWatchCanceledErr() error {
   121  	return ErrWatchCanceled{
   122  		error: fmt.Errorf("watch was canceled by the caller"),
   123  	}
   124  }
   125  
   126  // NewWatchDisabledErr constructs a new watch is disabled error.
   127  func NewWatchDisabledErr(reason string) error {
   128  	return ErrWatchDisabled{
   129  		error: fmt.Errorf("watch is currently disabled: %s", reason),
   130  	}
   131  }
   132  
   133  // NewWatchTemporaryErr wraps another error in watch, indicating that the error is likely
   134  // a temporary condition and clients may consider retrying by calling watch again (vs a fatal error).
   135  func NewWatchTemporaryErr(wrapped error) error {
   136  	return ErrWatchRetryable{
   137  		error: fmt.Errorf("watch has failed with a temporary condition: %w. please retry the watch", wrapped),
   138  	}
   139  }
   140  
   141  // NewReadonlyErr constructs an error for when a request has failed because
   142  // the datastore has been configured to be read-only.
   143  func NewReadonlyErr() error {
   144  	return ErrReadOnly{
   145  		error: fmt.Errorf("datastore is in read-only mode"),
   146  	}
   147  }
   148  
   149  // NewInvalidRevisionErr constructs a new invalid revision error.
   150  func NewInvalidRevisionErr(revision Revision, reason InvalidRevisionReason) error {
   151  	switch reason {
   152  	case RevisionStale:
   153  		return ErrInvalidRevision{
   154  			error:    fmt.Errorf("revision has expired"),
   155  			revision: revision,
   156  			reason:   reason,
   157  		}
   158  
   159  	default:
   160  		return ErrInvalidRevision{
   161  			error:    fmt.Errorf("revision was invalid"),
   162  			revision: revision,
   163  			reason:   reason,
   164  		}
   165  	}
   166  }
   167  
   168  // ErrCaveatNameNotFound is the error returned when a caveat is not found by its name
   169  type ErrCaveatNameNotFound struct {
   170  	error
   171  	name string
   172  }
   173  
   174  var _ ErrNotFound = ErrCaveatNameNotFound{}
   175  
   176  func (err ErrCaveatNameNotFound) IsNotFoundError() bool {
   177  	return true
   178  }
   179  
   180  // CaveatName returns the name of the caveat that couldn't be found
   181  func (err ErrCaveatNameNotFound) CaveatName() string {
   182  	return err.name
   183  }
   184  
   185  // NewCaveatNameNotFoundErr constructs a new caveat name not found error.
   186  func NewCaveatNameNotFoundErr(name string) error {
   187  	return ErrCaveatNameNotFound{
   188  		error: fmt.Errorf("caveat with name `%s` not found", name),
   189  		name:  name,
   190  	}
   191  }
   192  
   193  // DetailsMetadata returns the metadata for details for this error.
   194  func (err ErrCaveatNameNotFound) DetailsMetadata() map[string]string {
   195  	return map[string]string{
   196  		"caveat_name": err.name,
   197  	}
   198  }
   199  
   200  var (
   201  	ErrClosedIterator        = errors.New("unable to iterate: iterator closed")
   202  	ErrCursorsWithoutSorting = errors.New("cursors are disabled on unsorted results")
   203  	ErrCursorEmpty           = errors.New("cursors are only available after the first result")
   204  )