Skip to content

Commit a4bdc22

Browse files
committed
fix: number handling
fixes: #46
1 parent 512f148 commit a4bdc22

2 files changed

Lines changed: 132 additions & 10 deletions

File tree

QueryKit.IntegrationTests/Tests/DatabaseFilteringTests.cs

Lines changed: 122 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,64 @@ public async Task can_filter_by_combo_complex()
123123
people[0].Id.Should().Be(fakePersonOne.Id);
124124
}
125125

126+
[Theory]
127+
[InlineData(88448)]
128+
[InlineData(-83388)]
129+
public async Task can_filter_by_int(int age)
130+
{
131+
// Arrange
132+
var testingServiceScope = new TestingServiceScope();
133+
var fakePersonOne = new FakeTestingPersonBuilder()
134+
.WithAge(age)
135+
.Build();
136+
var fakePersonTwo = new FakeTestingPersonBuilder()
137+
.WithFirstName(fakePersonOne.FirstName)
138+
.Build();
139+
await testingServiceScope.InsertAsync(fakePersonOne, fakePersonTwo);
140+
141+
var input = $"""age == {fakePersonOne.Age}""";
142+
var config = new QueryKitConfiguration(_ =>
143+
{
144+
});
145+
146+
// Act
147+
var queryablePeople = testingServiceScope.DbContext().People;
148+
var appliedQueryable = queryablePeople.ApplyQueryKitFilter(input, config);
149+
var people = await appliedQueryable.ToListAsync();
150+
151+
// Assert
152+
people.Count.Should().Be(1);
153+
people[0].Id.Should().Be(fakePersonOne.Id);
154+
}
155+
156+
[Fact]
157+
public async Task can_filter_by_and_also_bool()
158+
{
159+
// Arrange
160+
var testingServiceScope = new TestingServiceScope();
161+
var fakePersonOne = new FakeTestingPersonBuilder()
162+
.WithFirstName("John")
163+
.WithAge(18)
164+
.Build();
165+
var fakePersonTwo = new FakeTestingPersonBuilder().Build();
166+
await testingServiceScope.InsertAsync(fakePersonOne, fakePersonTwo);
167+
168+
var input = $"""adult_johns == true""";
169+
var config = new QueryKitConfiguration(config =>
170+
{
171+
config.DerivedProperty<TestingPerson>(tp => tp.Age >= 18 && tp.FirstName == "John").HasQueryName("adult_johns");
172+
});
173+
174+
// Act
175+
var queryablePeople = testingServiceScope.DbContext().People;
176+
var appliedQueryable = queryablePeople.ApplyQueryKitFilter(input, config);
177+
var people = await appliedQueryable.ToListAsync();
178+
179+
// Assert
180+
people.Count.Should().Be(1);
181+
people[0].Id.Should().Be(fakePersonOne.Id);
182+
}
183+
126184
[Fact]
127185
public async Task can_filter_by_combo()
128186
{
@@ -691,7 +749,7 @@ public async Task can_filter_nested_property_using_ownsone_with_alias()
691749
.WithPhysicalAddress(new Address(faker.Address.StreetAddress()
692750
, faker.Address.SecondaryAddress()
693751
, faker.Address.City()
694-
, faker.Address.State()
752+
, Guid.NewGuid().ToString()
695753
, faker.Address.ZipCode()
696754
, faker.Address.Country()))
697755
.Build();
@@ -735,6 +793,31 @@ public async Task can_filter_by_decimal()
735793
people.Count(x => x.Id == fakePersonOne.Id).Should().Be(1);
736794
}
737795

