Exemple #1
0
        /// <summary>
        /// QueryableResourceExpression visit method.
        /// </summary>
        /// <param name="rse">QueryableResourceExpression expression to visit</param>
        /// <returns>Visited QueryableResourceExpression expression</returns>
        internal override Expression VisitQueryableResourceExpression(QueryableResourceExpression rse)
        {
            if ((ResourceExpressionType)rse.NodeType == ResourceExpressionType.ResourceNavigationProperty)
            {
                if (rse.IsOperationInvocation && !(rse.Source is QueryableResourceExpression))
                {
                    var normalizerRewrites = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance);
                    var e = Evaluator.PartialEval(rse.Source);
                    e = ExpressionNormalizer.Normalize(e, normalizerRewrites);
                    e = ResourceBinder.Bind(e, this.context);
                    this.Visit(e);
                }
                else
                {
                    this.Visit(rse.Source);
                }

                this.uriBuilder.Append(UriHelper.FORWARDSLASH).Append(this.ExpressionToString(rse.MemberExpression, /*inPath*/ true));
            }
            else if (rse.MemberExpression != null)
            {
                // this is a resource set expression
                // we should be at the very beginning of
                // the URI
                Debug.Assert(this.uriBuilder.Length == 0, "The builder is not empty while we are adding a resourceset");
                string entitySetName = (String)((ConstantExpression)rse.MemberExpression).Value;
                this.uriBuilder.Append(this.context.BaseUriResolver.GetEntitySetUri(entitySetName));
            }
            else
            {
                this.uriBuilder.Append(this.context.BaseUriResolver.BaseUriOrNull);
            }

            WebUtil.RaiseVersion(ref this.uriVersion, rse.UriVersion);

            if (rse.ResourceTypeAs != null)
            {
                this.uriBuilder.Append(UriHelper.FORWARDSLASH);
                UriHelper.AppendTypeSegment(this.uriBuilder, rse.ResourceTypeAs, this.context, /*inPath*/ true, ref this.uriVersion);
            }

            if (rse.KeyPredicateConjuncts.Count > 0)
            {
                this.context.UrlKeyDelimiter.AppendKeyExpression(rse.GetKeyProperties(), kvp => ClientTypeUtil.GetServerDefinedName(kvp.Key), kvp => kvp.Value.Value, this.uriBuilder);
            }

            if (rse.IsOperationInvocation)
            {
                this.VisitOperationInvocation(rse);
            }

            if (rse.CountOption == CountOption.CountSegment)
            {
                // append $count segment: /$count
                this.uriBuilder.Append(UriHelper.FORWARDSLASH).Append(UriHelper.DOLLARSIGN).Append(UriHelper.COUNT);
            }

            this.VisitQueryOptions(rse);
            return(rse);
        }
        /// <summary>
        /// Retargets this input reference to point to the resource set specified by <paramref name="newTarget"/>.
        /// </summary>
        /// <param name="newTarget">The <see cref="QueryableResourceExpression"/> that this input reference should use as its target</param>
        internal void OverrideTarget(QueryableResourceExpression newTarget)
        {
            Debug.Assert(newTarget != null, "Resource set cannot be null");
            Debug.Assert(newTarget.ResourceType.Equals(this.Type), "Cannot reference a resource set with a different resource type");

            this.target = newTarget;
        }
        /// <summary>
        /// Retargets this input reference to point to the resource set specified by <paramref name="newTarget"/>.
        /// </summary>
        /// <param name="newTarget">The <see cref="QueryableResourceExpression"/> that this input reference should use as its target</param>
        internal void OverrideTarget(QueryableResourceExpression newTarget)
        {
            Debug.Assert(newTarget != null, "Resource set cannot be null");
            Debug.Assert(newTarget.ResourceType.Equals(this.Type), "Cannot reference a resource set with a different resource type");

            this.target = newTarget;
        }
        /// <summary>
        /// Creates a navigation resource expression
        /// </summary>
        /// <param name="expressionType">The expression type.</param>
        /// <param name="type">the return type of the expression</param>
        /// <param name="source">the source expression</param>
        /// <param name="memberExpression">property member name</param>
        /// <param name="resourceType">the element type of the resource</param>
        /// <param name="expandPaths">expand paths for resource set</param>
        /// <param name="countOption">count query option for the resource</param>
        /// <param name="customQueryOptions">custom query options for resource</param>
        /// <param name="projection">the projection expression</param>
        /// <param name="resourceTypeAs">TypeAs type</param>
        /// <param name="uriVersion">version of the Uri from the expand and projection paths</param>
        /// <param name="operationName">The operation name.</param>
        /// <param name="operationParameters">The operation parameter names and parameters pair for Resource</param>
        /// <returns>The navigation resource expression.</returns>
        internal static QueryableResourceExpression CreateNavigationResourceExpression(ExpressionType expressionType, Type type, Expression source, Expression memberExpression, Type resourceType, List <string> expandPaths, CountOption countOption, Dictionary <ConstantExpression, ConstantExpression> customQueryOptions, ProjectionQueryOptionExpression projection, Type resourceTypeAs, Version uriVersion, string operationName, Dictionary <string, string> operationParameters)
        {
            Debug.Assert(
                expressionType == (ExpressionType)ResourceExpressionType.RootResourceSet || expressionType == (ExpressionType)ResourceExpressionType.ResourceNavigationProperty || expressionType == (ExpressionType)ResourceExpressionType.RootSingleResource,
                "Expression type is not one of following: RootResourceSet, ResourceNavigationProperty, RootSingleResource.");

            QueryableResourceExpression expression = null;

            if (expressionType == (ExpressionType)ResourceExpressionType.RootResourceSet || expressionType == (ExpressionType)ResourceExpressionType.ResourceNavigationProperty)
            {
                expression = new ResourceSetExpression(type, source, memberExpression, resourceType, expandPaths, countOption, customQueryOptions, projection, resourceTypeAs, uriVersion);
            }

            if (expressionType == (ExpressionType)ResourceExpressionType.RootSingleResource)
            {
                expression = new SingletonResourceExpression(type, source, memberExpression, resourceType, expandPaths, countOption, customQueryOptions, projection, resourceTypeAs, uriVersion);
            }

            if (expression != null)
            {
                expression.OperationName       = operationName;
                expression.OperationParameters = operationParameters;
                return(expression);
            }

            return(null);
        }
