/*
* 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
}
}