1using System.Linq.Expressions;
2using System.Reflection;
8internal class SubQuerySwitch : DefaultExpressionSwitch<Query>
10 private readonly LookupTable _lookup;
12 public SubQuerySwitch(LookupTable lookup)
17 protected override Query ApplyDefault(Expression? expr) =>
18 throw IQuerySource.Fail(expr);
20 protected override Query ConstantExpr(ConstantExpression expr)
24 return QH.CollectionAll(col);
28 return QH.CollectionIndex(idx);
32 return QH.Const(expr.Value);
36 protected override Query LambdaExpr(LambdaExpression expr)
38 var ps = expr.Parameters;
39 var pinner =
string.Join(
", ", ps.Select(p => p.Name));
40 var param = ps.Count() == 1 ? pinner : $
"({pinner})";
41 var arrow =
QH.Expr($
"{param} =>");
43 return arrow.Concat(
QH.Parens(Apply(expr.Body)));
46 protected override Query ParameterExpr(ParameterExpression expr) =>
QH.Expr(expr.Name!);
48 protected override Query BinaryExpr(BinaryExpression expr)
50 var op = expr.NodeType
switch
52 ExpressionType.Add =>
"+",
53 ExpressionType.AddChecked =>
"+",
54 ExpressionType.And =>
"&",
55 ExpressionType.AndAlso =>
"&&",
57 ExpressionType.Coalesce =>
"??",
58 ExpressionType.Divide =>
"/",
59 ExpressionType.Equal =>
"==",
60 ExpressionType.ExclusiveOr =>
"^",
61 ExpressionType.GreaterThan =>
">",
62 ExpressionType.GreaterThanOrEqual =>
">=",
63 ExpressionType.LeftShift =>
"<<",
64 ExpressionType.LessThan =>
"<",
65 ExpressionType.LessThanOrEqual =>
"<=",
66 ExpressionType.Modulo =>
"%",
67 ExpressionType.Multiply =>
"*",
68 ExpressionType.MultiplyChecked =>
"*",
69 ExpressionType.NotEqual =>
"!=",
70 ExpressionType.Or =>
"|",
71 ExpressionType.OrElse =>
"||",
72 ExpressionType.Power =>
"**",
73 ExpressionType.RightShift =>
">>",
74 ExpressionType.Subtract =>
"-",
75 ExpressionType.SubtractChecked =>
"-",
76 _ =>
throw IQuerySource.Fail(expr)
79 var lhs = Apply(expr.Left);
80 var rhs = Apply(expr.Right);
82 return QH.Parens(
QH.Op(lhs, op, rhs));
85 protected override Query CallExpr(MethodCallExpression expr)
87 var (callee, args, ext) = Expressions.GetCalleeAndArgs(expr);
88 var name = _lookup.MethodLookup(expr.Method, callee)?.Name;
89 if (name is
null)
throw IQuerySource.Fail(expr);
90 return QH.MethodCall(Apply(callee), name, ApplyAll(args));
93 protected override Query MemberAccessExpr(MemberExpression expr)
95 var callee = expr.Expression;
98 var val = Expression.Lambda(expr).Compile().DynamicInvoke();
101 else if (callee.Type.IsClosureType())
103 var val = Expression.Lambda(expr).Compile().DynamicInvoke();
104 return QH.Const(val);
107 switch (Apply(callee))
110 var c = Expression.Constant(v.Unwrap);
111 var access = Expression.PropertyOrField(c, expr.Member.Name);
112 var val = Expression.Lambda(access).Compile().DynamicInvoke();
113 return QH.Const(val);
116 var name = expr.Member is PropertyInfo prop ?
117 _lookup.FieldLookup(prop, callee)?.Name :
120 if (name is
null)
throw IQuerySource.Fail(expr);
121 return QH.FieldAccess(q, name);
Fauna.Linq.IntermediateQueryHelpers QH
Represents the abstract base class for constructing FQL queries.
Represents a generic value holder for FQL queries. This class allows embedding values of various type...