private static QueryModelReference ComputeDerivedDataReference(
            MethodCallExpression methodCall, QueryModelReference source)
        {
            var method = methodCall.Method;

            // Source is a sequence of T and output is also a sequence of T
            var sourceType = method.GetParameters()[0]
                             .ParameterType.FindGenericType(typeof(IEnumerable <>));
            var resultType = method.ReturnType
                             .FindGenericType(typeof(IEnumerable <>));

            if (sourceType == resultType)
            {
                return(new DerivedDataReference(source));
            }

            // Source is a sequence of T and output is a single T
            var sourceElementType = sourceType.GetGenericArguments()[0];

            if (method.ReturnType == sourceElementType)
            {
                return(new CollectionElementReference(source));
            }

            // TODO GitHubIssue#29 : Handle projection operators in query expression
            return(null);
        }
Пример #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PropertyModelReference" /> class.
        /// </summary>
        /// <param name="source">
        /// A source query model reference.
        /// </param>
        /// <param name="propertyName">
        /// The name of a property.
        /// </param>
        internal PropertyModelReference(QueryModelReference source, string propertyName)
        {
            Ensure.NotNull(propertyName, nameof(propertyName));
            this.propertyName = propertyName;

            Ensure.NotNull(source, nameof(source));
            Source = source;
        }
Пример #3
0
        private QueryModelReference ComputeParameterModelReference(ParameterExpression parameter)
        {
            QueryModelReference modelReference = null;

            foreach (var node in this.GetExpressionTrail())
            {
                var methodCall = node as MethodCallExpression;
                if (methodCall == null)
                {
                    continue;
                }

                modelReference = this.GetModelReferenceForNode(node);
                if (modelReference == null)
                {
                    continue;
                }

                var method     = methodCall.Method;
                var sourceType = method.GetParameters()[0].ParameterType.FindGenericType(typeof(IEnumerable <>));
                var resultType = method.ReturnType.FindGenericType(typeof(IEnumerable <>));
                if (sourceType != resultType)
                {
                    // In case sourceType IEnumerable<Person> and resultType is
                    // IEnumerable <SelectExpandBinder.SelectAllAndExpand<Person>>
                    // or IEnumerable<SelectExpandBinder.SelectAll<Person>>
                    // or IEnumerable<SelectExpandBinder.SelectSome<Person>>
                    // or IEnumerable<SelectExpandBinder.SelectSomeAndInheritance<Person>>
                    if (sourceType == null || resultType == null)
                    {
                        continue;
                    }

                    var resultGenericType = resultType.GenericTypeArguments[0];
                    if (!resultGenericType.IsGenericType ||
                        resultGenericType.GenericTypeArguments[0] != sourceType.GenericTypeArguments[0])
                    {
                        continue;
                    }
                }

                var typeOfT = sourceType.GenericTypeArguments[0];
                if (parameter.Type == typeOfT)
                {
                    var collectionType = modelReference.Type as IEdmCollectionType;
                    if (collectionType != null)
                    {
                        modelReference = new ParameterModelReference(
                            modelReference.EntitySet,
                            collectionType.ElementType.Definition);
                        return(modelReference);
                    }
                }
            }

            return(modelReference);
        }
Пример #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PropertyModelReference" /> class.
        /// </summary>
        /// <param name="propertyName">
        /// The name of a property.
        /// </param>
        /// <param name="property">
        /// EDM property instance
        /// </param>
        /// <param name="source">
        /// A source query model reference.
        /// </param>
        internal PropertyModelReference(string propertyName, IEdmProperty property, QueryModelReference source)
        {
            Ensure.NotNull(propertyName, "propertyName");
            this.propertyName = propertyName;

            Ensure.NotNull(property, "property");
            this.property = property;
            this.Source   = source;
        }
Пример #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PropertyModelReference" /> class.
        /// </summary>
        /// <param name="propertyName">
        /// The name of a property.
        /// </param>
        /// <param name="property">
        /// EDM property instance
        /// </param>
        /// <param name="source">
        /// A source query model reference.
        /// </param>
        internal PropertyModelReference(string propertyName, IEdmProperty property, QueryModelReference source)
        {
            Ensure.NotNull(propertyName, nameof(propertyName));
            this.propertyName = propertyName;

            Ensure.NotNull(property, nameof(property));
            this.property = property;
            Source        = source;
        }
