Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1144: Enable retrieve the clr element type from GroupbyWrapper #1278

Draft
wants to merge 1 commit into
base: release-8.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion sample/ODataRoutingSample/Controllers/v1/CustomersController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,29 @@ public CustomersController(MyDataContext context)
}
}

// For example: http://localhost:5000/v1/customers?$apply=groupby((Name), aggregate($count as count))&$orderby=name desc
// For example: http://localhost:5000/v1/customers?$apply=groupby((Name), aggregate($count as count))&$orderby=Name desc
/* You could get:
{
"@odata.context": "http://localhost:5000/v1/$metadata#Customers(Name,count)",
"value": [
{
"@odata.id": null,
"Name": "Sam",
"count": 2
},
{
"@odata.id": null,
"Name": "Peter",
"count": 1
},
{
"@odata.id": null,
"Name": "Jonier",
"count": 1
}
]
}
*/
[HttpGet]
[EnableQuery]
public IActionResult Get()
Expand Down
17 changes: 17 additions & 0 deletions src/Microsoft.AspNetCore.OData/Common/TypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,29 @@ public static bool IsDynamicTypeWrapper(this Type type)
return (type != null && typeof(DynamicTypeWrapper).IsAssignableFrom(type));
}

public static bool IsCollectionDynamicTypeWrapper(this Type type)
{
if (!IsCollection(type, out Type elementType))
{
return false;
}

//while (elementType != null && elementType != typeof(object))
//{
// elementType = elementType.BaseType;
//}

return elementType.IsDynamicTypeWrapper();
}

public static bool IsDeltaSetWrapper(this Type type, out Type entityType) => IsTypeWrapper(typeof(DeltaSet<>), type, out entityType);

public static bool IsSelectExpandWrapper(this Type type, out Type entityType) => IsTypeWrapper(typeof(SelectExpandWrapper<>), type, out entityType);

public static bool IsComputeWrapper(this Type type, out Type entityType) => IsTypeWrapper(typeof(ComputeWrapper<>), type, out entityType);

public static bool IsGroupByWrapper(this Type type, out Type entityType) => IsTypeWrapper(typeof(GroupByWrapper<>), type, out entityType);

private static bool IsTypeWrapper(Type wrappedType, Type type, out Type entityType)
{
if (type == null)
Expand Down
5 changes: 5 additions & 0 deletions src/Microsoft.AspNetCore.OData/Edm/DefaultODataTypeMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ private IEdmType GetEdmType(IEdmModel edmModel, Type clrType, bool testCollectio
elementClrType = entityType;
}

if (elementClrType.IsGroupByWrapper(out entityType))
{
elementClrType = entityType;
}

IEdmType elementType = GetEdmType(edmModel, elementClrType, testCollections: false);
if (elementType != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ public virtual IODataSerializer GetODataPayloadSerializer(Type type, HttpRequest
{
return _serviceProvider.GetRequiredService<ODataDeltaResourceSetSerializer>();
}
else if (type.IsDynamicTypeWrapper())
{
return _serviceProvider.GetRequiredService<ODataResourceSerializer>();
}
else if (type.IsCollectionDynamicTypeWrapper())
{
return _serviceProvider.GetRequiredService<ODataResourceSetSerializer>();
}

IEdmModel model = request.GetModel();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ internal AggregationBinder(ODataQuerySettings settings, IAssemblyResolver assemb
case TransformationNodeKind.Aggregate:
var aggregateClause = this._transformation as AggregateTransformationNode;
_aggregateExpressions = FixCustomMethodReturnTypes(aggregateClause.AggregateExpressions);
ResultClrType = typeof(NoGroupByAggregationWrapper);
ResultClrType = typeof(NoGroupByAggregationWrapper<>).MakeGenericType(elementType);
break;
case TransformationNodeKind.GroupBy:
var groupByClause = this._transformation as GroupByTransformationNode;
Expand All @@ -66,15 +66,15 @@ internal AggregationBinder(ODataQuerySettings settings, IAssemblyResolver assemb
}
}

_groupByClrType = typeof(GroupByWrapper);
ResultClrType = typeof(AggregationWrapper);
_groupByClrType = typeof(GroupByWrapper<>).MakeGenericType(elementType);
ResultClrType = typeof(AggregationWrapper<>).MakeGenericType(elementType);
break;
default:
throw new NotSupportedException(String.Format(CultureInfo.InvariantCulture,
SRResources.NotSupportedTransformationKind, transformation.Kind));
}

_groupByClrType = _groupByClrType ?? typeof(NoGroupByWrapper);
_groupByClrType = _groupByClrType ?? typeof(NoGroupByWrapper<>).MakeGenericType(elementType);
}

private static Expression WrapDynamicCastIfNeeded(Expression propertyAccessor)
Expand Down Expand Up @@ -393,7 +393,7 @@ MethodInfo selectManyMethod
properties.Add(new NamedPropertyExpression(Expression.Constant(aggExpression.Alias), CreateAggregationExpression(innerAccum, aggExpression, selectedElementType)));
}