Exemple #5
0
        /// <summary>
        /// Visit Query options for Resource
        /// </summary>
        /// <param name="re">Resource Expression with query options</param>
        internal void VisitQueryOptions(ResourceExpression re)
        {
            if (re.HasQueryOptions)
            {
                this.uriBuilder.Append(UriHelper.QUESTIONMARK);

                QueryableResourceExpression rse = re as QueryableResourceExpression;
                if (rse != null)
                {
                    IEnumerator options = rse.SequenceQueryOptions.GetEnumerator();
                    while (options.MoveNext())
                    {
                        Expression e = ((Expression)options.Current);
                        ResourceExpressionType et = (ResourceExpressionType)e.NodeType;
                        switch (et)
                        {
                            case ResourceExpressionType.SkipQueryOption:
                                this.VisitQueryOptionExpression((SkipQueryOptionExpression)e);
                                break;
                            case ResourceExpressionType.TakeQueryOption:
                                this.VisitQueryOptionExpression((TakeQueryOptionExpression)e);
                                break;
                            case ResourceExpressionType.OrderByQueryOption:
                                this.VisitQueryOptionExpression((OrderByQueryOptionExpression)e);
                                break;
                            case ResourceExpressionType.FilterQueryOption:
                                this.VisitQueryOptionExpression((FilterQueryOptionExpression)e);
                                break;
                            default:
                                Debug.Assert(false, "Unexpected expression type " + (int)et);
                                break;
                        }
                    }
                }

                if (re.ExpandPaths.Count > 0)
                {
                    this.VisitExpandOptions(re.ExpandPaths);
                }

                if (re.Projection != null && re.Projection.Paths.Count > 0)
                {
                    this.VisitProjectionPaths(re.Projection.Paths);
                }

                if (re.CountOption == CountOption.CountQuery)
                {
                    this.VisitCountQueryOptions();
                }

                if (re.CustomQueryOptions.Count > 0)
                {
                    this.VisitCustomQueryOptions(re.CustomQueryOptions);
                    }

                this.AppendCachedQueryOptionsToUriBuilder();
                }
            }
