summaryrefslogtreecommitdiff
path: root/vendor/github.com/authzed/spicedb/pkg/datastore/errors.go
blob: 84057d57e6940ead41903af1b86c68fd4fdfa9d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
package datastore

import (
	"errors"
	"fmt"

	"github.com/rs/zerolog"

	core "github.com/authzed/spicedb/pkg/proto/core/v1"
)

// ErrNotFound is a shared interface for not found errors.
type ErrNotFound interface {
	IsNotFoundError() bool
}

// NamespaceNotFoundError occurs when a namespace was not found.
type NamespaceNotFoundError struct {
	error
	namespaceName string
}

var _ ErrNotFound = NamespaceNotFoundError{}

func (err NamespaceNotFoundError) IsNotFoundError() bool {
	return true
}

// NotFoundNamespaceName is the name of the namespace not found.
func (err NamespaceNotFoundError) NotFoundNamespaceName() string {
	return err.namespaceName
}

// MarshalZerologObject implements zerolog object marshalling.
func (err NamespaceNotFoundError) MarshalZerologObject(e *zerolog.Event) {
	e.Err(err.error).Str("namespace", err.namespaceName)
}

// DetailsMetadata returns the metadata for details for this error.
func (err NamespaceNotFoundError) DetailsMetadata() map[string]string {
	return map[string]string{
		"definition_name": err.namespaceName,
	}
}

// WatchDisconnectedError occurs when a watch has fallen too far behind and was forcibly disconnected
// as a result.
type WatchDisconnectedError struct{ error }

// WatchCanceledError occurs when a watch was canceled by the caller.
type WatchCanceledError struct{ error }

// WatchDisabledError occurs when watch is disabled by being unsupported by the datastore.
type WatchDisabledError struct{ error }

// ReadOnlyError is returned when the operation cannot be completed because the datastore is in
// read-only mode.
type ReadOnlyError struct{ error }

// WatchRetryableError is returned when a transient/temporary error occurred in watch and indicates that
// the caller *may* retry the watch after some backoff time.
type WatchRetryableError struct{ error }

// InvalidRevisionReason is the reason the revision could not be used.
type InvalidRevisionReason int

const (
	// RevisionStale is the reason returned when a revision is outside the window of
	// validity by being too old.
	RevisionStale InvalidRevisionReason = iota

	// CouldNotDetermineRevision is the reason returned when a revision for a
	// request could not be determined.
	CouldNotDetermineRevision
)

// InvalidRevisionError occurs when a revision specified to a call was invalid.
type InvalidRevisionError struct {
	error
	revision Revision
	reason   InvalidRevisionReason
}

// InvalidRevision is the revision that failed.
func (err InvalidRevisionError) InvalidRevision() Revision {
	return err.revision
}

// Reason is the reason the revision failed.
func (err InvalidRevisionError) Reason() InvalidRevisionReason {
	return err.reason
}

// MarshalZerologObject implements zerolog object marshalling.
func (err InvalidRevisionError) MarshalZerologObject(e *zerolog.Event) {
	switch err.reason {
	case RevisionStale:
		e.Err(err.error).Str("reason", "stale")
	case CouldNotDetermineRevision:
		e.Err(err.error).Str("reason", "indeterminate")
	default:
		e.Err(err.error).Str("reason", "unknown")
	}
}

// NewNamespaceNotFoundErr constructs a new namespace not found error.
func NewNamespaceNotFoundErr(nsName string) error {
	return NamespaceNotFoundError{
		error:         fmt.Errorf("object definition `%s` not found", nsName),
		namespaceName: nsName,
	}
}

// NewWatchDisconnectedErr constructs a new watch was disconnected error.
func NewWatchDisconnectedErr() error {
	return WatchDisconnectedError{
		error: fmt.Errorf("watch fell too far behind and was disconnected; consider increasing watch buffer size via the flag --datastore-watch-buffer-length"),
	}
}

// NewWatchCanceledErr constructs a new watch was canceled error.
func NewWatchCanceledErr() error {
	return WatchCanceledError{
		error: fmt.Errorf("watch was canceled by the caller"),
	}
}

// NewWatchDisabledErr constructs a new watch is disabled error.
func NewWatchDisabledErr(reason string) error {
	return WatchDisabledError{
		error: fmt.Errorf("watch is currently disabled: %s", reason),
	}
}

// NewWatchTemporaryErr wraps another error in watch, indicating that the error is likely
// a temporary condition and clients may consider retrying by calling watch again (vs a fatal error).
func NewWatchTemporaryErr(wrapped error) error {
	return WatchRetryableError{
		error: fmt.Errorf("watch has failed with a temporary condition: %w. please retry the watch", wrapped),
	}
}

