Skip to content

refactor(read-state): rename persisted isUnread fields to isRead#38

Open
johan456789 wants to merge 1 commit into
mainfrom
refactor/rename-isunread-to-isread
Open

refactor(read-state): rename persisted isUnread fields to isRead#38
johan456789 wants to merge 1 commit into
mainfrom
refactor/rename-isunread-to-isread

Conversation

@johan456789
Copy link
Copy Markdown
Owner

Summary

  • Renamed Room model fields from isUnread to isRead (Article, ArticleMeta, PendingReadStateOp)
  • Used @ColumnInfo(name = "isUnread") to map to existing database column, avoiding migrations
  • Updated DAO parameters and inverted SQL logic to maintain correct behavior
  • Updated all callers in services, repositories, and tests

Test plan

  • Build compiles successfully (./gradlew assembleDebug)
  • Unit tests pass (./gradlew testFdroidDebugUnitTest)
  • Manual testing: verify read/unread state behaves correctly

Closes #23

Made with Cursor

Rename Room model fields from `isUnread` to `isRead` with proper
boolean semantics while preserving database compatibility:

- Article.isUnread -> Article.isRead (default false)
- ArticleMeta.isUnread -> ArticleMeta.isRead (default false)
- PendingReadStateOp.isUnread -> PendingReadStateOp.isRead

Use @ColumnInfo(name = "isUnread") to map to the existing database
column, avoiding the need for Room migrations. Update DAO parameters
from storedUnread to isRead with inverted SQL logic (isUnread = NOT
:isRead) to maintain correct behavior. Update all callers in services,
repositories and tests.

Closes #23

Made-with: Cursor
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the article read state tracking by replacing the isUnread property with isRead across the domain models, database access objects, and services. While the goal is to simplify the logic, the current implementation introduces a critical logic inversion bug: by mapping the new isRead field to the existing isUnread database column via @ColumnInfo(name = "isUnread") without a data migration or value inversion, the application will incorrectly treat unread articles as read. Feedback also points out that several DAO method names are now inconsistent with their renamed parameters, which may cause confusion for future maintenance.

Comment on lines +44 to +45
@field:ColumnInfo(name = "isUnread")
var isRead: Boolean = false,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

This change introduces a logic inversion bug. By renaming the field to isRead but mapping it to the existing isUnread database column via @ColumnInfo(name = "isUnread"), the boolean logic is flipped upon persistence.

In the database, isUnread = 1 (true) represents an unread article. When Room loads this value into the new isRead field, it will set isRead = true, meaning the application will treat unread articles as read.

To fix this while avoiding database migrations, you should keep the underlying field named isUnread (matching the database semantics) and use a computed property for isRead (reverting the changes in lines 57-61). If you truly want to rename the persisted field, you must provide a database migration to rename the column and invert all existing boolean values (isRead = NOT isUnread).

Comment on lines +13 to +14
@field:ColumnInfo(name = "isUnread")
var isRead: Boolean = false,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

Similar to the Article model, renaming this field to isRead while mapping it to the isUnread column inverts the logic. Articles that are unread in the database (isUnread = 1) will be loaded as isRead = true. This will break the read/unread state tracking throughout the application.

Comment on lines +20 to +21
@ColumnInfo(name = "isUnread")
val isRead: Boolean,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

Renaming this field to isRead while mapping it to the isUnread column inverts the logic. Pending operations stored in the database will be interpreted with the opposite meaning when loaded, leading to incorrect synchronization with remote services.

text: String,
groupId: String,
isUnread: Boolean,
isRead: Boolean,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The parameter has been renamed to isRead, but the method name searchArticleByGroupIdWhenIsUnread still contains 'WhenIsUnread'. This creates a confusing API where passing isRead = true to a 'WhenIsUnread' method returns read articles. If the refactor proceeds (after fixing the logic inversion in the models), these methods should be renamed to something more neutral like searchArticleByGroupIdByReadState to maintain clarity.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f21779d12e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +44 to +45
@field:ColumnInfo(name = "isUnread")
var isRead: Boolean = false,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve unread inversion in Article entity mapping

Article.isRead is now bound directly to the legacy isUnread column, but Room does not invert booleans. That means rows stored as unread (isUnread = 1) are materialized as isRead = true, and inserts with isRead = true persist back as unread. Code paths that trust article.isRead (for example read/unread UI state and diff toggling) will therefore treat unread items as read and can apply the opposite action. Keep an explicit inversion layer when mapping this column.

Useful? React with 👍 / 👎.

Comment on lines +13 to +14
@field:ColumnInfo(name = "isUnread")
var isRead: Boolean = false,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore correct read semantics for ArticleMeta

ArticleMeta.isRead is now also mapped directly from isUnread, so metadata-based sync logic reads inverted states. In GoogleReaderRssService, local unread/read sets are built from queryMetadataAll via filterNot { it.isRead } and filter { it.isRead }; with this mapping those sets are swapped, so reconciliation can miss true local-vs-remote read mismatches and skip necessary updates. ArticleMeta.isRead must remain inverted from the stored unread flag (or SQL should project an inverted value).

Useful? React with 👍 / 👎.

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.

Rename persisted unread storage to read semantics

1 participant