Exemple #6
0
        /// <summary>
        /// Visit Function Invocation
        /// </summary>
        /// <param name="rse">Resource Expression with function invocation</param>
        internal void VisitOperationInvocation(QueryableResourceExpression rse)
        {
            if (!this.uriBuilder.ToString().EndsWith(UriHelper.FORWARDSLASH.ToString(), StringComparison.Ordinal))
            {
                this.uriBuilder.Append(UriHelper.FORWARDSLASH);
            }

            if (rse.IsOperationInvocation)
            {
                this.uriBuilder.Append(rse.OperationName);
                if (rse.IsAction)
                {
                    return;
                }

                this.uriBuilder.Append(UriHelper.LEFTPAREN);
                bool needComma = false;
                KeyValuePair <string, string>[] parameters = rse.OperationParameters.ToArray();
                for (int i = 0; i < parameters.Length; ++i)
                {
                    KeyValuePair <string, string> param = parameters[i];
                    if (needComma)
                    {
                        this.uriBuilder.Append(UriHelper.COMMA);
                    }

                    this.uriBuilder.Append(param.Key);
                    this.uriBuilder.Append(UriHelper.EQUALSSIGN);

                    // non-primitive value, use alias.
                    if (!UriHelper.IsPrimitiveValue(param.Value))
                    {
                        string aliasName = UriHelper.ATSIGN + param.Key;
                        int    count     = 1;
                        while (this.alias.ContainsKey(aliasName))
                        {
                            aliasName = UriHelper.ATSIGN + param.Key + count;
                            count++;
                        }

                        this.uriBuilder.Append(aliasName);

                        this.alias.Add(aliasName, param.Value);
                    }
                    else
                    {
                        // primitive value, do not use alias.
                        this.uriBuilder.Append(param.Value);
                    }

                    needComma = true;
                }

                this.uriBuilder.Append(UriHelper.RIGHTPAREN);
            }
        }
        /// <summary>
        /// QueryableResourceExpression visit method.
        /// </summary>
        /// <param name="rse">QueryableResource expression to visit</param>
        /// <returns>Visited QueryableResourceExpression expression</returns>
        internal virtual Expression VisitQueryableResourceExpression(QueryableResourceExpression rse)
        {
            Expression source = this.Visit(rse.Source);

            if (source != rse.Source)
            {
                rse = QueryableResourceExpression.CreateNavigationResourceExpression(rse.NodeType, rse.Type, source, rse.MemberExpression, rse.ResourceType, rse.ExpandPaths, rse.CountOption, rse.CustomQueryOptions, rse.Projection, rse.ResourceTypeAs, rse.UriVersion);
            }

            return(rse);
        }
        /// <summary>
        /// QueryableResourceExpression visit method.
        /// </summary>
        /// <param name="rse">QueryableResource expression to visit</param>
        /// <returns>Visited QueryableResourceExpression expression</returns>
        internal virtual Expression VisitQueryableResourceExpression(QueryableResourceExpression rse)
        {
            Expression source = this.Visit(rse.Source);

            if (source != rse.Source)
            {
                rse = QueryableResourceExpression.CreateNavigationResourceExpression(rse.NodeType, rse.Type, source, rse.MemberExpression, rse.ResourceType, rse.ExpandPaths, rse.CountOption, rse.CustomQueryOptions, rse.Projection, rse.ResourceTypeAs, rse.UriVersion, rse.OperationName, rse.OperationParameters);
            }

            return rse;
        }
        /// <summary>
        /// Instructs this resource set expression to use the input reference expression from <paramref name="newInput"/> as it's
        /// own input reference, and to retarget the input reference from <paramref name="newInput"/> to this resource set expression.
        /// </summary>
        /// <param name="newInput">The resource set expression from which to take the input reference.</param>
        /// <remarks>Used exclusively by ResourceBinder.RemoveTransparentScope.</remarks>
        internal void OverrideInputReference(QueryableResourceExpression newInput)
        {
            Debug.Assert(newInput != null, "Original resource set cannot be null");
            Debug.Assert(this.inputRef == null, "OverrideInputReference cannot be called if the target has already been referenced");

            InputReferenceExpression inputRef = newInput.inputRef;

            if (inputRef != null)
            {
                this.inputRef = inputRef;
                inputRef.OverrideTarget(this);
            }
        }
        /// <summary>
        /// Create a clone with new type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns>The new clone.</returns>
        internal override ResourceExpression CreateCloneWithNewType(Type type)
        {
            QueryableResourceExpression clone = this.CreateCloneWithNewTypes(type, TypeSystem.GetElementType(type));

            if (this.keyPredicateConjuncts != null && this.keyPredicateConjuncts.Count > 0)
            {
                clone.SetKeyPredicate(this.keyPredicateConjuncts);
            }

            clone.keyFilter            = this.keyFilter;
            clone.sequenceQueryOptions = this.sequenceQueryOptions;
            clone.transparentScope     = this.transparentScope;
            return(clone);
        }
        /// <summary>
        /// Create a clone of the ResourceExpression.
        /// </summary>
        /// <returns>The new clone.</returns>
        internal override ResourceExpression CreateCloneResourceExpression()
        {
            QueryableResourceExpression clone = this.CreateClone();

            if (this.keyPredicateConjuncts != null && this.keyPredicateConjuncts.Count > 0)
            {
                clone.SetKeyPredicate(this.keyPredicateConjuncts);
            }

            clone.keyFilter            = this.keyFilter;
            clone.sequenceQueryOptions = this.sequenceQueryOptions;
            clone.transparentScope     = this.transparentScope;
            return(clone);
        }
