public Expression ConvertFluentToQuery(Expression node) { node = node.Clone(); var artificialParent = new ExpressionStatement(); artificialParent.Expression = node; DecompileQueries(node); // After all queries were decompiled, detect degenerate queries (queries not property terminated with 'select' or 'group') // and fix them, either by adding a degenerate select, or by combining them with another query. foreach (QueryExpression query in artificialParent.Descendants.OfType <QueryExpression>()) { QueryFromClause fromClause = (QueryFromClause)query.Clauses.First(); if (IsDegenerateQuery(query)) { string identifierName = fromClause.Identifier; // introduce select for degenerate query query.Clauses.Add(new QuerySelectClause { Expression = new IdentifierExpression(identifierName) }); } if (fromClause.Type.IsNull) { // See if the data source of this query is a degenerate query, // and combine the queries if possible. QueryExpression innerQuery = fromClause.Expression as QueryExpression; while (IsDegenerateQuery(innerQuery)) { QueryFromClause innerFromClause = (QueryFromClause)innerQuery.Clauses.First(); if (fromClause.Identifier != innerFromClause.Identifier && !innerFromClause.Identifier.StartsWith("<>")) { break; } // Replace the fromClause with all clauses from the inner query fromClause.Remove(); foreach (var identifierChild in innerQuery.Descendants.OfType <Identifier>().Where(identifier => identifier.Name == innerFromClause.Identifier)) { //When the identifier is "<>X", then replace it with the outer one identifierChild.ReplaceWith(fromClause.IdentifierToken.Clone()); } QueryClause insertionPos = null; foreach (var clause in innerQuery.Clauses) { query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); } fromClause = innerFromClause; innerQuery = fromClause.Expression as QueryExpression; } } } return(artificialParent.Expression.Clone()); }
bool TryRemoveTransparentIdentifier(QueryExpression query, QueryFromClause fromClause, QueryExpression innerQuery, string continuationIdentifier, out string transparentIdentifier) { transparentIdentifier = fromClause.Identifier; Match match = selectTransparentIdentifierPattern.Match(innerQuery.Clauses.Last()); if (!match.Success) { return(false); } QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last(); Expression nae1 = match.Get <Expression>("nae1").SingleOrDefault(); string nae1Name = ExtractExpressionName(ref nae1); if (nae1Name == null) { return(false); } Expression nae2 = match.Get <Expression>("nae2").SingleOrDefault(); string nae2Name = ExtractExpressionName(ref nae2); if (nae1Name == null) { return(false); } bool introduceLetClause = true; var nae1Identifier = nae1 as IdentifierExpression; var nae2Identifier = nae2 as IdentifierExpression; if (nae1Identifier != null && nae2Identifier != null && nae1Identifier.Identifier == nae1Name && nae2Identifier.Identifier == nae2Name) { introduceLetClause = false; } if (nae1Name != continuationIdentifier) { if (nae2Name == continuationIdentifier) { //Members are in reversed order string tempName = nae1Name; Expression tempNae = nae1; nae1Name = nae2Name; nae1 = nae2; nae2Name = tempName; nae2 = tempNae; } else { return(false); } } if (introduceLetClause && innerQuery.Clauses.OfType <QueryFromClause>().Any(from => from.Identifier == nae2Name)) { return(false); } if (introduceLetClause && innerQuery.Clauses.OfType <QueryJoinClause>().Any(join => join.JoinIdentifier == nae2Name)) { return(false); } // from * in (from x in ... select new { x = x, y = expr }) ... // => // from x in ... let y = expr ... fromClause.Remove(); selectClause.Remove(); // Move clauses from innerQuery to query QueryClause insertionPos = null; foreach (var clause in innerQuery.Clauses) { query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); } if (introduceLetClause) { query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = nae2Name, Expression = nae2.Detach() }); } return(true); }