Skip to content

Commit 929dd4b

Browse files
authored
Add enumeration support to the odata language (#7)
Also provide a few helper methods for enum conversions usable by other languages
1 parent 378128e commit 929dd4b

File tree

8 files changed

+474
-63
lines changed

8 files changed

+474
-63
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace StringToExpression.Exceptions
6+
{
7+
/// <summary>
8+
/// Exception when a string can not be parsed as an enumeration
9+
/// </summary>
10+
public class EnumParseException : Exception
11+
{
12+
/// <summary>
13+
/// The string that was attempted to be parsed.
14+
/// </summary>
15+
public readonly string StringValue;
16+
17+
/// <summary>
18+
/// The enumeration that the string was attempted to be parsed as.
19+
/// </summary>
20+
public readonly Type EnumType;
21+
22+
public EnumParseException(string stringValue, Type enumType, Exception ex)
23+
: base($"'{stringValue}' is not a valid value for enum type '{enumType}'", ex)
24+
{
25+
StringValue = stringValue;
26+
EnumType = enumType;
27+
}
28+
}
29+
}

src/StringToExpression/Languages/ODataFilterLanguage.cs

+95-14
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,73 @@ namespace StringToExpression.LanguageDefinitions
1616
/// </summary>
1717
public class ODataFilterLanguage
1818
{
19+
/// <summary>
20+
/// Access to common String Members
21+
/// </summary>
22+
protected static class StringMembers
23+
{
24+
/// <summary>
25+
/// The MethodInfo for the StartsWith method
26+
/// </summary>
27+
public static MethodInfo StartsWith = Type<string>.Method(x => x.StartsWith(default(string)));
28+
29+
/// <summary>
30+
/// The MethodInfo for the EndsWith method
31+
/// </summary>
32+
public static MethodInfo EndsWith = Type<string>.Method(x => x.EndsWith(default(string)));
33+
34+
/// <summary>
35+
/// The MethodInfo for the Contains method
36+
/// </summary>
37+
public static MethodInfo Contains = Type<string>.Method(x => x.Contains(default(string)));
38+
39+
/// <summary>
40+
/// The MethodInfo for the ToLower method
41+
/// </summary>
42+
public static MethodInfo ToLower = Type<string>.Method(x => x.ToLower());
43+
44+
/// <summary>
45+
/// The MethodInfo for the ToUpper method
46+
/// </summary>
47+
public static MethodInfo ToUpper = Type<string>.Method(x => x.ToUpper());
48+
}
49+
50+
/// <summary>
51+
/// Access to common DateTime Members
52+
/// </summary>
53+
protected static class DateTimeMembers
54+
{
55+
/// <summary>
56+
/// The MemberInfo for the Year property
57+
/// </summary>
58+
public static MemberInfo Year = Type<DateTime>.Member(x => x.Year);
59+
60+
/// <summary>
61+
/// The MemberInfo for the Month property
62+
/// </summary>
63+
public static MemberInfo Month = Type<DateTime>.Member(x => x.Month);
64+
65+
/// <summary>
66+
/// The MemberInfo for the Day property
67+
/// </summary>
68+
public static MemberInfo Day = Type<DateTime>.Member(x => x.Day);
69+
70+
/// <summary>
71+
/// The MemberInfo for the Hour property
72+
/// </summary>
73+
public static MemberInfo Hour = Type<DateTime>.Member(x => x.Hour);
74+
75+
/// <summary>
76+
/// The MemberInfo for the Minute property
77+
/// </summary>
78+
public static MemberInfo Minute = Type<DateTime>.Member(x => x.Minute);
79+
80+
/// <summary>
81+
/// The MemberInfo for the Second property
82+
/// </summary>
83+
public static MemberInfo Second = Type<DateTime>.Member(x => x.Second);
84+
}
85+
1986
private readonly Language language;
2087

2188
/// <summary>
@@ -144,12 +211,12 @@ protected virtual IEnumerable<GrammerDefinition> LogicalOperatorDefinitions()
144211
name:"EQ",
145212
regex: @"eq",
146213
orderOfPrecedence:11,
147-
expressionBuilder: (left,right) => Expression.Equal(left, right)),
214+
expressionBuilder: ConvertEnumsIfRequired((left,right) => Expression.Equal(left, right))),
148215
new BinaryOperatorDefinition(
149216
name:"NE",
150217
regex: @"ne",
151218
orderOfPrecedence:12,
152-
expressionBuilder: (left,right) => Expression.NotEqual(left, right)),
219+
expressionBuilder: ConvertEnumsIfRequired((left,right) => Expression.NotEqual(left, right))),
153220

