/* * 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.Collections.Generic; using System.Linq; using Amazon.DynamoDBv2.Model; using System.IO; using Amazon.Runtime.Internal.Util; using Amazon.Util; namespace Amazon.DynamoDBv2.DocumentModel { /// /// A DynamoDBEntry that represents a primitive list DynamoDB type /// public class PrimitiveList : DynamoDBEntry, IEquatable { private static DynamoDBEntryConversion V1Conversion = DynamoDBEntryConversion.V1; #region Constructors /// /// Constructs an empty PrimitiveList. /// Values are configured to be saved as strings. /// public PrimitiveList() : this(DynamoDBEntryType.String) { } /// /// Constructs an empty PrimitiveList and specifies /// the type of its elements. /// /// public PrimitiveList(DynamoDBEntryType type) { Entries = new List(); Type = type; } internal PrimitiveList(IEnumerable primitives) : this() { DynamoDBEntryType? listType = null; foreach (var primitive in primitives) { listType = primitive.Type; Entries.Add(primitive); } Type = listType.GetValueOrDefault(DynamoDBEntryType.String); } #endregion #region Properties/Accessors /// /// Collection of Primitive entries /// public List Entries { get; set; } /// /// Type of Primitive items in the list /// public DynamoDBEntryType Type { get; set; } /// /// Gets or sets Primitive at a specific location in the list. /// /// Index of the Primitive in question. /// Primitive in question. public Primitive this[int i] { get { return Entries[i]; } set { if (i < Entries.Count && i >= 0) { Entries[i] = value; } else { throw new ArgumentOutOfRangeException("i"); } } } /// /// Adds a Primitive to the end of the list. /// /// Primitive to add. public void Add(Primitive value) { this.Entries.Add(value); } #endregion #region Internal conversion methods internal override AttributeValue ConvertToAttributeValue(AttributeConversionConfig conversionConfig) { if (Entries == null || Entries.Count == 0) return null; AttributeValue attribute = new AttributeValue(); if (Type == DynamoDBEntryType.Numeric || Type == DynamoDBEntryType.String) { List values = new List(); foreach (var entry in Entries) { values.Add(entry.StringValue); } if (Type == DynamoDBEntryType.Numeric) { attribute.NS = values; } else { attribute.SS = values; } } else if (Type == DynamoDBEntryType.Binary) { List values = new List(); foreach (var entry in Entries) { MemoryStream stream = new MemoryStream(entry.AsByteArray()); values.Add(stream); } attribute.BS = values; } else { throw new InvalidOperationException("Unsupported Type"); } return attribute; } internal List GetSortedEntries() { var sortedEntries = new List(Entries); sortedEntries.Sort(PrimitiveComparer.Comparer); return sortedEntries; } private 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 Comparer = new PrimitiveComparer(); } #endregion #region Explicit and Implicit conversions #region Primitive-PrimitiveList conversions /// /// Explicitly convert DynamoDBEntry to Primitive[] /// /// Primitive[] value of this object public override Primitive[] AsArrayOfPrimitive() { return AsListOfPrimitive().ToArray(); } /// /// Implicitly convert Primitive[] to DynamoDBEntry /// /// Primitive[] data to convert /// DynamoDBEntry representing the data public static implicit operator PrimitiveList(Primitive[] data) { return (PrimitiveList)(data.ToList()); } /// /// Explicitly convert DynamoDBEntry to Primitive[] /// /// DynamoDBEntry to convert /// Primitive[] value of DynamoDBEntry public static explicit operator Primitive[](PrimitiveList p) { return p.AsArrayOfPrimitive(); } /// /// Explicitly convert PrimitiveList to List<Primitive> /// /// List<Primitive> value of this object public override List AsListOfPrimitive() { return Entries; } /// /// Implicitly convert List<Primitive> to PrimitiveList /// /// List<Primitive> data to convert /// PrimitiveList representing the data public static implicit operator PrimitiveList(List data) { return new PrimitiveList(data); } /// /// Explicitly convert PrimitiveList to List<Primitive> /// /// PrimitiveList to convert /// List<Primitive> value of PrimitiveList public static explicit operator List(PrimitiveList p) { return p.AsListOfPrimitive(); } /// /// Explicitly convert PrimitiveList to HashSet<Primitive> /// /// HashSet<Primitive> value of this object public override HashSet AsHashSetOfPrimitive() { return new HashSet(Entries, PrimitiveEqualityComparer.Default); } /// /// Implicitly convert HashSet<Primitive> to PrimitiveList /// /// HashSet<Primitive> data to convert /// PrimitiveList representing the data public static implicit operator PrimitiveList(HashSet data) { return new PrimitiveList(data); } /// /// Explicitly convert PrimitiveList to HashSet<Primitive> /// /// PrimitiveList to convert /// HashSet<Primitive> value of PrimitiveList public static explicit operator HashSet(PrimitiveList p) { return p.AsHashSetOfPrimitive(); } #endregion /// /// Explicitly convert DynamoDBEntry to String[] /// /// String[] value of this object public override String[] AsArrayOfString() { return AsListOfString().ToArray(); } /// /// Implicitly convert String[] to DynamoDBEntry /// /// String[] data to convert /// DynamoDBEntry representing the data public static implicit operator PrimitiveList(String[] data) { return V1Conversion.ConvertToEntry(data).ToPrimitiveList(); } /// /// Explicitly convert DynamoDBEntry to String[] /// /// DynamoDBEntry to convert /// String[] value of DynamoDBEntry public static explicit operator String[](PrimitiveList p) { return p.AsArrayOfString(); } /// /// Explicitly convert PrimitiveList to List<String> /// /// List<String> value of this object public override List AsListOfString() { return V1Conversion.ConvertFromEntry>(this); } /// /// Implicitly convert List<String> to PrimitiveList /// /// List<String> data to convert /// PrimitiveList representing the data public static implicit operator PrimitiveList(List data) { return V1Conversion.ConvertToEntry>(data).ToPrimitiveList(); } /// /// Explicitly convert PrimitiveList to List<String> /// /// PrimitiveList to convert /// List<String> value of PrimitiveList public static explicit operator List(PrimitiveList p) { return p.AsListOfString(); } /// /// Explicitly convert DynamoDBEntry to HashSet<String> /// /// List<String> value of this object public override HashSet AsHashSetOfString() { return V1Conversion.ConvertFromEntry>(this); } /// /// Implicitly convert HashSet<String> to PrimitiveList /// /// HashSet<String> data to convert /// PrimitiveList representing the data public static implicit operator PrimitiveList(HashSet data) { return V1Conversion.ConvertToEntry>(data).ToPrimitiveList(); } /// /// Explicitly convert PrimitiveList to HashSet<String> /// /// PrimitiveList to convert /// HashSet<String> value of PrimitiveList public static explicit operator HashSet(PrimitiveList p) { return p.AsHashSetOfString(); } /// /// Explicitly convert PrimitiveList to byte[] /// /// List<byte[]> value of this object public override List AsListOfByteArray() { return V1Conversion.ConvertFromEntry>(this); } /// /// Implicitly convert List<byte[]> to PrimitiveList /// /// List<byte[]> data to convert /// PrimitiveList representing the data public static implicit operator PrimitiveList(List data) { return V1Conversion.ConvertToEntry>(data).ToPrimitiveList(); } /// /// Explicitly convert PrimitiveList to List<byte[]> /// /// PrimitiveList to convert /// List<byte[]> value of PrimitiveList public static explicit operator List(PrimitiveList p) { return p.AsListOfByteArray(); } /// /// Explicitly convert PrimitiveList to HashSet<byte[]> /// /// HashSet<byte[]> value of this object public override HashSet AsHashSetOfByteArray() { return V1Conversion.ConvertFromEntry>(this); } /// /// Implicitly convert HashSet<byte[]> to PrimitiveList /// /// HashSet<byte[]> data to convert /// PrimitiveList representing the data public static implicit operator PrimitiveList(HashSet data) { return V1Conversion.ConvertToEntry>(data).ToPrimitiveList(); } /// /// Explicitly convert PrimitiveList to HashSet<byte[]> /// /// PrimitiveList to convert /// HashSet<byte[]> value of PrimitiveList public static explicit operator HashSet(PrimitiveList p) { return V1Conversion.ConvertFromEntry>(p); } /// /// Explicitly convert PrimitiveList to List<MemoryStream> /// /// List<MemoryStream> value of this object public override List AsListOfMemoryStream() { return V1Conversion.ConvertFromEntry>(this); } /// /// Implicitly convert List<MemoryStream> to PrimitiveList /// /// List<MemoryStream> data to convert /// PrimitiveList representing the data public static implicit operator PrimitiveList(List data) { return V1Conversion.ConvertToEntry>(data).ToPrimitiveList(); } /// /// Explicitly convert PrimitiveList to List<MemoryStream> /// /// PrimitiveList to convert /// List<MemoryStream> value of PrimitiveList public static explicit operator List(PrimitiveList p) { return p.AsListOfMemoryStream(); } #endregion #region Public overrides /// /// Implement the Clone method. /// /// public override object Clone() { PrimitiveList list = new PrimitiveList(this.Type); foreach (Primitive entry in this.Entries) { list.Add(entry.Clone() as Primitive); } return list; } /// /// Implement the GetHashCode method. /// /// public override int GetHashCode() { var typeHashCode = this.Type.GetHashCode(); var entriesHashCode = 0; foreach(var entry in this.Entries) { // Hash entries in such a way that order doesn't matter entriesHashCode = entriesHashCode ^ entry.GetHashCode(); } return Hashing.CombineHashes(typeHashCode, entriesHashCode); } /// /// Implement the Equals method. /// /// /// public override bool Equals(object obj) { PrimitiveList entryOther = obj as PrimitiveList; if (entryOther == null || this.Type != entryOther.Type) return false; if (entryOther.Entries.Count != this.Entries.Count) return false; var thisSortedEntries = this.GetSortedEntries(); var otherSortedEntries = entryOther.GetSortedEntries(); for (int i = 0; i < this.Entries.Count; i++) { Primitive thisPrim = thisSortedEntries[i]; Primitive otherPrim = otherSortedEntries[i]; if (thisPrim == null && otherPrim == null) continue; else if (thisPrim == null || otherPrim == null) return false; else if (!thisPrim.Equals(otherPrim)) return false; } return true; } #endregion #region IEquatable Members /// /// Implement the Equals method from IEquatable /// /// /// public bool Equals(PrimitiveList other) { return this.Equals((object)other); } #endregion } }