Пример #6
0
        /// <summary>
        /// Gets a reference to the model element
        /// that represents an expression node.
        /// </summary>
        /// <param name="node">
        /// An expression node.
        /// </param>
        /// <returns>
        /// A reference to the model element
        /// that represents the expression node.
        /// </returns>
        public QueryModelReference GetModelReferenceForNode(Expression node)
        {
            QueryModelReference modelReference = null;

            if (node != null)
            {
                this.modelReferences.TryGetValue(node, out modelReference);
            }

            return(modelReference);
        }
Пример #7
0
        private QueryModelReference ComputeMemberModelReference(MemberExpression member)
        {
            QueryModelReference modelReference = null;
            var memberExp = member.Expression;

            if (memberExp == null)
            {
                throw new Exception(string.Format(Resources.QueryMemberNotAccessible, member.ToString()));
            }

            if (memberExp.NodeType == ExpressionType.Parameter)
            {
                modelReference = GetModelReferenceForNode(memberExp);
            }
            else if (memberExp.NodeType == ExpressionType.TypeAs)
            {
                var resultType          = memberExp.Type;
                var parameterExpression = (memberExp as UnaryExpression).Operand;

                // Handle result is employee, and get person's property case
                // member expression will be "Param_0 As Person"
                if (parameterExpression.Type.IsSubclassOf(resultType))
                {
                    modelReference = GetModelReferenceForNode(parameterExpression);
                }
                else
                {
                    // member expression will be "Param_0 As Employee"
                    var emdEntityType = QueryContext.Model.FindDeclaredType(resultType.FullName);

                    if (emdEntityType is IEdmStructuredType structuredType)
                    {
                        var property = structuredType.FindProperty(member.Member.Name);
                        modelReference = GetModelReferenceForNode(parameterExpression);
                        modelReference = new PropertyModelReference(modelReference, member.Member.Name, property);
                        return(modelReference);
                    }
                }
            }

            if (modelReference != null)
            {
                modelReference = new PropertyModelReference(modelReference, member.Member.Name);
            }

            return(modelReference);
        }
Пример #8
0
        private QueryModelReference ComputeMemberModelReference(MemberExpression member)
        {
            QueryModelReference modelReference = null;
            var memberExp = member.Expression;

            if (memberExp.NodeType == ExpressionType.Parameter)
            {
                modelReference = this.GetModelReferenceForNode(memberExp);
            }
            else if (memberExp.NodeType == ExpressionType.TypeAs)
            {
                var resultType          = memberExp.Type;
                var parameterExpression = (memberExp as UnaryExpression).Operand;

                // Handle result is employee, and get person's property case
                // member expression will be "Param_0 As Person"
                if (parameterExpression.Type.IsSubclassOf(resultType))
                {
                    modelReference = this.GetModelReferenceForNode(parameterExpression);
                }
                else
                {
                    // member expression will be "Param_0 As Employee"
                    var emdEntityType = this.QueryContext.Model.FindDeclaredType(resultType.FullName);

                    var structuredType = emdEntityType as IEdmStructuredType;
                    if (structuredType != null)
                    {
                        var property = structuredType.FindProperty(member.Member.Name);
                        modelReference = this.GetModelReferenceForNode(parameterExpression);
                        modelReference = new PropertyModelReference(member.Member.Name, property, modelReference);
                        return(modelReference);
                    }
                }
            }

            if (modelReference != null)
            {
                modelReference = new PropertyModelReference(
                    modelReference, member.Member.Name);
            }

            return(modelReference);
        }
Пример #9
0
        private QueryModelReference ComputeModelReference()
        {
            QueryModelReference modelReference = null;

            var methodCall = this.VisitedNode as MethodCallExpression;

            if (methodCall != null)
            {
                var method = methodCall.Method;
                if (method.DeclaringType == typeof(DataSourceStub) &&
                    method.Name != MethodNameOfDataSourceStubValue)
                {
                    modelReference = ComputeDataSourceStubReference(methodCall);
                }
                else if (method.GetCustomAttributes <ExtensionAttribute>().Any())
                {
                    var thisModelReference = this.GetModelReferenceForNode(methodCall.Arguments[0]);
                    if (thisModelReference != null)
                    {
                        var model = this.QueryContext.Model;
                        modelReference = ComputeQueryModelReference(methodCall, thisModelReference, model);
                    }
                }

                return(modelReference);
            }

            var parameter = this.VisitedNode as ParameterExpression;

            if (parameter != null)
            {
                return(ComputeParameterModelReference(parameter));
            }

            var member = this.VisitedNode as MemberExpression;

            if (member != null)
            {
                return(ComputeMemberModelReference(member));
            }

            return(null);
        }
