//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Data.Common.CommandTrees;
using System.Data.Common.Utils;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Linq;
namespace System.Data.Mapping.ViewGeneration.Structures
{
using DomainConstraint = System.Data.Common.Utils.Boolean.DomainConstraint;
using DomainVariable = System.Data.Common.Utils.Boolean.DomainVariable;
using DomainBoolExpr = System.Data.Common.Utils.Boolean.BoolExpr>;
using DomainNotExpr = System.Data.Common.Utils.Boolean.NotExpr >;
using DomainTermExpr = System.Data.Common.Utils.Boolean.TermExpr>;
///
/// A class that ties up all the literals in boolean expressions.
/// Conditions represented by s need to be synchronized with s,
/// which may be modified upon calling . This is what the method is used for.
///
internal abstract class BoolLiteral : InternalBase
{
#region Fields
internal static readonly IEqualityComparer EqualityComparer = new BoolLiteralComparer();
internal static readonly IEqualityComparer EqualityIdentifierComparer = new IdentifierComparer();
#endregion
#region Static MakeTermExpression methods
///
/// Creates a term expression of the form: " in with all possible values being ".
///
internal static DomainTermExpr MakeTermExpression(BoolLiteral literal, IEnumerable domain, IEnumerable range)
{
Set domainSet = new Set(domain, Constant.EqualityComparer);
Set rangeSet = new Set(range, Constant.EqualityComparer);
return MakeTermExpression(literal, domainSet, rangeSet);
}
///
/// Creates a term expression of the form: " in with all possible values being ".
///
internal static DomainTermExpr MakeTermExpression(BoolLiteral literal, Set domain, Set range)
{
domain.MakeReadOnly();
range.MakeReadOnly();
DomainVariable variable = new DomainVariable(literal, domain, EqualityIdentifierComparer);
DomainConstraint constraint = new DomainConstraint(variable, range);
DomainTermExpr result = new DomainTermExpr(EqualityComparer.Default, constraint);
return result;
}
#endregion
#region Virtual methods
///
/// Fixes the range of the literal using the new values provided in and returns a boolean expression corresponding to the new value.
///
internal abstract DomainBoolExpr FixRange(Set range, MemberDomainMap memberDomainMap);
internal abstract DomainBoolExpr GetDomainBoolExpression(MemberDomainMap domainMap);
///
/// See .
///
internal abstract BoolLiteral RemapBool(Dictionary remap);
///
/// See .
///
///
///
internal abstract void GetRequiredSlots(MemberProjectionIndex projectedSlotMap, bool[] requiredSlots);
///
/// See .
///
internal abstract StringBuilder AsEsql(StringBuilder builder, string blockAlias, bool skipIsNotNull);
///
/// See .
///
internal abstract DbExpression AsCqt(DbExpression row, bool skipIsNotNull);
internal abstract StringBuilder AsUserString(StringBuilder builder, string blockAlias, bool skipIsNotNull);
internal abstract StringBuilder AsNegatedUserString(StringBuilder builder, string blockAlias, bool skipIsNotNull);
///
/// Checks if the identifier in this is the same as the one in .
///
protected virtual bool IsIdentifierEqualTo(BoolLiteral right)
{
return IsEqualTo(right);
}
protected abstract bool IsEqualTo(BoolLiteral right);
///
/// Get the hash code based on the identifier.
///
protected virtual int GetIdentifierHash()
{
return GetHashCode();
}
#endregion
#region Comparer class
///
/// This class compares boolean expressions.
///
private sealed class BoolLiteralComparer : IEqualityComparer
{
public bool Equals(BoolLiteral left, BoolLiteral right)
{
// Quick check with references
if (object.ReferenceEquals(left, right))
{
// Gets the Null and Undefined case as well
return true;
}
// One of them is non-null at least
if (left == null || right == null)
{
return false;
}
// Both are non-null at this point
return left.IsEqualTo(right);
}
public int GetHashCode(BoolLiteral literal)
{
return literal.GetHashCode();
}
}
#endregion
#region Identifier Comparer class
///
/// This class compares just the identifier in boolean expressions.
///
private sealed class IdentifierComparer : IEqualityComparer
{
public bool Equals(BoolLiteral left, BoolLiteral right)
{
// Quick check with references
if (object.ReferenceEquals(left, right))
{
// Gets the Null and Undefined case as well
return true;
}
// One of them is non-null at least
if (left == null || right == null)
{
return false;
}
// Both are non-null at this point
return left.IsIdentifierEqualTo(right);
}
public int GetHashCode(BoolLiteral literal)
{
return literal.GetIdentifierHash();
}
}
#endregion
}
internal abstract class TrueFalseLiteral : BoolLiteral
{
internal override DomainBoolExpr GetDomainBoolExpression(MemberDomainMap domainMap)
{
// Essentially say that the variable can take values true or false and here its value is only true
IEnumerable actualValues = new Constant[] { new ScalarConstant(true) };
IEnumerable possibleValues = new Constant[] { new ScalarConstant(true), new ScalarConstant(false) };
Set variableDomain = new Set(possibleValues, Constant.EqualityComparer).MakeReadOnly();
Set thisDomain = new Set(actualValues, Constant.EqualityComparer).MakeReadOnly();
DomainTermExpr result = MakeTermExpression(this, variableDomain, thisDomain);
return result;
}
internal override DomainBoolExpr FixRange(Set range, MemberDomainMap memberDomainMap)
{
Debug.Assert(range.Count == 1, "For BoolLiterals, there should be precisely one value - true or false");
ScalarConstant scalar = (ScalarConstant)range.First();
DomainBoolExpr expr = GetDomainBoolExpression(memberDomainMap);
if ((bool)scalar.Value == false)
{
// The range of the variable was "inverted". Return a NOT of
// the expression
expr = new DomainNotExpr(expr);
}
return expr;
}
}
}