Refactor bracket validation logic to support draft state
This commit updates the bracket validation process by introducing a new `ValidateDraft` method, allowing for incomplete edits in the draft state. The existing `Validate` method has been modified to enforce complete validation only upon confirmation. Additionally, new tests have been added to ensure that incomplete drafts are accepted until confirmation, while still rejecting invalid references. Documentation has been updated to reflect these changes in the API and architecture.
This commit is contained in:
@@ -81,7 +81,15 @@ func NewBracketDraft(eventID string, teamIDs []string) (*BracketDraft, error) {
|
||||
return draft, draft.Validate()
|
||||
}
|
||||
|
||||
func (d BracketDraft) ValidateDraft() error {
|
||||
return d.validate(false)
|
||||
}
|
||||
|
||||
func (d BracketDraft) Validate() error {
|
||||
return d.validate(true)
|
||||
}
|
||||
|
||||
func (d BracketDraft) validate(requireComplete bool) error {
|
||||
if d.EventID == "" || len(d.TeamIDs) < 2 || len(d.Matches) == 0 {
|
||||
return fmt.Errorf("%w: incomplete bracket", ErrInvalid)
|
||||
}
|
||||
@@ -114,23 +122,28 @@ func (d BracketDraft) Validate() error {
|
||||
for _, source := range []SlotSource{match.SlotA, match.SlotB} {
|
||||
switch source.Kind {
|
||||
case SlotTeam:
|
||||
if !teams[source.TeamID] || source.MatchID != "" {
|
||||
if source.MatchID != "" || (source.TeamID != "" && !teams[source.TeamID]) {
|
||||
return fmt.Errorf("%w: unknown team source", ErrInvalid)
|
||||
}
|
||||
if requireComplete && source.TeamID == "" {
|
||||
return fmt.Errorf("%w: empty bracket slot", ErrInvalid)
|
||||
}
|
||||
case SlotWinner, SlotLoser:
|
||||
upstream, ok := matches[source.MatchID]
|
||||
if !ok || upstream.Round >= match.Round || source.TeamID != "" {
|
||||
return fmt.Errorf("%w: match source must reference an earlier round", ErrInvalid)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("%w: empty bracket slot", ErrInvalid)
|
||||
if requireComplete || source.Kind != "" || source.TeamID != "" || source.MatchID != "" {
|
||||
return fmt.Errorf("%w: empty bracket slot", ErrInvalid)
|
||||
}
|
||||
}
|
||||
}
|
||||
if match.SlotA.Kind == SlotTeam && match.SlotB.Kind == SlotTeam && match.SlotA.TeamID == match.SlotB.TeamID {
|
||||
if requireComplete && match.SlotA.Kind == SlotTeam && match.SlotB.Kind == SlotTeam && match.SlotA.TeamID == match.SlotB.TeamID {
|
||||
return fmt.Errorf("%w: a team cannot play itself", ErrInvalid)
|
||||
}
|
||||
}
|
||||
if finals != 1 {
|
||||
if requireComplete && finals != 1 {
|
||||
return fmt.Errorf("%w: the last round must contain exactly one match", ErrInvalid)
|
||||
}
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user