Пример #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PropertyModelReference" /> class.
        /// </summary>
        /// <param name="propertyName">
        /// The name of a property.
        /// </param>
        /// <param name="property">
        /// EDM property instance
        /// </param>
        /// <param name="source">
        /// A source query model reference.
        /// </param>
        internal PropertyModelReference(string propertyName, IEdmProperty property, QueryModelReference source)
        {
            Ensure.NotNull(propertyName, "propertyName");
            this.propertyName = propertyName;

            Ensure.NotNull(property, "property");
            this.property = property;
            this.Source = source;
        }
Пример #11
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DerivedDataReference" /> class.
 /// </summary>
 /// <param name="source">
 /// A source query model reference.
 /// </param>
 public DerivedDataReference(QueryModelReference source)
 {
     Ensure.NotNull(source, "source");
     this.Source = source;
 }
Пример #12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CollectionElementReference" /> class.
 /// </summary>
 /// <param name="source">
 /// A source query model reference.
 /// </param>
 public CollectionElementReference(QueryModelReference source)
     : base(source)
 {
 }
Пример #13
0
        /// <summary>
        /// This method is called by method call like Where/OfType/SelectMany and so on
        /// to create a model reference for whole function call.
        /// </summary>
        /// <param name="methodCall">
        /// An method call expression node.
        /// </param>
        /// <param name="source">
        /// The parameter model reference.
        /// </param>
        /// <param name="model">
        /// The edm model.
        /// </param>
        /// <returns>
        /// A reference to the model element
        /// that represents the expression node.
        /// </returns>
        private static QueryModelReference ComputeQueryModelReference(
            MethodCallExpression methodCall, QueryModelReference source, IEdmModel model)
        {
            var method = methodCall.Method;

            // source is a sequence of T and output is also a sequence of T
            var sourceType = method.GetParameters()[0].ParameterType.FindGenericType(typeof(IEnumerable <>));
            var resultType = method.ReturnType.FindGenericType(typeof(IEnumerable <>));

            if (sourceType == resultType)
            {
                return(new QueryModelReference(source.EntitySet, source.Type));
            }

            Type resultElementType = null;

            if (resultType != null)
            {
                resultElementType = resultType.GenericTypeArguments[0];
            }

            // In case sourceType IEnumerable<Person> and resultType is
            // IEnumerable <SelectExpandBinder.SelectAllAndExpand<Person>>
            // or IEnumerable<SelectExpandBinder.SelectAll<Person>>
            // or IEnumerable<SelectExpandBinder.SelectSome<Person>>
            // or IEnumerable<SelectExpandBinder.SelectSomeAndInheritance<Person>>
            if (sourceType != null && resultType != null)
            {
                var resultGenericType = resultElementType;
                if (resultGenericType.IsGenericType)
                {
                    var resultFinalElementType = resultGenericType.GenericTypeArguments[0];
                    var sourceElementType      = sourceType.GenericTypeArguments[0];

                    // Handle source is type of sub class and result is a base class
                    if (resultFinalElementType.IsAssignableFrom(sourceElementType))
                    {
                        return(new QueryModelReference(source.EntitySet, source.Type));
                    }
                }
            }

            // In this case, the sourceType is null
            if (method.Name.Equals(MethodNameOfType))
            {
                // Did not consider multiple namespaces have same entity type case or customized namespace
                var edmEntityType  = model.FindDeclaredType(resultElementType.FullName);
                var collectionType = new EdmCollectionType(
                    new EdmEntityTypeReference((IEdmEntityType)edmEntityType, false));
                return(new QueryModelReference(source.EntitySet, collectionType));
            }

            // Till here, it means the result is not part of previous result and entity set will be null
            // This mean result is a collection as resultType is IEnumerable<>
            if (resultType != null)
            {
                // Did not consider multiple namespaces have same entity type case or customized namespace
                var edmElementType = model.FindDeclaredType(resultElementType.FullName);

                // This means result is collection of Entity/Complex/Enum
                IEdmTypeReference edmTypeReference = null;
                if (edmElementType != null)
                {
                    var edmType = edmElementType as IEdmType;
                    edmTypeReference = edmType.GetTypeReference();

                    if (edmTypeReference != null)
                    {
                        var collectionType = new EdmCollectionType(edmTypeReference);
                        return(new QueryModelReference(null, collectionType));
                    }
                }

                // TODO Here means a collection of primitive type
            }

            // TODO Need to handle single result case
            // TODO GitHubIssue#29 : Handle projection operators in query expression
            return(null);
        }
