//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Data.Common.CommandTrees;
using System.Data.Common.CommandTrees.ExpressionBuilder;
using System.Data.Common.Utils;
using System.Data.Metadata.Edm;
using System.Data.Mapping.ViewGeneration.CqlGeneration;
using System.Data.Mapping.ViewGeneration.Utils;
namespace System.Data.Mapping.ViewGeneration.Structures
{
///
/// A wrapper around MemberPath that allows members to be marked as ProjectedSlots.
///
internal sealed class MemberProjectedSlot : ProjectedSlot
{
#region Constructor
///
/// Creates a projected slot that references the relevant celltree node.
///
internal MemberProjectedSlot(MemberPath node)
{
m_memberPath = node;
}
#endregion
#region Fields
private readonly MemberPath m_memberPath;
#endregion
#region Properties
///
/// Returns the full metadata path from the root extent to this node, e.g., Person.Adrs.zip
///
internal MemberPath MemberPath
{
get { return m_memberPath; }
}
#endregion
#region Methods
internal override StringBuilder AsEsql(StringBuilder builder, MemberPath outputMember, string blockAlias, int indentLevel)
{
TypeUsage outputMemberStoreTypeUsage;
if (NeedToCastCqlValue(outputMember, out outputMemberStoreTypeUsage))
{
builder.Append("CAST(");
m_memberPath.AsEsql(builder, blockAlias);
builder.Append(" AS ");
CqlWriter.AppendEscapedTypeName(builder, outputMemberStoreTypeUsage.EdmType);
builder.Append(')');
}
else
{
m_memberPath.AsEsql(builder, blockAlias);
}
return builder;
}
internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember)
{
DbExpression cqt = m_memberPath.AsCqt(row);
TypeUsage outputMemberTypeUsage;
if (NeedToCastCqlValue(outputMember, out outputMemberTypeUsage))
{
cqt = cqt.CastTo(outputMemberTypeUsage);
}
return cqt;
}
///
/// True iff and types do not match,
/// We assume that the mapping loader has already checked that the casts are ok and emitted warnings.
///
private bool NeedToCastCqlValue(MemberPath outputMember, out TypeUsage outputMemberTypeUsage)
{
TypeUsage memberPathTypeUsage = Helper.GetModelTypeUsage(m_memberPath.LeafEdmMember);
outputMemberTypeUsage = Helper.GetModelTypeUsage(outputMember.LeafEdmMember);
return !memberPathTypeUsage.EdmType.Equals(outputMemberTypeUsage.EdmType);
}
internal override void ToCompactString(StringBuilder builder)
{
m_memberPath.ToCompactString(builder);
}
internal string ToUserString()
{
return m_memberPath.PathToString(false);
}
protected override bool IsEqualTo(ProjectedSlot right)
{
MemberProjectedSlot rightSlot = right as MemberProjectedSlot;
if (rightSlot == null)
{
return false;
}
// We want equality of the paths
return MemberPath.EqualityComparer.Equals(m_memberPath, rightSlot.m_memberPath);
}
protected override int GetHash()
{
return MemberPath.EqualityComparer.GetHashCode(m_memberPath);
}
///
/// Given a slot and the new mapping, returns the corresponding new slot.
///
internal MemberProjectedSlot RemapSlot(Dictionary remap)
{
MemberPath remappedNode = null;
if (remap.TryGetValue(MemberPath, out remappedNode))
{
return new MemberProjectedSlot(remappedNode);
}
else
{
return new MemberProjectedSlot(MemberPath);
}
}
#endregion
#region Helper methods
///
/// Given the , determines the slots in that correspond to the entity key for the entity set or the
/// association set end. Returns the list of slots. Returns null if even one of the key slots is not present in slots.
///
/// corresponds to an entity set or an association end
internal static List GetKeySlots(IEnumerable slots, MemberPath prefix)
{
// Get the entity type of the hosted end or entity set
EntitySet entitySet = prefix.EntitySet;
Debug.Assert(entitySet != null, "Prefix must have associated entity set");
List keys = ExtentKey.GetKeysForEntityType(prefix, entitySet.ElementType);
Debug.Assert(keys.Count > 0, "No keys for entity?");
Debug.Assert(keys.Count == 1, "Currently, we only support primary keys");
// Get the slots for the key
List keySlots = GetSlots(slots, keys[0].KeyFields);
return keySlots;
}
///
/// Searches for members in and returns the corresponding slots in the same order as present in
/// . Returns null if even one member is not present in slots.
///
internal static List GetSlots(IEnumerable slots, IEnumerable members)
{
List result = new List();
foreach (MemberPath member in members)
{
MemberProjectedSlot slot = GetSlotForMember(Helpers.AsSuperTypeList(slots), member);
if (slot == null)
{
return null;
}
result.Add(slot);
}
return result;
}
///
/// Searches for in and returns the corresponding slot. If none is found, returns null.
///
internal static MemberProjectedSlot GetSlotForMember(IEnumerable slots, MemberPath member)
{
foreach (MemberProjectedSlot slot in slots)
{
if (MemberPath.EqualityComparer.Equals(slot.MemberPath, member))
{
return slot;
}
}
return null;
}
#endregion
}
}