/* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ using System; using System.Globalization; using System.IO; using Amazon.DynamoDBv2.Model; using Amazon.Runtime.Internal.Util; using Amazon.Util; using System.Collections; using System.Collections.Generic; namespace Amazon.DynamoDBv2.DocumentModel { /// /// Enumerator describing type of DynamoDB data in a Primitive or PrimitiveList /// public enum DynamoDBEntryType { /// /// DynamoDB String type. /// String, /// /// DynamoDB Numeric type. /// Numeric, /// /// DynamoDB Binary type. /// Binary } /// /// A DynamoDBEntry that represents a scalar DynamoDB type /// public class Primitive : DynamoDBEntry, IEquatable { #region Private members private static DynamoDBEntryConversion V1Conversion = DynamoDBEntryConversion.V1; #endregion #region Constructors /// /// Constructs an empty Primitive /// public Primitive() : this(null, DynamoDBEntryType.String) { } /// /// Constructs a Primitive with the specified value. /// Value is stored as a string, not numeric. /// /// Value of the Primitive public Primitive(string value) : this(value, DynamoDBEntryType.String) { } /// /// Constructs a Primitive with the specified value /// and specifies whether it should be stored as a number or not. /// /// Value of the Primitive /// /// Flag, set to true if value should be treated as a number instead of a string /// public Primitive(string value, bool saveAsNumeric) : this(value, saveAsNumeric ? DynamoDBEntryType.Numeric : DynamoDBEntryType.String) { } /// /// Constructs a Binary Primitive with the specified MemoryStream value. /// Note: Primitive's Value is set to the stream's ToArray() response. /// /// Value of the Primitive public Primitive(MemoryStream value) : this(value.ToArray()) { } /// /// Constructs a Binary Primitive with the specified byte[] value. /// /// Value of the Primitive public Primitive(byte[] value) : this(value, DynamoDBEntryType.Binary) { } internal Primitive(object value, DynamoDBEntryType type) { Value = value; Type = type; } #endregion #region Properties /// /// Value of the Primitive. /// If Type is String or Numeric, this property is a string. /// If Type is Binary, this property is a byte array. /// public object Value { get; set; } /// /// Type of this primitive object /// public DynamoDBEntryType Type { get; set; } #endregion #region Internal conversion methods internal override AttributeValue ConvertToAttributeValue(AttributeConversionConfig conversionConfig) { if (this.Value == null) return null; if (conversionConfig.IsEmptyStringValueEnabled) { if (this.Type != DynamoDBEntryType.Binary && StringValue == null) { return null; } } else { if (this.Type != DynamoDBEntryType.Binary && string.IsNullOrEmpty(this.StringValue)) { return null; } } AttributeValue attribute = new AttributeValue(); switch (this.Type) { case DynamoDBEntryType.Numeric: attribute.N = StringValue; break; case DynamoDBEntryType.String: attribute.S = StringValue; break; case DynamoDBEntryType.Binary: byte[] bytes = (byte[])Value; attribute.B = new MemoryStream(bytes); break; } return attribute; } internal string StringValue { get { if (this.Type == DynamoDBEntryType.Numeric || this.Type == DynamoDBEntryType.String) return this.Value as string; return null; } } #endregion #region Explicit and Implicit conversions /// /// Explicitly convert Primitive to Boolean /// /// Boolean value of this object public override Boolean AsBoolean() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Boolean to Primitive /// /// Boolean data to convert /// Primitive representing the data public static implicit operator Primitive(Boolean data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Boolean /// /// Primitive to convert /// Boolean value of Primitive public static explicit operator Boolean(Primitive p) { return p.AsBoolean(); } /// /// Explicitly convert Primitive to Byte /// /// Byte value of this object public override Byte AsByte() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Byte to Primitive /// /// Byte data to convert /// Primitive representing the data public static implicit operator Primitive(Byte data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Byte /// /// Primitive to convert /// Byte value of Primitive public static explicit operator Byte(Primitive p) { return p.AsByte(); } /// /// Explicitly convert Primitive to SByte /// /// SByte value of this object [CLSCompliant(false)] public override SByte AsSByte() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert SByte to Primitive /// /// SByte data to convert /// Primitive representing the data [CLSCompliant(false)] public static implicit operator Primitive(SByte data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to SByte /// /// Primitive to convert /// SByte value of Primitive [CLSCompliant(false)] public static explicit operator SByte(Primitive p) { return p.AsSByte(); } /// /// Explicitly convert Primitive to UInt16 /// /// UInt16 value of this object [CLSCompliant(false)] public override UInt16 AsUShort() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert UInt16 to Primitive /// /// UInt16 data to convert /// Primitive representing the data [CLSCompliant(false)] public static implicit operator Primitive(UInt16 data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to UInt16 /// /// Primitive to convert /// UInt16 value of Primitive [CLSCompliant(false)] public static explicit operator UInt16(Primitive p) { return p.AsUShort(); } /// /// Explicitly convert Primitive to Int16 /// /// Int16 value of this object public override Int16 AsShort() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Int16 to Primitive /// /// Int16 data to convert /// Primitive representing the data public static implicit operator Primitive(Int16 data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Int16 /// /// Primitive to convert /// Int16 value of Primitive public static explicit operator Int16(Primitive p) { return p.AsShort(); } /// /// Explicitly convert Primitive to UInt32 /// /// UInt32 value of this object [CLSCompliant(false)] public override UInt32 AsUInt() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert UInt32 to Primitive /// /// UInt32 data to convert /// Primitive representing the data [CLSCompliant(false)] public static implicit operator Primitive(UInt32 data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to UInt32 /// /// Primitive to convert /// UInt32 value of Primitive [CLSCompliant(false)] public static explicit operator UInt32(Primitive p) { return p.AsUInt(); } /// /// Explicitly convert Primitive to Int32 /// /// Int32 value of this object public override Int32 AsInt() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Int32 to Primitive /// /// Int32 data to convert /// Primitive representing the data public static implicit operator Primitive(Int32 data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Int32 /// /// Primitive to convert /// Int32 value of Primitive public static explicit operator Int32(Primitive p) { return p.AsInt(); } /// /// Explicitly convert Primitive to UInt64 /// /// UInt64 value of this object [CLSCompliant(false)] public override UInt64 AsULong() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert UInt64 to Primitive /// /// UInt64 data to convert /// Primitive representing the data [CLSCompliant(false)] public static implicit operator Primitive(UInt64 data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to UInt64 /// /// Primitive to convert /// UInt64 value of Primitive [CLSCompliant(false)] public static explicit operator UInt64(Primitive p) { return p.AsULong(); } /// /// Explicitly convert Primitive to Int64 /// /// Int64 value of this object public override Int64 AsLong() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Int64 to Primitive /// /// Int64 data to convert /// Primitive representing the data public static implicit operator Primitive(Int64 data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Int64 /// /// Primitive to convert /// Int64 value of Primitive public static explicit operator Int64(Primitive p) { return p.AsLong(); } /// /// Explicitly convert Primitive to Single /// /// Single value of this object public override Single AsSingle() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Single to Primitive /// /// Single data to convert /// Primitive representing the data public static implicit operator Primitive(Single data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Single /// /// Primitive to convert /// Single value of Primitive public static explicit operator Single(Primitive p) { return p.AsSingle(); } /// /// Explicitly convert Primitive to Double /// /// Double value of this object public override Double AsDouble() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Double to Primitive /// /// Double data to convert /// Primitive representing the data public static implicit operator Primitive(Double data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Double /// /// Primitive to convert /// Double value of Primitive public static explicit operator Double(Primitive p) { return p.AsDouble(); } /// /// Explicitly convert Primitive to Decimal /// /// Decimal value of this object public override Decimal AsDecimal() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Decimal to Primitive /// /// Decimal data to convert /// Primitive representing the data public static implicit operator Primitive(Decimal data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Decimal /// /// Primitive to convert /// Decimal value of Primitive public static explicit operator Decimal(Primitive p) { return p.AsDecimal(); } /// /// Explicitly convert Primitive to Char /// /// Char value of this object public override Char AsChar() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Char to Primitive /// /// Char data to convert /// Primitive representing the data public static implicit operator Primitive(Char data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Char /// /// Primitive to convert /// Char value of Primitive public static explicit operator Char(Primitive p) { return p.AsChar(); } /// /// Explicitly convert Primitive to String /// /// String value of this object public override String AsString() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert String to Primitive /// /// String data to convert /// Primitive representing the data public static implicit operator Primitive(String data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to String /// /// Primitive to convert /// String value of Primitive public static implicit operator String(Primitive p) { return p.AsString(); } /// /// Explicitly convert Primitive to DateTime /// /// DateTime value of this object public override DateTime AsDateTime() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert DateTime to Primitive /// /// DateTime data to convert /// Primitive representing the data public static implicit operator Primitive(DateTime data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to DateTime /// /// Primitive to convert /// DateTime value of Primitive public static explicit operator DateTime(Primitive p) { return p.AsDateTime(); } /// /// Explicitly convert Primitive to Guid /// /// Guid value of this object public override Guid AsGuid() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert Guid to Primitive /// /// Guid data to convert /// Primitive representing the data public static implicit operator Primitive(Guid data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to Guid /// /// Primitive to convert /// Guid value of Primitive public static explicit operator Guid(Primitive p) { return p.AsGuid(); } /// /// Explicitly convert Primitive to byte[] /// /// byte[] value of this object public override byte[] AsByteArray() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert byte[] to Primitive /// /// byte[] data to convert /// Primitive representing the data public static implicit operator Primitive(byte[] data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to byte[] /// /// Primitive to convert /// byte[] value of Primitive public static explicit operator byte[](Primitive p) { return p.AsByteArray(); } /// /// Explicitly convert Primitive to MemoryStream /// /// MemoryStream value of this object public override MemoryStream AsMemoryStream() { return V1Conversion.ConvertFromEntry(this); } /// /// Implicitly convert MemoryStream to Primitive /// /// MemoryStream data to convert /// Primitive representing the data public static implicit operator Primitive(MemoryStream data) { return V1Conversion.ConvertToEntry(data).AsPrimitive(); } /// /// Explicitly convert Primitive to MemoryStream /// /// Primitive to convert /// MemoryStream value of Primitive public static explicit operator MemoryStream(Primitive p) { return p.AsMemoryStream(); } #endregion #region Public overrides /// /// Implement the ToString method. /// /// public override string ToString() { if (this.Value == null) return string.Empty; return this.Value.ToString(); } /// /// Implement the Clone method. /// /// public override object Clone() { return new Primitive(this.Value, this.Type); } /// /// Implement the GetHashCode method. /// /// public override int GetHashCode() { var typeHashCode = this.Type.GetHashCode(); var valueHashCode = 0; if (this.Value != null) { if (this.Type == DynamoDBEntryType.Numeric || this.Type == DynamoDBEntryType.String) valueHashCode = this.Value.GetHashCode(); else if (this.Type == DynamoDBEntryType.Binary) { var bytes = this.Value as byte[]; if (bytes != null) { for (int i = 0; i < bytes.Length; i++) { byte b = bytes[i]; valueHashCode = Hashing.CombineHashes(valueHashCode, b.GetHashCode()); } } } } return Hashing.CombineHashes(typeHashCode, valueHashCode); } /// /// Implement the Equals method. /// /// /// public override bool Equals(object obj) { Primitive entryOther = obj as Primitive; if (entryOther == null) return false; if (this.Type != entryOther.Type) return false; if (this.Type == DynamoDBEntryType.Numeric || this.Type == DynamoDBEntryType.String) { return (string.Equals(this.StringValue, entryOther.StringValue)); } else if (this.Type == DynamoDBEntryType.Binary) { byte[] thisByteArray = this.Value as byte[]; byte[] otherByteArray = entryOther.Value as byte[]; if (thisByteArray.Length != otherByteArray.Length) return false; for (int i = 0; i < thisByteArray.Length; i++) { if (thisByteArray[i] != otherByteArray[i]) return false; } return true; } else { return false; } } #endregion #region IEquatable Members /// /// Implement the Equals method from the IEquatable interface. /// /// /// public bool Equals(Primitive other) { return this.Equals((object)other); } #endregion } internal class PrimitiveEqualityComparer : IEqualityComparer { public static readonly PrimitiveEqualityComparer Default = new PrimitiveEqualityComparer(); public bool Equals(Primitive x, Primitive y) { if (x == null || y == null) return (x == y); return x.Equals(y); } public int GetHashCode(Primitive obj) { if (obj == null) return 0; return obj.GetHashCode(); } } internal class PrimitiveComparer : IComparer { public int Compare(Primitive x, Primitive y) { if (x.Type != y.Type) return x.Type.CompareTo(y.Type); if (x.Type == DynamoDBEntryType.Numeric || x.Type == DynamoDBEntryType.String) { return (string.Compare(x.StringValue, y.StringValue, StringComparison.Ordinal)); } else if (x.Type == DynamoDBEntryType.Binary) { byte[] xByteArray = x.Value as byte[]; byte[] yByteArray = y.Value as byte[]; if (xByteArray.Length != yByteArray.Length) return xByteArray.Length.CompareTo(yByteArray.Length); for (int i = 0; i < xByteArray.Length; i++) { byte xb = xByteArray[i]; byte yb = yByteArray[i]; int byteCompare = xb.CompareTo(yb); if (byteCompare != 0) return byteCompare; } return 0; } else { throw new InvalidOperationException("Unknown type of Primitive: " + x.Type); } } public static PrimitiveComparer Default = new PrimitiveComparer(); } }