Exemple #12
0
        internal override Expression VisitMemberAccess(MemberExpression m)
        {
            if (m.Expression == this.oldLambdaParameter)
            {
                // Member is only a valid projection target if it is the target of the current scope
                QueryableResourceExpression resourceExpression = this.projectionSource as QueryableResourceExpression;
                if (resourceExpression != null && resourceExpression.HasTransparentScope && resourceExpression.TransparentScope.Accessor == m.Member.Name)
                {
                    Debug.Assert(m.Type == this.newLambdaParameter.Type, "Should not be rewriting a parameter with a different type than the original");
                    return(this.newLambdaParameter);
                }
                else
                {
                    this.successfulRebind = false;
                }
            }

            return(base.VisitMemberAccess(m));
        }
Exemple #13
0
        /// <summary>
        /// Visit Function Invocation
        /// </summary>
        /// <param name="rse">Resource Expression with function invocation</param>
        internal void VisitOperationInvocation(QueryableResourceExpression rse)
        {
            if (!this.uriBuilder.ToString().EndsWith(UriHelper.FORWARDSLASH.ToString(), StringComparison.Ordinal))
            {
                this.uriBuilder.Append(UriHelper.FORWARDSLASH);
            }

            if (rse.IsOperationInvocation)
            {
                bool   isOperationImport = rse.MemberExpression == null;
                string operationName     = isOperationImport ? rse.OperationName : (rse.OperationParameters.Last().Value + "." + rse.OperationName);
                this.uriBuilder.Append(operationName);
                if (rse.IsAction)
                {
                    return;
                }

                this.uriBuilder.Append(UriHelper.LEFTPAREN);
                bool needComma = false;
                KeyValuePair <string, string>[] parameters = rse.OperationParameters.ToArray();
                for (int i = 0; i < parameters.Length - (isOperationImport ? 0 : 1); ++i)
                {
                    KeyValuePair <string, string> param = parameters[i];
                    if (needComma)
                    {
                        this.uriBuilder.Append(UriHelper.COMMA);
                    }

                    this.uriBuilder.Append(param.Key);
                    this.uriBuilder.Append(UriHelper.EQUALSSIGN);
                    this.uriBuilder.Append(param.Value);

                    needComma = true;
                }

                this.uriBuilder.Append(UriHelper.RIGHTPAREN);
            }
        }
        /// <summary>
        /// Cast QueryableResourceExpression to new type without affecting member type
        /// </summary>
        /// <param name="type">The new expression type</param>
        /// <returns>A copy of this with the new types</returns>
        internal QueryableResourceExpression CreateCloneForTransparentScope(Type type)
        {
            // QueryableResourceExpression can always have order information,
            // so return them as IOrderedQueryable<> always. Necessary to allow
            // OrderBy results that get aliased to a previous expression work
            // with ThenBy.
            Type elementType = TypeSystem.GetElementType(type);

            Debug.Assert(elementType != null, "elementType != null -- otherwise the set isn't going to act like a collection");
            Type newType = typeof(IOrderedQueryable <>).MakeGenericType(elementType);

            QueryableResourceExpression clone = this.CreateCloneWithNewTypes(newType, this.ResourceType);

            if (this.keyPredicateConjuncts != null && this.keyPredicateConjuncts.Count > 0)
            {
                clone.SetKeyPredicate(this.keyPredicateConjuncts);
            }

            clone.keyFilter            = this.keyFilter;
            clone.sequenceQueryOptions = this.sequenceQueryOptions;
            clone.transparentScope     = this.transparentScope;
            return(clone);
        }
