private void WriteDocument(BlittableJsonTextWriter writer, JsonOperationContext context, Document document, HashSet <string> propertiesPreviewToSend, HashSet <string> fullPropertiesToSend)
        {
            if (_buffers == null)
            {
                _buffers = new BlittableJsonReaderObject.PropertiesInsertionBuffer();
            }

            writer.WriteStartObject();

            document.Data.TryGet(Constants.Documents.Metadata.Key, out BlittableJsonReaderObject metadata);

            bool first = true;

            var objectsStubs = new HashSet <LazyStringValue>();
            var arraysStubs  = new HashSet <LazyStringValue>();
            var trimmedValue = new HashSet <LazyStringValue>();

            var size = document.Data.GetPropertiesByInsertionOrder(_buffers);
            var prop = new BlittableJsonReaderObject.PropertyDetails();

            for (int i = 0; i < size; i++)
            {
                document.Data.GetPropertyByIndex(_buffers.Properties[i], ref prop);
                var sendFull = fullPropertiesToSend.Contains(prop.Name);
                if (sendFull || propertiesPreviewToSend.Contains(prop.Name))
                {
                    var strategy = sendFull ? ValueWriteStrategy.Passthrough : FindWriteStrategy(prop.Token & BlittableJsonReaderBase.TypesMask, prop.Value);

                    if (strategy == ValueWriteStrategy.Passthrough || strategy == ValueWriteStrategy.Trim)
                    {
                        if (first == false)
                        {
                            writer.WriteComma();
                        }
                        first = false;
                    }

                    switch (strategy)
                    {
                    case ValueWriteStrategy.Passthrough:
                        writer.WritePropertyName(prop.Name);
                        writer.WriteValue(prop.Token & BlittableJsonReaderBase.TypesMask, prop.Value);
                        break;

                    case ValueWriteStrategy.SubstituteWithArrayStub:
                        arraysStubs.Add(prop.Name);
                        break;

                    case ValueWriteStrategy.SubstituteWithObjectStub:
                        objectsStubs.Add(prop.Name);
                        break;

                    case ValueWriteStrategy.Trim:
                        writer.WritePropertyName(prop.Name);
                        WriteTrimmedValue(writer, prop.Token & BlittableJsonReaderBase.TypesMask, prop.Value);
                        trimmedValue.Add(prop.Name);
                        break;
                    }
                }
            }
            if (first == false)
            {
                writer.WriteComma();
            }

            var extraMetadataProperties = new DynamicJsonValue
            {
                [ObjectStubsKey]  = new DynamicJsonArray(objectsStubs),
                [ArrayStubsKey]   = new DynamicJsonArray(arraysStubs),
                [TrimmedValueKey] = new DynamicJsonArray(trimmedValue)
            };

            if (metadata != null)
            {
                metadata.Modifications = extraMetadataProperties;
                metadata = context.ReadObject(metadata, document.Id);
            }
            else
            {
                metadata = context.ReadObject(extraMetadataProperties, document.Id);
            }

            writer.WriteMetadata(document, metadata);
            writer.WriteEndObject();
        }
        private unsafe void WriteDocument(BlittableJsonTextWriter writer, JsonOperationContext context, Document document, HashSet <string> propertiesPreviewToSend, HashSet <string> fullPropertiesToSend)
        {
            writer.WriteStartObject();

            document.Data.TryGet(Constants.Documents.Metadata.Key, out BlittableJsonReaderObject metadata);

            bool first = true;

            var arrayStubsJson  = new DynamicJsonValue();
            var objectStubsJson = new DynamicJsonValue();
            var trimmedValue    = new HashSet <LazyStringValue>();

            var prop = new BlittableJsonReaderObject.PropertyDetails();

            using (var buffers = document.Data.GetPropertiesByInsertionOrder())
            {
                for (int i = 0; i < buffers.Size; i++)
                {
                    document.Data.GetPropertyByIndex(buffers.Properties[i], ref prop);
                    var sendFull = fullPropertiesToSend.Contains(prop.Name);
                    if (sendFull || propertiesPreviewToSend.Contains(prop.Name))
                    {
                        var strategy = sendFull ? ValueWriteStrategy.Passthrough : FindWriteStrategy(prop.Token & BlittableJsonReaderBase.TypesMask, prop.Value);

                        if (strategy == ValueWriteStrategy.Passthrough || strategy == ValueWriteStrategy.Trim)
                        {
                            if (first == false)
                            {
                                writer.WriteComma();
                            }
                            first = false;
                        }

                        switch (strategy)
                        {
                        case ValueWriteStrategy.Passthrough:
                            writer.WritePropertyName(prop.Name);
                            writer.WriteValue(prop.Token & BlittableJsonReaderBase.TypesMask, prop.Value);
                            break;

                        case ValueWriteStrategy.SubstituteWithArrayStub:
                            arrayStubsJson[prop.Name] = ((BlittableJsonReaderArray)prop.Value).Length;
                            break;

                        case ValueWriteStrategy.SubstituteWithObjectStub:
                            objectStubsJson[prop.Name] = ((BlittableJsonReaderObject)prop.Value).Count;
                            break;

                        case ValueWriteStrategy.Trim:
                            writer.WritePropertyName(prop.Name);
                            WriteTrimmedValue(writer, prop.Token & BlittableJsonReaderBase.TypesMask, prop.Value);
                            trimmedValue.Add(prop.Name);
                            break;
                        }
                    }
                }
            }
            if (first == false)
            {
                writer.WriteComma();
            }

            var extraMetadataProperties = new DynamicJsonValue(metadata)
            {
                [ObjectStubsKey]  = objectStubsJson,
                [ArrayStubsKey]   = arrayStubsJson,
                [TrimmedValueKey] = new DynamicJsonArray(trimmedValue)
            };

            if (metadata != null)
            {
                metadata.Modifications = extraMetadataProperties;

                if (document.Flags.Contain(DocumentFlags.HasCounters) || document.Flags.Contain(DocumentFlags.HasAttachments) || document.Flags.Contain(DocumentFlags.HasTimeSeries))
                {
                    metadata.Modifications.Remove(Constants.Documents.Metadata.Counters);
                    metadata.Modifications.Remove(Constants.Documents.Metadata.Attachments);
                    metadata.Modifications.Remove(Constants.Documents.Metadata.TimeSeries);
                }

                using (var old = metadata)
                {
                    metadata = context.ReadObject(metadata, document.Id);
                }
            }
            else
            {
                metadata = context.ReadObject(extraMetadataProperties, document.Id);
            }

            writer.WriteMetadata(document, metadata);
            writer.WriteEndObject();
        }