diff --git a/src/AutoFilterer/Attributes/ToLowerEqualsComparisonAttribute.cs b/src/AutoFilterer/Attributes/ToLowerEqualsComparisonAttribute.cs
new file mode 100644
index 0000000..47e9005
--- /dev/null
+++ b/src/AutoFilterer/Attributes/ToLowerEqualsComparisonAttribute.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Text;
+
+namespace AutoFilterer.Attributes;
+
+///
+/// This class generates equal query, for string fields.
+///
+public class ToLowerEqualsComparisonAttribute : FilteringOptionsBaseAttribute
+{
+ public override Expression BuildExpression(ExpressionBuildContext context)
+ {
+ var equalsMethod = typeof(string).GetMethod(nameof(string.Equals), types: new[] { typeof(string) });
+
+ var toLowerMethod = typeof(string).GetMethod(nameof(string.ToLower), types: new Type[0]);
+
+ var comparison = Expression.Equal(
+ Expression.Call(
+ method: equalsMethod,
+ instance: Expression.Call(method: toLowerMethod, instance: Expression.Property(context.ExpressionBody, context.TargetProperty.Name)
+ ),
+ arguments: new[] { Expression.Call(method: toLowerMethod, instance: context.FilterPropertyExpression) }),
+ Expression.Constant(true));
+
+ return comparison;
+ }
+}
diff --git a/tests/AutoFilterer.Tests/Attributes/ToLowerEqualsComparisonAttributeTests.cs b/tests/AutoFilterer.Tests/Attributes/ToLowerEqualsComparisonAttributeTests.cs
new file mode 100644
index 0000000..f35d186
--- /dev/null
+++ b/tests/AutoFilterer.Tests/Attributes/ToLowerEqualsComparisonAttributeTests.cs
@@ -0,0 +1,208 @@
+using AutoFilterer.Extensions;
+using AutoFilterer.Tests.Core;
+using AutoFilterer.Tests.Environment.Dtos;
+using AutoFilterer.Tests.Environment.Models;
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+using AutoFilterer.Attributes;
+using AutoFilterer.Types;
+using System;
+
+namespace AutoFilterer.Tests.Attributes;
+
+public class ToLowerEqualsComparisonAttributeTests
+{
+ [Theory, AutoMoqData(count: 16)]
+ public void BuildExpression_ShouldGenerateQueryCorrect_WithAttribute(List dummyData)
+ {
+ // Arrange
+ var filter = new BookFilter_LowerEquals
+ {
+ Title = "Test Book"
+ };
+ IQueryable query = dummyData.AsQueryable();
+
+ // Act
+ var filteredQuery = query.ApplyFilter(filter);
+ var result = filteredQuery.ToList();
+
+ // Assert
+ var actualResult = query.Where(x => x.Title.ToLower().Equals(filter.Title.ToLower())).ToList();
+
+ Assert.Equal(result.Count, actualResult.Count);
+ }
+
+ [Theory, AutoMoqData(count: 16)]
+ public void BuildExpression_ShouldBeCaseInsensitive(List dummyData)
+ {
+ // Arrange
+ var filter = new BookFilter_LowerEquals
+ {
+ Title = "TEST BOOK"
+ };
+ IQueryable query = dummyData.AsQueryable();
+
+ // Act
+ var filteredQuery = query.ApplyFilter(filter);
+ var result = filteredQuery.ToList();
+
+ // Assert
+ var actualResult = query.Where(x => x.Title.ToLower().Equals(filter.Title.ToLower())).ToList();
+
+ Assert.Equal(result.Count, actualResult.Count);
+ }
+
+ [Theory, AutoMoqData(count: 16)]
+ public void BuildExpression_ShouldHandleEmptyString(List dummyData)
+ {
+ // Arrange
+ var filter = new BookFilter_LowerEquals
+ {
+ Title = ""
+ };
+ IQueryable query = dummyData.AsQueryable();
+
+ // Act
+ var filteredQuery = query.ApplyFilter(filter);
+ var result = filteredQuery.ToList();
+
+ // Assert
+ var actualResult = query.Where(x => x.Title.ToLower().Equals(filter.Title.ToLower())).ToList();
+
+ Assert.Equal(result.Count, actualResult.Count);
+ }
+
+ [Theory, AutoMoqData(count: 16)]
+ public void BuildExpression_ShouldHandleNullValue(List dummyData)
+ {
+ // Arrange
+ var filter = new BookFilter_LowerEquals
+ {
+ Title = null
+ };
+ IQueryable query = dummyData.AsQueryable();
+
+ // Act
+ var filteredQuery = query.ApplyFilter(filter);
+ var result = filteredQuery.ToList();
+
+ // Assert
+ // When filter value is null, the framework should skip the filter entirely
+ // and return all results (no filtering applied)
+ Assert.Equal(dummyData.Count, result.Count);
+ }
+
+ [Theory, AutoMoqData(count: 16)]
+ public void BuildExpression_ShouldHandleSpecialCharacters(List dummyData)
+ {
+ // Arrange
+ var filter = new BookFilter_LowerEquals
+ {
+ Title = "Test-Book_123"
+ };
+ IQueryable query = dummyData.AsQueryable();
+
+ // Act
+ var filteredQuery = query.ApplyFilter(filter);
+ var result = filteredQuery.ToList();
+
+ // Assert
+ var actualResult = query.Where(x => x.Title.ToLower().Equals(filter.Title.ToLower())).ToList();
+
+ Assert.Equal(result.Count, actualResult.Count);
+ }
+
+ [Theory, AutoMoqData(count: 16)]
+ public void BuildExpression_ShouldHandleWhitespace(List dummyData)
+ {
+ // Arrange
+ var filter = new BookFilter_LowerEquals
+ {
+ Title = " Test Book "
+ };
+ IQueryable query = dummyData.AsQueryable();
+
+ // Act
+ var filteredQuery = query.ApplyFilter(filter);
+ var result = filteredQuery.ToList();
+
+ // Assert
+ var actualResult = query.Where(x => x.Title.ToLower().Equals(filter.Title.ToLower())).ToList();
+
+ Assert.Equal(result.Count, actualResult.Count);
+ }
+
+ [Theory, AutoMoqData(count: 16)]
+ public void BuildExpression_ShouldHandleUnicodeCharacters(List dummyData)
+ {
+ // Arrange
+ var filter = new BookFilter_LowerEquals
+ {
+ Title = "Café Book"
+ };
+ IQueryable query = dummyData.AsQueryable();
+
+ // Act
+ var filteredQuery = query.ApplyFilter(filter);
+ var result = filteredQuery.ToList();
+
+ // Assert
+ var actualResult = query.Where(x => x.Title.ToLower().Equals(filter.Title.ToLower())).ToList();
+
+ Assert.Equal(result.Count, actualResult.Count);
+ }
+
+ [Theory, AutoMoqData(count: 16)]
+ public void BuildExpression_ShouldReturnEmptyResult_WhenNoMatch(List dummyData)
+ {
+ // Arrange
+ var filter = new BookFilter_LowerEquals
+ {
+ Title = "NonExistentBook"
+ };
+ IQueryable query = dummyData.AsQueryable();
+
+ // Act
+ var filteredQuery = query.ApplyFilter(filter);
+ var result = filteredQuery.ToList();
+
+ // Assert
+ var actualResult = query.Where(x => x.Title.ToLower().Equals(filter.Title.ToLower())).ToList();
+
+ Assert.Equal(result.Count, actualResult.Count);
+ Assert.Empty(result);
+ }
+
+ [Theory, AutoMoqData(count: 16)]
+ public void BuildExpression_ShouldReturnExactMatchesOnly(List dummyData)
+ {
+ // Arrange
+ var filter = new BookFilter_LowerEquals
+ {
+ Title = "Test"
+ };
+ IQueryable query = dummyData.AsQueryable();
+
+ // Act
+ var filteredQuery = query.ApplyFilter(filter);
+ var result = filteredQuery.ToList();
+
+ // Assert
+ var actualResult = query.Where(x => x.Title.ToLower().Equals(filter.Title.ToLower())).ToList();
+
+ Assert.Equal(result.Count, actualResult.Count);
+
+ // Verify that all results are exact matches (not partial matches)
+ foreach (var book in result)
+ {
+ Assert.Equal(filter.Title.ToLower(), book.Title.ToLower());
+ }
+ }
+}
+
+public class BookFilter_LowerEquals : FilterBase
+{
+ [ToLowerEqualsComparison]
+ public string Title { get; set; }
+}
\ No newline at end of file