You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
468 lines
18 KiB
Go
468 lines
18 KiB
Go
package errors
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"knowfoolery/backend/shared/types"
|
|
)
|
|
|
|
// DomainError represents a base error type for all domain errors
|
|
type DomainError struct {
|
|
Code string
|
|
Message string
|
|
Cause error
|
|
}
|
|
|
|
// Error implements the error interface
|
|
func (e *DomainError) Error() string {
|
|
if e.Cause != nil {
|
|
return fmt.Sprintf("%s: %s (caused by: %v)", e.Code, e.Message, e.Cause)
|
|
}
|
|
return fmt.Sprintf("%s: %s", e.Code, e.Message)
|
|
}
|
|
|
|
// Unwrap returns the underlying cause
|
|
func (e *DomainError) Unwrap() error {
|
|
return e.Cause
|
|
}
|
|
|
|
// NewDomainError creates a new domain error
|
|
func NewDomainError(code, message string, cause error) *DomainError {
|
|
return &DomainError{
|
|
Code: code,
|
|
Message: message,
|
|
Cause: cause,
|
|
}
|
|
}
|
|
|
|
// Error codes for different domain errors
|
|
const (
|
|
// User errors
|
|
ErrCodeInvalidPlayerName = "INVALID_PLAYER_NAME"
|
|
ErrCodeUserNotFound = "USER_NOT_FOUND"
|
|
ErrCodeUserAlreadyExists = "USER_ALREADY_EXISTS"
|
|
|
|
// Game Session errors
|
|
ErrCodeSessionNotFound = "SESSION_NOT_FOUND"
|
|
ErrCodeSessionAlreadyExists = "SESSION_ALREADY_EXISTS"
|
|
ErrCodeSessionExpired = "SESSION_EXPIRED"
|
|
ErrCodeSessionNotActive = "SESSION_NOT_ACTIVE"
|
|
ErrCodeInvalidSessionTransition = "INVALID_SESSION_TRANSITION"
|
|
ErrCodeSessionTimedOut = "SESSION_TIMED_OUT"
|
|
ErrCodeUserAlreadyHasActiveSession = "USER_ALREADY_HAS_ACTIVE_SESSION"
|
|
|
|
// Attempt errors
|
|
ErrCodeMaxAttemptsExceeded = "MAX_ATTEMPTS_EXCEEDED"
|
|
ErrCodeInvalidAttempt = "INVALID_ATTEMPT"
|
|
ErrCodeAttemptTooFast = "ATTEMPT_TOO_FAST"
|
|
|
|
// Question errors
|
|
ErrCodeQuestionNotFound = "QUESTION_NOT_FOUND"
|
|
ErrCodeQuestionAlreadyAnswered = "QUESTION_ALREADY_ANSWERED"
|
|
ErrCodeInvalidQuestion = "INVALID_QUESTION"
|
|
ErrCodeNoQuestionsAvailable = "NO_QUESTIONS_AVAILABLE"
|
|
|
|
// Theme errors
|
|
ErrCodeThemeNotFound = "THEME_NOT_FOUND"
|
|
ErrCodeInvalidTheme = "INVALID_THEME"
|
|
|
|
// Answer errors
|
|
ErrCodeInvalidAnswer = "INVALID_ANSWER"
|
|
ErrCodeEmptyAnswer = "EMPTY_ANSWER"
|
|
|
|
// Hint errors
|
|
ErrCodeHintNotAvailable = "HINT_NOT_AVAILABLE"
|
|
ErrCodeHintAlreadyUsed = "HINT_ALREADY_USED"
|
|
|
|
// Scoring errors
|
|
ErrCodeInvalidScore = "INVALID_SCORE"
|
|
ErrCodeScoringFailed = "SCORING_FAILED"
|
|
|
|
// Validation errors
|
|
ErrCodeValidationFailed = "VALIDATION_FAILED"
|
|
ErrCodeBusinessRuleViolation = "BUSINESS_RULE_VIOLATION"
|
|
|
|
// General errors
|
|
ErrCodeOperationNotAllowed = "OPERATION_NOT_ALLOWED"
|
|
ErrCodeInternalError = "INTERNAL_ERROR"
|
|
|
|
// Leaderboard errors
|
|
ErrCodeInvalidLeaderboardID = "INVALID_LEADERBOARD_ID"
|
|
ErrCodeLeaderboardNotFound = "LEADERBOARD_NOT_FOUND"
|
|
ErrCodeLeaderboardAlreadyExists = "LEADERBOARD_ALREADY_EXISTS"
|
|
ErrCodeLeaderboardFrozen = "LEADERBOARD_FROZEN"
|
|
ErrCodeLeaderboardArchived = "LEADERBOARD_ARCHIVED"
|
|
ErrCodeInvalidRank = "INVALID_RANK"
|
|
ErrCodePlayerNotFound = "PLAYER_NOT_FOUND"
|
|
ErrCodeInvalidResetFrequency = "INVALID_RESET_FREQUENCY"
|
|
ErrCodeInvalidResetAction = "INVALID_RESET_ACTION"
|
|
ErrCodeInvalidResetInterval = "INVALID_RESET_INTERVAL"
|
|
ErrCodeInvalidTimezone = "INVALID_TIMEZONE"
|
|
ErrCodeInvalidPreserveCount = "INVALID_PRESERVE_COUNT"
|
|
ErrCodeInvalidResetTime = "INVALID_RESET_TIME"
|
|
ErrCodeInvalidNotificationTime = "INVALID_NOTIFICATION_TIME"
|
|
ErrCodeInvalidDisplayFormat = "INVALID_DISPLAY_FORMAT"
|
|
ErrCodeInvalidSortOrder = "INVALID_SORT_ORDER"
|
|
ErrCodeInvalidRankDisplay = "INVALID_RANK_DISPLAY"
|
|
ErrCodeInvalidEntriesPerPage = "INVALID_ENTRIES_PER_PAGE"
|
|
ErrCodeInvalidHighlightCount = "INVALID_HIGHLIGHT_COUNT"
|
|
ErrCodeInvalidColorKey = "INVALID_COLOR_KEY"
|
|
ErrCodeInvalidColorValue = "INVALID_COLOR_VALUE"
|
|
ErrCodeInvalidLabelKey = "INVALID_LABEL_KEY"
|
|
ErrCodeInvalidLabelValue = "INVALID_LABEL_VALUE"
|
|
ErrCodeInvalidMetadata = "INVALID_METADATA"
|
|
ErrCodeInvalidGameCount = "INVALID_GAME_COUNT"
|
|
ErrCodeInvalidPlayerCount = "INVALID_PLAYER_COUNT"
|
|
ErrCodeInvalidStreak = "INVALID_STREAK"
|
|
ErrCodeInvalidPlayerID = "INVALID_PLAYER_ID"
|
|
ErrCodeInvalidSessionID = "INVALID_SESSION_ID"
|
|
ErrCodeInvalidRankRange = "INVALID_RANK_RANGE"
|
|
ErrCodeInvalidTopCount = "INVALID_TOP_COUNT"
|
|
ErrCodeInvalidContext = "INVALID_CONTEXT"
|
|
ErrCodeInvalidCompetitionName = "INVALID_COMPETITION_NAME"
|
|
ErrCodeInvalidCompetitionStatus = "INVALID_COMPETITION_STATUS"
|
|
ErrCodeCompetitionNotYetStarted = "COMPETITION_NOT_YET_STARTED"
|
|
ErrCodeCompetitionNotActive = "COMPETITION_NOT_ACTIVE"
|
|
ErrCodeCompetitionAlreadyCompleted = "COMPETITION_ALREADY_COMPLETED"
|
|
ErrCodePlayerNotQualified = "PLAYER_NOT_QUALIFIED"
|
|
ErrCodeCompetitionFull = "COMPETITION_FULL"
|
|
ErrCodeScoreBelowMinimum = "SCORE_BELOW_MINIMUM"
|
|
ErrCodeTooManyEntriesPerPlayer = "TOO_MANY_ENTRIES_PER_PLAYER"
|
|
ErrCodeEntryNotFound = "ENTRY_NOT_FOUND"
|
|
ErrCodeInvalidStartTime = "INVALID_START_TIME"
|
|
ErrCodeInvalidEndTime = "INVALID_END_TIME"
|
|
)
|
|
|
|
// User-related errors
|
|
|
|
// ErrInvalidPlayerName indicates the player name doesn't meet validation requirements
|
|
func ErrInvalidPlayerName(name string, reason string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeInvalidPlayerName,
|
|
fmt.Sprintf("invalid player name '%s': %s", name, reason),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrUserNotFound indicates a user was not found
|
|
func ErrUserNotFound(userID types.UserID) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeUserNotFound,
|
|
fmt.Sprintf("user not found: %s", userID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrUserAlreadyExists indicates a user already exists
|
|
func ErrUserAlreadyExists(name string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeUserAlreadyExists,
|
|
fmt.Sprintf("user already exists: %s", name),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// Game Session-related errors
|
|
|
|
// ErrSessionNotFound indicates a game session was not found
|
|
func ErrSessionNotFound(sessionID types.GameSessionID) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeSessionNotFound,
|
|
fmt.Sprintf("game session not found: %s", sessionID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrSessionExpired indicates a game session has expired
|
|
func ErrSessionExpired(sessionID types.GameSessionID) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeSessionExpired,
|
|
fmt.Sprintf("game session expired: %s", sessionID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrSessionNotActive indicates operation requires an active session
|
|
func ErrSessionNotActive(sessionID types.GameSessionID, status types.SessionStatus) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeSessionNotActive,
|
|
fmt.Sprintf("session %s is not active (current status: %s)", sessionID, status),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrInvalidSessionTransition indicates an invalid session status transition
|
|
func ErrInvalidSessionTransition(from, to types.SessionStatus) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeInvalidSessionTransition,
|
|
fmt.Sprintf("invalid session transition from %s to %s", from, to),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrUserAlreadyHasActiveSession indicates user already has an active session
|
|
func ErrUserAlreadyHasActiveSession(userID types.UserID, existingSessionID types.GameSessionID) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeUserAlreadyHasActiveSession,
|
|
fmt.Sprintf("user %s already has active session: %s", userID, existingSessionID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// Attempt-related errors
|
|
|
|
// ErrMaxAttemptsExceeded indicates maximum attempts for a question have been exceeded
|
|
func ErrMaxAttemptsExceeded(questionID types.QuestionID, maxAttempts int) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeMaxAttemptsExceeded,
|
|
fmt.Sprintf("maximum attempts (%d) exceeded for question: %s", maxAttempts, questionID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrAttemptTooFast indicates an attempt was made too quickly (anti-cheat)
|
|
func ErrAttemptTooFast(minInterval string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeAttemptTooFast,
|
|
fmt.Sprintf("attempt made too quickly, minimum interval: %s", minInterval),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// Question-related errors
|
|
|
|
// ErrQuestionNotFound indicates a question was not found
|
|
func ErrQuestionNotFound(questionID types.QuestionID) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeQuestionNotFound,
|
|
fmt.Sprintf("question not found: %s", questionID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrQuestionAlreadyAnswered indicates question was already answered in this session
|
|
func ErrQuestionAlreadyAnswered(questionID types.QuestionID, sessionID types.GameSessionID) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeQuestionAlreadyAnswered,
|
|
fmt.Sprintf("question %s already answered in session %s", questionID, sessionID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrNoQuestionsAvailable indicates no questions are available for selection
|
|
func ErrNoQuestionsAvailable() *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeNoQuestionsAvailable,
|
|
"no questions available for selection",
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// Theme-related errors
|
|
|
|
// ErrThemeNotFound indicates a theme was not found
|
|
func ErrThemeNotFound(themeID types.ThemeID) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeThemeNotFound,
|
|
fmt.Sprintf("theme not found: %s", themeID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrInvalidTheme indicates an invalid theme
|
|
func ErrInvalidTheme(reason string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeInvalidTheme,
|
|
fmt.Sprintf("invalid theme: %s", reason),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// Answer-related errors
|
|
|
|
// ErrInvalidAnswer indicates an answer is invalid
|
|
func ErrInvalidAnswer(reason string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeInvalidAnswer,
|
|
fmt.Sprintf("invalid answer: %s", reason),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrEmptyAnswer indicates an empty answer was provided
|
|
func ErrEmptyAnswer() *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeEmptyAnswer,
|
|
"answer cannot be empty",
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrInvalidQuestion indicates an invalid question
|
|
func ErrInvalidQuestion(reason string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeInvalidQuestion,
|
|
fmt.Sprintf("invalid question: %s", reason),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// Hint-related errors
|
|
|
|
// ErrHintNotAvailable indicates no hint is available for the question
|
|
func ErrHintNotAvailable(questionID types.QuestionID) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeHintNotAvailable,
|
|
fmt.Sprintf("no hint available for question: %s", questionID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrHintAlreadyUsed indicates hint was already used for this question
|
|
func ErrHintAlreadyUsed(questionID types.QuestionID) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeHintAlreadyUsed,
|
|
fmt.Sprintf("hint already used for question: %s", questionID),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// Scoring-related errors
|
|
|
|
// ErrScoringFailed indicates a scoring operation failed
|
|
func ErrScoringFailed(reason string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeScoringFailed,
|
|
fmt.Sprintf("scoring failed: %s", reason),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// Validation-related errors
|
|
|
|
// ErrValidationFailed indicates domain validation failed
|
|
func ErrValidationFailed(field string, reason string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeValidationFailed,
|
|
fmt.Sprintf("validation failed for %s: %s", field, reason),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrBusinessRuleViolation indicates a business rule was violated
|
|
func ErrBusinessRuleViolation(rule string, details string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeBusinessRuleViolation,
|
|
fmt.Sprintf("business rule violation - %s: %s", rule, details),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// General errors
|
|
|
|
// ErrOperationNotAllowed indicates the requested operation is not allowed
|
|
func ErrOperationNotAllowed(operation string, reason string) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeOperationNotAllowed,
|
|
fmt.Sprintf("operation '%s' not allowed: %s", operation, reason),
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// ErrInternalError indicates an internal domain error occurred
|
|
func ErrInternalError(reason string, cause error) *DomainError {
|
|
return NewDomainError(
|
|
ErrCodeInternalError,
|
|
fmt.Sprintf("internal error: %s", reason),
|
|
cause,
|
|
)
|
|
}
|
|
|
|
// Error checking functions
|
|
|
|
// IsErrorOfType checks if an error is of a specific domain error type
|
|
func IsErrorOfType(err error, code string) bool {
|
|
if domainErr, ok := err.(*DomainError); ok {
|
|
return domainErr.Code == code
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsUserError checks if error is user-related
|
|
func IsUserError(err error) bool {
|
|
return IsErrorOfType(err, ErrCodeInvalidPlayerName) ||
|
|
IsErrorOfType(err, ErrCodeUserNotFound) ||
|
|
IsErrorOfType(err, ErrCodeUserAlreadyExists)
|
|
}
|
|
|
|
// IsSessionError checks if error is session-related
|
|
func IsSessionError(err error) bool {
|
|
return IsErrorOfType(err, ErrCodeSessionNotFound) ||
|
|
IsErrorOfType(err, ErrCodeSessionExpired) ||
|
|
IsErrorOfType(err, ErrCodeSessionNotActive) ||
|
|
IsErrorOfType(err, ErrCodeInvalidSessionTransition) ||
|
|
IsErrorOfType(err, ErrCodeUserAlreadyHasActiveSession)
|
|
}
|
|
|
|
// IsValidationError checks if error is validation-related
|
|
func IsValidationError(err error) bool {
|
|
return IsErrorOfType(err, ErrCodeValidationFailed) ||
|
|
IsErrorOfType(err, ErrCodeInvalidPlayerName) ||
|
|
IsErrorOfType(err, ErrCodeInvalidAnswer)
|
|
}
|
|
|
|
// IsBusinessRuleError checks if error is business rule violation
|
|
func IsBusinessRuleError(err error) bool {
|
|
return IsErrorOfType(err, ErrCodeBusinessRuleViolation) ||
|
|
IsErrorOfType(err, ErrCodeMaxAttemptsExceeded) ||
|
|
IsErrorOfType(err, ErrCodeAttemptTooFast)
|
|
}
|
|
|
|
// Leaderboard-related error variables
|
|
var (
|
|
ErrInvalidLeaderboardID = NewDomainError(ErrCodeInvalidLeaderboardID, "invalid leaderboard ID", nil)
|
|
ErrLeaderboardNotFound = NewDomainError(ErrCodeLeaderboardNotFound, "leaderboard not found", nil)
|
|
ErrLeaderboardAlreadyExists = NewDomainError(ErrCodeLeaderboardAlreadyExists, "leaderboard already exists", nil)
|
|
ErrLeaderboardFrozen = NewDomainError(ErrCodeLeaderboardFrozen, "leaderboard is frozen", nil)
|
|
ErrLeaderboardArchived = NewDomainError(ErrCodeLeaderboardArchived, "leaderboard is archived", nil)
|
|
ErrInvalidRank = NewDomainError(ErrCodeInvalidRank, "invalid rank", nil)
|
|
ErrPlayerNotFound = NewDomainError(ErrCodePlayerNotFound, "player not found", nil)
|
|
ErrInvalidResetFrequency = NewDomainError(ErrCodeInvalidResetFrequency, "invalid reset frequency", nil)
|
|
ErrInvalidResetAction = NewDomainError(ErrCodeInvalidResetAction, "invalid reset action", nil)
|
|
ErrInvalidResetInterval = NewDomainError(ErrCodeInvalidResetInterval, "invalid reset interval", nil)
|
|
ErrInvalidTimezone = NewDomainError(ErrCodeInvalidTimezone, "invalid timezone", nil)
|
|
ErrInvalidPreserveCount = NewDomainError(ErrCodeInvalidPreserveCount, "invalid preserve count", nil)
|
|
ErrInvalidResetTime = NewDomainError(ErrCodeInvalidResetTime, "invalid reset time", nil)
|
|
ErrInvalidNotificationTime = NewDomainError(ErrCodeInvalidNotificationTime, "invalid notification time", nil)
|
|
ErrInvalidDisplayFormat = NewDomainError(ErrCodeInvalidDisplayFormat, "invalid display format", nil)
|
|
ErrInvalidSortOrder = NewDomainError(ErrCodeInvalidSortOrder, "invalid sort order", nil)
|
|
ErrInvalidRankDisplay = NewDomainError(ErrCodeInvalidRankDisplay, "invalid rank display", nil)
|
|
ErrInvalidEntriesPerPage = NewDomainError(ErrCodeInvalidEntriesPerPage, "invalid entries per page", nil)
|
|
ErrInvalidHighlightCount = NewDomainError(ErrCodeInvalidHighlightCount, "invalid highlight count", nil)
|
|
ErrInvalidColorKey = NewDomainError(ErrCodeInvalidColorKey, "invalid color key", nil)
|
|
ErrInvalidColorValue = NewDomainError(ErrCodeInvalidColorValue, "invalid color value", nil)
|
|
ErrInvalidLabelKey = NewDomainError(ErrCodeInvalidLabelKey, "invalid label key", nil)
|
|
ErrInvalidLabelValue = NewDomainError(ErrCodeInvalidLabelValue, "invalid label value", nil)
|
|
ErrInvalidMetadata = NewDomainError(ErrCodeInvalidMetadata, "invalid metadata", nil)
|
|
ErrInvalidGameCount = NewDomainError(ErrCodeInvalidGameCount, "invalid game count", nil)
|
|
ErrInvalidPlayerCount = NewDomainError(ErrCodeInvalidPlayerCount, "invalid player count", nil)
|
|
ErrInvalidStreak = NewDomainError(ErrCodeInvalidStreak, "invalid streak", nil)
|
|
ErrInvalidPlayerID = NewDomainError(ErrCodeInvalidPlayerID, "invalid player ID", nil)
|
|
ErrInvalidSessionID = NewDomainError(ErrCodeInvalidSessionID, "invalid session ID", nil)
|
|
ErrInvalidScore = NewDomainError(ErrCodeInvalidScore, "invalid score", nil)
|
|
ErrInvalidRankRange = NewDomainError(ErrCodeInvalidRankRange, "invalid rank range", nil)
|
|
ErrInvalidTopCount = NewDomainError(ErrCodeInvalidTopCount, "invalid top count", nil)
|
|
ErrInvalidContext = NewDomainError(ErrCodeInvalidContext, "invalid context", nil)
|
|
ErrInvalidCompetitionName = NewDomainError(ErrCodeInvalidCompetitionName, "invalid competition name", nil)
|
|
ErrInvalidCompetitionStatus = NewDomainError(ErrCodeInvalidCompetitionStatus, "invalid competition status", nil)
|
|
ErrCompetitionNotYetStarted = NewDomainError(ErrCodeCompetitionNotYetStarted, "competition not yet started", nil)
|
|
ErrCompetitionNotActive = NewDomainError(ErrCodeCompetitionNotActive, "competition not active", nil)
|
|
ErrCompetitionAlreadyCompleted = NewDomainError(ErrCodeCompetitionAlreadyCompleted, "competition already completed", nil)
|
|
ErrPlayerNotQualified = NewDomainError(ErrCodePlayerNotQualified, "player not qualified", nil)
|
|
ErrCompetitionFull = NewDomainError(ErrCodeCompetitionFull, "competition full", nil)
|
|
ErrScoreBelowMinimum = NewDomainError(ErrCodeScoreBelowMinimum, "score below minimum", nil)
|
|
ErrTooManyEntriesPerPlayer = NewDomainError(ErrCodeTooManyEntriesPerPlayer, "too many entries per player", nil)
|
|
ErrEntryNotFound = NewDomainError(ErrCodeEntryNotFound, "entry not found", nil)
|
|
ErrInvalidStartTime = NewDomainError(ErrCodeInvalidStartTime, "invalid start time", nil)
|
|
ErrInvalidEndTime = NewDomainError(ErrCodeInvalidEndTime, "invalid end time", nil)
|
|
) |