Skip to content

Migrate the message reaction lists to the generated ReactionResponse model - #6682

Merged
gpunto merged 2 commits into
developfrom
migrate/message-reaction-lists
Sep 9, 2026
Merged

Migrate the message reaction lists to the generated ReactionResponse model#6682
gpunto merged 2 commits into
developfrom
migrate/message-reaction-lists

Conversation

@gpunto

@gpunto gpunto commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Goal

Parse a message's latest_reactions and own_reactions with the generated ReactionResponse.

Part of AND-1291

Implementation

  • Point both reaction lists at ReactionResponse and replace the DTO list mapper with toReactions(messageId). The name differs because JVM erasure would clash with the DownstreamReactionDto overload. ReactionResponse.toDomain() already exists, so no per-reaction mapping is added, and the @StreamHandsOff recording why the list is filtered by message id carries over.
  • Give the reaction fixtures the fields the generated model needs: both timestamps on the reaction, and created_at, updated_at and language on its user.
  • Give the event fixture's reaction its own nested user. The shared createUserJsonString is an own-user shape carrying unread counts, devices, mutes and invisible, none of which the wire sends for a reaction's user, and through the generated model they either vanish or land in custom.

DownstreamReactionDto stays for the reaction events, which still parse it.

Notes

The generated model requires both timestamps and a non-null user where the DTO allowed them absent. payload.ReactionResponse declares User as a value type with a plain tag and both timestamps without omitempty, and MessageResponse.LatestReactions/OwnReactions are that same struct, so an embedded reaction always carries them.

Testing

  • Device probe: sent a message, reacted with a score, an emoji code and custom data, then read it back through getMessage and queryChannels. Every reaction in both lists mapped fully, each nested user carried the three required fields, and the emoji and custom values round-tripped while emoji_code stayed out of extraData.
  • Mutation sweep over ReactionResponse.toDomain: all 9 mapped fields are caught by a test.
  • Dropping the per-message filter, or swapping the two lists, each fail tests.

latest_reactions comes back empty from a channel query because only some endpoints add EnrichLatestReactions server-side, while own_reactions is populated. It arrives as an empty array rather than null: the property is non-null with no default, and NullCollectionsAsEmptyFactory only applies to the generated package, so neither a null nor an absent key would be coerced. Unchanged by this PR, where the field was equally non-null.

Summary by CodeRabbit

  • Bug Fixes

    • Improved reaction data handling so latest and personal reactions are correctly mapped from current response data.
    • Preserved complete reaction user details, including language and creation/update timestamps.
  • Tests

    • Updated message and reaction parsing fixtures to reflect the current response format.
    • Added coverage for reaction timestamps and embedded user data.

@gpunto gpunto added the pr:internal Internal changes / housekeeping label Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 6.10 MB 6.10 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.41 MB 11.41 MB 0.00 MB 🟢
stream-chat-android-compose 13.09 MB 13.09 MB 0.00 MB 🟢

@gpunto
gpunto force-pushed the migrate/message-reaction-lists branch from b51475b to 9559175 Compare September 8, 2026 09:46
@gpunto
gpunto marked this pull request as ready for review September 8, 2026 09:46
@gpunto
gpunto requested a review from a team as a code owner September 8, 2026 09:46
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: c2e62e8e-d47c-4dbf-a50d-f357712d211d

📥 Commits

Reviewing files that changed from the base of the PR and between c05a1a1 and 9559175.

📒 Files selected for processing (8)
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DomainMapping.kt
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/MessageDtos.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/EventChatJsonProvider.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/Mother.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser/EventArguments.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/testdata/MessageDtoTestData.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/testdata/MessageTestData.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/testdata/ReactionDtoTestData.kt

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.


Walkthrough

The message DTO now uses generated ReactionResponse values for latest and own reactions. Domain mapping filters reactions by messageId. Event and parser fixtures include the corresponding user and timestamp fields.

Changes

ReactionResponse migration

