public static void ToStream <TItem>(Stream stream, TItem item, CollectionSchema collectionSchema = null) { var bufferedStream = new BufferedStream(stream); var useProtocolBuffers = collectionSchema == null; // use protocol buffers only for requests not for business objects var useCompression = collectionSchema != null && collectionSchema.UseCompression; var mode = SerializationMode.ProtocolBuffers; if (!useProtocolBuffers) { mode = SerializationMode.Json; } var writer = new BinaryWriter(bufferedStream); const int itemCount = 1; writer.Write(itemCount); var data = SerializationHelper.ObjectToBytes(item, mode, useCompression); writer.Write(useProtocolBuffers); writer.Write(useCompression); writer.Write(0D); writer.Write(data.Length); writer.Write(data); writer.Flush(); }
public static PackedObject Pack <TObject>(TObject instance, [NotNull] CollectionSchema typeDescription, string collectionName = null) { if (instance == null) { throw new ArgumentNullException(nameof(instance)); } if (typeDescription == null) { throw new ArgumentNullException(nameof(typeDescription)); } var result = new PackedObject { // scalar values that are visible server-side Values = new KeyValue[typeDescription.ServerSide.Count(k => !k.IsCollection)], // vector values that are visible server-side CollectionValues = new KeyValues[typeDescription.ServerSide.Count(k => k.IsCollection)] }; // process server-side values var pos = 0; var collectionPos = 0; foreach (var metadata in typeDescription.ServerSide) { var getter = ExpressionTreeHelper.Getter <TObject>(metadata.Name); var value = getter(instance); if (!metadata.IsCollection) { // if the primary key is an empty Guid generate a value if (metadata.IndexType == IndexType.Primary) { if (Guid.Empty.Equals(value)) { value = Guid.NewGuid(); } } result.Values[pos++] = new KeyValue(value, metadata); } else { if (value is IEnumerable values && !(value is string)) { if (metadata.IndexType == IndexType.Ordered) { throw new NotSupportedException($"The property {metadata.Name} is a collection. It can be indexed as a dictionary but not as an ordered index"); } var keyValues = values.Cast <object>().Select(v => new KeyValue(v, metadata)); result.CollectionValues[collectionPos++] = new KeyValues(metadata.Name, keyValues); }
/// <summary> /// Factory method used to create a precompiled type description. /// This version of the method uses a tagged type ( Attributes are attached to the public properties /// which are indexed in the cache) /// In order to be cacheable, a type must be serializable and must have exactly one primary key /// Optionally it can have multiple unique keys and index keys /// </summary> /// <param name="type"> type to register (must be properly decorated) </param> /// <returns> not null type description if successful </returns> public static CollectionSchema FromType(Type type) { if (type == null) { throw new ArgumentNullException(nameof(type)); } var useCompression = false; var storage = type.GetCustomAttributes(typeof(StorageAttribute), false).FirstOrDefault(); if (storage != null) { var storageParams = (StorageAttribute)storage; useCompression = storageParams.UseCompression; } var result = new CollectionSchema { UseCompression = useCompression, CollectionName = type.Name }; var props = type.GetProperties(); foreach (var info in props) { var key = BuildPropertyMetadata(info); if (key != null) { result.ServerSide.Add(key); } var fullText = info.GetCustomAttributes(typeof(FullTextIndexationAttribute), true) .FirstOrDefault(); if (fullText != null) { result.FullText.Add(info.Name); } } // Adjust order. Line numbers give relative order of keys but they need to be adjusted to a continuous range with the primary key at index 0 and the collections at the end var lineNumbers = new HashSet <int>(); foreach (var keyInfo in result.ServerSide) { lineNumbers.Add(keyInfo.Order); } var lineNumberByPosition = lineNumbers.OrderBy(x => x).ToList(); foreach (var keyInfo in result.ServerSide) { var adjustedOrder = lineNumberByPosition.FindIndex(l => l == keyInfo.Order); keyInfo.Order = adjustedOrder; } result.ServerSide = result.ServerSide.OrderBy(k => k.Order).ToList(); //check if the newly registered type is valid if (result.PrimaryKeyField == null) { throw new NotSupportedException($"No primary key defined for type {type}"); } return(result); }
internal FluentToken(CollectionSchema schema) { Product = schema; }