public static void WriteDocumentMetadata(this BlittableJsonTextWriter writer, JsonOperationContext context,
                                                 Document document)
        {
            if (_buffers == null)
            {
                _buffers = new BlittableJsonReaderObject.PropertiesInsertionBuffer();
            }

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

            writer.WriteEndObject();
        }
        private static HashSet <LazyStringValue> ExtractColumnNames(Document[] documents, DocumentsOperationContext context)
        {
            if (_buffers == null)
            {
                _buffers = new BlittableJsonReaderObject.PropertiesInsertionBuffer();
            }

            var columns = new HashSet <LazyStringValue>();

            foreach (var document in documents)
            {
                FetchColumnNames(document.Data, columns, _buffers);
            }

            RemoveMetadata(context, columns);

            return(columns);
        }
        private static void WriteDocumentProperties(this BlittableJsonTextWriter writer, JsonOperationContext context, Document document)
        {
            if (_buffers == null)
            {
                _buffers = new BlittableJsonReaderObject.PropertiesInsertionBuffer();
            }

            var first = true;
            BlittableJsonReaderObject metadata = null;
            var metadataField = context.GetLazyStringForFieldWithCaching(MetadataKeySegment);

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

            for (var i = 0; i < size; i++)
            {
                document.Data.GetPropertyByIndex(_buffers.Properties[i], ref prop);
                if (metadataField.Equals(prop.Name))
                {
                    metadata = (BlittableJsonReaderObject)prop.Value;
                    continue;
                }
                if (first == false)
                {
                    writer.WriteComma();
                }
                first = false;
                writer.WritePropertyName(prop.Name);
                writer.WriteValue(prop.Token & BlittableJsonReaderBase.TypesMask, prop.Value);
            }

            if (first == false)
            {
                writer.WriteComma();
            }
            WriteMetadata(writer, document, metadata);
        }
        public static void WriteDocumentPropertiesWithoutMetdata(this BlittableJsonTextWriter writer, JsonOperationContext context, Document document)
        {
            if (_buffers == null)
            {
                _buffers = new BlittableJsonReaderObject.PropertiesInsertionBuffer();
            }

            var first = true;

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

            for (var i = 0; i < size; i++)
            {
                document.Data.GetPropertyByIndex(_buffers.Properties[i], ref prop);
                if (first == false)
                {
                    writer.WriteComma();
                }
                first = false;
                writer.WritePropertyName(prop.Name);
                writer.WriteValue(prop.Token & BlittableJsonReaderBase.TypesMask, prop.Value);
            }
        }
        public static void FetchColumnNames(BlittableJsonReaderObject data, HashSet <LazyStringValue> columns, BlittableJsonReaderObject.PropertiesInsertionBuffer buffers)
        {
            var size = data.GetPropertiesByInsertionOrder(buffers);
            var prop = new BlittableJsonReaderObject.PropertyDetails();

            for (var i = 0; i < size; i++)
            {
                data.GetPropertyByIndex(buffers.Properties[i], ref prop);
                var propName = prop.Name;
                if (columns.Contains(propName) == false)
                {
                    columns.Add(prop.Name);
                }
            }
        }
 static StudioCollectionsHandler()
 {
     ThreadLocalCleanup.ReleaseThreadLocalState += () => _buffers = null;
 }
        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();
        }
        public Task GetCollectionFields()
        {
            var collection = GetStringQueryString("collection", required: false);
            var prefix     = GetStringQueryString("prefix", required: false);

            using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
                using (context.OpenReadTransaction())
                {
                    long   totalResults;
                    string changeVector;
                    string etag = null;

                    if (string.IsNullOrEmpty(collection))
                    {
                        changeVector = DocumentsStorage.GetDatabaseChangeVector(context);
                        totalResults = Database.DocumentsStorage.GetNumberOfDocuments(context);
                        etag         = $"{changeVector}/{totalResults}";
                    }
                    else
                    {
                        changeVector = Database.DocumentsStorage.GetLastDocumentChangeVector(context, collection);
                        totalResults = Database.DocumentsStorage.GetCollection(collection, context).Count;

                        if (changeVector != null)
                        {
                            etag = $"{changeVector}/{totalResults}";
                        }
                    }

                    if (etag != null && GetStringFromHeaders("If-None-Match") == etag)
                    {
                        HttpContext.Response.StatusCode = (int)HttpStatusCode.NotModified;
                        return(Task.CompletedTask);
                    }
                    HttpContext.Response.Headers["ETag"] = "\"" + etag + "\"";

                    if (_buffers == null)
                    {
                        _buffers = new BlittableJsonReaderObject.PropertiesInsertionBuffer();
                    }

                    var fields = new Dictionary <LazyStringValue, FieldType>(LazyStringValueComparer.Instance);

                    if (string.IsNullOrEmpty(collection))
                    {
                        foreach (var collectionStats in Database.DocumentsStorage.GetCollections(context))
                        {
                            FetchFieldsForCollection(context, collectionStats.Name, prefix, fields, _buffers);
                        }
                    }
                    else
                    {
                        FetchFieldsForCollection(context, collection, prefix, fields, _buffers);
                    }

                    using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                    {
                        writer.WriteStartObject();

                        var first = true;
                        foreach (var field in fields)
                        {
                            if (first == false)
                            {
                                writer.WriteComma();
                            }
                            first = false;

                            writer.WritePropertyName(field.Key);
                            writer.WriteString(field.Value.ToString());
                        }

                        writer.WriteEndObject();
                    }

                    return(Task.CompletedTask);
                }
        }
        public void FetchFields(BlittableJsonReaderObject data, Dictionary <LazyStringValue, FieldType> fields, BlittableJsonReaderObject.PropertiesInsertionBuffer buffers)
        {
            var size = data.GetPropertiesByInsertionOrder(buffers);
            var prop = new BlittableJsonReaderObject.PropertyDetails();

            for (var i = 0; i < size; i++)
            {
                data.GetPropertyByIndex(buffers.Properties[i], ref prop);
                var type = GetFieldType(prop.Token & BlittableJsonReaderBase.TypesMask, prop.Value);
                if (fields.TryGetValue(prop.Name, out var token))
                {
                    if (token != type)
                    {
                        fields[prop.Name] = token | type;
                    }
                }
                else
                {
                    fields[prop.Name] = type;
                }
            }
        }
        public void FetchFieldsForCollection(DocumentsOperationContext context, string collection, string prefix,
                                             Dictionary <LazyStringValue, FieldType> fields, BlittableJsonReaderObject.PropertiesInsertionBuffer buffers)
        {
            var document = Database.DocumentsStorage.GetDocumentsInReverseEtagOrder(context, collection, 0, 1).FirstOrDefault();

            if (document != null)
            {
                var data = document.Data;
                if (string.IsNullOrEmpty(prefix))
                {
                    FetchFields(data, fields, _buffers);
                }
                else
                {
                    var prefixFields = prefix.Split('.', StringSplitOptions.RemoveEmptyEntries);
                    for (var i = 0; i < prefixFields.Length; i++)
                    {
                        var prefixField = prefixFields[i];
                        var index       = data.GetPropertyIndex(prefixField);
                        if (index < 0)
                        {
                            break;
                        }

                        var prop = new BlittableJsonReaderObject.PropertyDetails();
                        data.GetPropertyByIndex(index, ref prop);
                        var token = prop.Token & BlittableJsonReaderBase.TypesMask;

                        if (i + 1 == prefixFields.Length)
                        {
                            switch (token)
                            {
                            case BlittableJsonToken.StartObject:
                                FetchFields((BlittableJsonReaderObject)prop.Value, fields, _buffers);
                                break;

                            case BlittableJsonToken.StartArray:
                                var array = (BlittableJsonReaderArray)prop.Value;
                                for (int j = 0; j < Math.Min(array.Length, MaxArrayItemsToFetch); j++)
                                {
                                    var item = array[i];
                                    if (item is BlittableJsonReaderObject itemObject)
                                    {
                                        FetchFields(itemObject, fields, _buffers);
                                    }
                                }
                                break;
                            }
                        }
                        else
                        {
                            if (token != BlittableJsonToken.StartObject)
                            {
                                break;
                            }

                            data = (BlittableJsonReaderObject)prop.Value;
                        }
                    }
                }
            }
        }