Skip to content

Conversation

@danniel
Copy link
Collaborator

@danniel danniel commented Feb 11, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced search functionality with word similarity matching for improved accuracy when searching NGOs and causes. Feature is enabled by default with configurable settings.
  • Bug Fixes

    • Optimized search result ordering for mixed NGO and cause queries.

@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

📝 Walkthrough

Walkthrough

These changes introduce a feature flag-controlled enhancement to NGO and cause search functionality, enabling conditional use of trigram word similarity alongside configurable similarity thresholds. A new feature flag defaults to enabled and drives the search strategy selection.

Changes

Cohort / File(s) Summary
Search Enhancement
backend/donations/views/common/search.py
Added TrigramWordSimilarity import and conditional logic controlled by ENABLE_NGO_SEARCH_WORD_SIMILARITY flag. NgoSearchMixin and CauseSearchMixin now select between word similarity (0.4 threshold) and standard similarity (0.3 threshold). Dynamic similarity variable replaces static comparisons. NgoCauseMixedSearchMixin reverses result ordering.
Feature Flag
backend/redirectioneaza/settings/feature_flags.py
Added ENABLE_NGO_SEARCH_WORD_SIMILARITY feature flag sourced from environment variables with default value True under new "Search tweaks" section.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Poem

🐰 Whiskers twitch with search delight,
Trigrams dance and words align just right,
Similarity thresholds shift with care,
Finding causes, donors everywhere!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introducing an optional trigram word similarity feature for NGO and Cause search through a new feature flag and conditional logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/improve-search-quality

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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

@greptile-apps
Copy link

greptile-apps bot commented Feb 11, 2026

Greptile Overview

Greptile Summary

This PR introduces TrigramWordSimilarity as an alternative to character-based TrigramSimilarity for NGO and Cause searches, controlled by the ENABLE_NGO_SEARCH_WORD_SIMILARITY feature flag (defaults to True).

Key Changes:

  • Imported TrigramWordSimilarity from Django's PostgreSQL search module
  • Added conditional logic to use word-based similarity (threshold 0.4) vs character-based similarity (threshold 0.3)
  • Feature flag defaults to True, enabling stricter word-aware matching by default
  • Added TODO comment highlighting existing logic issue at line 61
  • Changed QuerySet union order in NgoCauseMixedSearchMixin from searched_causes | ngos_causes to ngos_causes | searched_causes

Impact:

  • Search results will be more semantically meaningful with word boundary awareness
  • Higher threshold (0.4 vs 0.3) may reduce false positive matches
  • Union order change may affect result ordering when combining NGO-based and direct cause searches

Confidence Score: 4/5

  • This PR is safe to merge with low risk - implements a well-understood Django feature with proper feature flag control
  • The changes are straightforward and use standard Django PostgreSQL search features. The feature flag allows easy rollback if needed. Minor concerns include the QuerySet union order change that should be tested, and the TODO comment indicating awareness of existing logic that may need future attention
  • Verify backend/donations/views/common/search.py line 137 union order produces expected search result ordering

Important Files Changed

Filename Overview
backend/redirectioneaza/settings/feature_flags.py Added ENABLE_NGO_SEARCH_WORD_SIMILARITY feature flag with default value True, following existing patterns
backend/donations/views/common/search.py Implemented word-based trigram similarity with configurable thresholds; includes TODO comment about existing logic issue and QuerySet union order change

Sequence Diagram

sequenceDiagram
    participant User
    participant SearchMixin
    participant FeatureFlag
    participant PostgreSQL
    
    User->>SearchMixin: Search query
    SearchMixin->>FeatureFlag: Check ENABLE_NGO_SEARCH_WORD_SIMILARITY
    
    alt Word Similarity Enabled (default)
        FeatureFlag-->>SearchMixin: True
        SearchMixin->>PostgreSQL: TrigramWordSimilarity(query, "name")
        Note over SearchMixin,PostgreSQL: Threshold: 0.4<br/>Word-aware matching
    else Character Similarity
        FeatureFlag-->>SearchMixin: False
        SearchMixin->>PostgreSQL: TrigramSimilarity("name", query)
        Note over SearchMixin,PostgreSQL: Threshold: 0.3<br/>Character-level matching
    end
    
    SearchMixin->>PostgreSQL: SearchRank(vector, query)
    PostgreSQL-->>SearchMixin: Annotated results
    SearchMixin->>SearchMixin: Filter (rank >= 0.3 OR similarity > threshold)
    SearchMixin-->>User: Search results
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

searched_causes = CauseSearchMixin.get_search_results(queryset, query, language_code)

return searched_causes | ngos_causes
return ngos_causes | searched_causes
Copy link

Choose a reason for hiding this comment

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

QuerySet union order changed from searched_causes | ngos_causes to ngos_causes | searched_causes - verify this produces expected result ordering in searches

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@backend/donations/views/common/search.py`:
- Around line 59-62: The code calls queryset.none() when queryset may be None,
causing AttributeError; update the logic in the method that manipulates queryset
so it never calls none() on a None object — e.g., change the block that reads
"if not queryset: if not self.queryset: return queryset.none()" to return a safe
empty queryset using either self.queryset.none() (if self.queryset is set), or
self.model.objects.none() (for model-agnostic mixins), or raise a clear
configuration error; reference the variables queryset and self.queryset and the
surrounding method to implement one of these safe alternatives.
🧹 Nitpick comments (2)
backend/redirectioneaza/settings/feature_flags.py (1)

4-5: Consider a more generic flag name.

The flag is named ENABLE_NGO_SEARCH_WORD_SIMILARITY but it also controls the similarity strategy for CauseSearchMixin. A name like ENABLE_SEARCH_WORD_SIMILARITY or ENABLE_TRIGRAM_WORD_SIMILARITY would better reflect its actual scope.

backend/donations/views/common/search.py (1)

82-87: Duplicated logic with CauseSearchMixin.

Lines 82-87 are identical to lines 109-114. Consider extracting this to a helper method or extending ConfigureSearch to keep the similarity strategy in one place.

♻️ Proposed refactor
 class ConfigureSearch:
+    `@staticmethod`
+    def trigram_similarity(query: str, field: str = "name"):
+        if settings.ENABLE_NGO_SEARCH_WORD_SIMILARITY:
+            return TrigramWordSimilarity(query, field), 0.4
+        return TrigramSimilarity(field, query), 0.3
+
     `@staticmethod`
     def query(query: str, language_code: str) -> SearchQuery:

Then in both mixins:

trigram_similarity, similarity_threshold = ConfigureSearch.trigram_similarity(query, "name")

Comment on lines 59 to 62
if not queryset:
if not self.queryset:
return queryset.none()
return queryset.none() # TODO: this looks weird
queryset = self.queryset
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical bug: queryset.none() will fail when queryset is None.

When queryset is None (falsy), calling queryset.none() raises AttributeError: 'NoneType' object has no attribute 'none'. The TODO comment correctly identifies this as problematic.

🐛 Proposed fix
         if not queryset:
             if not self.queryset:
-                return queryset.none()  # TODO: this looks weird
+                return Ngo.objects.none()  # Return an empty QuerySet
             queryset = self.queryset

Alternatively, if the mixin should be model-agnostic, consider using self.model.objects.none() or raising an exception to fail fast on misconfiguration.

🤖 Prompt for AI Agents
In `@backend/donations/views/common/search.py` around lines 59 - 62, The code
calls queryset.none() when queryset may be None, causing AttributeError; update
the logic in the method that manipulates queryset so it never calls none() on a
None object — e.g., change the block that reads "if not queryset: if not
self.queryset: return queryset.none()" to return a safe empty queryset using
either self.queryset.none() (if self.queryset is set), or
self.model.objects.none() (for model-agnostic mixins), or raise a clear
configuration error; reference the variables queryset and self.queryset and the
surrounding method to implement one of these safe alternatives.

@danniel danniel merged commit ca3eef4 into main Feb 11, 2026
10 checks passed
@danniel danniel deleted the feature/improve-search-quality branch February 11, 2026 11:59
@coderabbitai coderabbitai bot mentioned this pull request Feb 11, 2026
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