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

     1  package graph
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/rs/zerolog"
     8  	"google.golang.org/grpc/codes"
     9  	"google.golang.org/grpc/status"
    10  
    11  	v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
    12  
    13  	"github.com/authzed/spicedb/internal/sharederrors"
    14  	dispatch "github.com/authzed/spicedb/pkg/proto/dispatch/v1"
    15  	"github.com/authzed/spicedb/pkg/spiceerrors"
    16  )
    17  
    18  // ErrCheckFailure occurs when check failed in some manner. Note this should not apply to
    19  // namespaces and relations not being found.
    20  type ErrCheckFailure struct {
    21  	error
    22  }
    23  
    24  func (e ErrCheckFailure) Unwrap() error {
    25  	return e.error
    26  }
    27  
    28  // NewCheckFailureErr constructs a new check failed error.
    29  func NewCheckFailureErr(baseErr error) error {
    30  	return ErrCheckFailure{
    31  		error: fmt.Errorf("error performing check: %w", baseErr),
    32  	}
    33  }
    34  
    35  // ErrExpansionFailure occurs when expansion failed in some manner. Note this should not apply to
    36  // namespaces and relations not being found.
    37  type ErrExpansionFailure struct {
    38  	error
    39  }
    40  
    41  func (e ErrExpansionFailure) Unwrap() error {
    42  	return e.error
    43  }
    44  
    45  // NewExpansionFailureErr constructs a new expansion failed error.
    46  func NewExpansionFailureErr(baseErr error) error {
    47  	return ErrExpansionFailure{
    48  		error: fmt.Errorf("error performing expand: %w", baseErr),
    49  	}
    50  }
    51  
    52  // ErrAlwaysFail is returned when an internal error leads to an operation
    53  // guaranteed to fail.
    54  type ErrAlwaysFail struct {
    55  	error
    56  }
    57  
    58  // NewAlwaysFailErr constructs a new always fail error.
    59  func NewAlwaysFailErr() error {
    60  	return ErrAlwaysFail{
    61  		error: errors.New("always fail"),
    62  	}
    63  }
    64  
    65  // ErrRelationNotFound occurs when a relation was not found under a namespace.
    66  type ErrRelationNotFound struct {
    67  	error
    68  	namespaceName string
    69  	relationName  string
    70  }
    71  
    72  // NamespaceName returns the name of the namespace in which the relation was not found.
    73  func (err ErrRelationNotFound) NamespaceName() string {
    74  	return err.namespaceName
    75  }
    76  
    77  // NotFoundRelationName returns the name of the relation not found.
    78  func (err ErrRelationNotFound) NotFoundRelationName() string {
    79  	return err.relationName
    80  }
    81  
    82  func (err ErrRelationNotFound) MarshalZerologObject(e *zerolog.Event) {
    83  	e.Err(err.error).Str("namespace", err.namespaceName).Str("relation", err.relationName)
    84  }
    85  
    86  // DetailsMetadata returns the metadata for details for this error.
    87  func (err ErrRelationNotFound) DetailsMetadata() map[string]string {
    88  	return map[string]string{
    89  		"definition_name":             err.namespaceName,
    90  		"relation_or_permission_name": err.relationName,
    91  	}
    92  }
    93  
    94  // NewRelationNotFoundErr constructs a new relation not found error.
    95  func NewRelationNotFoundErr(nsName string, relationName string) error {
    96  	return ErrRelationNotFound{
    97  		error:         fmt.Errorf("relation/permission `%s` not found under definition `%s`", relationName, nsName),
    98  		namespaceName: nsName,
    99  		relationName:  relationName,
   100  	}
   101  }
   102  
   103  var _ sharederrors.UnknownRelationError = ErrRelationNotFound{}
   104  
   105  // ErrRelationMissingTypeInfo defines an error for when type information is missing from a relation
   106  // during a lookup.
   107  type ErrRelationMissingTypeInfo struct {
   108  	error
   109  	namespaceName string
   110  	relationName  string
   111  }
   112  
   113  // NamespaceName returns the name of the namespace in which the relation was found.
   114  func (err ErrRelationMissingTypeInfo) NamespaceName() string {
   115  	return err.namespaceName
   116  }
   117  
   118  // RelationName returns the name of the relation missing type information.
   119  func (err ErrRelationMissingTypeInfo) RelationName() string {
   120  	return err.relationName
   121  }
   122  
   123  func (err ErrRelationMissingTypeInfo) MarshalZerologObject(e *zerolog.Event) {
   124  	e.Err(err.error).Str("namespace", err.namespaceName).Str("relation", err.relationName)
   125  }
   126  
   127  // DetailsMetadata returns the metadata for details for this error.
   128  func (err ErrRelationMissingTypeInfo) DetailsMetadata() map[string]string {
   129  	return map[string]string{
   130  		"definition_name": err.namespaceName,
   131  		"relation_name":   err.relationName,
   132  	}
   133  }
   134  
   135  // NewRelationMissingTypeInfoErr constructs a new relation not missing type information error.
   136  func NewRelationMissingTypeInfoErr(nsName string, relationName string) error {
   137  	return ErrRelationMissingTypeInfo{
   138  		error:         fmt.Errorf("relation/permission `%s` under definition `%s` is missing type information", relationName, nsName),
   139  		namespaceName: nsName,
   140  		relationName:  relationName,
   141  	}
   142  }
   143  
   144  // ErrInvalidArgument occurs when a request sent has an invalid argument.
   145  type ErrInvalidArgument struct {
   146  	error
   147  }
   148  
   149  // NewErrInvalidArgument constructs a request sent has an invalid argument.
   150  func NewErrInvalidArgument(baseErr error) error {
   151  	return ErrInvalidArgument{
   152  		error: baseErr,
   153  	}
   154  }
   155  
   156  func (e ErrInvalidArgument) Unwrap() error {
   157  	return e.error
   158  }
   159  
   160  // ErrUnimplemented is returned when some functionality is not yet supported.
   161  type ErrUnimplemented struct {
   162  	error
   163  }
   164  
   165  // NewUnimplementedErr constructs a new unimplemented error.
   166  func NewUnimplementedErr(baseErr error) error {
   167  	return ErrUnimplemented{
   168  		error: baseErr,
   169  	}
   170  }
   171  
   172  func (e ErrUnimplemented) Unwrap() error {
   173  	return e.error
   174  }
   175  
   176  // ErrInvalidCursor is returned when a cursor is no longer valid.
   177  type ErrInvalidCursor struct {
   178  	error
   179  }
   180  
   181  // NewInvalidCursorErr constructs a new unimplemented error.
   182  func NewInvalidCursorErr(dispatchCursorVersion uint32, cursor *dispatch.Cursor) error {
   183  	return ErrInvalidCursor{
   184  		error: fmt.Errorf("the supplied cursor is no longer valid: found version %d, expected version %d", cursor.DispatchVersion, dispatchCursorVersion),
   185  	}
   186  }
   187  
   188  // GRPCStatus implements retrieving the gRPC status for the error.
   189  func (err ErrInvalidCursor) GRPCStatus() *status.Status {
   190  	return spiceerrors.WithCodeAndDetails(
   191  		err,
   192  		codes.InvalidArgument,
   193  		spiceerrors.ForReason(
   194  			v1.ErrorReason_ERROR_REASON_INVALID_CURSOR,
   195  			map[string]string{
   196  				"details": "cursor was used against an incompatible version of SpiceDB",
   197  			},
   198  		),
   199  	)
   200  }