Skip to content

Commit e9cf2b5

Browse files
committed
added lte, gt & gte
1 parent 91dc46a commit e9cf2b5

File tree

7 files changed

+78
-3
lines changed

7 files changed

+78
-3
lines changed

src/GoatQuery/src/Evaluator/FilterEvaluator.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ public static Result<Expression> Evaluate(QueryExpression expression, ParameterE
5656
return Expression.Call(property, method, value);
5757
case Keywords.Lt:
5858
return Expression.LessThan(property, value);
59+
case Keywords.Lte:
60+
return Expression.LessThanOrEqual(property, value);
61+
case Keywords.Gt:
62+
return Expression.GreaterThan(property, value);
63+
case Keywords.Gte:
64+
return Expression.GreaterThanOrEqual(property, value);
5965
default:
6066
return Result.Fail($"Unsupported operator: {exp.Operator}");
6167
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using System.Linq;
3+
4+
public static class StringExtension
5+
{
6+
public static bool In(this string str, params string[] strings)
7+
{
8+
return strings.Contains(str, StringComparer.OrdinalIgnoreCase);
9+
}
10+
}

src/GoatQuery/src/Parser/Parser.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ private Result<InfixExpression> ParseFilterStatement()
130130
{
131131
var identifier = new Identifier(_currentToken, _currentToken.Literal);
132132

133-
if (!PeekIdentifierIn(Keywords.Eq, Keywords.Ne, Keywords.Contains, Keywords.Lt))
133+
if (!PeekIdentifierIn(Keywords.Eq, Keywords.Ne, Keywords.Contains, Keywords.Lt, Keywords.Lte, Keywords.Gt, Keywords.Gte))
134134
{
135135
return Result.Fail("Invalid conjunction within filter");
136136
}
@@ -151,9 +151,9 @@ private Result<InfixExpression> ParseFilterStatement()
151151
return Result.Fail("Value must be a string when using 'contains' operand");
152152
}
153153

154-
if (statement.Operator.Equals(Keywords.Lt) && _currentToken.Type != TokenType.INT)
154+
if (statement.Operator.In(Keywords.Lt, Keywords.Lte, Keywords.Gt, Keywords.Gte) && _currentToken.Type != TokenType.INT)
155155
{
156-
return Result.Fail("Value must be an integer when using 'lt' operand");
156+
return Result.Fail($"Value must be an integer when using '{statement.Operator}' operand");
157157
}
158158

159159
switch (_currentToken.Type)

src/GoatQuery/src/Token/Token.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ public static class Keywords
1818
internal const string Ne = "ne";
1919
internal const string Contains = "contains";
2020
internal const string Lt = "lt";
21+
internal const string Lte = "lte";
22+
internal const string Gt = "gt";
23+
internal const string Gte = "gte";
2124
internal const string And = "and";
2225
internal const string Or = "or";
2326
}

src/GoatQuery/tests/Filter/FilterLexerTest.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,39 @@ public static IEnumerable<object[]> Parameters()
191191
new (TokenType.INT, "50"),
192192
}
193193
};
194+
195+
yield return new object[]
196+
{
197+
"age lte 50",
198+
new KeyValuePair<TokenType, string>[]
199+
{
200+
new (TokenType.IDENT, "age"),
201+
new (TokenType.IDENT, "lte"),
202+
new (TokenType.INT, "50"),
203+
}
204+
};
205+
206+
yield return new object[]
207+
{
208+
"age gt 50",
209+
new KeyValuePair<TokenType, string>[]
210+
{
211+
new (TokenType.IDENT, "age"),
212+
new (TokenType.IDENT, "gt"),
213+
new (TokenType.INT, "50"),
214+
}
215+
};
216+
217+
yield return new object[]
218+
{
219+
"age gte 50",
220+
new KeyValuePair<TokenType, string>[]
221+
{
222+
new (TokenType.IDENT, "age"),
223+
new (TokenType.IDENT, "gte"),
224+
new (TokenType.INT, "50"),
225+
}
226+
};
194227
}
195228

196229
[Theory]

src/GoatQuery/tests/Filter/FilterParserTest.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ public sealed class FilterParserTest
1010
[InlineData("Name contains 'John'", "Name", "contains", "John")]
1111
[InlineData("Id eq e4c7772b-8947-4e46-98ed-644b417d2a08", "Id", "eq", "e4c7772b-8947-4e46-98ed-644b417d2a08")]
1212
[InlineData("Age lt 99", "Age", "lt", "99")]
13+
[InlineData("Age lte 99", "Age", "lte", "99")]
14+
[InlineData("Age gt 99", "Age", "gt", "99")]
15+
[InlineData("Age gte 99", "Age", "gte", "99")]
1316
public void Test_ParsingFilterStatement(string input, string expectedLeft, string expectedOperator, string expectedRight)
1417
{
1518
var lexer = new QueryLexer(input);

src/GoatQuery/tests/Filter/FilterTest.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,26 @@ public static IEnumerable<object[]> Parameters()
113113
"age lt 1",
114114
Array.Empty<User>()
115115
};
116+
117+
yield return new object[] {
118+
"age lte 2",
119+
new[] { _users["John"], _users["Jane"], _users["Apple"], _users["Harry"] }
120+
};
121+
122+
yield return new object[] {
123+
"age gt 1",
124+
new[] { _users["John"], _users["Apple"], _users["Doe"], _users["Egg"] }
125+
};
126+
127+
yield return new object[] {
128+
"age gte 3",
129+
new[] { _users["Doe"], _users["Egg"] }
130+
};
131+
132+
yield return new object[] {
133+
"age lt 3 and age gt 1",
134+
new[] { _users["John"], _users["Apple"] }
135+
};
116136
}
117137

118138
[Theory]

0 commit comments

Comments
 (0)