Exemple #15
0
 /// <summary>
 /// Constructs a new InputBinder based on the specified input resources, which is represented by the specified ParameterExpression.
 /// </summary>
 /// <param name="resource">The current input resource from which valid references must start</param>
 /// <param name="setReferenceParam">The parameter that must be referenced in order to refer to the specified input resources</param>
 private InputBinder(ResourceExpression resource, ParameterExpression setReferenceParam)
 {
     this.input = resource;
     this.inputResource = resource as QueryableResourceExpression;
     this.inputParameter = setReferenceParam;
 }
Exemple #16
0
        /// <summary>
        /// Visit Function Invocation
        /// </summary>
        /// <param name="rse">Resource Expression with function invocation</param>
        internal void VisitOperationInvocation(QueryableResourceExpression rse)
        {
            if (!this.uriBuilder.ToString().EndsWith(UriHelper.FORWARDSLASH.ToString(), StringComparison.Ordinal))
            {
                this.uriBuilder.Append(UriHelper.FORWARDSLASH);   
            }

            if (rse.IsOperationInvocation)
            {
                this.uriBuilder.Append(rse.OperationName);
                if (rse.IsAction)
                {
                    return;
                }

                this.uriBuilder.Append(UriHelper.LEFTPAREN);
                bool needComma = false;
                KeyValuePair<string, string>[] parameters = rse.OperationParameters.ToArray();
                for (int i = 0; i < parameters.Length; ++i)
                {
                    KeyValuePair<string, string> param = parameters[i];
                    if (needComma)
                    {
                        this.uriBuilder.Append(UriHelper.COMMA);
                    }

                    this.uriBuilder.Append(param.Key);
                    this.uriBuilder.Append(UriHelper.EQUALSSIGN);

                    // non-primitive value, use alias.
                    if (!UriHelper.IsPrimitiveValue(param.Value))
                    {
                        string aliasName = UriHelper.ATSIGN + param.Key;
                        int count = 1;
                        while (this.alias.ContainsKey(aliasName))
                        {
                            aliasName = UriHelper.ATSIGN + param.Key + count;
                            count++;
                        }

                        this.uriBuilder.Append(aliasName);

                        this.alias.Add(aliasName, param.Value);
                    }
                    else
                    {
                        // primitive value, do not use alias.
                        this.uriBuilder.Append(param.Value);
                    }

                    needComma = true;
                }

                this.uriBuilder.Append(UriHelper.RIGHTPAREN);
            }
        }
