Skip to content

Commit 3355008

Browse files
authored
Use Enum Member Values (#4)
* added new tests * update test container nuget packages * change to older ubuntu version for mongo tests
1 parent 076fbd6 commit 3355008

File tree

4 files changed

+62
-7
lines changed

4 files changed

+62
-7
lines changed

.github/workflows/dotnet.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88

99
jobs:
1010
build-ubuntu:
11-
runs-on: ubuntu-latest
11+
runs-on: ubuntu-20.04
1212

1313
steps:
1414
- uses: actions/checkout@v2

src/Searchlight/Parsing/SyntaxParser.cs

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Reflection;
5+
using System.Runtime.Serialization;
46
using Searchlight.Exceptions;
57
using Searchlight.Expressions;
68
using Searchlight.Nesting;
@@ -592,17 +594,43 @@ private static IExpressionValue ParseParameter(DataSource source, SyntaxTree syn
592594
// Special case for enum types
593595
if (column.EnumType != null || fieldType.IsEnum)
594596
{
597+
var fields = fieldType.GetFields(BindingFlags.Public | BindingFlags.Static);
598+
var enumMembers = fields.Select(f =>
599+
{
600+
var attr = f.GetCustomAttribute<EnumMemberAttribute>();
601+
if (attr != null && attr.Value != null)
602+
{
603+
return (f.Name, attr.Value);
604+
}
605+
return (null, null);
606+
}).Where(e => e.Name != null).ToList();
607+
608+
var dictionary = enumMembers.ToDictionary(p => p.Value, p => p.Name);
609+
595610
try
596611
{
612+
if (dictionary.TryGetValue(valueToken, out var enumValueToken))
613+
{
614+
valueToken = enumValueToken;
615+
}
597616
var parsed = Enum.Parse(column.EnumType ?? fieldType, valueToken);
598617
return ConstantValue.From(Convert.ChangeType(parsed, fieldType));
599618
}
600619
catch
601620
{
621+
var expectedTokens = Enum.GetNames(column.EnumType ?? fieldType);
622+
var valueDictionary = enumMembers.ToDictionary(p => p.Name, p => p.Value);
623+
for (var i = 0; i < expectedTokens.Length; i++)
624+
{
625+
if (valueDictionary.TryGetValue(expectedTokens[i], out var newToken))
626+
{
627+
expectedTokens[i] = newToken;
628+
}
629+
}
602630
syntax.AddError(new InvalidToken
603631
{
604632
BadToken = valueToken,
605-
ExpectedTokens = Enum.GetNames(column.EnumType ?? fieldType),
633+
ExpectedTokens = expectedTokens,
606634
OriginalFilter = tokens.OriginalText,
607635
});
608636
return null;

tests/Searchlight.Tests/ParseModelTests.cs

+28-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.VisualStudio.TestTools.UnitTesting;
33
using Searchlight.Query;
44
using System.Linq;
5+
using System.Runtime.Serialization;
56
using System.Threading.Tasks;
67
using Searchlight.Exceptions;
78
using Searchlight.Expressions;
@@ -509,13 +510,23 @@ public enum TestEnumValueCategory
509510
Generic = 2,
510511
}
511512

513+
public enum TestEnumAttributeValueCategory
514+
{
515+
[EnumMember(Value = "Not Anything")]
516+
None = 0,
517+
Special = 1,
518+
Generic = 2,
519+
}
520+
512521
[SearchlightModel(DefaultSort = "Name ascending")]
513522
public class TestClassWithEnumValues
514523
{
515524
[SearchlightField(OriginalName = "field_name")]
516525
public string Name { get; set; }
517526
[SearchlightField(OriginalName = "field_category")]
518527
public TestEnumValueCategory Category { get; set; }
528+
[SearchlightField(OriginalName = "field_category_attribute")]
529+
public TestEnumAttributeValueCategory AttributeCategory { get; set; }
519530
}
520531

521532

@@ -524,11 +535,13 @@ public void TestValidEnumFilters()
524535
{
525536
var source = DataSource.Create(null, typeof(TestClassWithEnumValues), AttributeMode.Strict);
526537
var columns = source.GetColumnDefinitions().ToArray();
527-
Assert.AreEqual(2, columns.Length);
538+
Assert.AreEqual(3, columns.Length);
528539
Assert.AreEqual("Name", columns[0].FieldName);
529540
Assert.AreEqual(typeof(string), columns[0].FieldType);
530541
Assert.AreEqual("Category", columns[1].FieldName);
531542
Assert.AreEqual(typeof(TestEnumValueCategory), columns[1].FieldType);
543+
Assert.AreEqual("AttributeCategory", columns[2].FieldName);
544+
Assert.AreEqual(typeof(TestEnumAttributeValueCategory), columns[2].FieldType);
532545

533546
// Query for a valid category
534547
var syntax1 = source.ParseFilter("category = None");
@@ -537,12 +550,26 @@ public void TestValidEnumFilters()
537550
// Query using the raw integer value, which is generally not advised but we accept it for historical reasons
538551
var syntax2 = source.ParseFilter("category = 0");
539552
Assert.IsNotNull(syntax2);
553+
554+
// Query attribute value
555+
var syntax3 = source.ParseFilter("attributecategory = 'Not Anything'");
556+
Assert.IsNotNull(syntax3);
557+
558+
// Query non attribute value in mixed enum
559+
var syntax4 = source.ParseFilter("attributecategory = Special");
560+
Assert.IsNotNull(syntax4);
540561

541562
// Query for a non-valid category
542563
var ex2 = Assert.ThrowsException<InvalidToken>(() => source.ParseFilter("category = InvalidValue"));
543564
Assert.AreEqual("InvalidValue", ex2.BadToken);
544565
CollectionAssert.AreEqual(new string[] { "None", "Special", "Generic" }, ex2.ExpectedTokens);
545566
Assert.AreEqual("The filter statement contained an unexpected token, 'InvalidValue'. Searchlight expects to find one of these next: None, Special, Generic", ex2.ErrorMessage);
567+
568+
// Query for a non-valid category in attribute enum
569+
var ex3 = Assert.ThrowsException<InvalidToken>(() => source.ParseFilter("attributecategory = InvalidValue"));
570+
Assert.AreEqual("InvalidValue", ex3.BadToken);
571+
CollectionAssert.AreEqual(new string[] { "Not Anything", "Special", "Generic" }, ex3.ExpectedTokens);
572+
Assert.AreEqual("The filter statement contained an unexpected token, 'InvalidValue'. Searchlight expects to find one of these next: Not Anything, Special, Generic", ex3.ErrorMessage);
546573
}
547574

548575
[SearchlightModel(DefaultSort = nameof(Name))]

tests/Searchlight.Tests/Searchlight.Tests.csproj

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
</PackageReference>
2222
<PackageReference Include="MySql.Data" Version="8.1.0" />
2323
<PackageReference Include="Npgsql" Version="7.0.4" />
24-
<PackageReference Include="Testcontainers" Version="3.4.0" />
25-
<PackageReference Include="Testcontainers.MsSql" Version="3.4.0" />
26-
<PackageReference Include="Testcontainers.MySql" Version="3.4.0" />
27-
<PackageReference Include="Testcontainers.PostgreSql" Version="3.4.0" />
24+
<PackageReference Include="Testcontainers" Version="4.2.0" />
25+
<PackageReference Include="Testcontainers.MsSql" Version="4.2.0" />
26+
<PackageReference Include="Testcontainers.MySql" Version="4.2.0" />
27+
<PackageReference Include="Testcontainers.PostgreSql" Version="4.2.0" />
2828
</ItemGroup>
2929

3030
<ItemGroup>

0 commit comments

Comments
 (0)