|
//---------------------------------------------------------------------
// <copyright file="ExpressionDumper.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Data.Common;
using System.Data.Metadata.Edm;
using System.Data.Common.CommandTrees;
namespace System.Data.Common.CommandTrees.Internal
{
/// <summary>
/// Writes a description of a given expression, in a format determined by the specific implementation of a derived type
/// </summary>
internal abstract class ExpressionDumper : DbExpressionVisitor
{
#region Constructors
internal ExpressionDumper() { }
#endregion
#region (Pseudo) Public API
/// <summary>
/// Begins a new Dump block with the specified name
/// </summary>
/// <param name="name">The name of the block</param>
internal void Begin(string name) { Begin(name, (Dictionary<string, object>)null); }
/// <summary>
/// Begins a new Dump block with the specified name and specified attributes
/// </summary>
/// <param name="name">The name of the block</param>
/// <param name="attrs">The named attributes of the block. May be null</param>
internal abstract void Begin(string name, Dictionary<string, object> attrs);
/// <summary>
/// Ends the Dump block with the specified name.
/// The caller should not assumer that this name will be verified
/// against the last name used in a Begin call.
/// </summary>
/// <param name="name">The name of the block</param>
internal abstract void End(string name);
/// <summary>
/// Dumps a DbExpression by visiting it.
/// </summary>
/// <param name="target">The DbExpression to dump</param>
internal void Dump(DbExpression target)
{
target.Accept(this);
}
/// <summary>
/// Dumps a DbExpression with the specified block name preceeding and succeeding (decorating) it.
/// </summary>
/// <param name="e">The DbExpression to dump</param>
/// <param name="name">The decorating block name</param>
internal void Dump(DbExpression e, string name)
{
Begin(name);
Dump(e);
End(name);
}
/// <summary>
/// Dumps a DbExpressionBinding with the specified decoration
/// </summary>
/// <param name="binding">The DbExpressionBinding to dump</param>
/// <param name="name">The decorating block name</param>
internal void Dump(DbExpressionBinding binding, string name)
{
Begin(name);
Dump(binding);
End(name);
}
/// <summary>
/// Dumps a DbExpressionBinding including its VariableName and DbExpression
/// </summary>
/// <param name="binding">The DbExpressionBinding to dump</param>
internal void Dump(DbExpressionBinding binding)
{
Begin("DbExpressionBinding", "VariableName", binding.VariableName);
Begin("Expression");
Dump(binding.Expression);
End("Expression");
End("DbExpressionBinding");
}
/// <summary>
/// Dumps a DbGroupExpressionBinding with the specified decoration
/// </summary>
/// <param name="binding">The DbGroupExpressionBinding to dump</param>
/// <param name="name">The decorating block name</param>
internal void Dump(DbGroupExpressionBinding binding, string name)
{
Begin(name);
Dump(binding);
End(name);
}
/// <summary>
/// Dumps a DbGroupExpressionBinding including its VariableName, GroupVariableName and DbExpression
/// </summary>
/// <param name="binding">The DbGroupExpressionBinding to dump</param>
internal void Dump(DbGroupExpressionBinding binding)
{
Begin("DbGroupExpressionBinding", "VariableName", binding.VariableName, "GroupVariableName", binding.GroupVariableName);
Begin("Expression");
Dump(binding.Expression);
End("Expression");
End("DbGroupExpressionBinding");
}
/// <summary>
/// Dumps each DbExpression in the specified enumerable. The entire output is decorated with the 'pluralName'
/// block name while each element DbExpression is decorated with the 'singularName' block name.
/// If the list is empty only the pluralName decoration start/end will appear.
/// </summary>
/// <param name="exprs">The enumerable list of Expressions to dump</param>
/// <param name="pluralName">The overall list decoration block name</param>
/// <param name="singularName">The decoration block name that will be applied to each element DbExpression</param>
internal void Dump(IEnumerable<DbExpression> exprs, string pluralName, string singularName)
{
Begin(pluralName);
foreach (DbExpression expr in exprs)
{
Begin(singularName);
this.Dump(expr);
End(singularName);
}
End(pluralName);
}
/// <summary>
/// Dumps each Parameter metadata in the specified enumerable. The entire output is decorated with the "Parameters"
/// block name while each metadata element is decorated with the "Parameter" block name.
/// If the list is empty only the "Parameters" decoration start/end will appear.
/// </summary>
/// <param name="paramList">The enumerable list of Parameter metadata to dump</param>
internal void Dump(IEnumerable<FunctionParameter> paramList)
{
Begin("Parameters");
foreach (FunctionParameter param in paramList)
{
Begin("Parameter", "Name", param.Name);
Dump(param.TypeUsage, "ParameterType");
End("Parameter");
}
End("Parameters");
}
/// <summary>
/// Dumps the specified Type metadata instance with the specified decoration
/// </summary>
/// <param name="type">The Type metadata to dump</param>
/// <param name="name">The decorating block name</param>
internal void Dump(TypeUsage type, string name)
{
Begin(name);
Dump(type);
End(name);
}
/// <summary>
/// Dumps the specified Type metadata instance
/// </summary>
/// <param name="type">The Type metadata to dump</param>
internal void Dump(TypeUsage type)
{
Dictionary<string, object> facetInfo = new Dictionary<string, object>();
foreach (Facet facet in type.Facets)
{
facetInfo.Add(facet.Name, facet.Value);
}
Begin("TypeUsage", facetInfo);
Dump(type.EdmType);
End("TypeUsage");
}
/// <summary>
/// Dumps the specified EDM type metadata instance with the specified decoration
/// </summary>
/// <param name="type">The type metadata to dump</param>
/// <param name="name">The decorating block name</param>
internal void Dump(EdmType type, string name)
{
Begin(name);
Dump(type);
End(name);
}
/// <summary>
/// Dumps the specified type metadata instance
/// </summary>
/// <param name="type">The type metadata to dump</param>
internal void Dump(EdmType type)
{
Begin("EdmType",
"BuiltInTypeKind", Enum.GetName(typeof(BuiltInTypeKind), type.BuiltInTypeKind),
"Namespace", type.NamespaceName,
"Name", type.Name);
End("EdmType");
}
/// <summary>
/// Dumps the specified Relation metadata instance with the specified decoration
/// </summary>
/// <param name="type">The Relation metadata to dump</param>
/// <param name="name">The decorating block name</param>
internal void Dump(RelationshipType type, string name)
{
Begin(name);
Dump(type);
End(name);
}
/// <summary>
/// Dumps the specified Relation metadata instance
/// </summary>
/// <param name="type">The Relation metadata to dump</param>
internal void Dump(RelationshipType type)
{
Begin(
"RelationshipType",
"Namespace", type.NamespaceName,
"Name",
type.Name
);
End("RelationshipType");
}
/// <summary>
/// Dumps the specified EdmFunction metadata instance
/// </summary>
/// <param name="function">The EdmFunction metadata to dump.</param>
internal void Dump(EdmFunction function)
{
Begin("Function", "Name", function.Name, "Namespace", function.NamespaceName);
Dump(function.Parameters);
if (function.ReturnParameters.Count == 1)
{
Dump(function.ReturnParameters[0].TypeUsage, "ReturnType");
}
else
{
Begin("ReturnTypes");
foreach (var returnParameter in function.ReturnParameters)
{
Dump(returnParameter.TypeUsage, returnParameter.Name);
}
End("ReturnTypes");
}
End("Function");
}
/// <summary>
/// Dumps the specified EdmProperty metadata instance
/// </summary>
/// <param name="prop">The EdmProperty metadata to dump</param>
internal void Dump(EdmProperty prop)
{
Begin("Property", "Name", prop.Name, "Nullable", prop.Nullable);
Dump(prop.DeclaringType, "DeclaringType");
Dump(prop.TypeUsage, "PropertyType");
End("Property");
}
/// <summary>
/// Dumps the specified Relation End EdmMember metadata instance with the specified decoration
/// </summary>
/// <param name="end">The Relation End metadata to dump</param>
/// <param name="name">The decorating block name</param>
internal void Dump(RelationshipEndMember end, string name)
{
Begin(name);
Begin(
"RelationshipEndMember",
"Name", end.Name,
//"IsParent", end.IsParent,
"RelationshipMultiplicity", Enum.GetName(typeof(RelationshipMultiplicity), end.RelationshipMultiplicity)
);
Dump(end.DeclaringType, "DeclaringRelation");
Dump(end.TypeUsage, "EndType");
End("RelationshipEndMember");
End(name);
}
/// <summary>
/// Dumps the specified Navigation Property EdmMember metadata instance with the specified decoration
/// </summary>
/// <param name="navProp">The Navigation Property metadata to dump</param>
/// <param name="name">The decorating block name</param>
internal void Dump(NavigationProperty navProp, string name)
{
Begin(name);
Begin(
"NavigationProperty",
"Name", navProp.Name,
//"IsParent", end.IsParent,
"RelationshipTypeName", navProp.RelationshipType.FullName,
"ToEndMemberName", navProp.ToEndMember.Name
);
Dump(navProp.DeclaringType, "DeclaringType");
Dump(navProp.TypeUsage, "PropertyType");
End("NavigationProperty");
End(name);
}
#if METHOD_EXPRESSION
/// <summary>
/// Dumps the specified Method metadata instance
/// </summary>
/// <param name="meth">The Method metadata to dump</param>
internal void Dump(MethodMetadata meth)
{
Begin("MethodMetadata", "Name", meth.Name, "IsStatic", meth.IsStatic);
Dump(meth.DefiningType, "DeclaringType");
Dump(meth.Parameters);
Dump(meth.Type, "ReturnType");
End("MethodMetadata");
}
#endif
/// <summary>
/// Dumps the specified DbLambda instance
/// </summary>
/// <param name="lambda">The DbLambda to dump.</param>
internal void Dump(DbLambda lambda)
{
Begin("DbLambda");
Dump(System.Linq.Enumerable.Cast<DbExpression>(lambda.Variables), "Variables", "Variable");
Dump(lambda.Body, "Body");
End("DbLambda");
}
#endregion
#region Private Implementation
private void Begin(DbExpression expr)
{
Begin(expr, new Dictionary<string, object>());
}
private void Begin(DbExpression expr, Dictionary<string, object> attrs)
{
attrs.Add("DbExpressionKind", Enum.GetName(typeof(DbExpressionKind), expr.ExpressionKind));
Begin(expr.GetType().Name, attrs);
Dump(expr.ResultType, "ResultType");
}
private void Begin(DbExpression expr, string attributeName, object attributeValue)
{
Dictionary<string, object> attrs = new Dictionary<string, object>();
attrs.Add(attributeName, attributeValue);
Begin(expr, attrs);
}
private void Begin(string expr, string attributeName, object attributeValue)
{
Dictionary<string, object> attrs = new Dictionary<string, object>();
attrs.Add(attributeName, attributeValue);
Begin(expr, attrs);
}
private void Begin(string expr,
string attributeName1,
object attributeValue1,
string attributeName2,
object attributeValue2)
{
Dictionary<string, object> attrs = new Dictionary<string, object>();
attrs.Add(attributeName1, attributeValue1);
attrs.Add(attributeName2, attributeValue2);
Begin(expr, attrs);
}
private void Begin(string expr,
string attributeName1,
object attributeValue1,
string attributeName2,
object attributeValue2,
string attributeName3,
object attributeValue3)
{
Dictionary<string, object> attrs = new Dictionary<string, object>();
attrs.Add(attributeName1, attributeValue1);
attrs.Add(attributeName2, attributeValue2);
attrs.Add(attributeName3, attributeValue3);
Begin(expr, attrs);
}
private void End(DbExpression expr)
{
End(expr.GetType().Name);
}
private void BeginUnary(DbUnaryExpression e)
{
Begin(e);
Begin("Argument");
Dump(e.Argument);
End("Argument");
}
private void BeginBinary(DbBinaryExpression e)
{
Begin(e);
Begin("Left");
Dump(e.Left);
End("Left");
Begin("Right");
Dump(e.Right);
End("Right");
}
#endregion
#region DbExpressionVisitor<DbExpression> Members
public override void Visit(DbExpression e)
{
Begin(e);
End(e);
}
public override void Visit(DbConstantExpression e)
{
Dictionary<string, object> attrs = new Dictionary<string,object>();
attrs.Add("Value", e.Value);
Begin(e, attrs);
End(e);
}
public override void Visit(DbNullExpression e)
{
Begin(e);
End(e);
}
public override void Visit(DbVariableReferenceExpression e)
{
Dictionary<string, object> attrs = new Dictionary<string, object>();
attrs.Add("VariableName", e.VariableName);
Begin(e, attrs);
End(e);
}
public override void Visit(DbParameterReferenceExpression e)
{
Dictionary<string, object> attrs = new Dictionary<string, object>();
attrs.Add("ParameterName", e.ParameterName);
Begin(e, attrs);
End(e);
}
public override void Visit(DbFunctionExpression e)
{
Begin(e);
Dump(e.Function);
Dump(e.Arguments, "Arguments", "Argument");
End(e);
}
public override void Visit(DbLambdaExpression expression)
{
Begin(expression);
Dump(expression.Lambda);
Dump(expression.Arguments, "Arguments", "Argument");
End(expression);
}
#if METHOD_EXPRESSION
public override void Visit(MethodExpression e)
{
Begin(e);
Dump(e.Method);
Dump(e.Arguments, "Arguments", "Argument");
if (e.Instance != null)
{
Dump(e.Instance, "Instance");
}
End(e);
}
#endif
public override void Visit(DbPropertyExpression e)
{
//
// Currently the DbPropertyExpression.EdmProperty member property may only be either:
// - EdmProperty
// - RelationshipEndMember
// - NavigationProperty
//
Begin(e);
RelationshipEndMember end = e.Property as RelationshipEndMember;
if (end != null)
{
Dump(end, "Property");
}
else if (Helper.IsNavigationProperty(e.Property))
{
Dump((NavigationProperty)e.Property, "Property");
}
else
{
Dump((EdmProperty)e.Property);
}
if (e.Instance != null)
{
Dump(e.Instance, "Instance");
}
End(e);
}
public override void Visit(DbComparisonExpression e)
{
BeginBinary(e);
End(e);
}
public override void Visit(DbLikeExpression e)
{
Begin(e);
Dump(e.Argument, "Argument");
Dump(e.Pattern, "Pattern");
Dump(e.Escape, "Escape");
End(e);
}
public override void Visit(DbLimitExpression e)
{
Begin(e, "WithTies", e.WithTies);
Dump(e.Argument, "Argument");
Dump(e.Limit, "Limit");
End(e);
}
public override void Visit(DbIsNullExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbArithmeticExpression e)
{
Begin(e);
Dump(e.Arguments, "Arguments", "Argument");
End(e);
}
public override void Visit(DbAndExpression e)
{
BeginBinary(e);
End(e);
}
public override void Visit(DbOrExpression e)
{
BeginBinary(e);
End(e);
}
public override void Visit(DbNotExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbDistinctExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbElementExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbIsEmptyExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbUnionAllExpression e)
{
BeginBinary(e);
End(e);
}
public override void Visit(DbIntersectExpression e)
{
BeginBinary(e);
End(e);
}
public override void Visit(DbExceptExpression e)
{
BeginBinary(e);
End(e);
}
public override void Visit(DbTreatExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbIsOfExpression e)
{
BeginUnary(e);
Dump(e.OfType, "OfType") ;
End(e);
}
public override void Visit(DbCastExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbCaseExpression e)
{
Begin(e);
Dump(e.When, "Whens", "When");
Dump(e.Then, "Thens", "Then");
Dump(e.Else, "Else");
}
public override void Visit(DbOfTypeExpression e)
{
BeginUnary(e);
Dump(e.OfType, "OfType");
End(e);
}
public override void Visit(DbNewInstanceExpression e)
{
Begin(e);
Dump(e.Arguments, "Arguments", "Argument");
if (e.HasRelatedEntityReferences)
{
Begin("RelatedEntityReferences");
foreach (DbRelatedEntityRef relatedRef in e.RelatedEntityReferences)
{
Begin("DbRelatedEntityRef");
Dump(relatedRef.SourceEnd, "SourceEnd");
Dump(relatedRef.TargetEnd, "TargetEnd");
Dump(relatedRef.TargetEntityReference, "TargetEntityReference");
End("DbRelatedEntityRef");
}
End("RelatedEntityReferences");
}
End(e);
}
public override void Visit(DbRelationshipNavigationExpression e)
{
Begin(e);
Dump(e.NavigateFrom, "NavigateFrom");
Dump(e.NavigateTo, "NavigateTo");
Dump(e.Relationship, "Relationship");
Dump(e.NavigationSource, "NavigationSource");
End(e);
}
public override void Visit(DbRefExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbDerefExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbRefKeyExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbEntityRefExpression e)
{
BeginUnary(e);
End(e);
}
public override void Visit(DbScanExpression e)
{
Begin(e);
Begin("Target", "Name", e.Target.Name, "Container", e.Target.EntityContainer.Name);
Dump(e.Target.ElementType, "TargetElementType");
End("Target");
End(e);
}
public override void Visit(DbFilterExpression e)
{
Begin(e);
Dump(e.Input, "Input");
Dump(e.Predicate, "Predicate");
End(e);
}
public override void Visit(DbProjectExpression e)
{
Begin(e);
Dump(e.Input, "Input");
Dump(e.Projection, "Projection");
End(e);
}
public override void Visit(DbCrossJoinExpression e)
{
Begin(e);
Begin("Inputs");
foreach (DbExpressionBinding binding in e.Inputs)
{
Dump(binding, "Input");
}
End("Inputs");
End(e);
}
public override void Visit(DbJoinExpression e)
{
Begin(e);
Dump(e.Left, "Left");
Dump(e.Right, "Right");
Dump(e.JoinCondition, "JoinCondition");
End(e);
}
public override void Visit(DbApplyExpression e)
{
Begin(e);
Dump(e.Input, "Input");
Dump(e.Apply, "Apply");
End(e);
}
public override void Visit(DbGroupByExpression e)
{
Begin(e);
Dump(e.Input, "Input");
Dump(e.Keys, "Keys", "Key");
Begin("Aggregates");
foreach (DbAggregate agg in e.Aggregates)
{
DbFunctionAggregate funcAgg = agg as DbFunctionAggregate;
if (funcAgg != null)
{
Begin("DbFunctionAggregate");
Dump(funcAgg.Function);
Dump(funcAgg.Arguments, "Arguments", "Argument");
End("DbFunctionAggregate");
}
else
{
DbGroupAggregate groupAgg = agg as DbGroupAggregate;
Debug.Assert(groupAgg != null, "Invalid DbAggregate");
Begin("DbGroupAggregate");
Dump(groupAgg.Arguments, "Arguments", "Argument");
End("DbGroupAggregate");
}
}
End("Aggregates");
End(e);
}
protected virtual void Dump(IList<DbSortClause> sortOrder)
{
Begin("SortOrder");
foreach (DbSortClause clause in sortOrder)
{
string collStr = clause.Collation;
if (null == collStr)
{
collStr = "";
}
Begin("DbSortClause", "Ascending", clause.Ascending, "Collation", collStr);
Dump(clause.Expression, "Expression");
End("DbSortClause");
}
End("SortOrder");
}
public override void Visit(DbSkipExpression e)
{
Begin(e);
Dump(e.Input, "Input");
Dump(e.SortOrder);
Dump(e.Count, "Count");
End(e);
}
public override void Visit(DbSortExpression e)
{
Begin(e);
Dump(e.Input, "Input");
Dump(e.SortOrder);
End(e);
}
public override void Visit(DbQuantifierExpression e)
{
Begin(e);
Dump(e.Input, "Input");
Dump(e.Predicate, "Predicate");
End(e);
}
#endregion
}
}
|