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

Selecting `{"stage_id":0,"number":2}` on table "group" must return a unique value #207

Open fluidpb opened 4 months ago

fluidpb commented 4 months ago

I have a double elimination bracket setup and upon updating a match game, this is the error I received. Looking at the raw JSON data, I can see the following:

{
"group": [
    {
      "id": 0,
      "number": 1,
      "stage_id": 0
    },
    {
      "id": 1,
      "number": 2,
      "stage_id": 0
    },
    {
      "id": 2,
      "number": 2,
      "stage_id": 0
    }
  ]
}

This is the error log:

Error: Selecting {"stage_id":0,"number":2} on table "group" must return a unique value.
    at BracketsManager.storage.selectFirst (webpack-internal:///(rsc)/./node_modules/brackets-manager/dist/manager.js:35:23)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Update.getNextMatchesWB (webpack-internal:///(rsc)/./node_modules/brackets-manager/dist/base/getter.js:244:30)
    at async Update.updateNext (webpack-internal:///(rsc)/./node_modules/brackets-manager/dist/base/updater.js:243:29)
    at async Update.updateRelatedMatches (webpack-internal:///(rsc)/./node_modules/brackets-manager/dist/base/updater.js:129:23)
    at async Update.updateMatch (webpack-internal:///(rsc)/./node_modules/brackets-manager/dist/base/updater.js:151:13)
    at async Update.updateParentMatch (webpack-internal:///(rsc)/./node_modules/brackets-manager/dist/base/updater.js:84:9)
    at async Update.updateMatchGame (webpack-internal:///(rsc)/./node_modules/brackets-manager/dist/base/updater.js:169:9)
    at async Update.matchGame (webpack-internal:///(rsc)/./node_modules/brackets-manager/dist/update.js:33:9)
    at async updateMatch (webpack-internal:///(rsc)/./src/lib/matches.ts:428:25)
    at async /Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:39:408
    at async rS (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:38:8043)
    at async r2 (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:41:1251)
    at async doRender (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/base-server.js:1433:30)
    at async cacheEntry.responseCache.get.routeKind (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/base-server.js:1582:40)
    at async DevServer.renderToResponseWithComponentsImpl (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/base-server.js:1502:28)
    at async DevServer.renderPageComponent (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/base-server.js:1919:24)
    at async DevServer.renderToResponseImpl (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/base-server.js:1957:32)
    at async DevServer.pipeImpl (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/base-server.js:915:25)
    at async NextNodeServer.handleCatchallRenderRequest (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/next-server.js:272:17)
    at async DevServer.handleRequestImpl (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/base-server.js:811:17)
    at async /Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/dev/next-dev-server.js:339:20
    at async Span.traceAsyncFn (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/trace/trace.js:154:20)
    at async DevServer.handleRequest (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/dev/next-dev-server.js:336:24)
    at async invokeRender (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/lib/router-server.js:174:21)
    at async handleRequest (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/lib/router-server.js:353:24)
    at async requestHandlerImpl (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/lib/router-server.js:377:13)
    at async Server.requestListener (/Users/thaihuynh/Documents/projects/fluid-web/node_modules/next/dist/server/lib/start-server.js:141:13)

It seems like the method of base/getter.js is looking for these specific combo:

async getLoserBracket(stageId) {
        return this.storage.selectFirst('group', { stage_id: stageId, number: 2 });
    }

What's the best way to handle this?

Drarig29 commented 4 months ago

What kind of storage implementation are you using?

fluidpb commented 4 months ago

memory-db. Debugging this some more and it seems like generating a double elimination bracket with the flag consolationFinal: true causes this issue:

await manager.create.stage({
          name: 'Elimination',
          tournamentId: bracket.id, 
          type: (bracket.roundOne === Elimination.Double || bracket.roundOne === Elimination.Double_Bronze) ? 'double_elimination' : 'single_elimination',
          settings: {
            matchesChildCount,
            balanceByes: true,
            // consolationFinal: bracket.bronzeMedal === true,
            consolationFinal: false,
            grandFinal: 'none'
          },
          seeding: rankings.map(ranking => {
            const players: string[] = [`${ranking.player.firstName} ${ranking.player.lastName}`];
            if (ranking.partner) {
              players.push(`${ranking.partner.firstName} ${ranking.partner.lastName}`);
            }
            return {
              id: ranking.id,
              name: players.join(" / "),
              tournament_id: bracket.id,
            }
          }),
        });
Drarig29 commented 4 months ago

Interesting. The 3rd group should have been number: 3