Skip to content

Commit

Permalink
Fixing the way we are generating / parsing linq statements.
Browse files Browse the repository at this point in the history
  • Loading branch information
ayende committed Oct 21, 2012
1 parent 57f6b4c commit 1d8b035
Show file tree
Hide file tree
Showing 14 changed files with 1,379 additions and 236 deletions.
64 changes: 27 additions & 37 deletions Raven.Database/Linq/Ast/CaptureQueryParameterNamesVisitor.cs
@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.CSharp;

Expand All @@ -18,54 +18,30 @@ public HashSet<string> QueryParameters

public override object VisitQueryFromClause(QueryFromClause queryFromClause, object data)
{
throw new NotSupportedException();
}
}

/*
public class CaptureQueryParameterNamesVisitor : DepthFirstAstVisitor<object, object>
{
public override object VisitQueryFromClause(QueryFromClause queryFromClause, object data)
{
var memberReferenceExpression = queryFromClause.InExpression as MemberReferenceExpression;
var memberReferenceExpression = queryFromClause.Expression as MemberReferenceExpression;
if (memberReferenceExpression != null)
{
var identifierExpression = memberReferenceExpression.TargetObject as IdentifierExpression;
var identifierExpression = memberReferenceExpression.Target as IdentifierExpression;
if (identifierExpression != null && identifierExpression.Identifier != "docs")
{
var generateExpression = GenerateExpression(queryExpressionFromClause.InExpression);
var generateExpression = GenerateExpression(queryFromClause.Expression);
if (generateExpression != null)
aliasToName[queryExpressionFromClause.Identifier] = generateExpression + ",";
aliasToName[queryFromClause.Identifier] = generateExpression + ",";
}
}
return base.VisitQueryExpressionFromClause(queryExpressionFromClause, data);
}

public override object VisitQuerySelectClause(QuerySelectClause querySelectClause, object data)
{
ProcessQuery(queryExpressionSelectClause.Projection);
return base.VisitQueryExpressionSelectClause(queryExpressionSelectClause, data);
}
public override object VisitQueryExpressionLetClause(QueryExpressionLetClause queryExpressionLetClause, object data)
{
var generateExpression = GenerateExpression(queryExpressionLetClause.Expression);
if (generateExpression != null)
aliasToName[queryExpressionLetClause.Identifier] = generateExpression + ".";
return base.VisitQueryExpressionLetClause(queryExpressionLetClause, data);
return base.VisitQueryFromClause(queryFromClause, data);
}

private void ProcessQuery(Expression queryExpressionSelectClause)
{
var objectCreateExpression = QueryParsingUtils.GetAnonymousCreateExpression(queryExpressionSelectClause) as ObjectCreateExpression;
if (objectCreateExpression == null ||
objectCreateExpression.IsAnonymousType == false)
var objectCreateExpression = QueryParsingUtils.GetAnonymousCreateExpression(queryExpressionSelectClause) as AnonymousTypeCreateExpression;
if (objectCreateExpression == null)
return;

foreach (
var expression in
objectCreateExpression.ObjectInitializer.CreateExpressions.OfType<NamedArgumentExpression>())
objectCreateExpression.Initializers.OfType<NamedArgumentExpression>())
{
var generateExpression = GenerateExpression(expression.Expression);
if (generateExpression != null)
Expand All @@ -74,7 +50,7 @@ private void ProcessQuery(Expression queryExpressionSelectClause)

foreach (
var expression in
objectCreateExpression.ObjectInitializer.CreateExpressions.OfType<MemberReferenceExpression>())
objectCreateExpression.Initializers.OfType<MemberReferenceExpression>())
{
var generateExpression = GenerateExpression(expression);
if (generateExpression != null)
Expand All @@ -93,12 +69,12 @@ private string GenerateExpression(Expression expression)

sb.Insert(0, memberReferenceExpression.MemberName);

expression = memberReferenceExpression.TargetObject;
expression = memberReferenceExpression.Target;
memberReferenceExpression = expression as MemberReferenceExpression;
}

var identifierExpression = expression as IdentifierExpression;
if(identifierExpression != null && sb.Length != 0)
if (identifierExpression != null && sb.Length != 0)
{
string path;
if (aliasToName.TryGetValue(identifierExpression.Identifier, out path))
Expand All @@ -111,6 +87,20 @@ private string GenerateExpression(Expression expression)

return sb.ToString();
}

public override object VisitQuerySelectClause(QuerySelectClause querySelectClause, object data)
{
ProcessQuery(querySelectClause.Expression);
return base.VisitQuerySelectClause(querySelectClause, data);
}

public override object VisitQueryLetClause(QueryLetClause queryExpressionLetClause, object data)
{
var generateExpression = GenerateExpression(queryExpressionLetClause.Expression);
if (generateExpression != null)
aliasToName[queryExpressionLetClause.Identifier] = generateExpression + ".";
return base.VisitQueryLetClause(queryExpressionLetClause, data);
}

}
*/
}
88 changes: 39 additions & 49 deletions Raven.Database/Linq/Ast/CaptureSelectNewFieldNamesVisitor.cs
Expand Up @@ -5,6 +5,7 @@
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;