var nestedResultType = typeof(EntitySetAggregationWrapper);
var nestedResultType = typeof(EntitySetAggregationWrapper<>).MakeGenericType(this.ElementType);
var wrapperProperty = nestedResultType.GetProperty("Container");
wrapperTypeMemberAssignments.Add(Expression.Bind(wrapperProperty, AggregationPropertyContainer.CreateNextNamedPropertyContainer(properties)));

Expand Down Expand Up @@ -589,10 +589,10 @@ private IQueryable BindGroupBy(IQueryable query)
// })
List<NamedPropertyExpression> properties = CreateGroupByMemberAssignments(_groupingProperties);

var wrapperProperty = typeof(GroupByWrapper).GetProperty(GroupByContainerProperty);
var wrapperProperty = typeof(GroupByWrapper<>).GetProperty(GroupByContainerProperty);
List<MemberAssignment> wta = new List<MemberAssignment>();
wta.Add(Expression.Bind(wrapperProperty, AggregationPropertyContainer.CreateNextNamedPropertyContainer(properties)));
groupLambda = Expression.Lambda(Expression.MemberInit(Expression.New(typeof(GroupByWrapper)), wta), LambdaParameter);
groupLambda = Expression.Lambda(Expression.MemberInit(Expression.New(typeof(GroupByWrapper<>).MakeGenericType(ElementType)), wta), LambdaParameter);
}
else
{
Expand All @@ -616,7 +616,7 @@ private List<NamedPropertyExpression> CreateGroupByMemberAssignments(IEnumerable
}
else
{
var wrapperProperty = typeof(GroupByWrapper).GetProperty(GroupByContainerProperty);
var wrapperProperty = typeof(GroupByWrapper<>).GetProperty(GroupByContainerProperty);
List<MemberAssignment> wta = new List<MemberAssignment>();
wta.Add(Expression.Bind(wrapperProperty, AggregationPropertyContainer.CreateNextNamedPropertyContainer(CreateGroupByMemberAssignments(grpProp.ChildTransformations))));
properties.Add(new NamedPropertyExpression(Expression.Constant(propertyName), Expression.MemberInit(Expression.New(typeof(GroupByWrapper)), wta)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1096,7 +1096,7 @@ internal Expression CreatePropertyAccessExpression(Expression source, QueryBinde
// return GetFlattenedPropertyExpression(propertyPath, context)
// ?? ConvertNonStandardPrimitives(GetPropertyExpression(source, (!propertyPath.Contains("\\", StringComparison.Ordinal) ? "Instance\\" : String.Empty) + propertyName), context);

bool isAggregated = context.ElementClrType == typeof(AggregationWrapper);
bool isAggregated = context.ElementClrType == typeof(AggregationWrapper<>);

return GetFlattenedPropertyExpression(propertyPath, context)
?? ConvertNonStandardPrimitives(GetPropertyExpression(source, propertyName, isAggregated), context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public QueryBinderContext(IEdmModel model, ODataQuerySettings querySettings, Typ
ElementType = Model.GetEdmTypeReference(ElementClrType)?.Definition;

// Check if element type is null and not of AggregationWrapper type and not of NoGroupByAggregationWrapper type.
if (ElementType == null && ElementClrType != typeof(AggregationWrapper) && ElementClrType != typeof(NoGroupByAggregationWrapper))
if (ElementType == null && !typeof(GroupByWrapper).IsAssignableFrom(ElementClrType))
{
throw new ODataException(Error.Format(SRResources.ClrTypeNotInModel, ElementClrType.FullName));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@

namespace Microsoft.AspNetCore.OData.Query.Wrapper
{
internal class AggregationWrapper : GroupByWrapper
internal class AggregationWrapper<T> : GroupByWrapper<T>
{
}

internal class AggregationWrapperConverter : JsonConverter<AggregationWrapper>
internal class AggregationWrapperConverter<T> : JsonConverter<AggregationWrapper<T>>
{
public override AggregationWrapper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override AggregationWrapper<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, nameof(AggregationWrapper)));
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, typeof(AggregationWrapper<T>).Name));
}

public override void Write(Utf8JsonWriter writer, AggregationWrapper value, JsonSerializerOptions options)
public override void Write(Utf8JsonWriter writer, AggregationWrapper<T> value, JsonSerializerOptions options)
{
if (value != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,32 +59,32 @@ public override JsonConverter CreateConverter(Type type, JsonSerializerOptions o
{
return (JsonConverter)Activator.CreateInstance(typeof(FlatteningWrapperConverter<>).MakeGenericType(new Type[] { elementType }));
}
}
else
{
if (type == typeof(AggregationWrapper))
//}
//else
//{
if (type == typeof(AggregationWrapper<>))
{
return (JsonConverter)Activator.CreateInstance(typeof(AggregationWrapperConverter));
return (JsonConverter)Activator.CreateInstance(typeof(AggregationWrapperConverter<>).MakeGenericType(new Type[] { elementType }));
}

if (type == typeof(EntitySetAggregationWrapper))
if (type == typeof(EntitySetAggregationWrapper<>))
{
return (JsonConverter)Activator.CreateInstance(typeof(EntitySetAggregationWrapperConverter));
return (JsonConverter)Activator.CreateInstance(typeof(EntitySetAggregationWrapperConverter<>).MakeGenericType(new Type[] { elementType }));
}

if (type == typeof(GroupByWrapper))
if (type == typeof(GroupByWrapper<>))
{
return (JsonConverter)Activator.CreateInstance(typeof(GroupByWrapperConverter));
return (JsonConverter)Activator.CreateInstance(typeof(GroupByWrapperConverter<>).MakeGenericType(new Type[] { elementType }));
}

if (type == typeof(NoGroupByAggregationWrapper))
if (type == typeof(NoGroupByAggregationWrapper<>))
{
return (JsonConverter)Activator.CreateInstance(typeof(NoGroupByAggregationWrapperConverter));
return (JsonConverter)Activator.CreateInstance(typeof(NoGroupByAggregationWrapperConverter<>).MakeGenericType(new Type[] { elementType }));
}

if (type == typeof(NoGroupByWrapper))
if (type == typeof(NoGroupByWrapper<>))
{
return (JsonConverter)Activator.CreateInstance(typeof(NoGroupByWrapperConverter));
return (JsonConverter)Activator.CreateInstance(typeof(NoGroupByWrapperConverter<>).MakeGenericType(new Type[] { elementType }));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@

namespace Microsoft.AspNetCore.OData.Query.Wrapper
{
internal class EntitySetAggregationWrapper : GroupByWrapper
internal class EntitySetAggregationWrapper<T> : GroupByWrapper<T>
{
}

internal class EntitySetAggregationWrapperConverter : JsonConverter<EntitySetAggregationWrapper>
internal class EntitySetAggregationWrapperConverter<T> : JsonConverter<EntitySetAggregationWrapper<T>>
{
public override EntitySetAggregationWrapper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override EntitySetAggregationWrapper<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, nameof(EntitySetAggregationWrapper)));
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, typeof(EntitySetAggregationWrapper<T>).Name));
}

public override void Write(Utf8JsonWriter writer, EntitySetAggregationWrapper value, JsonSerializerOptions options)
public override void Write(Utf8JsonWriter writer, EntitySetAggregationWrapper<T> value, JsonSerializerOptions options)
{
if (value != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
//------------------------------------------------------------------------------

using System;
using System.Diagnostics.Contracts;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Microsoft.AspNetCore.OData.Query.Wrapper
{
internal class FlatteningWrapper<T> : GroupByWrapper
internal class FlatteningWrapper<T> : GroupByWrapper<T>
{
// TODO: how to use 'Source'?
public T Source { get; set; }
Expand Down
11 changes: 7 additions & 4 deletions src/Microsoft.AspNetCore.OData/Query/Wrapper/GroupByWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

namespace Microsoft.AspNetCore.OData.Query.Wrapper
{
internal class GroupByWrapper<T> : GroupByWrapper
{ }

internal class GroupByWrapper : DynamicTypeWrapper
{
private Dictionary<string, object> _values;
Expand Down Expand Up @@ -86,14 +89,14 @@ private void EnsureValues()
}
}

internal class GroupByWrapperConverter : JsonConverter<GroupByWrapper>
internal class GroupByWrapperConverter<T> : JsonConverter<GroupByWrapper<T>>
{
public override GroupByWrapper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override GroupByWrapper<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, nameof(GroupByWrapper)));
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, typeof(GroupByWrapper<T>).Name));
}

public override void Write(Utf8JsonWriter writer, GroupByWrapper value, JsonSerializerOptions options)
public override void Write(Utf8JsonWriter writer, GroupByWrapper<T> value, JsonSerializerOptions options)
{
if (value != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@

namespace Microsoft.AspNetCore.OData.Query.Wrapper
{
internal class NoGroupByAggregationWrapper : GroupByWrapper
internal class NoGroupByAggregationWrapper<T> : GroupByWrapper<T>
{
}

internal class NoGroupByAggregationWrapperConverter : JsonConverter<NoGroupByAggregationWrapper>
internal class NoGroupByAggregationWrapperConverter<T> : JsonConverter<NoGroupByAggregationWrapper<T>>
{
public override NoGroupByAggregationWrapper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override NoGroupByAggregationWrapper<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, nameof(NoGroupByAggregationWrapper)));
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, typeof(NoGroupByAggregationWrapper<T>).Name));
}

public override void Write(Utf8JsonWriter writer, NoGroupByAggregationWrapper value, JsonSerializerOptions options)
public override void Write(Utf8JsonWriter writer, NoGroupByAggregationWrapper<T> value, JsonSerializerOptions options)
{
if (value != null)
{
Expand Down
10 changes: 5 additions & 5 deletions src/Microsoft.AspNetCore.OData/Query/Wrapper/NoGroupByWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@

namespace Microsoft.AspNetCore.OData.Query.Wrapper
{
internal class NoGroupByWrapper : GroupByWrapper
internal class NoGroupByWrapper<T> : GroupByWrapper<T>
{
}

internal class NoGroupByWrapperConverter : JsonConverter<NoGroupByWrapper>
internal class NoGroupByWrapperConverter<T> : JsonConverter<NoGroupByWrapper<T>>
{
public override NoGroupByWrapper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public override NoGroupByWrapper<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, nameof(NoGroupByWrapper)));
throw new NotImplementedException(Error.Format(SRResources.JsonConverterDoesnotSupportRead, typeof(NoGroupByWrapper<T>).Name));
}

public override void Write(Utf8JsonWriter writer, NoGroupByWrapper value, JsonSerializerOptions options)
public override void Write(Utf8JsonWriter writer, NoGroupByWrapper<T> value, JsonSerializerOptions options)
{
if (value != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ namespace Microsoft.AspNetCore.OData.Tests.Commons
public class TypeHelperTest
{
[Theory]
[InlineData(typeof(AggregationWrapper), true)]
[InlineData(typeof(AggregationWrapper<object>), true)]
[InlineData(typeof(ComputeWrapper<object>), true)]
[InlineData(typeof(EntitySetAggregationWrapper), true)]
[InlineData(typeof(EntitySetAggregationWrapper<object>), true)]
[InlineData(typeof(FlatteningWrapper<object>), true)]
[InlineData(typeof(GroupByWrapper), true)]
[InlineData(typeof(NoGroupByAggregationWrapper), true)]
[InlineData(typeof(NoGroupByWrapper), true)]
[InlineData(typeof(NoGroupByAggregationWrapper<object>), true)]
[InlineData(typeof(NoGroupByWrapper<object>), true)]
[InlineData(typeof(object), false)]
[InlineData(typeof(SelectExpandWrapper), false)]
[InlineData(null, false)]
Expand Down
Loading
Loading