Layer / File(s) Summary
Reaction model and domain mapping
stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/model/dto/MessageDtos.kt, stream-chat-android-client/src/main/java/io/getstream/chat/android/client/api2/mapping/DomainMapping.kt, stream-chat-android-client/src/test/java/io/getstream/chat/android/client/Mother.kt
Message reaction fields and test factories use ReactionResponse. Domain mapping filters by messageId and converts matching reactions.
Event reaction fixtures
stream-chat-android-client/src/test/java/io/getstream/chat/android/client/EventChatJsonProvider.kt, stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser/EventArguments.kt
Event fixtures add reaction-specific users, language fields, and reaction update timestamps.
Parser reaction fixtures
stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/testdata/MessageDtoTestData.kt, stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/testdata/MessageTestData.kt, stream-chat-android-client/src/test/java/io/getstream/chat/android/client/parser2/testdata/ReactionDtoTestData.kt
Parser test data uses ReactionResponse JSON and objects. Expected reaction users include language, creation, and update timestamps.

Estimated code review effort: 2 (Simple) | ~15 minutes

Merge Risk: ⚪ Minimal · up to 95591

Message reaction lists now use the generated response model while preserving reaction filtering and domain mapping. The supplied coverage and fixture updates align with the new wire shape, with no identified merge-blocking risk.

Sequence Diagram(s)

Reaction mapping flow

sequenceDiagram
  participant MessageDto
  participant DomainMapping
  participant ReactionResponse
  MessageDto->>DomainMapping: map latest_reactions and own_reactions
  DomainMapping->>ReactionResponse: filter by messageId
  DomainMapping-->>MessageDto: return domain reactions
Loading

Suggested reviewers: velikovpetar, andremion

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 8 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: migrating message reaction lists to the generated ReactionResponse model.
Description check ✅ Passed The description includes the goal, implementation details, testing coverage, model constraints, and issue reference. The UI, GIF, and checklist sections are not completed, but they are non-critical fo…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch migrate/message-reaction-lists

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit hops through fields of green
Reaction shapes are now more keen
Message ids guide the trail
User timestamps fill the tale
Tests bloom softly, fresh and bright

Comment @coderabbitai help to get the list of available commands.

@andremion andremion left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. One thing that has no line to sit on: the Notes say a null latest_reactions is coerced to an empty list, but the property is non-null with no default, so a JSON null throws unexpectedNull. Your probe working suggests it comes back as [] instead. Could you fix the note? Nits inline, all optional.

@gpunto

gpunto commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

On the note: you are right, and my wording had it backwards. The property is non-null with no default, and NullCollectionsAsEmptyFactory is gated to io.getstream.chat.android.network.models, so it never sees a hand-written DTO. Neither a null nor an absent key gets coerced; both would throw. The probe passing is the proof that the endpoint sends an empty array. Fixed the note to say that.

Worth knowing while we are here: the only outbound builder is NewMessageResponse, and its assignment is conditional on message.LatestReactions != nil while the tag has no omitempty. So a nil slice there would serialize as null, and the state layer does have paths that nil it out. I did not manage to pin down whether any endpoint actually reaches one, and the exposure is identical on develop, where the field was equally non-null. If you would rather not rely on that, making both lists nullable with an emptyList() default is a two-line follow-up.

@sonarqubecloud

sonarqubecloud Bot commented Sep 9, 2026

Copy link
Copy Markdown

@gpunto
gpunto enabled auto-merge September 9, 2026 13:01
@gpunto
gpunto added this pull request to the merge queue Sep 9, 2026
Merged via the queue into develop with commit 944aef4 Sep 9, 2026
20 checks passed
@gpunto
gpunto deleted the migrate/message-reaction-lists branch September 9, 2026 14:02
@stream-public-bot stream-public-bot added the released Included in a release label Sep 10, 2026
@stream-public-bot

Copy link
Copy Markdown
Contributor

🚀 Available in v7.11.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:internal Internal changes / housekeeping released Included in a release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants