Use contains operator for text field search filters#86598
Use contains operator for text field search filters#86598wildan-m wants to merge 10 commits intoExpensify:mainfrom
Conversation
The search parser maps : to the eq (exact match) operator for all fields, which means merchant:coffee only finds expenses with the exact merchant "coffee" and not "Coffee shop". Text fields like merchant and description should use partial/substring matching. Add applyContainsOperatorToTextFields() which transforms the AST before sending to the backend, converting eq to contains for free-text fields. This enables partial matching while preserving the user-facing : syntax. Fixes Expensify#86235
…-text-field-contains
8625d87 to
4d232c1
Compare
…patibility" This reverts commit fb2ed75.
|
@ikevin127 Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 58328d5bf1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppscreen-20260328-165331.mp4Android: mWeb Chromescreen-20260328-165455.mp4iOS: HybridAppSimulator.Screen.Recording.-.iPhone.17.Pro.Max.-.2026-03-28.at.16.35.43.moviOS: mWeb SafariSimulator.Screen.Recording.-.iPhone.17.Pro.Max.-.2026-03-28.at.16.42.36.movMacOS: Chrome / SafariScreen.Recording.2026-03-28.at.16.51.41.mov |
ikevin127
left a comment
There was a problem hiding this comment.
The implementation is solid, well-tested, and follows best practices - safe to merge.
Status: ✅ Approved
🔥 Edge Cases / Destructive Tests
- Unicode/Emoji in text fields - Test international characters in merchant/description ✅ (tested w/ Sanskrit)
- Very long text values - Test with 1000+ character merchant names
- Special characters - Merchants containing
:,-,$, etc ✅ - savedSearch vs regular search - Ensure saved searches preserve original operators ✅
- Concurrent rapid searches - Rapid typing with text filters should not corrupt state ✅
- Backend error recovery - Network failure should preserve query integrity ✅
Explanation of Change
When searching
merchant:coffee, the search parser maps:to theeq(exact match) operator for all fields uniformly. Text fields likemerchantanddescriptionneed thecontains(substring) operator so thatmerchant:coffeematches "Coffee shop", "My coffee", etc.The
search()function inSearch.tspassed the AST filters unchanged to the backend, so thecontainsoperator that already existed inCONST.SEARCH.SYNTAX_OPERATORSwas never used.Fix: added
applyContainsOperatorToTextFields()inSearchQueryUtils.tsthat recursively traverses the AST and replaceseqwithcontainsfor free-text filter fields (merchant,description). It is called insearch()before the query is sent to the backend. The transformation happens at the query construction layer — no parser grammar changes needed, existing parser tests are unaffected, and adding future text fields is a one-line Set addition.Fixed Issues
$ #86235
PROPOSAL: #86235 (comment)
Tests
Coffee Shop Downtownand descriptionLunch with clientmerchant:coffeein the search bardescription:lunchin the search baramount,date, andcurrencystill perform exact matching (unaffected)Offline tests
This change only affects API query construction — offline behavior is unchanged.
Coffee Shop Downtownand descriptionLunch with clientmerchant:coffeein the search bardescription:lunchin the search barQA Steps
Coffee Shop Downtownand descriptionLunch with clientmerchant:coffeein the search bardescription:lunchin the search barPR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Kapture.2026-03-29.at.03.04.55.mp4
Android: mWeb Chrome
Kapture.2026-03-29.at.03.08.27.mp4
iOS: Native
Kapture.2026-03-29.at.02.12.16.mp4
iOS: mWeb Safari
Kapture.2026-03-29.at.02.48.33.mp4
MacOS: Chrome / Safari
Kapture.2026-03-29.at.02.06.09.mp4