796+
[Fact]
797+
public async Task can_filter_by_negative_decimal()
798+
{
799+
// Arrange
800+
var testingServiceScope = new TestingServiceScope();
801+
var faker = new Faker();
802+
var fakePersonOne = new FakeTestingPersonBuilder()
803+
.WithRating(-3.533M)
804+
.Build();
805+
var fakePersonTwo = new FakeTestingPersonBuilder()
806+
.WithRating(2M)
807+
.Build();
808+
await testingServiceScope.InsertAsync(fakePersonOne, fakePersonTwo);
809+
810+
var input = $"""{nameof(TestingPerson.Rating)} == -3.533""";
811+
812+
// Act
813+
var queryablePeople = testingServiceScope.DbContext().People;
814+
var appliedQueryable = queryablePeople.ApplyQueryKitFilter(input);
815+
var people = await appliedQueryable.ToListAsync();
816+
817+
// Assert
818+
people.Count(x => x.Id == fakePersonOne.Id).Should().Be(1);
819+
}
820+
738821
[Fact]
739822
public async Task can_filter_complex_expression()
740823
{
@@ -801,24 +884,58 @@ public async Task can_handle_in_for_int()
801884
// Arrange
802885
var testingServiceScope = new TestingServiceScope();
803886
var fakePersonOne = new FakeTestingPersonBuilder()
804-
.WithAge(22)
887+
.WithAge(-22)
805888
.Build();
806889
var fakePersonTwo = new FakeTestingPersonBuilder()
890+
.WithAge(40)
891+
.Build();
892+
var fakePersonThree = new FakeTestingPersonBuilder()
807893
.WithAge(60)
808894
.Build();
809-
await testingServiceScope.InsertAsync(fakePersonOne, fakePersonTwo);
895+
await testingServiceScope.InsertAsync(fakePersonOne, fakePersonTwo, fakePersonThree);
810896

811-
var input = """Age ^^ [22, 30, 40]""";
897+
var input = """Age ^^ [-22, 60]""";
812898

813899
// Act
814900
var queryablePeople = testingServiceScope.DbContext().People;
815901
var appliedQueryable = queryablePeople.ApplyQueryKitFilter(input);
816902
var people = await appliedQueryable.ToListAsync();
817903

818904
// Assert
819-
people.Count.Should().BeGreaterOrEqualTo(1);
905+
people.Count.Should().BeGreaterOrEqualTo(2);
906+
people.FirstOrDefault(x => x.Id == fakePersonOne.Id).Should().NotBeNull();
907+
people.FirstOrDefault(x => x.Id == fakePersonTwo.Id).Should().BeNull();
908+
people.FirstOrDefault(x => x.Id == fakePersonThree.Id).Should().NotBeNull();
909+
}
910+
911+
[Fact]
912+
public async Task can_handle_in_for_decimal()
913+
{
914+
// Arrange
915+
var testingServiceScope = new TestingServiceScope();
916+
var fakePersonOne = new FakeTestingPersonBuilder()
917+
.WithRating(-22.44M)
918+
.Build();
919+
var fakePersonTwo = new FakeTestingPersonBuilder()
920+
.WithRating(40.55M)
921+
.Build();
922+
var fakePersonThree = new FakeTestingPersonBuilder()
923+
.WithRating(60.99M)
924+
.Build();
925+
await testingServiceScope.InsertAsync(fakePersonOne, fakePersonTwo, fakePersonThree);
926+
927+
var input = """Rating ^^ [-22.44, 60.99]""";
928+
929+
// Act
930+
var queryablePeople = testingServiceScope.DbContext().People;
931+
var appliedQueryable = queryablePeople.ApplyQueryKitFilter(input);
932+
var people = await appliedQueryable.ToListAsync();
933+
934+
// Assert
935+
people.Count.Should().BeGreaterOrEqualTo(2);
820936
people.FirstOrDefault(x => x.Id == fakePersonOne.Id).Should().NotBeNull();
821937
people.FirstOrDefault(x => x.Id == fakePersonTwo.Id).Should().BeNull();
938+
people.FirstOrDefault(x => x.Id == fakePersonThree.Id).Should().NotBeNull();
822939
}
823940

824941
[Fact]

QueryKit/FilterParser.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ from timeZone in Parse.Regex(@"Z|[+-]\d{2}(:\d{2})?").Text().Optional().Select(x
114114
from micros in Parse.Regex(@"\.\d{1,6}").Text().Optional().Select(x => x.GetOrElse(""))
115115
select dateFormat + timeFormat + micros + timeZone;
116116

117+
private static Parser<string> NumberParser =>
118+
from sign in Parse.Char('-').Optional().Select(x => x.IsDefined ? "-" : "")
119+
from number in Parse.Decimal
120+
select sign + number;
117121

118122
private static Parser<string> GuidFormatParser => Parse.Regex(@"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}").Text();
119123

@@ -132,20 +136,21 @@ from value in Parse.String("null").Text()
132136
.XOr(Identifier)
133137
.XOr(DateTimeFormatParser)
134138
.XOr(TimeFormatParser)
135-
.XOr(Parse.Decimal)
136-
.XOr(Parse.Number)
139+
.XOr(NumberParser)
137140
.XOr(RawStringLiteralParser.Or(DoubleQuoteParser))
138141
.XOr(SquareBracketParser)
139142
from trailingSpaces in Parse.WhiteSpace.Many()
140143
select atSign.IsDefined ? "@" + value : value;
141144

142145
private static Parser<string> SquareBracketParser =>
143146
from openingBracket in Parse.Char('[')
144-
from content in DoubleQuoteParser
147+
from content in Parse.String("null").Text()
145148
.Or(GuidFormatParser)
146-
.Or(Parse.Decimal)
147-
.Or(Parse.Number)
148149
.Or(Identifier)
150+
.Or(DateTimeFormatParser)
151+
.Or(TimeFormatParser)
152+
.Or(NumberParser)
153+
.Or(RawStringLiteralParser.Or(DoubleQuoteParser))
149154
.DelimitedBy(Parse.Char(',').Token())
150155
from closingBracket in Parse.Char(']')
151156
select "[" + string.Join(",", content) + "]";

0 commit comments

Comments
 (0)