diff --git a/Iceshrimp.Backend/Core/Extensions/QueryableFtsExtensions.cs b/Iceshrimp.Backend/Core/Extensions/QueryableFtsExtensions.cs index cc182af9..151d780e 100644 --- a/Iceshrimp.Backend/Core/Extensions/QueryableFtsExtensions.cs +++ b/Iceshrimp.Backend/Core/Extensions/QueryableFtsExtensions.cs @@ -271,37 +271,21 @@ public static class QueryableFtsExtensions Justification = "Projectable chain must have consistent visibility")] internal static bool FtsQueryPreEscaped( this Note note, string query, bool negated, CaseFilterType caseSensitivity, MatchFilterType matchType - ) => matchType.Equals(MatchFilterType.Substring) - ? caseSensitivity.Equals(CaseFilterType.Sensitive) - ? negated - ? !EF.Functions.Like(note.Text!, "%" + query + "%", @"\") - && !EF.Functions.Like(note.Cw!, "%" + query + "%", @"\") - && !EF.Functions.Like(note.CombinedAltText!, "%" + query + "%", @"\") - : EF.Functions.Like(note.Text!, "%" + query + "%", @"\") - || EF.Functions.Like(note.Cw!, "%" + query + "%", @"\") - || EF.Functions.Like(note.CombinedAltText!, "%" + query + "%", @"\") - : negated - ? !EF.Functions.ILike(note.Text!, "%" + query + "%", @"\") - && !EF.Functions.ILike(note.Cw!, "%" + query + "%", @"\") - && !EF.Functions.ILike(note.CombinedAltText!, "%" + query + "%", @"\") - : EF.Functions.ILike(note.Text!, "%" + query + "%", @"\") - || EF.Functions.ILike(note.Cw!, "%" + query + "%", @"\") - || EF.Functions.ILike(note.CombinedAltText!, "%" + query + "%", @"\") - : caseSensitivity.Equals(CaseFilterType.Sensitive) - ? negated - ? !Regex.IsMatch(note.Text!, "\\y" + query + "\\y") - && !Regex.IsMatch(note.Cw!, "\\y" + query + "\\y") - && !Regex.IsMatch(note.CombinedAltText!, "\\y" + query + "\\y") - : Regex.IsMatch(note.Text!, "\\y" + query + "\\y") - || Regex.IsMatch(note.Cw!, "\\y" + query + "\\y") - || Regex.IsMatch(note.CombinedAltText!, "\\y" + query + "\\y") - : negated - ? !Regex.IsMatch(note.Text!, "\\y" + query + "\\y", RegexOptions.IgnoreCase) - && !Regex.IsMatch(note.Cw!, "\\y" + query + "\\y", RegexOptions.IgnoreCase) - && !Regex.IsMatch(note.CombinedAltText!, "\\y" + query + "\\y", RegexOptions.IgnoreCase) - : Regex.IsMatch(note.Text!, "\\y" + query + "\\y", RegexOptions.IgnoreCase) - || Regex.IsMatch(note.Cw!, "\\y" + query + "\\y", RegexOptions.IgnoreCase) - || Regex.IsMatch(note.CombinedAltText!, "\\y" + query + "\\y", RegexOptions.IgnoreCase); + ) => negated + ? matchType.Equals(MatchFilterType.Substring) + ? FtsQueryMatchSubstringPreEscaped(note.Text, query, negated, caseSensitivity) + && FtsQueryMatchSubstringPreEscaped(note.Cw, query, negated, caseSensitivity) + && FtsQueryMatchSubstringPreEscaped(note.CombinedAltText, query, negated, caseSensitivity) + : FtsQueryMatchWordPreEscaped(note.Text, query, negated, caseSensitivity) + && FtsQueryMatchWordPreEscaped(note.Cw, query, negated, caseSensitivity) + && FtsQueryMatchWordPreEscaped(note.CombinedAltText, query, negated, caseSensitivity) + : matchType.Equals(MatchFilterType.Substring) + ? FtsQueryMatchSubstringPreEscaped(note.Text, query, negated, caseSensitivity) + || FtsQueryMatchSubstringPreEscaped(note.Cw, query, negated, caseSensitivity) + || FtsQueryMatchSubstringPreEscaped(note.CombinedAltText, query, negated, caseSensitivity) + : FtsQueryMatchWordPreEscaped(note.Text, query, negated, caseSensitivity) + || FtsQueryMatchWordPreEscaped(note.Cw, query, negated, caseSensitivity) + || FtsQueryMatchWordPreEscaped(note.CombinedAltText, query, negated, caseSensitivity); [Projectable] [SuppressMessage("ReSharper", "MemberCanBePrivate.Global", @@ -337,4 +321,30 @@ public static class QueryableFtsExtensions this Note note, IEnumerable words, CaseFilterType caseSensitivity, MatchFilterType matchType ) => words.Select(p => PreEscapeFtsQuery(p, matchType)) .Any(p => note.FtsQueryPreEscaped(p, false, caseSensitivity, matchType)); + + [Projectable] + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global", + Justification = "Projectable chain must have consistent visibility")] + internal static bool FtsQueryMatchSubstringPreEscaped( + string? match, string query, bool negated, CaseFilterType caseSensitivity + ) => caseSensitivity.Equals(CaseFilterType.Sensitive) + ? negated + ? !EF.Functions.Like(match!, "%" + query + "%", @"\") + : EF.Functions.Like(match!, "%" + query + "%", @"\") + : negated + ? !EF.Functions.ILike(match!, "%" + query + "%", @"\") + : EF.Functions.ILike(match!, "%" + query + "%", @"\"); + + [Projectable] + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global", + Justification = "Projectable chain must have consistent visibility")] + internal static bool FtsQueryMatchWordPreEscaped( + string? match, string query, bool negated, CaseFilterType caseSensitivity + ) => caseSensitivity.Equals(CaseFilterType.Sensitive) + ? negated + ? match == null || !Regex.IsMatch(match, "\\y" + query + "\\y") + : match != null && Regex.IsMatch(match, "\\y" + query + "\\y") + : negated + ? match == null || !Regex.IsMatch(match, "\\y" + query + "\\y", RegexOptions.IgnoreCase) + : match != null && Regex.IsMatch(match, "\\y" + query + "\\y", RegexOptions.IgnoreCase); }