Skip to content

Commit

Permalink
Merge pull request #75 from leo-schick/feature/custom-json-property-name
Browse files Browse the repository at this point in the history
support custom property names via attributes
  • Loading branch information
rvanoord authored Nov 3, 2023
2 parents 5d29df7 + 5acca11 commit 6d4aa01
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 3 deletions.
32 changes: 30 additions & 2 deletions src/BccCode.Linq/Client/QueryProvider/ApiQueryProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
using System.Globalization;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using BccCode.Platform;
using Newtonsoft.Json;

namespace BccCode.Linq.Client;

Expand Down Expand Up @@ -385,7 +387,32 @@ protected override Expression VisitMember(MemberExpression node)
{
if (_activeParameters.TryGetValue(parameterNode, out var apiCaller))
{
string ApiMemberName() => node.Member.Name.ToCamelCase();
string ApiMemberToJsonString(MemberInfo member)
{
var dataMemberAttribute = member.GetCustomAttribute<DataMemberAttribute>();
if (dataMemberAttribute != null)
{
return dataMemberAttribute.Name;
}

#if NET6_0_OR_GREATER
var jsonPropertyNameAttribute = member.GetCustomAttribute<System.Text.Json.Serialization.JsonPropertyNameAttribute>();
if (jsonPropertyNameAttribute != null)
{
return jsonPropertyNameAttribute.Name;
}
#endif

var jsonPropertyAttribute = member.GetCustomAttribute<JsonPropertyAttribute>();
if (jsonPropertyAttribute != null)
{
return jsonPropertyAttribute.PropertyName ?? member.Name.ToCamelCase();
}

return member.Name.ToCamelCase();
}

string ApiMemberName() => ApiMemberToJsonString(node.Member);

string ApiMemberPath(string splitter = ".")
{
Expand All @@ -394,7 +421,7 @@ string ApiMemberPath(string splitter = ".")
foreach (var nestedMemberExpression in nestedMemberExpressions)
{
memberPath.Append(
nestedMemberExpression.Member.Name.ToCamelCase()
ApiMemberToJsonString(nestedMemberExpression.Member)
);
memberPath.Append(splitter);
}
Expand Down Expand Up @@ -486,6 +513,7 @@ string ApiMemberPath(string splitter = ".")
case VisitLinqLambdaMode.Convert:
{
//We assume conversion is implicitly handled on the server side
Debug.Assert(_where != null);
_where.Append(ApiMemberPath(splitter: "\": {\""));
return Expression.Empty();
}
Expand Down
15 changes: 14 additions & 1 deletion tests/BccCode.Linq.Tests/Helpers/TestClass.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
namespace BccCode.Linq.Tests.Helpers;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using Newtonsoft.Json;

namespace BccCode.Linq.Tests.Helpers;

public class TestClass
{
Expand All @@ -20,6 +24,15 @@ public class TestClass
#if NET6_0_OR_GREATER
public DateOnly DateOnly { get; set; }
#endif

[DataMember(Name = "custom_name")]
public NestedClass CustomNameByDataMemberAttribute { get; set; }

[JsonPropertyName("custom_name")]
public NestedClass CustomNameByJsonPropertyNameAttribute { get; set; }

[JsonProperty("custom_name")]
public NestedClass CustomNameByNewtonsoftJsonPropertyAttribute { get; set; }
}

public class NestedClass
Expand Down
54 changes: 54 additions & 0 deletions tests/BccCode.Linq.Tests/LinqTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2285,6 +2285,60 @@ public void IncludeThenIncludeAfterEnumerableTest()
Assert.Equal(5, persons.Count);
}

[Fact]
public void IncludeCustomNameByDataMemberAttributeTest()
{
var api = new ApiClientMockup();

var query = api.Empty
.Include(p => p.CustomNameByDataMemberAttribute);

var emptyList = query.ToList();
Assert.Equal("empty", api.PageEndpoint);
Assert.Null(api.ClientQuery?.Filter);
Assert.Equal("*,custom_name.*", api.ClientQuery?.Fields);
Assert.Null(api.ClientQuery?.Sort);
Assert.Null(api.ClientQuery?.Offset);
Assert.Null(api.ClientQuery?.Limit);
Assert.Empty(emptyList);
}

[Fact]
public void IncludeCustomNameByJsonPropertyNameAttributeTest()
{
var api = new ApiClientMockup();

var query = api.Empty
.Include(p => p.CustomNameByJsonPropertyNameAttribute);

var emptyList = query.ToList();
Assert.Equal("empty", api.PageEndpoint);
Assert.Null(api.ClientQuery?.Filter);
Assert.Equal("*,custom_name.*", api.ClientQuery?.Fields);
Assert.Null(api.ClientQuery?.Sort);
Assert.Null(api.ClientQuery?.Offset);
Assert.Null(api.ClientQuery?.Limit);
Assert.Empty(emptyList);
}

[Fact]
public void IncludeCustomNameByNewtonsoftJsonPropertyAttributeTest()
{
var api = new ApiClientMockup();

var query = api.Empty
.Include(p => p.CustomNameByNewtonsoftJsonPropertyAttribute);

var emptyList = query.ToList();
Assert.Equal("empty", api.PageEndpoint);
Assert.Null(api.ClientQuery?.Filter);
Assert.Equal("*,custom_name.*", api.ClientQuery?.Fields);
Assert.Null(api.ClientQuery?.Sort);
Assert.Null(api.ClientQuery?.Offset);
Assert.Null(api.ClientQuery?.Limit);
Assert.Empty(emptyList);
}

#endregion


Expand Down

0 comments on commit 6d4aa01

Please sign in to comment.