Exemple #17
0
 /// <summary>
 /// Constructs a new InputBinder based on the specified input resources, which is represented by the specified ParameterExpression.
 /// </summary>
 /// <param name="resource">The current input resource from which valid references must start</param>
 /// <param name="setReferenceParam">The parameter that must be referenced in order to refer to the specified input resources</param>
 private InputBinder(ResourceExpression resource, ParameterExpression setReferenceParam)
 {
     this.input          = resource;
     this.inputResource  = resource as QueryableResourceExpression;
     this.inputParameter = setReferenceParam;
 }
Exemple #18
0
        /// <summary>
        /// Resolves member accesses that represent transparent scope property accesses to the corresponding resource,
        /// iff the input resource is enclosed in a transparent scope and the specified MemberExpression represents
        /// such a property access.
        /// </summary>
        /// <param name="m">MemberExpression expression to visit</param>
        /// <returns>
        /// An InputReferenceExpression if the member access represents a transparent scope property
        /// access that can be resolved to a resource in the path that produces the input resource;
        /// otherwise the same MemberExpression is returned.
        /// </returns>
        internal override Expression VisitMemberAccess(MemberExpression m)
        {
            // If the current input resource is not enclosed in a transparent scope, then this
            // MemberExpression cannot represent a valid transparent scope access based on the input parameter.
            if (this.inputResource == null ||
                !this.inputResource.HasTransparentScope)
            {
                return(base.VisitMemberAccess(m));
            }

            ParameterExpression  innerParamRef  = null;
            Stack <PropertyInfo> nestedAccesses = new Stack <PropertyInfo>();
            MemberExpression     memberRef      = m;

            while (memberRef != null &&
                   PlatformHelper.IsProperty(memberRef.Member) &&
                   memberRef.Expression != null)
            {
                nestedAccesses.Push((PropertyInfo)memberRef.Member);

                if (memberRef.Expression.NodeType == ExpressionType.Parameter)
                {
                    innerParamRef = (ParameterExpression)memberRef.Expression;
                }

                memberRef = memberRef.Expression as MemberExpression;
            }

            // Only continue if the inner non-MemberExpression is the input reference ParameterExpression and
            // at least one property reference is present - otherwise this cannot be a transparent scope access.
            if (innerParamRef != this.inputParameter || nestedAccesses.Count == 0)
            {
                return(m);
            }

            ResourceExpression          target         = this.input;
            QueryableResourceExpression targetResource = this.inputResource;
            bool transparentScopeTraversed             = false;

            // Process all the traversals through transparent scopes.
            while (nestedAccesses.Count > 0)
            {
                if (targetResource == null || !targetResource.HasTransparentScope)
                {
                    break;
                }

                // Peek the property; pop it once it's consumed
                // (it could be a non-transparent-identifier access).
                PropertyInfo currentProp = nestedAccesses.Peek();

                // If this is the accessor for the target, then the member
                // refers to the target itself.
                if (currentProp.Name.Equals(targetResource.TransparentScope.Accessor, StringComparison.Ordinal))
                {
                    target = targetResource;
                    nestedAccesses.Pop();
                    transparentScopeTraversed = true;
                    continue;
                }

                // This member could also be one of the in-scope sources of the target.
                Expression source;
                if (!targetResource.TransparentScope.SourceAccessors.TryGetValue(currentProp.Name, out source))
                {
                    break;
                }

                transparentScopeTraversed = true;
                nestedAccesses.Pop();
                Debug.Assert(source != null, "source != null -- otherwise ResourceBinder created an accessor to nowhere");
                InputReferenceExpression sourceReference = source as InputReferenceExpression;
                if (sourceReference == null)
                {
                    targetResource = source as QueryableResourceExpression;
                    if (targetResource == null || !targetResource.HasTransparentScope)
                    {
                        target = (ResourceExpression)source;
                    }
                }
                else
                {
                    targetResource = sourceReference.Target as QueryableResourceExpression;
                    target         = targetResource;
                }
            }

            // If no traversals were made, the original expression is OK.
            if (!transparentScopeTraversed)
            {
                return(m);
            }

            // Process traversals after the transparent scope.
            Expression result = this.CreateReference(target);

            while (nestedAccesses.Count > 0)
            {
                result = Expression.Property(result, nestedAccesses.Pop());
            }

            return(result);
        }
        /// <summary>
        /// Instructs this resource set expression to use the input reference expression from <paramref name="newInput"/> as it's
        /// own input reference, and to retarget the input reference from <paramref name="newInput"/> to this resource set expression.
        /// </summary>
        /// <param name="newInput">The resource set expression from which to take the input reference.</param>
        /// <remarks>Used exclusively by ResourceBinder.RemoveTransparentScope.</remarks>
        internal void OverrideInputReference(QueryableResourceExpression newInput)
        {
            Debug.Assert(newInput != null, "Original resource set cannot be null");
            Debug.Assert(this.inputRef == null, "OverrideInputReference cannot be called if the target has already been referenced");

            InputReferenceExpression inputRef = newInput.inputRef;
            if (inputRef != null)
            {
                this.inputRef = inputRef;
                inputRef.OverrideTarget(this);
            }
        }
