Keep group identity in live match payload

This commit is contained in:
Daniel Schädler 2026-04-24 16:12:43 +02:00
parent 4dc8198bc2
commit 35e66f6aeb
4 changed files with 38 additions and 5 deletions

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class LiveMatchSerializer < ApplicationSerializer class LiveMatchSerializer < ApplicationSerializer
attributes :position, :state, :teams attributes :position, :state, :teams, :group, :stage
has_many :match_scores has_many :match_scores
@ -13,4 +13,24 @@ class LiveMatchSerializer < ApplicationSerializer
} }
end end
end end
def group
return nil if object.group.nil?
{
id: object.group.id,
number: object.group.number
}
end
def stage
stage = object.stage || object.group&.stage
return nil if stage.nil?
{
id: stage.id,
level: stage.level,
state: stage.state
}
end
end end

View File

@ -91,6 +91,8 @@ Use this when page only needs match cards/list updates:
- match id - match id
- position - position
- state - state
- group identity
- stage identity
- teams - teams
- score rows - score rows
@ -136,6 +138,15 @@ Payload:
"id": 456, "id": 456,
"position": 0, "position": 0,
"state": "in_progress", "state": "in_progress",
"group": {
"id": 44,
"number": 1
},
"stage": {
"id": 33,
"level": -1,
"state": "in_progress"
},
"teams": [ "teams": [
{ {
"id": 10, "id": 10,
@ -234,7 +245,7 @@ Recommended update handling:
- do not patch a single nested field from websocket payload - do not patch a single nested field from websocket payload
- replace the full snapshot for that channel/filter - replace the full snapshot for that channel/filter
- use `match.id`, `team.id`, and `match_score.id` as stable keys - use `match.id`, `group.id`, `stage.id`, `team.id`, and `match_score.id` as stable keys
- tolerate duplicate payloads - tolerate duplicate payloads
- tolerate fast sequences like score update followed by match finish - tolerate fast sequences like score update followed by match finish

View File

@ -47,7 +47,7 @@ RSpec.describe MatchesController, type: :controller do
get :index, params: { tournament_id: @tournament.to_param } get :index, params: { tournament_id: @tournament.to_param }
match = deserialize_response(response).first match = deserialize_response(response).first
expect(match.keys).to match_array(%i[id position state teams match_scores]) expect(match.keys).to match_array(%i[id position state teams match_scores group stage])
expect(match[:teams]).to all(include(:id, :name)) expect(match[:teams]).to all(include(:id, :name))
end end
end end

View File

@ -21,14 +21,16 @@ RSpec.describe 'Tournament live payloads' do
describe TournamentMatchesPayload do describe TournamentMatchesPayload do
it 'serializes only match live fields used by matches API and websocket' do it 'serializes only match live fields used by matches API and websocket' do
tournament = create(:group_stage_tournament, match_factory: :filled_group_match) tournament = create(:group_stage_tournament, match_factory: :filled_group_match)
match = tournament.matches.first match = tournament.stages.find { |stage| stage.level == -1 }.groups.first.matches.first
payload = described_class.build(tournament) payload = described_class.build(tournament)
serialized_match = payload.find { |candidate| candidate[:id] == match.id } serialized_match = payload.find { |candidate| candidate[:id] == match.id }
expect(serialized_match.keys).to match_array(%i[id position state teams match_scores]) expect(serialized_match.keys).to match_array(%i[id position state teams match_scores group stage])
expect(serialized_match[:state]).to eq(match.state) expect(serialized_match[:state]).to eq(match.state)
expect(serialized_match[:position]).to eq(match.position) expect(serialized_match[:position]).to eq(match.position)
expect(serialized_match.dig(:group, :id)).to eq(match.group_id)
expect(serialized_match.dig(:stage, :id)).to eq(match.group.stage_id)
expect(serialized_match[:teams].map { |team| team[:id] }).to match_array(match.teams.map(&:id)) expect(serialized_match[:teams].map { |team| team[:id] }).to match_array(match.teams.map(&:id))
expect(serialized_match[:match_scores].map { |score| score[:team][:id] }).to match_array(match.teams.map(&:id)) expect(serialized_match[:match_scores].map { |score| score[:team][:id] }).to match_array(match.teams.map(&:id))
end end