namespace Raven.Database.Linq.Ast
Expand All @@ -14,9 +15,10 @@ public class CaptureSelectNewFieldNamesVisitor : DepthFirstAstVisitor<object,obj
public HashSet<string> FieldNames = new HashSet<string>();
private bool queryProcessed;

public override object VisitQueryFromClause(QueryFromClause queryFromClause, object data)
public override object VisitQuerySelectClause(QuerySelectClause querySelectClause, object data)
{
throw new NotSupportedException();
ProcessQuery(querySelectClause.Expression);
return base.VisitQuerySelectClause(querySelectClause, data);
}


Expand All @@ -26,18 +28,44 @@ public void Clear()
FieldNames.Clear();
}

/*

public override object VisitQueryExpressionSelectClause(QueryExpressionSelectClause queryExpressionSelectClause,
object data)
private void ProcessQuery(AstNode queryExpressionSelectClause)
{
ProcessQuery(queryExpressionSelectClause.Projection);
return base.VisitQueryExpressionSelectClause(queryExpressionSelectClause, data);
var objectCreateExpression = QueryParsingUtils.GetAnonymousCreateExpression(queryExpressionSelectClause) as AnonymousTypeCreateExpression;
if (objectCreateExpression == null)
return;

// we only want the outer most value
if (queryProcessed)
return;

queryProcessed = true;

foreach (var expression in objectCreateExpression.Initializers.OfType<NamedArgumentExpression>())
{
FieldNames.Add(expression.Name);
}

foreach (var expression in objectCreateExpression.Initializers.OfType<NamedExpression>())
{
FieldNames.Add(expression.Name);
}


foreach (var expression in objectCreateExpression.Initializers.OfType<MemberReferenceExpression>())
{
FieldNames.Add(expression.MemberName);
}

foreach (var expression in objectCreateExpression.Initializers.OfType<IdentifierExpression>())
{
FieldNames.Add(expression.Identifier);
}
}

public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
var memberReferenceExpression = invocationExpression.TargetObject as MemberReferenceExpression;
var memberReferenceExpression = invocationExpression.Target as MemberReferenceExpression;

if (memberReferenceExpression == null)
return base.VisitInvocationExpression(invocationExpression, data);
Expand All @@ -48,12 +76,12 @@ public override object VisitInvocationExpression(InvocationExpression invocation
case "Select":
if (invocationExpression.Arguments.Count != 1)
return base.VisitInvocationExpression(invocationExpression, data);
lambdaExpression = invocationExpression.Arguments[0].AsLambdaExpression();
lambdaExpression = invocationExpression.Arguments.First().AsLambdaExpression();
break;
case "SelectMany":
if (invocationExpression.Arguments.Count != 2)
return base.VisitInvocationExpression(invocationExpression, data);
lambdaExpression = invocationExpression.Arguments[1].AsLambdaExpression();
lambdaExpression = invocationExpression.Arguments.ElementAt(0).AsLambdaExpression();
break;
default:
return base.VisitInvocationExpression(invocationExpression, data);
Expand All @@ -62,47 +90,9 @@ public override object VisitInvocationExpression(InvocationExpression invocation
if (lambdaExpression == null)
return base.VisitInvocationExpression(invocationExpression, data);

ProcessQuery(lambdaExpression.ExpressionBody);
ProcessQuery(lambdaExpression.Body);

return base.VisitInvocationExpression(invocationExpression, data);
}
private void ProcessQuery(Expression queryExpressionSelectClause)
{
var objectCreateExpression = QueryParsingUtils.GetAnonymousCreateExpression(queryExpressionSelectClause) as ObjectCreateExpression;
if (objectCreateExpression == null ||
objectCreateExpression.IsAnonymousType == false)
return;
// we only want the outer most value
if (queryProcessed)
return;
queryProcessed = true;
foreach (
var expression in
objectCreateExpression.ObjectInitializer.CreateExpressions.OfType<NamedArgumentExpression>())
{
FieldNames.Add(expression.Name);
}
foreach (
var expression in
objectCreateExpression.ObjectInitializer.CreateExpressions.OfType<MemberReferenceExpression>())
{
FieldNames.Add(expression.MemberName);
}
foreach (
var expression in
objectCreateExpression.ObjectInitializer.CreateExpressions.OfType<IdentifierExpression>())
{
FieldNames.Add(expression.Identifier);
}
}
*/
}
}
Expand Up @@ -27,7 +27,7 @@ public override object VisitInvocationExpression(InvocationExpression invocation
invocationExpression.Arguments.Add(memberReferenceExpression.Target);
var newInvocation = new InvocationExpression(
new MemberReferenceExpression(
new TypeReferenceExpression(AstType.Create(typeof (DynamicExtensionMethods))),
new TypeReferenceExpression(new SimpleType(typeof (DynamicExtensionMethods).FullName)),
memberReferenceExpression.MemberName),
invocationExpression.Arguments
);
Expand Down
50 changes: 26 additions & 24 deletions Raven.Database/Linq/Ast/ThrowOnInvalidMethodCalls.cs
@@ -1,16 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using ICSharpCode.NRefactory.CSharp;

namespace Raven.Database.Linq.Ast
{
public class ThrowOnInvalidMethodCalls : DepthFirstAstVisitor<object,object>
{
public override object VisitQueryFromClause(QueryFromClause queryFromClause, object data)
{
throw new NotSupportedException();
}

/*public class ForbiddenMethod
public class ForbiddenMethod
{
public string[] TypeAliases;
public string[] Names;
Expand All @@ -34,33 +32,26 @@ public ForbiddenMethod(string[] names, string[] typeAliases, string error)
Using {0} invalidate that premise, and is not allowed"),
};

public override object VisitQueryExpressionOrderClause(QueryExpressionOrderClause queryExpressionOrderClause, object data)
public override object VisitQueryOrderClause(QueryOrderClause queryOrderClause, object data)
{
var text = QueryParsingUtils.ToText(queryExpressionOrderClause);
var text = QueryParsingUtils.ToText(queryOrderClause);
throw new InvalidOperationException(
@"OrderBy calls are not valid during map or reduce phase, but the following was found:
" + text + @"
OrderBy calls modify the indexing output, but doesn't actually impact the order of results returned from the database.
You should be calling OrderBy on the QUERY, not on the index, if you want to specify ordering.");
}

public override object VisitQueryExpressionLetClause(QueryExpressionLetClause queryExpressionLetClause, object data)
public override object VisitQueryLetClause(QueryLetClause queryLetClause, object data)
{
if (SimplifyLetExpression(queryExpressionLetClause.Expression) is LambdaExpression)

if (SimplifyLetExpression(queryLetClause.Expression) is LambdaExpression)
{
var text = QueryParsingUtils.ToText(queryExpressionLetClause);
var text = QueryParsingUtils.ToText(queryLetClause);
throw new SecurityException("Let expression cannot contain labmda expressions, but got: " + text);
}

return base.VisitQueryExpressionLetClause(queryExpressionLetClause, data);
}
public override object VisitLambdaExpression(LambdaExpression lambdaExpression, object data)
{
if (lambdaExpression.StatementBody == null || lambdaExpression.StatementBody.IsNull)
return base.VisitLambdaExpression(lambdaExpression, data);
var text = QueryParsingUtils.ToText(lambdaExpression);
throw new SecurityException("Lambda expression can only consist of a single expression, not a statement, but got: " + text);
return base.VisitQueryLetClause(queryLetClause, data);
}

private Expression SimplifyLetExpression(Expression expression)
Expand All @@ -74,12 +65,23 @@ private Expression SimplifyLetExpression(Expression expression)
return expression;
}

public override object VisitLambdaExpression(LambdaExpression lambdaExpression, object data)
{
if (lambdaExpression.Body == null || lambdaExpression.Body.IsNull)
return base.VisitLambdaExpression(lambdaExpression, data);
if(lambdaExpression.Body is BlockStatement == false)
return base.VisitLambdaExpression(lambdaExpression, data);

var text = QueryParsingUtils.ToText(lambdaExpression);
throw new SecurityException("Lambda expression can only consist of a single expression, not a statement, but got: " + text);
}

public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data)
{
foreach (var forbidden in Members.Where(x => x.Names.Contains(memberReferenceExpression.MemberName)))
{
var identifierExpression = GetTarget(memberReferenceExpression);
if(forbidden.TypeAliases.Contains(identifierExpression) == false)
if (forbidden.TypeAliases.Contains(identifierExpression) == false)
continue;

var text = QueryParsingUtils.ToText(memberReferenceExpression);
Expand All @@ -91,15 +93,15 @@ public override object VisitMemberReferenceExpression(MemberReferenceExpression

private static string GetTarget(MemberReferenceExpression memberReferenceExpression)
{
var identifierExpression = memberReferenceExpression.TargetObject as IdentifierExpression;
var identifierExpression = memberReferenceExpression.Target as IdentifierExpression;
if(identifierExpression!=null)
return identifierExpression.Identifier;

var mre = memberReferenceExpression.TargetObject as MemberReferenceExpression;
var mre = memberReferenceExpression.Target as MemberReferenceExpression;
if(mre != null)
return GetTarget(mre) + "." + mre.MemberName;

return null;
}*/
}
}
}

0 comments on commit 1d8b035

Please sign in to comment.