Skip to content

Commit

Permalink
Add MatchPattern Method (#483)
Browse files Browse the repository at this point in the history
  • Loading branch information
kirollosonsi authored Oct 1, 2024
1 parent ef7135e commit 7aa7ab7
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ We'd love your contributions! If you want to contribute please read our [Contrib
* [@PrudiusVladislav](https://github.com/PrudiusVladislav)
* [@CormacLennon](https://github.com/CormacLennon)
* [@ahmedisam99](https://github.com/ahmedisam99)
* [@kirollosonsi](https://github.com/kirollosonsi)
<!-- Logo -->
[Logo]: images/logo.svg
Expand Down
8 changes: 8 additions & 0 deletions src/Redis.OM/Common/ExpressionParserUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ internal static string TranslateMethodExpressions(MethodCallExpression exp, List
"Contains" => TranslateContainsStandardQuerySyntax(exp, parameters),
nameof(StringExtension.FuzzyMatch) => TranslateFuzzyMatch(exp),
nameof(StringExtension.MatchContains) => TranslateMatchContains(exp),
nameof(StringExtension.MatchPattern) => TranslateMatchPattern(exp),
nameof(StringExtension.MatchStartsWith) => TranslateMatchStartsWith(exp),
nameof(StringExtension.MatchEndsWith) => TranslateMatchEndsWith(exp),
nameof(VectorExtensions.VectorRange) => TranslateVectorRange(exp, parameters),
Expand Down Expand Up @@ -784,6 +785,13 @@ private static string TranslateMatchContains(MethodCallExpression exp)
return $"({source}:*{infix}*)";
}

private static string TranslateMatchPattern(MethodCallExpression exp)
{
var source = GetOperandString(exp.Arguments[0]);
var pattern = GetOperandString(exp.Arguments[1]);
return $"({source}:{pattern})";
}

private static string TranslateFuzzyMatch(MethodCallExpression exp)
{
var source = GetOperandString(exp.Arguments[0]);
Expand Down
14 changes: 14 additions & 0 deletions src/Redis.OM/Extensions/StringExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ public static bool MatchContains(this string source, string infix)
return terms.Any(t => t.EndsWith(infix));
}

/// <summary>
/// Checks the source string to see if any tokens within the source matches the pattern.
/// </summary>
/// <param name="source">The string to check.</param>
/// <param name="pattern">The pattern to look for within the string.</param>
/// <returns>Whether any token within the source string matches the pattern.</returns>
/// <remarks>This is meant to be a shadow method that runs within an expression, a working implementation is
/// provided here for completeness.</remarks>
public static bool MatchPattern(this string source, string pattern)
{
var terms = source.Split(SplitChars);
return terms.Any(t => t.EndsWith(pattern));
}

/// <summary>
/// Wagner-Fischer dynamic programming string distance algorithm.
/// </summary>
Expand Down
25 changes: 25 additions & 0 deletions test/Redis.OM.Unit.Tests/RediSearchTests/SearchFunctionalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1245,5 +1245,30 @@ public void TestMultipleSearchAttributesOnEmbeddedDoc()
var res = collection.First(x => x.Address.City == "Long" && x.Address.State == "New");
Assert.Equal(obj.Id, res.Id);
}

[Theory]
[InlineData("Ste*", 1)]
[InlineData("*orello*", 1)]
[InlineData("Sto* & Lor*", 0)]
[InlineData("Sto* | Lor*", 1)]
[InlineData("%%Pittor%%", 1)]
[InlineData("%Pittor%", 0)]
[InlineData("%%%Pittor%%%", 1)]
[InlineData("%%Pittor%% & Ha*", 1)]
[InlineData("Ste* | Ha*", 2)]
public async Task TestSearchByMatchPattern(string pattern, int existingRecordsCount)
{
var collection = new RedisCollection<Person>(_connection);
var persons = await collection.ToListAsync();
await collection.DeleteAsync(persons);

var person1 = new Person { Name = "Steve Lorello" };
var person2 = new Person { Name = "Harry Potter" };
collection.Insert(person1);
collection.Insert(person2);

var res = await collection.Where(x => x.Name.MatchPattern(pattern)).ToListAsync();
Assert.Equal(existingRecordsCount, res.Count);
}
}
}
20 changes: 19 additions & 1 deletion test/Redis.OM.Unit.Tests/RediSearchTests/SearchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,25 @@ public void TestMatchContains()
"0",
"100");
}


[Fact]
public void TestMatchPattern()
{
_substitute.ClearSubstitute();
_substitute.Execute(Arg.Any<string>(), Arg.Any<object[]>()).Returns(_mockReply);

var collection = new RedisCollection<Person>(_substitute);
var ddfgdf = collection.Where(x => x.Name.MatchPattern("Ste* Lo*")).ToList();

_substitute.Received().Execute(
"FT.SEARCH",
"person-idx",
"(@Name:Ste* Lo*)",
"LIMIT",
"0",
"100");
}

[Fact]
public void TestTagContains()
{
Expand Down

0 comments on commit 7aa7ab7

Please sign in to comment.