/// <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> /// Converts expression to Uri /// </summary> /// <param name="e">The expression</param> /// <returns>Converted uri</returns> public virtual Uri Convert(Expression e) { Uri uri; Dictionary <Expression, Expression> rewrites = null; if (!(e is ResourceSetExpression)) { rewrites = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance); e = Evaluator.PartialEval(e); e = ExpressionNormalizer.Normalize(e, rewrites); e = ResourceBinder.Bind(e); } UriWriter.Translate(false, e, out uri); return(uri); }
internal string Bind(Expression expression) { Argument.AssertNotNull(expression, nameof(expression)); Dictionary <Expression, Expression> normalizerRewrites = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance); // Evaluate any local evaluatable expressions ( lambdas etc) Expression partialEvaluatedExpression = Evaluator.PartialEval(expression); // Normalize expression, replace String Comparisons etc. Expression normalizedExpression = ExpressionNormalizer.Normalize(partialEvaluatedExpression, normalizerRewrites); // Parse the Bound expression into sub components, i.e. take count, filter, select columns, request options, opcontext, etc. ExpressionParser parser = GetExpressionParser(); parser.Translate(normalizedExpression); // Return the FilterString. return(parser.FilterString == "true" ? null : parser.FilterString); }
internal ExecutionInfo Bind() { ExecutionInfo retVal = new ExecutionInfo(); // IQueryable impl if (this.Expression != null) { Dictionary <Expression, Expression> normalizerRewrites = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance); // Step 1. Evaluate any local evaluatable expressions ( lambdas etc) Expression partialEvaluatedExpression = Evaluator.PartialEval(this.Expression); // Step 2. Normalize expression, replace String Comparisons etc. Expression normalizedExpression = ExpressionNormalizer.Normalize(partialEvaluatedExpression, normalizerRewrites); // Step 3. Bind Expression, Analyze predicates and create query option expressions. End result is a single ResourceSetExpression Expression boundExpression = ResourceBinder.Bind(normalizedExpression); // Step 4. Parse the Bound expression into sub components, i.e. take count, filter, select columns, request options, opcontext, etc. ExpressionParser parser = new ExpressionParser(); parser.Translate(boundExpression); // Step 5. Store query components & params this.TakeCount = parser.TakeCount; this.FilterString = parser.FilterString; this.SelectColumns = parser.SelectColumns; retVal.RequestOptions = parser.RequestOptions; retVal.OperationContext = parser.OperationContext; // Step 6. If projection & no resolver then generate a resolver to perform the projection if (parser.Resolver == null) { if (parser.Projection != null && parser.Projection.Selector != ProjectionQueryOptionExpression.DefaultLambda) { Type intermediateType = parser.Projection.Selector.Parameters[0].Type; // Convert Expression to take type object as input to allow for direct invocation. ParameterExpression paramExpr = Expression.Parameter(typeof(object)); Func <object, TElement> projectorFunc = Expression.Lambda <Func <object, TElement> >( Expression.Invoke(parser.Projection.Selector, Expression.Convert(paramExpr, intermediateType)), paramExpr).Compile(); // Generate a resolver to do the projection. retVal.Resolver = (pk, rk, ts, props, etag) => { // Parse to intermediate type ITableEntity intermediateObject = (ITableEntity)EntityUtilities.InstantiateEntityFromType(intermediateType); intermediateObject.PartitionKey = pk; intermediateObject.RowKey = rk; intermediateObject.Timestamp = ts; intermediateObject.ReadEntity(props, parser.OperationContext); intermediateObject.ETag = etag; // Invoke lambda expression return(projectorFunc(intermediateObject)); }; } else { // No op - No resolver or projection specified. } } else { retVal.Resolver = (EntityResolver <TElement>)parser.Resolver.Value; } } retVal.RequestOptions = TableRequestOptions.ApplyDefaults(retVal.RequestOptions, this.queryProvider.Table.ServiceClient); retVal.OperationContext = retVal.OperationContext ?? new OperationContext(); return(retVal); }