Drarig29 / brackets-manager.js

A simple library to manage tournament brackets (round-robin, single elimination, double elimination).
https://drarig29.github.io/brackets-docs
MIT License
245 stars 38 forks source link

Support custom participants #143

Closed zestsystem closed 1 year ago

zestsystem commented 2 years ago

Hello!

This PR is related to discussion #142.

Found that the best practice for using this lib with MongoDB is to store each tournament in its own document to minimize the number of database queries and guarantee atomicity on tournament updates. I ran into two issues following this approach:

  1. In order to get additional information about the contestant, like an avatar pic link or a nickname or a nationality or etc., I would have to query for the player info using the id stored in the participants field, but the Participant type only allowed id, tournament_id, and name, and because id field only allowed for number type, I would be forced to store MongoDB ObjectId in the "name" field.

  2. Rather than having to fetch from a string id, I wanted an option to use embedded documents to represent a list of participants.

In order to solve this, I implemented an option to pass in a list of javascript objects as seeding (previously just string, number, and null allowed).

How to Use

This is what a tournament document could look like:

import { Group, Match, MatchGame, Participant, Round, Stage } from 'brackets-model';
import { SharedObjects } from 'some-lib';

interface CustomSingleParticipant extends Participant {
    contestantId: string;
    nationality: string;
    profileImage: string;
    titles: string[];
    type: 'Single';
}

interface CustomTeamParticipant extends Participant {
    contestantId: string;
    members: UserDoc[] | TeamDoc[];
    type: 'Team';
}

interface TournamentDoc extends mongoose.Document {
    id: string;
    stage: Stage[] | [];
    group: Group[] | [];
    round: Round[] | [];
    match: Match[] | [];
    match_game: MatchGame[] | [];
    participant: CustomSingleParticipant[] | CustomTeamParticipant[] | [];
    extraEventInfo: SharedObjects['ExtraInfo'] | [];    
    schemaVersion: number;
}

And this is how you would fetch participant info like nationality or profile image instead of, well, querying against a user collection:

const contstantWithInfo = tournament.participants[match[0].opponent1.id]

What's Next

Currently, the CustomParticipant, CustomSeeding, and CustomInputStage types just extend the types from brackets-model lib. I think it would be cleaner to directly apply these changes in the brackets-model library, so they can all just drop the "Custom" qualifier and be called Participant, Seeding, or InputStage. I would be happy to make those changes in the brackets-model lib if I get the go-ahead.

Drarig29 commented 2 years ago

Hey @zestsystem! Thanks for the PR. I'm in holidays so I won't have much time to review this (and to accept it, since I'll want to make the changes on brackets-model as you said).

In the meantime, could you remove those single-whitespace changes in the JSDoc comments? It clutters the diff of your PR, which makes it harder to review.

PS: You pushed a fixup! commit, I think you want to squash it :wink:

Drarig29 commented 1 year ago

You're welcome! Thank you for waiting this long... :sweat_smile:

Drarig29 commented 1 year ago

Available in v1.5.0