using Google.Protobuf; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using Tango.Core.ExtensionMethods; using Tango.PMR; using Tango.PMR.Common; using Tango.PMR.DataStore; namespace Tango.DataStore { /// /// Contains data store helper methods. /// public static class DataStoreHelper { /// /// Gets the data store data type by the specified object type. /// /// The value. /// public static DataType GetDataType(Object value) { return GetDataType(value.GetType()); } /// /// Gets data store data type by the specified .net type. /// /// The type. /// /// public static DataType GetDataType(Type type) { if (type == typeof(int)) { return DataType.Int32; } else if (type == typeof(Int64)) { return DataType.Int32; } else if (type == typeof(float)) { return DataType.Float; } else if (type == typeof(double)) { return DataType.Double; } else if (type == typeof(String)) { return DataType.String; } else if (type == typeof(bool)) { return DataType.Boolean; } else if (type == typeof(byte[])) { return DataType.Bytes; } else if (type == typeof(DataStoreProtoObject)) { return DataType.Proto; } else if (typeof(IMessage).IsAssignableFrom(type)) { return DataType.Proto; } throw new NotSupportedException($"The specified type '{type.Name}' is not supported by the data store."); } /// /// Formats the data store item as a string. /// /// The item. /// public static String FormatDataStoreItem(IDataStoreItem item) { return FormatDataStoreValue(item.Type, item.Value); } /// /// Formats the data store value. /// /// The type. /// The object. /// public static String FormatDataStoreValue(DataType type, object obj) { if (type == DataType.Bytes) { return Convert.ToBase64String((byte[])obj); } else if (type == DataType.Proto) { return (obj as DataStoreProtoObject).Message.ToJsonString(); } else { return obj.ToStringSafe(); } } /// /// Parses a data store value from a string. /// /// The type. /// The string. /// Type of the proto message (if type is Proto). /// /// No PMR message type specified. /// The specified data store type is not supported. public static Object ParseDataStoreValue(DataType type, String text, DataStoreMessageType? protoMessageType = null) { switch (type) { case DataType.String: return text; case DataType.Int32: return int.Parse(text); case DataType.Float: return float.Parse(text); case DataType.Double: return double.Parse(text); case DataType.Boolean: return bool.Parse(text); case DataType.Proto: if (protoMessageType == null) throw new ArgumentNullException("No PMR message type specified."); var messageType = MessageFactory.GetDataStorePMRTypeFromDataStoreMessageType(protoMessageType.Value); var instance = Activator.CreateInstance(messageType) as IMessage; instance = instance.GetParser().ParseJson(text); return DataStoreProtoObject.FromMessage(instance); case DataType.Bytes: return Convert.FromBase64String(text); } throw new NotSupportedException("The specified data store type is not supported."); } /// /// Validates the name of the collection or key. /// /// The name. /// public static bool ValidateCollectionOrKeyName(String name) { var regexItem = new Regex("^[a-zA-Z0-9_-]*$"); return regexItem.IsMatch(name); } /// /// Creates a data store value from byte array that are stored in database. /// /// The type. /// The bytes. /// /// The specified type is not supported. public static Object CreateObject(DataType type, byte[] bytes) { switch (type) { case DataType.Int32: return BitConverter.ToInt32(bytes, 0); case DataType.Float: return BitConverter.ToSingle(bytes, 0); case DataType.Double: return BitConverter.ToDouble(bytes, 0); case DataType.Boolean: return BitConverter.ToBoolean(bytes, 0); case DataType.String: return Encoding.Default.GetString(bytes); case DataType.Bytes: return bytes; case DataType.Proto: return DataStoreProtoObject.FromBytes(bytes); } throw new NotSupportedException("The specified type is not supported."); } /// /// Creates a byte array that can be stored on database from the specified data store type and value. /// /// The type. /// The object. /// /// /// DataStoreProtoObject /// or /// The specified type is not supported. /// public static byte[] CreateBytes(DataType type, Object obj) { switch (type) { case DataType.Int32: return BitConverter.GetBytes((int)obj); case DataType.Float: return BitConverter.GetBytes((float)obj); case DataType.Double: return BitConverter.GetBytes((double)obj); case DataType.Boolean: return BitConverter.GetBytes((bool)obj); case DataType.String: return Encoding.Default.GetBytes(obj.ToString()); case DataType.Bytes: return (byte[])obj; case DataType.Proto: if (obj is DataStoreProtoObject protoMessage) { return protoMessage.ToBytes(); } else { throw new NotSupportedException($"Data type is 'Proto' but object is not of type '{nameof(DataStoreProtoObject)}'."); } } throw new NotSupportedException("The specified type is not supported."); } } }