Skip to content

Commit

Permalink
Support dotted identifier property expressions. Resolves #1
Browse files Browse the repository at this point in the history
  • Loading branch information
paulirwin committed May 2, 2019
1 parent 38a2222 commit 390ed34
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 9 deletions.
13 changes: 7 additions & 6 deletions Example/Controllers/CustomersController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,19 @@ public class CustomersController : ControllerBase
{
// Names generated from http://random-name-generator.info/random/?n=10&g=1&st=2
// Ages generated from https://www.random.org/integers/?num=10&min=18&max=100&col=5&base=10&format=html&rnd=new
// Loyalty program member numbers generated from https://www.random.org/integers/?num=10&min=100000&max=1000000&col=5&base=10&format=html&rnd=new
// Any similarity to persons real or fictional is coincidental!
private static readonly Customer[] _customers =
{
new Customer(1, "Daryl", "Barber", 73, true),
new Customer(2, "Cheryl", "Jimenez", 54, true),
new Customer(1, "Daryl", "Barber", 73, true, 832373, CustomerLoyaltyProgramLevel.Gold),
new Customer(2, "Cheryl", "Jimenez", 54, true, 775751, CustomerLoyaltyProgramLevel.Silver),
new Customer(3, "Caleb", "Mitchell", 29, false),
new Customer(4, "Joanne", "Griffin", 61, true),
new Customer(4, "Joanne", "Griffin", 61, true, 534424, CustomerLoyaltyProgramLevel.Bronze),
new Customer(5, "Irma", "Holloway", 40, false),
new Customer(6, "Arthur", "Sandoval", 64, true),
new Customer(7, "Tracy", "Frank", 45, true),
new Customer(6, "Arthur", "Sandoval", 64, true, 229658, CustomerLoyaltyProgramLevel.Gold),
new Customer(7, "Tracy", "Frank", 45, true, 860876, CustomerLoyaltyProgramLevel.Silver),
new Customer(8, "Sherman", "Drake", 89, false),
new Customer(9, "Gwen", "Brown", 48, true),
new Customer(9, "Gwen", "Brown", 48, true, 373442, CustomerLoyaltyProgramLevel.Bronze),
new Customer(10, "Melvin", "Woods", 54, false)
};

Expand Down
30 changes: 29 additions & 1 deletion Example/Models/Customer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using F23.Hateoas;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace Example.Models
{
Expand All @@ -8,13 +10,22 @@ public Customer()
{
}

public Customer(int id, string firstName, string lastName, int age, bool isPreferred)
public Customer(int id, string firstName, string lastName, int age, bool isPreferred, int? memberNumber = null, CustomerLoyaltyProgramLevel? loyaltyLevel = null)
{
Id = id;
FirstName = firstName;
LastName = lastName;
Age = age;
IsPreferred = isPreferred;

if (memberNumber.HasValue && loyaltyLevel.HasValue)
{
LoyaltyProgram = new CustomerLoyaltyProgram
{
MemberNumber = memberNumber.Value,
Level = loyaltyLevel.Value
};
}
}

public int Id { get; set; }
Expand All @@ -26,5 +37,22 @@ public Customer(int id, string firstName, string lastName, int age, bool isPrefe
public int Age { get; set; }

public bool IsPreferred { get; set; }

public CustomerLoyaltyProgram LoyaltyProgram { get; set; }
}

public class CustomerLoyaltyProgram
{
public int MemberNumber { get; set; }

[JsonConverter(typeof(StringEnumConverter))]
public CustomerLoyaltyProgramLevel Level { get; set; }
}

public enum CustomerLoyaltyProgramLevel
{
Bronze,
Silver,
Gold
}
}
2 changes: 1 addition & 1 deletion F23.ODataLite/F23.ODataLite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PackageTags>odata asp.net core lite</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Copyright>2019, feature[23]</Copyright>
<Version>1.1.1</Version>
<Version>1.2.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
45 changes: 44 additions & 1 deletion F23.ODataLite/Internal/ExpressionQueryTokenVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,50 @@ public Expression Visit(InToken tokenIn)

public Expression Visit(DottedIdentifierToken tokenIn)
{
throw new NotImplementedException();
var parts = tokenIn.Identifier.Split('.');

var propExprs = new List<MemberExpression>();

var prop = _properties.FirstOrDefault(i => i.Name.Equals(parts[0], StringComparison.OrdinalIgnoreCase));

if (prop == null)
throw new InvalidOperationException($"Property {parts[0]} not found on type {_parameter.Type.Name}");

var nullExpr = Expression.Constant(null);

var propExpr = Expression.Property(_parameter, prop);
propExprs.Add(propExpr);

for (int i = 1; i < parts.Length; i++)
{
var parentType = prop.PropertyType;
var props = parentType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
prop = props.FirstOrDefault(p => p.Name.Equals(parts[i], StringComparison.OrdinalIgnoreCase));

if (prop == null)
throw new InvalidOperationException($"Property {parts[i]} not found on type {parentType.Name}");

propExpr = Expression.Property(propExpr, prop);
propExprs.Add(propExpr);
}

var finalType = prop.PropertyType;
Expression expr = propExprs[propExprs.Count - 1];

if (propExprs.Count > 1)
{
for (int i = propExprs.Count - 2; i >= 0; i--)
{
propExpr = propExprs[i];

expr = Expression.Condition(
Expression.Equal(Expression.Convert(propExpr, typeof(object)), nullExpr),
Expression.Default(finalType),
expr);
}
}

return expr;
}

public Expression Visit(ExpandToken tokenIn)
Expand Down

0 comments on commit 390ed34

Please sign in to comment.