//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Data.Common.CommandTrees;
using System.Data.Common.CommandTrees.ExpressionBuilder;
using System.Data.Common.Utils;
using System.Data.Mapping.ViewGeneration.Structures;
using System.Text;
using System.Diagnostics;
namespace System.Data.Mapping.ViewGeneration.CqlGeneration
{
///
/// A class that keeps track of slot information in a .
///
internal sealed class SlotInfo : InternalBase
{
#region Constructor
///
/// Creates a for a X with information about whether this slot is needed by X's parent
/// (), whether X projects it () along with the slot value () and
/// the output member path ( (for regular/non-boolean slots) for the slot.
///
internal SlotInfo(bool isRequiredByParent, bool isProjected, ProjectedSlot slotValue, MemberPath outputMember)
: this(isRequiredByParent, isProjected, slotValue, outputMember, false /* enforceNotNull */)
{ }
///
/// Creates a for a X with information about whether this slot is needed by X's parent
/// (), whether X projects it () along with the slot value () and
/// the output member path ( (for regular/non-boolean slots) for the slot.
///
/// We need to ensure that _from variables are never null since view generation uses 2-valued boolean logic.
/// If =true, the generated Cql adds a condition (AND NOT NULL).
/// This flag is used only for boolean slots.
internal SlotInfo(bool isRequiredByParent, bool isProjected, ProjectedSlot slotValue, MemberPath outputMember, bool enforceNotNull)
{
m_isRequiredByParent = isRequiredByParent;
m_isProjected = isProjected;
m_slotValue = slotValue;
m_outputMember = outputMember;
m_enforceNotNull = enforceNotNull;
Debug.Assert(false == m_isRequiredByParent || m_slotValue != null, "Required slots cannot be null");
Debug.Assert(m_slotValue is QualifiedSlot ||
(m_slotValue == null && m_outputMember == null) || // unused boolean slot
(m_slotValue is BooleanProjectedSlot) == (m_outputMember == null),
"If slot is boolean slot, there is no member path for it and vice-versa");
}
#endregion
#region Fields
///
/// If slot is required by the parent. Can be reset to false in method.
///
private bool m_isRequiredByParent;
///
/// If the node is capable of projecting this slot.
///
private readonly bool m_isProjected;
///
/// The slot represented by this .
///
private readonly ProjectedSlot m_slotValue;
///
/// The output member path of this slot.
///
private readonly MemberPath m_outputMember;
///
/// Whether to add AND NOT NULL to Cql.
///
private readonly bool m_enforceNotNull;
#endregion
#region Properties
///
/// Returns true iff this slot is required by the 's parent.
/// Can be reset to false by calling method.
///
internal bool IsRequiredByParent
{
get { return m_isRequiredByParent; }
}
///
/// Returns true iff this slot is projected by this .
///
internal bool IsProjected
{
get { return m_isProjected; }
}
///
/// Returns the output memberpath of this slot
///
internal MemberPath OutputMember
{
get { return m_outputMember; }
}
///
/// Returns the slot value corresponfing to this object.
///
internal ProjectedSlot SlotValue
{
get { return m_slotValue; }
}
///
/// Returns the Cql alias for this slot, e.g., "CPerson1_Pid", "_from0", etc
///
internal string CqlFieldAlias
{
get
{
return m_slotValue != null ? m_slotValue.GetCqlFieldAlias(m_outputMember) : null;
}
}
///
/// Returns true if Cql generated for the slot needs to have an extra AND IS NOT NULL condition.
///
internal bool IsEnforcedNotNull
{
get { return m_enforceNotNull; }
}
#endregion
#region Methods
///
/// Sets the to false.
/// Note we don't have a setter because we don't want people to set this field to true after the object has been created.
///
internal void ResetIsRequiredByParent()
{
m_isRequiredByParent = false;
}
///
/// Generates eSQL representation of the slot. For different slots, the result is different, e.g., "_from0", "CPerson1.pid", "TREAT(....)".
///
internal StringBuilder AsEsql(StringBuilder builder, string blockAlias, int indentLevel)
{
if (m_enforceNotNull)
{
builder.Append('(');
m_slotValue.AsEsql(builder, m_outputMember, blockAlias, indentLevel);
builder.Append(" AND ");
m_slotValue.AsEsql(builder, m_outputMember, blockAlias, indentLevel);
builder.Append(" IS NOT NULL)");
}
else
{
m_slotValue.AsEsql(builder, m_outputMember, blockAlias, indentLevel);
}
return builder;
}
///
/// Generates CQT representation of the slot.
///
internal DbExpression AsCqt(DbExpression row)
{
DbExpression cqt = m_slotValue.AsCqt(row, m_outputMember);
if (m_enforceNotNull)
{
cqt = cqt.And(cqt.IsNull().Not());
}
return cqt;
}
internal override void ToCompactString(StringBuilder builder)
{
if (m_slotValue != null)
{
builder.Append(CqlFieldAlias);
}
}
#endregion
}
}