// NewReadonlyErr constructs an error for when a request has failed because
// the datastore has been configured to be read-only.
func NewReadonlyErr() error {
	return ReadOnlyError{
		error: fmt.Errorf("datastore is in read-only mode"),
	}
}

// NewInvalidRevisionErr constructs a new invalid revision error.
func NewInvalidRevisionErr(revision Revision, reason InvalidRevisionReason) error {
	switch reason {
	case RevisionStale:
		return InvalidRevisionError{
			error:    fmt.Errorf("revision has expired"),
			revision: revision,
			reason:   reason,
		}

	default:
		return InvalidRevisionError{
			error:    fmt.Errorf("revision was invalid"),
			revision: revision,
			reason:   reason,
		}
	}
}

// CaveatNameNotFoundError is the error returned when a caveat is not found by its name
type CaveatNameNotFoundError struct {
	error
	name string
}

var _ ErrNotFound = CaveatNameNotFoundError{}

func (err CaveatNameNotFoundError) IsNotFoundError() bool {
	return true
}

// CaveatName returns the name of the caveat that couldn't be found
func (err CaveatNameNotFoundError) CaveatName() string {
	return err.name
}

// NewCaveatNameNotFoundErr constructs a new caveat name not found error.
func NewCaveatNameNotFoundErr(name string) error {
	return CaveatNameNotFoundError{
		error: fmt.Errorf("caveat with name `%s` not found", name),
		name:  name,
	}
}

// DetailsMetadata returns the metadata for details for this error.
func (err CaveatNameNotFoundError) DetailsMetadata() map[string]string {
	return map[string]string{
		"caveat_name": err.name,
	}
}

// CounterNotRegisteredError indicates that a counter was not registered.
type CounterNotRegisteredError struct {
	error
	counterName string
}

// NewCounterNotRegisteredErr constructs a new counter not registered error.
func NewCounterNotRegisteredErr(counterName string) error {
	return CounterNotRegisteredError{
		error:       fmt.Errorf("counter with name `%s` not found", counterName),
		counterName: counterName,
	}
}

// DetailsMetadata returns the metadata for details for this error.
func (err CounterNotRegisteredError) DetailsMetadata() map[string]string {
	return map[string]string{
		"counter_name": err.counterName,
	}
}

// CounterAlreadyRegisteredError indicates that a counter  was already registered.
type CounterAlreadyRegisteredError struct {
	error

	counterName string
	filter      *core.RelationshipFilter
}

// NewCounterAlreadyRegisteredErr constructs a new filter not registered error.
func NewCounterAlreadyRegisteredErr(counterName string, filter *core.RelationshipFilter) error {
	return CounterAlreadyRegisteredError{
		error:       fmt.Errorf("counter with name `%s` already registered", counterName),
		counterName: counterName,
		filter:      filter,
	}
}

// DetailsMetadata returns the metadata for details for this error.
func (err CounterAlreadyRegisteredError) DetailsMetadata() map[string]string {
	subjectType := ""
	subjectID := ""
	subjectRelation := ""
	if err.filter.OptionalSubjectFilter != nil {
		subjectType = err.filter.OptionalSubjectFilter.SubjectType
		subjectID = err.filter.OptionalSubjectFilter.OptionalSubjectId

		if err.filter.OptionalSubjectFilter.GetOptionalRelation() != nil {
			subjectRelation = err.filter.OptionalSubjectFilter.GetOptionalRelation().Relation
		}
	}

	return map[string]string{
		"counter_name":                  err.counterName,
		"new_filter_resource_type":      err.filter.ResourceType,
		"new_filter_resource_id":        err.filter.OptionalResourceId,
		"new_filter_resource_id_prefix": err.filter.OptionalResourceIdPrefix,
		"new_filter_relation":           err.filter.OptionalRelation,
		"new_filter_subject_type":       subjectType,
		"new_filter_subject_id":         subjectID,
		"new_filter_subject_relation":   subjectRelation,
	}
}

// MaximumChangesSizeExceededError is returned when the maximum size of changes is exceeded.
type MaximumChangesSizeExceededError struct {
	error
	maxSize uint64
}

// NewMaximumChangesSizeExceededError creates a new MaximumChangesSizeExceededError.
func NewMaximumChangesSizeExceededError(maxSize uint64) error {
	return MaximumChangesSizeExceededError{fmt.Errorf("maximum changes byte size of %d exceeded", maxSize), maxSize}
}

var (
	ErrClosedIterator        = errors.New("unable to iterate: iterator closed")
	ErrCursorsWithoutSorting = errors.New("cursors are disabled on unsorted results")
	ErrCursorEmpty           = errors.New("cursors are only available after the first result")
)