Exemple #20
0
        /// <summary>
        /// QueryableResourceExpression visit method.
        /// </summary>
        /// <param name="rse">QueryableResourceExpression expression to visit</param>
        /// <returns>Visited QueryableResourceExpression expression</returns>
        internal override Expression VisitQueryableResourceExpression(QueryableResourceExpression rse)
        {
            if ((ResourceExpressionType)rse.NodeType == ResourceExpressionType.ResourceNavigationProperty)
            {
                if (rse.IsOperationInvocation && !(rse.Source is QueryableResourceExpression))
                {
                    var normalizerRewrites = new Dictionary<Expression, Expression>(ReferenceEqualityComparer<Expression>.Instance);
                    var e = Evaluator.PartialEval(rse.Source);
                    e = ExpressionNormalizer.Normalize(e, normalizerRewrites);
                    e = ResourceBinder.Bind(e, this.context);
                    this.Visit(e);
                }
                else
                {
                    this.Visit(rse.Source);
                }

                this.uriBuilder.Append(UriHelper.FORWARDSLASH).Append(this.ExpressionToString(rse.MemberExpression, /*inPath*/ true));
            }
            else if (rse.MemberExpression != null)
            {
                // this is a resource set expression
                // we should be at the very begining of
                // the URI
                Debug.Assert(this.uriBuilder.Length == 0, "The builder is not empty while we are adding a resourset");
                string entitySetName = (String)((ConstantExpression)rse.MemberExpression).Value;
                this.uriBuilder.Append(this.context.BaseUriResolver.GetEntitySetUri(entitySetName));
            }
            else
            {
                this.uriBuilder.Append(this.context.BaseUriResolver.BaseUriOrNull);
            }

            WebUtil.RaiseVersion(ref this.uriVersion, rse.UriVersion);

            if (rse.ResourceTypeAs != null)
            {
                this.uriBuilder.Append(UriHelper.FORWARDSLASH);
                UriHelper.AppendTypeSegment(this.uriBuilder, rse.ResourceTypeAs, this.context, /*inPath*/ true, ref this.uriVersion);
            }

            if (rse.KeyPredicateConjuncts.Count > 0)
            {
                this.context.UrlConventions.AppendKeyExpression(rse.GetKeyProperties(), kvp => ClientTypeUtil.GetServerDefinedName(kvp.Key), kvp => kvp.Value.Value, this.uriBuilder);
            }

            if (rse.IsOperationInvocation)
            {
                this.VisitOperationInvocation(rse);
            }

            if (rse.CountOption == CountOption.CountSegment)
            {
                // append $count segment: /$count
                this.uriBuilder.Append(UriHelper.FORWARDSLASH).Append(UriHelper.DOLLARSIGN).Append(UriHelper.COUNT);
            }
            
            this.VisitQueryOptions(rse);
            return rse;
        }