コード例 #1
0
        public ParseContext Parse(ODataUriParser parser, ParseContext sourceParseContext)
        {
            SourceParseContext = sourceParseContext;
            var targetParseContext            = new ParseContext();
            var targetQueryableSourceEntities = new List <Dictionary <string, object> >();
            var sourceEdmSetting = sourceParseContext.EdmEntityTypeSettings.FirstOrDefault();
            var targetEdmSetting = new EdmEntityTypeSettings()
            {
                RouteName  = "Groups",
                Personas   = sourceEdmSetting.Personas,
                Properties = new List <EdmEntityTypePropertySetting>()
            };
            var latestStateDictionary = new Dictionary <string, object>();

            var edmEntityType = new EdmEntityType(EdmNamespaceName, "Groups");
            //This may only be used if we client uses Custom.List as aggregation
            var edmComplexType    = new EdmComplexType(EdmNamespaceName, "List");
            var aggregatePropList = new Dictionary <string, AggregateExpression>();
            var applyClause       = parser.ParseApply();

            //We support only single transformation
            if (applyClause.Transformations.Count() > 1)
            {
                throw new FeatureNotSupportedException(ApplyParser, "Multiple Transformations");
            }

            if (applyClause.Transformations.Count() == 0)
            {
                throw new FeatureNotSupportedException(ApplyParser, "Zero Transformations");
            }

            foreach (var transformation in applyClause.Transformations)
            {
                if (transformation.Kind == TransformationNodeKind.GroupBy)
                {
                    var transform = (GroupByTransformationNode)transformation;

                    ///Add all the grouping properties
                    foreach (var groupingProperty in transform.GroupingProperties)
                    {
                        var sourceProperty = sourceEdmSetting.Properties.FirstOrDefault(predicate => predicate.PropertyName.Equals(groupingProperty.Name));

                        edmEntityType.AddStructuralProperty(groupingProperty.Name, groupingProperty.TypeReference.PrimitiveKind());

                        targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting
                        {
                            PropertyName = sourceProperty.PropertyName,
                            PropertyType = sourceProperty.PropertyType,
                            IsNullable   = sourceProperty.IsNullable
                        });
                    }


                    //Add all the aggregate properties
                    if (transform.ChildTransformations != null)
                    {
                        var aggregationProperties = (AggregateTransformationNode)transform.ChildTransformations;
                        AddAggregationPropertiesToModel(aggregationProperties
                                                        , sourceEdmSetting, edmEntityType, aggregatePropList, targetEdmSetting
                                                        , edmComplexType, latestStateDictionary);
                    }

                    //Register these dynamic types to model
                    sourceParseContext.Model.AddElement(edmEntityType);
                    sourceParseContext.Model.AddElement(edmComplexType);
                    ((EdmEntityContainer)sourceParseContext.Model.EntityContainer).AddEntitySet("Groups", edmEntityType);

                    var fields = transform.GroupingProperties.Select(p => p.Name).ToList();
                    var groups = sourceParseContext.QueryableSourceEntities
                                 .GroupBy(r => fields.ToDictionary(c => c, c => r[c]), new CustomEqualityComparer());

                    var entityRef     = new EdmEntityTypeReference(edmEntityType, true);
                    var collectionRef = new EdmCollectionTypeReference(new EdmCollectionType(entityRef));
                    var collection    = new EdmEntityObjectCollection(collectionRef);
                    latestStateDictionary.Add(RequestFilterConstants.GetEntityTypeKeyName(ApplyParser, StepIndex), entityRef);
                    foreach (var group in groups)
                    {
                        var targetQueryableDictionary = new Dictionary <string, object>();
                        var obj = new EdmEntityObject(edmEntityType);
                        foreach (var prop in fields)
                        {
                            var value = group.Key[prop];
                            obj.TrySetPropertyValue(prop, value);
                            targetQueryableDictionary.Add(prop, value);
                        }
                        AddAggregationPropertyValuesToModel(targetQueryableDictionary, obj, group, edmComplexType, aggregatePropList);
                        collection.Add(obj);
                        targetQueryableSourceEntities.Add(targetQueryableDictionary);
                    }
                    targetParseContext.Result = collection;
                    targetParseContext.Model  = sourceParseContext.Model;
                    targetParseContext.QueryableSourceEntities = targetQueryableSourceEntities;
                    targetParseContext.EdmEntityTypeSettings   = new List <EdmEntityTypeSettings> {
                        targetEdmSetting
                    };
                    targetParseContext.LatestStateDictionary = latestStateDictionary;
                    return(targetParseContext);
                }
                else if (transformation.Kind == TransformationNodeKind.Aggregate)
                {
                    var targetQueryableDictionary = new Dictionary <string, object>();
                    var obj = new EdmEntityObject(edmEntityType);
                    var aggregationProperties = (AggregateTransformationNode)transformation;
                    AddAggregationPropertiesToModel(aggregationProperties
                                                    , sourceEdmSetting, edmEntityType, aggregatePropList, targetEdmSetting
                                                    , edmComplexType, latestStateDictionary);
                    //Register these dynamic types to model
                    sourceParseContext.Model.AddElement(edmEntityType);
                    sourceParseContext.Model.AddElement(edmComplexType);
                    var entityRef     = new EdmEntityTypeReference(edmEntityType, true);
                    var collectionRef = new EdmCollectionTypeReference(new EdmCollectionType(entityRef));
                    var collection    = new EdmEntityObjectCollection(collectionRef);
                    latestStateDictionary.Add(RequestFilterConstants.GetEntityTypeKeyName(ApplyParser, StepIndex), entityRef);
                    AddAggregationPropertyValuesToModel(targetQueryableDictionary, obj, sourceParseContext.QueryableSourceEntities, edmComplexType, aggregatePropList);
                    collection.Add(obj);
                    targetQueryableSourceEntities.Add(targetQueryableDictionary);
                    targetParseContext.Result = collection;
                    targetParseContext.Model  = sourceParseContext.Model;
                    targetParseContext.QueryableSourceEntities = targetQueryableSourceEntities;
                    targetParseContext.EdmEntityTypeSettings   = new List <EdmEntityTypeSettings> {
                        targetEdmSetting
                    };
                    targetParseContext.LatestStateDictionary = latestStateDictionary;
                    return(targetParseContext);
                }
                else
                {
                    throw new FeatureNotSupportedException(ApplyParser, $"Transformation Kind {transformation.Kind} is not supported");
                }
            }
            throw new FeatureNotSupportedException(ApplyParser, "Invalid Apply Clause");
        }
