|
//---------------------------------------------------------------------
// <copyright file="PropertyRef.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
//using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
// It is fine to use Debug.Assert in cases where you assert an obvious thing that is supposed
// to prevent from simple mistakes during development (e.g. method argument validation
// in cases where it was you who created the variables or the variables had already been validated or
// in "else" clauses where due to code changes (e.g. adding a new value to an enum type) the default
// "else" block is chosen why the new condition should be treated separately). This kind of asserts are
// (can be) helpful when developing new code to avoid simple mistakes but have no or little value in
// the shipped product.
// PlanCompiler.Assert *MUST* be used to verify conditions in the trees. These would be assumptions
// about how the tree was built etc. - in these cases we probably want to throw an exception (this is
// what PlanCompiler.Assert does when the condition is not met) if either the assumption is not correct
// or the tree was built/rewritten not the way we thought it was.
// Use your judgment - if you rather remove an assert than ship it use Debug.Assert otherwise use
// PlanCompiler.Assert.
using System.Globalization;
using System.Data.Common;
using md = System.Data.Metadata.Edm;
//
// The PropertyRef class (and its subclasses) represent references to a property
// of a type.
// The PropertyRefList class represents a list of expected properties
// where each property from the type is described as a PropertyRef
//
// These classes are used by the StructuredTypeEliminator module as part of
// eliminating all structured types. The basic idea of this module is that all
// structured types are flattened out into a single level. To avoid a large amount
// of potentially unnecessary information, we try to identify what pieces of information
// are really necessary at each node of the tree. This is where PropertyRef comes in.
// A PropertyRef (and more generally, a PropertyRefList) identifies a list of
// properties, and can be attached to a node/var to indicate that these were the
// only desired properties.
//
namespace System.Data.Query.PlanCompiler
{
/// <summary>
/// A PropertyRef class encapsulates a reference to one or more properties of
/// a complex instance - a record type, a complex type or an entity type.
/// A PropertyRef may be of the following kinds.
/// - a simple property reference (just a reference to a simple property)
/// - a typeid reference - applies only to entitytype and complextypes
/// - an entitysetid reference - applies only to ref and entity types
/// - a nested property reference (a reference to a nested property - a.b)
/// - an "all" property reference (all properties)
/// </summary>
internal abstract class PropertyRef
{
/// <summary>
/// trivial constructor
/// </summary>
internal PropertyRef() { }
/// <summary>
/// Create a nested property ref, with "p" as the prefix.
/// The best way to think of this function as follows.
/// Consider a type T where "this" describes a property X on T. Now
/// consider a new type S, where "p" is a property of S and is of type T.
/// This function creates a PropertyRef that describes the same property X
/// from S.p instead
/// </summary>
/// <param name="p">the property to prefix with</param>
/// <returns>the nested property reference</returns>
internal virtual PropertyRef CreateNestedPropertyRef(PropertyRef p)
{
return new NestedPropertyRef(p, this);
}
/// <summary>
/// Create a nested property ref for a simple property. Delegates to the function
/// above
/// </summary>
/// <param name="p">the simple property</param>
/// <returns>a nestedPropertyRef</returns>
internal PropertyRef CreateNestedPropertyRef(md.EdmMember p)
{
return CreateNestedPropertyRef(new SimplePropertyRef(p));
}
/// <summary>
/// Creates a nested property ref for a rel-property. Delegates to the function above
/// </summary>
/// <param name="p">the rel-property</param>
/// <returns>a nested property ref</returns>
internal PropertyRef CreateNestedPropertyRef(InternalTrees.RelProperty p)
{
return CreateNestedPropertyRef(new RelPropertyRef(p));
}
/// <summary>
/// The tostring method for easy debuggability
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "";
}
}
/// <summary>
/// A "simple" property ref - represents a simple property of the type
/// </summary>
internal class SimplePropertyRef : PropertyRef
{
private md.EdmMember m_property;
/// <summary>
/// Simple constructor
/// </summary>
/// <param name="property">the property metadata</param>
internal SimplePropertyRef(md.EdmMember property)
{
m_property = property;
}
/// <summary>
/// Gets the property metadata
/// </summary>
internal md.EdmMember Property { get { return m_property; } }
/// <summary>
/// Overrides the default equality function. Two SimplePropertyRefs are
/// equal, if they describe the same property
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
SimplePropertyRef other = obj as SimplePropertyRef;
return (other != null &&
InternalTrees.Command.EqualTypes(m_property.DeclaringType, other.m_property.DeclaringType) &&
other.m_property.Name.Equals(this.m_property.Name));
}
/// <summary>
/// Overrides the default hashcode function.
/// Simply returns the hashcode for the property instead
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return m_property.Name.GetHashCode();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return m_property.Name;
}
}
/// <summary>
/// A TypeId propertyref represents a reference to the TypeId property
/// of a type (complex type, entity type etc.)
/// </summary>
internal class TypeIdPropertyRef : PropertyRef
{
private TypeIdPropertyRef() : base() { }
/// <summary>
/// Gets the default instance of this type
/// </summary>
internal static TypeIdPropertyRef Instance = new TypeIdPropertyRef();
/// <summary>
/// Friendly string for debugging.
/// </summary>
public override string ToString()
{
return "TYPEID";
}
}
/// <summary>
/// An NullSentinel propertyref represents the NullSentinel property for
/// a row type.
/// As with TypeId, this class is a singleton instance
/// </summary>
internal class NullSentinelPropertyRef : PropertyRef
{
private static NullSentinelPropertyRef s_singleton = new NullSentinelPropertyRef();
private NullSentinelPropertyRef() : base() { }
/// <summary>
/// Gets the singleton instance
/// </summary>
internal static NullSentinelPropertyRef Instance
{
get { return s_singleton; }
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "NULLSENTINEL";
}
}
/// <summary>
/// An EntitySetId propertyref represents the EntitySetId property for
/// an entity type or a ref type.
/// As with TypeId, this class is a singleton instance
/// </summary>
internal class EntitySetIdPropertyRef : PropertyRef
{
private EntitySetIdPropertyRef() : base() { }
/// <summary>
/// Gets the singleton instance
/// </summary>
internal static EntitySetIdPropertyRef Instance = new EntitySetIdPropertyRef();
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "ENTITYSETID";
}
}
/// <summary>
/// A nested propertyref describes a nested property access - think "a.b.c"
/// </summary>
internal class NestedPropertyRef : PropertyRef
{
private readonly PropertyRef m_inner;
private readonly PropertyRef m_outer;
/// <summary>
/// Basic constructor.
/// Represents the access of property "propertyRef" within property "property"
/// </summary>
/// <param name="innerProperty">the inner property</param>
/// <param name="outerProperty">the outer property</param>
internal NestedPropertyRef(PropertyRef innerProperty, PropertyRef outerProperty)
{
PlanCompiler.Assert(!(innerProperty is NestedPropertyRef), "innerProperty cannot be a NestedPropertyRef");
m_inner = innerProperty;
m_outer = outerProperty;
}
/// <summary>
/// the nested property
/// </summary>
internal PropertyRef OuterProperty { get { return m_outer; } }
/// <summary>
/// the parent property
/// </summary>
internal PropertyRef InnerProperty { get { return m_inner; } }
/// <summary>
/// Overrides the default equality function. Two NestedPropertyRefs are
/// equal if the have the same property name, and the types are the same
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
NestedPropertyRef other = obj as NestedPropertyRef;
return (other != null &&
m_inner.Equals(other.m_inner) &&
m_outer.Equals(other.m_outer));
}
/// <summary>
/// Overrides the default hashcode function. Simply adds the hashcodes
/// of the "property" and "propertyRef" fields
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return m_inner.GetHashCode() ^ m_outer.GetHashCode();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return m_inner + "." + m_outer;
}
}
/// <summary>
/// A reference to "all" properties of a type
/// </summary>
internal class AllPropertyRef : PropertyRef
{
private AllPropertyRef() : base() { }
/// <summary>
/// Get the singleton instance
/// </summary>
internal static AllPropertyRef Instance = new AllPropertyRef();
/// <summary>
/// Create a nested property ref, with "p" as the prefix
/// </summary>
/// <param name="p">the property to prefix with</param>
/// <returns>the nested property reference</returns>
internal override PropertyRef CreateNestedPropertyRef(PropertyRef p)
{
return p;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "ALL";
}
}
/// <summary>
/// A rel-property ref - represents a rel property of the type
/// </summary>
internal class RelPropertyRef : PropertyRef
{
#region private state
private InternalTrees.RelProperty m_property;
#endregion
#region constructor
/// <summary>
/// Simple constructor
/// </summary>
/// <param name="property">the property metadata</param>
internal RelPropertyRef(InternalTrees.RelProperty property)
{
m_property = property;
}
#endregion
#region public apis
/// <summary>
/// Gets the property metadata
/// </summary>
internal InternalTrees.RelProperty Property { get { return m_property; } }
/// <summary>
/// Overrides the default equality function. Two RelPropertyRefs are
/// equal, if they describe the same property
/// </summary>
/// <param name="obj">the other object to compare to</param>
/// <returns>true, if the objects are equal</returns>
public override bool Equals(object obj)
{
RelPropertyRef other = obj as RelPropertyRef;
return (other != null &&
m_property.Equals(other.m_property));
}
/// <summary>
/// Overrides the default hashcode function.
/// Simply returns the hashcode for the property instead
/// </summary>
/// <returns>hashcode for the relpropertyref</returns>
public override int GetHashCode()
{
return m_property.GetHashCode();
}
/// <summary>
/// debugging support
/// </summary>
/// <returns></returns>
public override string ToString()
{
return m_property.ToString();
}
#endregion
}
/// <summary>
/// Represents a collection of property references
/// </summary>
internal class PropertyRefList
{
private Dictionary<PropertyRef, PropertyRef> m_propertyReferences;
private bool m_allProperties;
/// <summary>
/// Get something that represents "all" property references
/// </summary>
internal static PropertyRefList All = new PropertyRefList(true);
/// <summary>
/// Trivial constructor
/// </summary>
internal PropertyRefList() : this(false) {}
private PropertyRefList(bool allProps)
{
this.m_propertyReferences = new Dictionary<PropertyRef, PropertyRef>();
if (allProps)
{
MakeAllProperties();
}
}
private void MakeAllProperties()
{
m_allProperties = true;
m_propertyReferences.Clear();
m_propertyReferences.Add(AllPropertyRef.Instance, AllPropertyRef.Instance);
}
/// <summary>
/// Add a new property reference to this list
/// </summary>
/// <param name="property">new property reference</param>
internal void Add(PropertyRef property)
{
if (m_allProperties)
return;
else if (property is AllPropertyRef)
MakeAllProperties();
else
m_propertyReferences[property] = property;
}
/// <summary>
/// Append an existing list of property references to myself
/// </summary>
/// <param name="propertyRefs">list of property references</param>
internal void Append(PropertyRefList propertyRefs)
{
if (m_allProperties)
return;
foreach (PropertyRef p in propertyRefs.m_propertyReferences.Keys)
{
this.Add(p);
}
}
/// <summary>
/// Do I contain "all" properties?
/// </summary>
internal bool AllProperties { get { return m_allProperties; } }
/// <summary>
/// Create a clone of myself
/// </summary>
/// <returns>a clone of myself</returns>
internal PropertyRefList Clone()
{
PropertyRefList newProps = new PropertyRefList(m_allProperties);
foreach (PropertyRef p in this.m_propertyReferences.Keys)
newProps.Add(p);
return newProps;
}
/// <summary>
/// Do I contain the specifed property?
/// </summary>
/// <param name="p">The property</param>
/// <returns>true, if I do</returns>
internal bool Contains(PropertyRef p)
{
return m_allProperties || m_propertyReferences.ContainsKey(p);
}
/// <summary>
/// Get the list of all properties
/// </summary>
internal IEnumerable<PropertyRef> Properties
{
get { return m_propertyReferences.Keys; }
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
string x = "{";
foreach (PropertyRef p in m_propertyReferences.Keys)
x += p.ToString() + ",";
x += "}";
return x;
}
}
}
|