154221
new BinaryOperatorDefinition(
155222
name:"GT",
@@ -271,7 +338,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
271338
expressionBuilder: (parameters) => {
272339
return Expression.Call(
273340
instance:parameters[0],
274-
method:Type<string>.Method(x=>x.StartsWith(null)),
341+
method:StringMembers.StartsWith,
275342
arguments: new [] { parameters[1] });
276343
}),
277344
new FunctionCallDefinition(
@@ -281,7 +348,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
281348
expressionBuilder: (parameters) => {
282349
return Expression.Call(
283350
instance:parameters[0],
284-
method:Type<string>.Method(x=>x.EndsWith(null)),
351+
method:StringMembers.EndsWith,
285352
arguments: new [] { parameters[1] });
286353
}),
287354
new FunctionCallDefinition(
@@ -291,7 +358,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
291358
expressionBuilder: (parameters) => {
292359
return Expression.Call(
293360
instance:parameters[1],
294-
method:Type<string>.Method(x=>x.Contains(null)),
361+
method:StringMembers.Contains,
295362
arguments: new [] { parameters[0] });
296363
}),
297364
new FunctionCallDefinition(
@@ -301,7 +368,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
301368
expressionBuilder: (parameters) => {
302369
return Expression.Call(
303370
instance:parameters[0],
304-
method:Type<string>.Method(x=>x.ToLower()));
371+
method:StringMembers.ToLower);
305372
}),
306373
new FunctionCallDefinition(
307374
name:"FN_TOUPPER",
@@ -310,7 +377,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
310377
expressionBuilder: (parameters) => {
311378
return Expression.Call(
312379
instance:parameters[0],
313-
method:Type<string>.Method(x=>x.ToUpper()));
380+
method:StringMembers.ToUpper);
314381
}),
315382

316383
new FunctionCallDefinition(
@@ -320,7 +387,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
320387
expressionBuilder: (parameters) => {
321388
return Expression.MakeMemberAccess(
322389
parameters[0],
323-
Type<DateTime>.Member(x=>x.Day));
390+
DateTimeMembers.Day);
324391
}),
325392
new FunctionCallDefinition(
326393
name:"FN_HOUR",
@@ -329,7 +396,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
329396
expressionBuilder: (parameters) => {
330397
return Expression.MakeMemberAccess(
331398
parameters[0],
332-
Type<DateTime>.Member(x=>x.Hour));
399+
DateTimeMembers.Hour);
333400
}),
334401
new FunctionCallDefinition(
335402
name:"FN_MINUTE",
@@ -338,7 +405,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
338405
expressionBuilder: (parameters) => {
339406
return Expression.MakeMemberAccess(
340407
parameters[0],
341-
Type<DateTime>.Member(x=>x.Minute));
408+
DateTimeMembers.Minute);
342409
}),
343410
new FunctionCallDefinition(
344411
name:"FN_MONTH",
@@ -347,7 +414,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
347414
expressionBuilder: (parameters) => {
348415
return Expression.MakeMemberAccess(
349416
parameters[0],
350-
Type<DateTime>.Member(x=>x.Month));
417+
DateTimeMembers.Month);
351418
}),
352419
new FunctionCallDefinition(
353420
name:"FN_YEAR",
@@ -356,7 +423,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
356423
expressionBuilder: (parameters) => {
357424
return Expression.MakeMemberAccess(
358425
parameters[0],
359-
Type<DateTime>.Member(x=>x.Year));
426+
DateTimeMembers.Year);
360427
}),
361428
new FunctionCallDefinition(
362429
name:"FN_SECOND",
@@ -365,7 +432,7 @@ protected virtual IEnumerable<FunctionCallDefinition> FunctionDefinitions()
365432
expressionBuilder: (parameters) => {
366433
return Expression.MakeMemberAccess(
367434
parameters[0],
368-
Type<DateTime>.Member(x=>x.Second));
435+
DateTimeMembers.Second);
369436
}),
370437
};
371438
}
@@ -401,6 +468,20 @@ protected virtual IEnumerable<GrammerDefinition> WhitespaceDefinitions()
401468
}
402469

403470

404-
471+
/// <summary>
472+
/// Wraps the function to convert any constants to enums if required
473+
/// </summary>
474+
/// <param name="expFn">Function to wrap</param>
475+
/// <returns></returns>
476+
protected Func<Expression, Expression, Expression> ConvertEnumsIfRequired(Func<Expression, Expression, Expression> expFn)
477+
{
478+
return (left, right) =>
479+
{
480+
var didConvertEnum = ExpressionConversions.TryEnumNumberConvert(ref left, ref right)
481+
|| ExpressionConversions.TryEnumStringConvert(ref left, ref right, ignoreCase: true);
482+
483+
return expFn(left, right);
484+
};
485+
}
405486
}
406487
}

src/StringToExpression/StringToExpression.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Out of the box configuration is provided for parsing arithmetic expressions and
1212
<PackageProjectUrl>https://github.com/codecutout/StringToExpression</PackageProjectUrl>
1313
<PackageTags>Expression Filter OData Arithmetic DSL</PackageTags>
1414
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
15-
<Version>1.0.1</Version>
15+
<Version>1.1.0</Version>
1616
</PropertyGroup>
1717

1818
</Project>

0 commit comments

Comments
 (0)