コード例 #2
0
        public ParseContext Parse(ODataUriParser parser, ParseContext sourceParseContext)
        {
            //Select implementation
            var targetParseContext            = new ParseContext();
            var targetQueryableSourceEntities = new List <Dictionary <string, object> >();
            var sourceEdmSetting = sourceParseContext.EdmEntityTypeSettings.FirstOrDefault();
            var targetEdmSetting = new EdmEntityTypeSettings()
            {
                RouteName  = SelectParser,
                Personas   = sourceEdmSetting.Personas,
                Properties = new List <EdmEntityTypePropertySetting>()
            };
            var selectExpandClause    = parser.ParseSelectAndExpand();
            var edmEntityType         = new EdmEntityType(EdmNamespaceName, SelectParser);
            var latestStateDictionary = new Dictionary <string, object>();

            //Construct the types. For now we support non-nested primitive types only. Everything else is an exception for now.
            var propertyList = new List <string>();

            foreach (var item in selectExpandClause.SelectedItems)
            {
                switch (item)
                {
                case PathSelectItem pathSelectItem:
                    IEnumerable <ODataPathSegment> segments = pathSelectItem.SelectedPath;
                    var firstPropertySegment = segments.FirstOrDefault();
                    if (firstPropertySegment != null)
                    {
                        var typeSetting = sourceEdmSetting.Properties.FirstOrDefault(predicate => predicate.PropertyName == firstPropertySegment.Identifier);

                        propertyList.Add(firstPropertySegment.Identifier);

                        if (typeSetting.GetEdmPrimitiveTypeKind() != EdmPrimitiveTypeKind.None)
                        {
                            var edmPrimitiveType = typeSetting.GetEdmPrimitiveTypeKind();
                            if (typeSetting.IsNullable.HasValue)
                            {
                                edmEntityType.AddStructuralProperty(firstPropertySegment.Identifier, edmPrimitiveType, typeSetting.IsNullable.Value);
                            }
                            else
                            {
                                edmEntityType.AddStructuralProperty(firstPropertySegment.Identifier, edmPrimitiveType);
                            }
                            targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting
                            {
                                PropertyName = typeSetting.PropertyName,
                                PropertyType = typeSetting.PropertyType,
                                IsNullable   = typeSetting.IsNullable
                            });
                        }
                        else
                        {
                            //We are doing $select on a property which is of type list. Which means
                            if (typeSetting.PropertyType == "List")
                            {
                                var edmComplexType = GetEdmComplexTypeReference(sourceParseContext);
                                edmEntityType.AddStructuralProperty(typeSetting.PropertyName, new EdmCollectionTypeReference(new EdmCollectionType(new EdmComplexTypeReference(edmComplexType, true))));
                                targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting
                                {
                                    PropertyName = typeSetting.PropertyName,
                                    PropertyType = typeSetting.PropertyType,
                                    IsNullable   = typeSetting.IsNullable
                                });
                            }
                            else
                            {
                                throw new FeatureNotSupportedException(SelectParser, $"Invalid Custom Selection-{typeSetting.PropertyName}-{typeSetting.PropertyType}");
                            }
                        }
                    }
                    else
                    {
                        throw new FeatureNotSupportedException(SelectParser, "Empty Path Segments");
                    }
                    break;

                case WildcardSelectItem wildcardSelectItem: throw new FeatureNotSupportedException(SelectParser, "WildcardSelect");

                case ExpandedNavigationSelectItem expandedNavigationSelectItem: throw new FeatureNotSupportedException(SelectParser, "ExpandedNavigation");

                case ExpandedReferenceSelectItem expandedReferenceSelectItem: throw new FeatureNotSupportedException(SelectParser, "ExpandedReference");

                case NamespaceQualifiedWildcardSelectItem namespaceQualifiedWildcardSelectItem: throw new FeatureNotSupportedException(SelectParser, "NamespaceQualifiedWildcard");
                }
            }

            //Register these dynamic types to model
            sourceParseContext.Model.AddElement(edmEntityType);
            ((EdmEntityContainer)sourceParseContext.Model.EntityContainer).AddEntitySet("Select", edmEntityType);


            //Construct the data
            var entityReferenceType         = new EdmEntityTypeReference(edmEntityType, true);
            var collectionRef               = new EdmCollectionTypeReference(new EdmCollectionType(entityReferenceType));
            var collection                  = new EdmEntityObjectCollection(collectionRef);
            var filteredQueryableEntityList = sourceParseContext.QueryableSourceEntities.Select(p => p.Where(p => propertyList.Contains(p.Key)));

            latestStateDictionary.Add(RequestFilterConstants.GetEntityTypeKeyName(SelectParser, StepIndex), entityReferenceType);

            foreach (var entity in filteredQueryableEntityList)
            {
                var entityDictionary = new Dictionary <string, object>();
                var obj = new EdmEntityObject(edmEntityType);
                foreach (var propertyKey in propertyList)
                {
                    var setting = targetEdmSetting.Properties.FirstOrDefault(predicate => predicate.PropertyName.Equals(propertyKey));
                    var data    = entity.FirstOrDefault(property => property.Key.Equals(propertyKey));

                    //This condition is when the type of selected property is a primitive type
                    if (setting.GetEdmPrimitiveTypeKind() != EdmPrimitiveTypeKind.None)
                    {
                        var propertyValue = !data.Equals(default(KeyValuePair <string, object>)) ? data.Value : null;
                        obj.TrySetPropertyValue(propertyKey, propertyValue);
                        entityDictionary.Add(propertyKey, propertyValue);
                    }
                    else
                    {
                        switch (setting.PropertyType)
                        {
                        case "List":
                            //TODO: There is scope for perf improvement
                            //We can re-use the previous constructed list instead of constructing one from scratch.
                            var subList        = (List <Dictionary <string, object> >)data.Value;
                            var subListContext = GetList(subList, GetEdmComplexTypeReference(sourceParseContext));
                            obj.TrySetPropertyValue(propertyKey, subListContext.Result);
                            entityDictionary.Add(propertyKey, subListContext.QueryAbleResult);
                            break;
                        }
                    }
                }
                collection.Add(obj);
                targetQueryableSourceEntities.Add(entityDictionary);
            }

            targetParseContext.Result = collection;
            targetParseContext.QueryableSourceEntities = targetQueryableSourceEntities;
            targetParseContext.Model = sourceParseContext.Model;
            targetParseContext.EdmEntityTypeSettings = new List <EdmEntityTypeSettings> {
                targetEdmSetting
            };
            targetParseContext.LatestStateDictionary = latestStateDictionary;
            return(targetParseContext);
        }