Пример #14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CollectionElementReference" /> class.
 /// </summary>
 /// <param name="source">
 /// A source query model reference.
 /// </param>
 public CollectionElementReference(QueryModelReference source)
     : base(source)
 {
 }
Пример #15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PropertyDataReference" /> class.
 /// </summary>
 /// <param name="source">
 /// A source query model reference.
 /// </param>
 /// <param name="propertyName">
 /// The name of a property.
 /// </param>
 public PropertyDataReference(QueryModelReference source, string propertyName)
     : base(source)
 {
     Ensure.NotNull(propertyName, "propertyName");
     this.propertyName = propertyName;
 }
        /// <summary>
        /// This method is called by method call like Where/OfType/SelectMany and so on
        /// to create a model reference for whole function call.
        /// </summary>
        /// <param name="methodCall">
        /// An method call expression node.
        /// </param>
        /// <param name="source">
        /// The parameter model reference.
        /// </param>
        /// <param name="model">
        /// The edm model.
        /// </param>
        /// <returns>
        /// A reference to the model element
        /// that represents the expression node.
        /// </returns>
        private static QueryModelReference ComputeQueryModelReference(
            MethodCallExpression methodCall, QueryModelReference source, IEdmModel model)
        {
            var method = methodCall.Method;

            // source is a sequence of T and output is also a sequence of T
            var sourceType = method.GetParameters()[0].ParameterType.FindGenericType(typeof(IEnumerable<>));
            var resultType = method.ReturnType.FindGenericType(typeof(IEnumerable<>));
            if (sourceType == resultType)
            {
                return new QueryModelReference(source.EntitySet, source.Type);
            }

            Type resultElementType = null;
            if (resultType != null)
            {
                resultElementType = resultType.GenericTypeArguments[0];
            }

            // In case sourceType IEnumerable<Person> and resultType is
            // IEnumerable <SelectExpandBinder.SelectAllAndExpand<Person>>
            // or IEnumerable<SelectExpandBinder.SelectAll<Person>>
            // or IEnumerable<SelectExpandBinder.SelectSome<Person>>
            // or IEnumerable<SelectExpandBinder.SelectSomeAndInheritance<Person>>
            if (sourceType != null && resultType != null)
            {
                var resultGenericType = resultElementType;
                if (resultGenericType.IsGenericType)
                {
                    var resultFinalElementType = resultGenericType.GenericTypeArguments[0];
                    var sourceElementType = sourceType.GenericTypeArguments[0];

                    // Handle source is type of sub class and result is a base class
                    if (resultFinalElementType.IsAssignableFrom(sourceElementType))
                    {
                        return new QueryModelReference(source.EntitySet, source.Type);
                    }
                }
            }

            // In this case, the sourceType is null
            if (method.Name.Equals(MethodNameOfType))
            {
                // Did not consider multiple namespaces have same entity type case or customized namespace
                var edmEntityType = model.FindDeclaredType(resultElementType.FullName);
                var collectionType = new EdmCollectionType(
                    new EdmEntityTypeReference((IEdmEntityType)edmEntityType, false));
                return new QueryModelReference(source.EntitySet, collectionType);
            }

            // Till here, it means the result is not part of previous result and entity set will be null
            // This mean result is a collection as resultType is IEnumerable<>
            if (resultType != null)
            {
                // Did not consider multiple namespaces have same entity type case or customized namespace
                var edmElementType = model.FindDeclaredType(resultElementType.FullName);

                // This means result is collection of Entity/Complex/Enum
                IEdmTypeReference edmTypeReference = null;
                if (edmElementType != null)
                {
                    var edmType = edmElementType as IEdmType;
                    edmTypeReference = edmType.GetTypeReference();

                    if (edmTypeReference != null)
                    {
                        var collectionType = new EdmCollectionType(edmTypeReference);
                        return new QueryModelReference(null, collectionType);
                    }
                }

                // TODO Here means a collection of primitive type
            }

            // TODO Need to handle single result case
            // TODO GitHubIssue#29 : Handle projection operators in query expression
            return null;
        }
