Skip to content

Commit 04bdf0f

Browse files
authored
Fix InMemory SearchExtension bug (#391)
* Fixed bug for in-memory LIKE impementation. * Cleanup.
1 parent 8d297e5 commit 04bdf0f

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

Specification/src/Ardalis.Specification/Evaluators/SearchExtension.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Text.RegularExpressions;
34

45
namespace Ardalis.Specification;
56

@@ -11,16 +12,34 @@ public static bool Like(this string input, string pattern)
1112
{
1213
return SqlLike(input, pattern);
1314
}
14-
catch (Exception)
15+
catch (Exception ex)
1516
{
16-
throw new InvalidSearchPatternException(pattern);
17+
throw new InvalidSearchPatternException(pattern, ex);
1718
}
1819
}
1920

21+
private static bool SqlLike(this string input, string pattern)
22+
{
23+
// Escape special regex characters, excluding those handled separately
24+
var regexPattern = Regex.Escape(pattern)
25+
.Replace("%", ".*") // Translate SQL LIKE wildcard '%' to regex '.*'
26+
.Replace("_", ".") // Translate SQL LIKE wildcard '_' to regex '.'
27+
.Replace(@"\[", "[") // Unescape '[' as it's used for character classes/ranges
28+
.Replace(@"\^", "^"); // Unescape '^' as it can be used for negation in character classes
29+
30+
// Ensure the pattern matches the entire string
31+
regexPattern = "^" + regexPattern + "$";
32+
var regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
33+
34+
return regex.IsMatch(input);
35+
}
36+
2037
// This C# implementation of SQL Like operator is based on the following SO post https://stackoverflow.com/a/8583383/10577116
2138
// It covers almost all of the scenarios, and it's faster than regex based implementations.
2239
// It may fail/throw in some very specific and edge cases, hence, wrap it in try/catch.
23-
private static bool SqlLike(string str, string pattern)
40+
// UPDATE: it returns incorrect results for some obvious cases.
41+
// More details in this issue https://github.com/ardalis/Specification/issues/390
42+
private static bool SqlLikeOption2(string str, string pattern)
2443
{
2544
var isMatch = true;
2645
var isWildCardOn = false;

Specification/tests/Ardalis.Specification.UnitTests/EvaluatorTests/SearchExtension_Like.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ public class SearchExtension_Like
7272
[InlineData(false, "_Stuff_.txt_", "1Stuff.txt4")]
7373
[InlineData(false, "_Stuff_.txt_", "1Stuff3.txt")]
7474
[InlineData(false, "_Stuff_.txt_", "Stuff3.txt4")]
75+
[InlineData(true, "%ab%", "ab")]
76+
[InlineData(true, "%ab%", "abb")]
77+
[InlineData(true, "%ab%", "aaab")]
78+
[InlineData(true, "%ab%", "aaaab")]
79+
[InlineData(true, "%ab%", "aaaaab")]
80+
[InlineData(true, "%ab%", "aab")]
7581
public void ReturnsExpectedResult_GivenPatternAndInput(bool expectedResult, string pattern, string input)
7682
{
7783
var result = input.Like(pattern);

0 commit comments

Comments
 (0)