コード例 #3
0
 private void AddAggregationPropertiesToModel(AggregateTransformationNode aggregationProperties
                                              , EdmEntityTypeSettings sourceEdmSetting
                                              , EdmEntityType edmEntityType
                                              , Dictionary <string, AggregateExpression> aggregatePropList
                                              , EdmEntityTypeSettings targetEdmSetting
                                              , EdmComplexType edmComplexType
                                              , Dictionary <string, object> latestStateDictionary)
 {
     foreach (var aggregationExpression in aggregationProperties.AggregateExpressions)
     {
         var expr = (AggregateExpression)aggregationExpression;
         if (expr.Method != AggregationMethod.Custom)
         {
             bool?  isNullable    = null;
             string propertyAlias = "";
             var    primitiveKind = expr.Expression.TypeReference.PrimitiveKind();
             if (expr.Method == AggregationMethod.VirtualPropertyCount)
             {
                 var sourceProperty = (CountVirtualPropertyNode)expr.Expression;
                 isNullable    = sourceProperty.TypeReference.IsNullable;
                 propertyAlias = !string.IsNullOrWhiteSpace(expr.Alias) ? expr.Alias : sourceProperty.Kind.ToString();
                 primitiveKind = EdmPrimitiveTypeKind.Int32;
             }
             else
             {
                 var sourceProperty    = (SingleValuePropertyAccessNode)expr.Expression;
                 var sourceEdmProperty = sourceEdmSetting.Properties.FirstOrDefault(predicate => predicate.PropertyName.Equals(sourceProperty.Property.Name));
                 isNullable    = sourceEdmProperty.IsNullable;
                 propertyAlias = !string.IsNullOrWhiteSpace(expr.Alias) ? expr.Alias : sourceProperty.Property.Name;
                 if (expr.Method == AggregationMethod.Average)
                 {
                     primitiveKind = EdmPrimitiveTypeKind.Double;
                 }
                 if (expr.Method == AggregationMethod.CountDistinct)
                 {
                     primitiveKind = EdmPrimitiveTypeKind.Int32;
                 }
             }
             edmEntityType.AddStructuralProperty(propertyAlias, primitiveKind);
             aggregatePropList.Add(propertyAlias, expr);
             targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting
             {
                 PropertyName = propertyAlias,
                 PropertyType = GetStringTypeFromEdmPrimitiveType(primitiveKind),
                 IsNullable   = isNullable
             });
         }
         else
         {
             //Create a list of source type
             if (expr.MethodDefinition.MethodLabel.Contains(ODataFilterConstants.AggregationMethod_Custom_List, StringComparison.OrdinalIgnoreCase))
             {
                 foreach (var property in sourceEdmSetting.Properties)
                 {
                     edmComplexType.AddStructuralProperty(property.PropertyName, property.GetEdmPrimitiveTypeKind());
                 }
                 var groupItemsPropertyName = !string.IsNullOrWhiteSpace(expr.Alias) ? expr.Alias : "Items";
                 var complexTypeReference   = new EdmComplexTypeReference(edmComplexType, true);
                 edmEntityType.AddStructuralProperty(groupItemsPropertyName, new EdmCollectionTypeReference(new EdmCollectionType(complexTypeReference)));
                 aggregatePropList.Add(groupItemsPropertyName, expr);
                 targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting
                 {
                     PropertyName = groupItemsPropertyName,
                     PropertyType = "List",
                     IsNullable   = null
                 });
                 latestStateDictionary.Add(RequestFilterConstants.GetComplexTypeKeyName(ApplyParser, StepIndex), edmComplexType);
             }
             else if (expr.MethodDefinition.MethodLabel.Contains(ODataFilterConstants.AggregationMethod_Custom_CountDistinct, StringComparison.OrdinalIgnoreCase) ||
                      expr.MethodDefinition.MethodLabel.Contains(ODataFilterConstants.AggregationMethod_Custom_Count, StringComparison.OrdinalIgnoreCase))
             {
                 var sourceProperty        = (SingleValuePropertyAccessNode)expr.Expression;
                 var primitiveKind         = EdmPrimitiveTypeKind.Int32;
                 var countDistinctPropName = !string.IsNullOrWhiteSpace(expr.Alias) ? expr.Alias : sourceProperty.Property.Name;
                 edmEntityType.AddStructuralProperty(countDistinctPropName, primitiveKind);
                 aggregatePropList.Add(countDistinctPropName, expr);
                 targetEdmSetting.Properties.Add(new EdmEntityTypePropertySetting
                 {
                     PropertyName = countDistinctPropName,
                     PropertyType = GetStringTypeFromEdmPrimitiveType(primitiveKind),
                     IsNullable   = null
                 });
             }
             else
             {
                 throw new FeatureNotSupportedException($"{ApplyParser}-Custom Aggregation-{expr.MethodDefinition.MethodLabel}", "Invalid Custom Aggregation");
             }
         }
     }
 }