Skip to content

Introduce typed id value classes - #229

Open
m4pl wants to merge 13 commits into
GrapheneOS:mainfrom
m4pl:task/173/219-typed-value-classes
Open

Introduce typed id value classes#229
m4pl wants to merge 13 commits into
GrapheneOS:mainfrom
m4pl:task/173/219-typed-value-classes

Conversation

@m4pl

@m4pl m4pl commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Closes #219

Adds value classes ConversationId, MessageId, ParticipantId, SubId. Primitives stay at persistence and Java boundaries via .value / fromOrNull.

Behavior changes: ConversationMessageUiModelMapper.map returns null instead of a blank messageId, which previously became a duplicate LazyColumn key. Some isEmpty() checks became isBlank(), since the id types only expose blank checks.

@m4pl

This comment was marked as resolved.

@m4pl
m4pl force-pushed the task/173/219-typed-value-classes branch from 4cf3f83 to 941abc6 Compare August 3, 2026 20:20
@m4pl
m4pl requested review from RankoR, inthewaves and sdsantos August 3, 2026 20:22
@m4pl
m4pl marked this pull request as ready for review August 3, 2026 20:30
val messageId = data.messageId?.takeIf { it.isNotBlank() }
val conversationId = data.conversationId?.takeIf { it.isNotBlank() }

if (messageId == null || conversationId == null) {

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.

Maybe log it?

internal const val PARTICIPANT_ID_1 = "p1"
internal const val PARTICIPANT_ID_2 = "p2"
internal const val PARTICIPANT_ID_3 = "p3"
internal val PARTICIPANT_ID_1 = ParticipantId("p1")

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.

Should be participantId1 as it's not const anymore

@y9san9 y9san9 Aug 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just curious, is it this project convention?

Asking, because in Kotlin we use screaming case for immutable top level data (even if it's not const, and even if it has delegating "get"): https://github.com/JetBrains/kotlin/blob/master/libraries%2Fstdlib%2Fsrc%2Fkotlin%2Fcoroutines%2Fintrinsics%2FIntrinsics.kt#L57

Recently it was added to coding conventions as well: https://kotlinlang.org/docs/coding-conventions.html#property-names

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.

@y9san9 oops, I missed that coding conventions have been updated; thanks! @m4pl this means that my comment is no longer relevant :)

@sdsantos sdsantos left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Just one small comment regarding the empty value classes.

val messageText: String = "",
val subjectText: String = "",
val selfParticipantId: String = "",
val selfParticipantId: ParticipantId = ParticipantId(""),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Does it make sense if these ParticipantId("") would be a constant to add some semantic meaning? Like ParticipantId.NO_ID or ParticipantId.UNDEFINED?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I decided to get rid of all the ConversationId("") that aren't made for testing. I'd like to avoid creating ParticipantId.UNDEFINED, as that could confuse the logic.

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.

To me empty value looks weird as well; Maybe val selfParticipantId: ParticipantId? = null then?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now all the empty value classes are only in the tests.

@m4pl
m4pl force-pushed the task/173/219-typed-value-classes branch from 941abc6 to 438a8c7 Compare August 9, 2026 18:57
@m4pl
m4pl requested a review from RankoR August 9, 2026 20:28
@m4pl
m4pl force-pushed the task/173/219-typed-value-classes branch from b1f7fe4 to f0cbf8b Compare August 9, 2026 20:30
@m4pl
m4pl force-pushed the task/173/219-typed-value-classes branch from f0cbf8b to 846a8d8 Compare August 12, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace raw String identifiers with typed value classes

4 participants