Skip to content

fix: port two index fixes from nitrite-java - #26

Open
anidotnet wants to merge 1 commit into
mainfrom
fix/port-nitrite-java-index-fixes
Open

fix: port two index fixes from nitrite-java#26
anidotnet wants to merge 1 commit into
mainfrom
fix/port-nitrite-java-index-fixes

Conversation

@anidotnet

@anidotnet anidotnet commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Two fixes found while reviewing the open PRs in nitrite/nitrite-java, both of which turned out to be present here too.

A unique index rejected a document over a key that document already holds

SimpleIndexInner::add_nitrite_ids treated any existing id under the key as a violation:

if self.is_unique() && nitrite_ids.len() == 1 { return Err(UNIQUE_CONSTRAINT_ERROR.clone()); }

so it counted the writer's own id against it. That bites:

  • a unique index over an array field with a repeated element — ["a", "b", "a"] visits a twice through for_each_element, and the second visit collided with the entry the first had just written;
  • any path that reaches a key the document already owns, such as an index rebuild or a replayed write.

The check now compares against the writer's own id: another document under the key is still a violation. From nitrite/nitrite-java#1295.

test_simple_index_add_index_element_unique_violation had encoded the bug — it wrote the same FieldValues twice and expected an error. It now uses two documents, which is the case it meant to cover, and a new test pins the same-document rewrite.

An update that left an indexed value unchanged rewrote the index anyway

update_index_entry treated an index as affected whenever the update document carried the indexed field, and then removed and rewrote the entry. An update that writes the whole document back — the common upsert shape — carries every indexed field with its old value, so every index was rebuilt on every update for nothing.

The old and new values are now compared (Value compares structurally, so arrays and embedded documents count as equal when their contents are) and the index is left alone when they match. A dirty index is not skipped: its rebuild still has to happen on the first write. From nitrite/nitrite-java#1297.

Not ported, and why

Tests

cargo test --workspace green: 2268 in nitrite, all crates pass. cargo clippy --workspace --all-targets clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Unique indexes now allow repeated keys from the same document, including repeated values in arrays, while continuing to reject conflicts between different documents.
    • Updating a document without changing its indexed values no longer causes unnecessary index rewrites.
    • Reapplying the same indexed value now completes successfully and preserves a single index entry.

- A unique index no longer rejects a document over a key that document already
  holds. add_nitrite_ids treated any existing id under the key as a violation,
  so it counted the writer's own id against it: a unique index over an array
  field with a repeated element (["a", "b", "a"]) collided with the entry it had
  just written, and so did an index rebuild or a replayed write. Another
  document under the key is still a violation. (nitrite/nitrite-java#1295)

- An update that leaves an indexed value unchanged no longer rewrites the index.
  "Affected" only meant the update carried the field, and an upsert that writes
  the whole document back carries every indexed field with its old value, so
  every index was rebuilt on every update for nothing. A dirty index is still
  rebuilt. (nitrite/nitrite-java#1297)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 60eb4b7c-58b3-4196-94bc-4eeb5bbc553d

📥 Commits

Reviewing files that changed from the base of the PR and between 7cbd557 and 14675fc.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • nitrite/src/collection/operation/index_writer.rs
  • nitrite/src/index/simple_index.rs

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The PR updates unique-index validation to allow repeated keys from the same document and adds index-entry short-circuiting when indexed values are unchanged and the index is clean. Tests and changelog entries document both fixes.

Changes

Index correctness

Layer / File(s) Summary
Skip unchanged index rewrites
nitrite/src/collection/operation/index_writer.rs, CHANGELOG.md
update_index_entry compares indexed values and skips rewrites for clean indexes when values are unchanged. Dirty indexes remain rebuildable.
Allow same-document unique keys
nitrite/src/index/simple_index.rs, CHANGELOG.md
Unique indexes reject keys owned by another document but allow repeated writes from the same document. Tests cover both cases and verify that only one ID remains stored.

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

Merge Risk: ⚪ Minimal · up to 14675

This change permits same-document unique-key rewrites while preserving cross-document uniqueness, and skips clean-index rewrites only when indexed values are unchanged. No current merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 2 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: porting two index fixes from nitrite-java.
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 2 files. (1 skipped: 1 unsupported.)

  • 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 fix/port-nitrite-java-index-fixes

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

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

@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.80%. Comparing base (7cbd557) to head (14675fc).

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #26   +/-   ##
=======================================
  Coverage   93.79%   93.80%           
=======================================
  Files         156      156           
  Lines       73939    73974   +35     
=======================================
+ Hits        69351    69388   +37     
+ Misses       4588     4586    -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

1 participant