Пример #17
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DerivedDataReference" /> class.
 /// </summary>
 /// <param name="source">
 /// A source query model reference.
 /// </param>
 public DerivedDataReference(QueryModelReference source)
 {
     Ensure.NotNull(source, "source");
     this.Source = source;
 }
Пример #18
0
        private QueryModelReference ComputeModelReference()
        {
            QueryModelReference modelReference = null;

            var methodCall = this.VisitedNode as MethodCallExpression;

            if (methodCall != null)
            {
                var method = methodCall.Method;
                if (method.DeclaringType == typeof(ApiData) &&
                    method.Name != MethodNameOfApiDataValue)
                {
                    modelReference = ComputeApiDataReference(methodCall);
                }
                else if (method.GetCustomAttributes <ExtensionAttribute>().Any())
                {
                    var thisModelReference = this.GetModelReferenceForNode(
                        methodCall.Arguments[0]);
                    if (thisModelReference != null)
                    {
                        modelReference = ComputeDerivedDataReference(
                            methodCall, thisModelReference);
                    }
                }
            }

            var parameter = this.VisitedNode as ParameterExpression;

            if (parameter != null)
            {
                foreach (var node in this.GetExpressionTrail())
                {
                    methodCall = node as MethodCallExpression;
                    if (methodCall != null)
                    {
                        modelReference = this.GetModelReferenceForNode(node);
                        if (modelReference != null)
                        {
                            var method     = methodCall.Method;
                            var sourceType = method.GetParameters()[0]
                                             .ParameterType.FindGenericType(typeof(IEnumerable <>));
                            var resultType = method.ReturnType
                                             .FindGenericType(typeof(IEnumerable <>));
                            if (sourceType == resultType)
                            {
                                var typeOfT = sourceType.GetGenericArguments()[0];
                                if (parameter.Type == typeOfT)
                                {
                                    modelReference = new CollectionElementReference(modelReference);
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            var member = this.VisitedNode as MemberExpression;

            if (member != null)
            {
                modelReference = this.GetModelReferenceForNode(member.Expression);
                if (modelReference != null)
                {
                    modelReference = new PropertyDataReference(
                        modelReference, member.Member.Name);
                }
            }

            return(modelReference);
        }
Пример #19
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PropertyModelReference" /> class.
        /// </summary>
        /// <param name="source">
        /// A source query model reference.
        /// </param>
        /// <param name="propertyName">
        /// The name of a property.
        /// </param>
        internal PropertyModelReference(QueryModelReference source, string propertyName)
        {
            Ensure.NotNull(propertyName, "propertyName");
            this.propertyName = propertyName;

            Ensure.NotNull(source, "source");
            this.Source = source;
        }
Пример #20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PropertyDataReference" /> class.
 /// </summary>
 /// <param name="source">
 /// A source query model reference.
 /// </param>
 /// <param name="propertyName">
 /// The name of a property.
 /// </param>
 public PropertyDataReference(QueryModelReference source, string propertyName)
     : base(source)
 {
     Ensure.NotNull(propertyName, "propertyName");
     this.propertyName = propertyName;
 }
Пример #21
0
        private static QueryModelReference ComputeDerivedDataReference(
            MethodCallExpression methodCall, QueryModelReference source)
        {
            var method = methodCall.Method;

            // Source is a sequence of T and output is also a sequence of T
            var sourceType = method.GetParameters()[0]
                .ParameterType.FindGenericType(typeof(IEnumerable<>));
            var resultType = method.ReturnType
                .FindGenericType(typeof(IEnumerable<>));
            if (sourceType == resultType)
            {
                return new DerivedDataReference(source);
            }

            // Source is a sequence of T and output is a single T
            var sourceElementType = sourceType.GetGenericArguments()[0];
            if (method.ReturnType == sourceElementType)
            {
                return new CollectionElementReference(source);
            }

            // TODO GitHubIssue#29 : Handle projection operators in query expression
            return null;
        }
Пример #22
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PropertyModelReference" /> class.
 /// </summary>
 /// <param name="propertyName">
 /// The name of a property.
 /// </param>
 /// <param name="property">
 /// EDM property instance
 /// </param>
 /// <param name="source">
 /// A source query model reference.
 /// </param>
 internal PropertyModelReference(QueryModelReference source, string propertyName, IEdmProperty property) :
     this(source, propertyName)
 {
     Ensure.NotNull(property, nameof(property));
     this.property = property;
 }