Skip to content

Support 'Match...' of string and IEnumerable<string>#551

Merged
slorello89 merged 4 commits into
redis:mainfrom
SMAH1:SearchStringArray
Jun 8, 2026
Merged

Support 'Match...' of string and IEnumerable<string>#551
slorello89 merged 4 commits into
redis:mainfrom
SMAH1:SearchStringArray

Conversation

@SMAH1

@SMAH1 SMAH1 commented Oct 25, 2025

Copy link
Copy Markdown
Contributor

Add

MatchStartsWith
MatchEndsWith
MatchContains
MatchPattern

for support IEnumerable<string>.


Note

Medium Risk
Changes query translation for Match* methods and fixes prior incorrect Contains/Pattern shadow behavior, which can alter search results for tag fields and in-memory eval paths; risk is mitigated by broad new tests.

Overview
Extends MatchStartsWith, MatchEndsWith, MatchContains, and MatchPattern so they work on IEnumerable<string> (tag-indexed fields like NickNames) in LINQ queries, not only on full-text string fields.

Expression translation (ExpressionParserUtilities) now branches on the receiver type: text fields keep the existing wildcard query shape; tag fields emit RediSearch tag syntax ({...}) with EscapeTagField on literals while preserving wildcards, including a case for hyphenated tags (e.g. Spider-Man).

In-process “shadow” implementations (StringExtension) add matching IEnumerable<string> overloads, fix MatchContains / MatchPattern on string (they incorrectly used EndsWith), use case-insensitive token checks, and implement MatchPattern via a WildcardToRegex helper aligned with Redis wildcard rules.

Coverage adds unit tests that assert generated FT.SEARCH query strings (including tag escaping) and functional Redis tests for text and tag Match* predicates.

Reviewed by Cursor Bugbot for commit 69fc325. Bugbot is set up for automated code reviews on this repo. Configure here.

SMAH1 and others added 3 commits October 25, 2025 09:56
- Fix two unit tests that asserted nothing: TestMatchStartsWithOfString and
  TestMatchStartsWithOfStringArray called _substitute.Execute(...) instead of
  _substitute.Received().Execute(...), so the generated query was never verified.
- Remove leftover junk (the `ddfgdf` locals) and dead trailing lines in the
  Match* substitute tests.
- Add functional (real-Redis) tests for the string overloads of MatchStartsWith,
  MatchEndsWith, and MatchContains (previously only MatchPattern had functional
  coverage), and for all four IEnumerable<string>/tag overloads, exercising the
  brace tag-query syntax end-to-end. The shared seed helper clears people first
  and each test clears again in a finally block so it stays order-independent and
  does not pollute the shared Person collection used by other tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 0ea08df. Configure here.

Comment thread src/Redis.OM/Common/ExpressionParserUtilities.cs Outdated
Per Cursor Bugbot: the tag-field paths of TranslateMatchStartsWith,
TranslateMatchEndsWith, and TranslateMatchContains emitted the prefix/suffix/
infix literal raw, unlike peer translators (TranslateStartsWith/EndsWith, tag
Contains) which wrap the literal in EscapeTagField. Special characters in the
search term (e.g. '-', '@', spaces) could therefore produce malformed or
unintended tag queries on indexed string-array fields like NickNames.

Wrap the literal with EscapeTagField in those three tag paths while keeping the
wildcard operators outside the escaped portion. MatchPattern is intentionally
left raw since its argument is a user-supplied wildcard pattern.

Add unit tests asserting the escaped query output and a functional test proving
a hyphenated tag value ("Spider-Man") matches end-to-end. Also make the new
functional Match* tests non-destructive: they insert uniquely-named records and
delete only those in a finally block, so they don't disturb the shared Person
collection other tests rely on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@slorello89 slorello89 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM 👍

@slorello89 slorello89 merged commit 4bac966 into redis:main Jun 8, 2026
3 checks passed
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.

2 participants