Skip to content

Commit ab7c9f9

Browse files
cstocktonChris Stockton
andauthored
feat: modernize IsNotFoundError handler to support errors.Is (#2392)
Replace type switch based error detection with shared sentinel errors and errors.Is. Each model error now implements Is() to map to the appropriate sentinel. Removes large IsNotFoundError and IsUniqueConstraintViolatedError switches. This is in preparation of future pull requests to modernize and refactor some error handling so we may add reliable error metrics. Co-authored-by: Chris Stockton <chris.stockton@supabase.io>
1 parent 1491157 commit ab7c9f9

4 files changed

Lines changed: 78 additions & 40 deletions

File tree

internal/models/errors.go

Lines changed: 66 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,16 @@
11
package models
22

3+
import "errors"
4+
5+
// sentinel error for all not found errors.
6+
var errNotFound = errors.New("not found")
7+
8+
// sentinel error for unique constraint violations.
9+
var errUniqueConstraintViolated = errors.New("unique constraint violated")
10+
311
// IsNotFoundError returns whether an error represents a "not found" error.
412
func IsNotFoundError(err error) bool {
5-
switch err.(type) {
6-
case UserNotFoundError, *UserNotFoundError:
7-
return true
8-
case SessionNotFoundError, *SessionNotFoundError:
9-
return true
10-
case ConfirmationTokenNotFoundError, *ConfirmationTokenNotFoundError:
11-
return true
12-
case ConfirmationOrRecoveryTokenNotFoundError, *ConfirmationOrRecoveryTokenNotFoundError:
13-
return true
14-
case RefreshTokenNotFoundError, *RefreshTokenNotFoundError:
15-
return true
16-
case IdentityNotFoundError, *IdentityNotFoundError:
17-
return true
18-
case ChallengeNotFoundError, *ChallengeNotFoundError:
19-
return true
20-
case FactorNotFoundError, *FactorNotFoundError:
21-
return true
22-
case SSOProviderNotFoundError, *SSOProviderNotFoundError:
23-
return true
24-
case SAMLRelayStateNotFoundError, *SAMLRelayStateNotFoundError:
25-
return true
26-
case FlowStateNotFoundError, *FlowStateNotFoundError:
27-
return true
28-
case OneTimeTokenNotFoundError, *OneTimeTokenNotFoundError:
29-
return true
30-
case OAuthServerClientNotFoundError, *OAuthServerClientNotFoundError:
31-
return true
32-
case OAuthServerAuthorizationNotFoundError, *OAuthServerAuthorizationNotFoundError:
33-
return true
34-
case OAuthClientStateNotFoundError, *OAuthClientStateNotFoundError:
35-
return true
36-
case CustomOAuthProviderNotFoundError, *CustomOAuthProviderNotFoundError:
37-
return true
38-
}
39-
return false
13+
return errors.Is(err, errNotFound)
4014
}
4115

4216
type SessionNotFoundError struct{}
@@ -45,55 +19,87 @@ func (e SessionNotFoundError) Error() string {
4519
return "Session not found"
4620
}
4721

22+
func (e SessionNotFoundError) Is(target error) bool {
23+
return target == errNotFound
24+
}
25+
4826
// UserNotFoundError represents when a user is not found.
4927
type UserNotFoundError struct{}
5028

5129
func (e UserNotFoundError) Error() string {
5230
return "User not found"
5331
}
5432

33+
func (e UserNotFoundError) Is(target error) bool {
34+
return target == errNotFound
35+
}
36+
5537
// IdentityNotFoundError represents when an identity is not found.
5638
type IdentityNotFoundError struct{}
5739

5840
func (e IdentityNotFoundError) Error() string {
5941
return "Identity not found"
6042
}
6143

44+
func (e IdentityNotFoundError) Is(target error) bool {
45+
return target == errNotFound
46+
}
47+
6248
// ConfirmationOrRecoveryTokenNotFoundError represents when a confirmation or recovery token is not found.
6349
type ConfirmationOrRecoveryTokenNotFoundError struct{}
6450

6551
func (e ConfirmationOrRecoveryTokenNotFoundError) Error() string {
6652
return "Confirmation or Recovery Token not found"
6753
}
6854

55+
func (e ConfirmationOrRecoveryTokenNotFoundError) Is(target error) bool {
56+
return target == errNotFound
57+
}
58+
6959
// ConfirmationTokenNotFoundError represents when a confirmation token is not found.
7060
type ConfirmationTokenNotFoundError struct{}
7161

7262
func (e ConfirmationTokenNotFoundError) Error() string {
7363
return "Confirmation Token not found"
7464
}
7565

66+
func (e ConfirmationTokenNotFoundError) Is(target error) bool {
67+
return target == errNotFound
68+
}
69+
7670
// RefreshTokenNotFoundError represents when a refresh token is not found.
7771
type RefreshTokenNotFoundError struct{}
7872

7973
func (e RefreshTokenNotFoundError) Error() string {
8074
return "Refresh Token not found"
8175
}
8276

77+
func (e RefreshTokenNotFoundError) Is(target error) bool {
78+
return target == errNotFound
79+
}
80+
8381
// FactorNotFoundError represents when a user is not found.
8482
type FactorNotFoundError struct{}
8583

8684
func (e FactorNotFoundError) Error() string {
8785
return "Factor not found"
8886
}
8987

88+
func (e FactorNotFoundError) Is(target error) bool {
89+
return target == errNotFound
90+
}
91+
9092
// ChallengeNotFoundError represents when a user is not found.
9193
type ChallengeNotFoundError struct{}
9294

9395
func (e ChallengeNotFoundError) Error() string {
9496
return "Challenge not found"
9597
}
9698

99+
func (e ChallengeNotFoundError) Is(target error) bool {
100+
return target == errNotFound
101+
}
102+
97103
// SSOProviderNotFoundError represents an error when a SSO Provider can't be
98104
// found.
99105
type SSOProviderNotFoundError struct{}
@@ -102,6 +108,10 @@ func (e SSOProviderNotFoundError) Error() string {
102108
return "SSO Identity Provider not found"
103109
}
104110

111+
func (e SSOProviderNotFoundError) Is(target error) bool {
112+
return target == errNotFound
113+
}
114+
105115
// SAMLRelayStateNotFoundError represents an error when a SAML relay state
106116
// can't be found.
107117
type SAMLRelayStateNotFoundError struct{}
@@ -110,6 +120,10 @@ func (e SAMLRelayStateNotFoundError) Error() string {
110120
return "SAML RelayState not found"
111121
}
112122

123+
func (e SAMLRelayStateNotFoundError) Is(target error) bool {
124+
return target == errNotFound
125+
}
126+
113127
// FlowStateNotFoundError represents an error when an FlowState can't be
114128
// found.
115129
type FlowStateNotFoundError struct{}
@@ -118,12 +132,12 @@ func (e FlowStateNotFoundError) Error() string {
118132
return "Flow State not found"
119133
}
120134

135+
func (e FlowStateNotFoundError) Is(target error) bool {
136+
return target == errNotFound
137+
}
138+
121139
func IsUniqueConstraintViolatedError(err error) bool {
122-
switch err.(type) {
123-
case UserEmailUniqueConflictError, *UserEmailUniqueConflictError:
124-
return true
125-
}
126-
return false
140+
return errors.Is(err, errUniqueConstraintViolated)
127141
}
128142

129143
type UserEmailUniqueConflictError struct{}
@@ -132,15 +146,27 @@ func (e UserEmailUniqueConflictError) Error() string {
132146
return "User email unique constraint violated"
133147
}
134148

149+
func (e UserEmailUniqueConflictError) Is(target error) bool {
150+
return target == errUniqueConstraintViolated
151+
}
152+
135153
type OAuthClientStateNotFoundError struct{}
136154

137155
func (e OAuthClientStateNotFoundError) Error() string {
138156
return "OAuth state not found"
139157
}
140158

159+
func (e OAuthClientStateNotFoundError) Is(target error) bool {
160+
return target == errNotFound
161+
}
162+
141163
// CustomOAuthProviderNotFoundError represents an error when a custom OAuth/OIDC provider can't be found
142164
type CustomOAuthProviderNotFoundError struct{}
143165

144166
func (e CustomOAuthProviderNotFoundError) Error() string {
145167
return "Custom OAuth provider not found"
146168
}
169+
170+
func (e CustomOAuthProviderNotFoundError) Is(target error) bool {
171+
return target == errNotFound
172+
}

internal/models/oauth_authorization.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,7 @@ type OAuthServerAuthorizationNotFoundError struct{}
303303
func (e OAuthServerAuthorizationNotFoundError) Error() string {
304304
return "OAuth authorization not found"
305305
}
306+
307+
func (e OAuthServerAuthorizationNotFoundError) Is(target error) bool {
308+
return target == errNotFound
309+
}

internal/models/oauth_client.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ func (e OAuthServerClientNotFoundError) Error() string {
205205
return "OAuth client not found"
206206
}
207207

208+
func (e OAuthServerClientNotFoundError) Is(target error) bool {
209+
return target == errNotFound
210+
}
211+
208212
type InvalidRedirectURIError struct {
209213
URI string
210214
}

internal/models/one_time_token.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ func (e OneTimeTokenNotFoundError) Error() string {
9999
return "One-time token not found"
100100
}
101101

102+
func (e OneTimeTokenNotFoundError) Is(target error) bool {
103+
return target == errNotFound
104+
}
105+
102106
type OneTimeToken struct {
103107
ID uuid.UUID `json:"id" db:"id"`
104108

0 commit comments

Comments
 (0)