/// <summary> /// Parses a continuation token and returns the corresponding to the /// next page's <see cref="SearchOptions"/>. /// </summary> /// <param name="continuationToken"> /// The serialized continuation token. /// </param> /// <returns>The continuation token's next page options.</returns> public static SearchOptions Deserialize(string continuationToken) { Argument.AssertNotNullOrEmpty(continuationToken, nameof(continuationToken)); byte[] decoded = Convert.FromBase64String(continuationToken); try { using JsonDocument json = JsonDocument.Parse(decoded); if (json.RootElement.ValueKind == JsonValueKind.Object && json.RootElement.TryGetProperty(ApiVersionName, out JsonElement apiVersion) && apiVersion.ValueKind == JsonValueKind.String && // Today we only validate against a single known version, // but in the future we may want to support a range of // valid continuation token serialization formats. This // will need to be updated accordingly. string.Equals( apiVersion.GetString(), SearchClientOptions.ContinuationTokenVersion.ToVersionString(), StringComparison.OrdinalIgnoreCase) && json.RootElement.TryGetProperty(NextPageParametersName, out JsonElement nextPageParams) && nextPageParams.ValueKind == JsonValueKind.Object) { // We only use the nextPageParameters because we do all of // our searching via HTTP POST requests return(SearchOptions.DeserializeSearchOptions(nextPageParams)); } } catch (JsonException) { } throw new ArgumentException("Invalid continuation token", nameof(continuationToken)); }
internal static SearchDocumentsResult DeserializeSearchDocumentsResult(JsonElement element) { Optional <long> odataCount = default; Optional <double> searchCoverage = default; Optional <IReadOnlyDictionary <string, IList <FacetResult> > > searchFacets = default; Optional <SearchOptions> searchNextPageParameters = default; IReadOnlyList <SearchResult> value = default; Optional <string> odataNextLink = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("@odata.count")) { odataCount = property.Value.GetInt64(); continue; } if (property.NameEquals("@search.coverage")) { searchCoverage = property.Value.GetDouble(); continue; } if (property.NameEquals("@search.facets")) { Dictionary <string, IList <FacetResult> > dictionary = new Dictionary <string, IList <FacetResult> >(); foreach (var property0 in property.Value.EnumerateObject()) { List <FacetResult> array = new List <FacetResult>(); foreach (var item in property0.Value.EnumerateArray()) { array.Add(FacetResult.DeserializeFacetResult(item)); } dictionary.Add(property0.Name, array); } searchFacets = dictionary; continue; } if (property.NameEquals("@search.nextPageParameters")) { searchNextPageParameters = SearchOptions.DeserializeSearchOptions(property.Value); continue; } if (property.NameEquals("value")) { List <SearchResult> array = new List <SearchResult>(); foreach (var item in property.Value.EnumerateArray()) { array.Add(SearchResult.DeserializeSearchResult(item)); } value = array; continue; } if (property.NameEquals("@odata.nextLink")) { odataNextLink = property.Value.GetString(); continue; } } return(new SearchDocumentsResult(Optional.ToNullable(odataCount), Optional.ToNullable(searchCoverage), Optional.ToDictionary(searchFacets), searchNextPageParameters.Value, value, odataNextLink.Value)); }
/// <summary> /// Read the @search.nextPageParameters property value. /// </summary> /// <param name="reader">The JSON reader.</param> /// <returns>The next SearchOptions.</returns> private static SearchOptions ReadNextPageOptions(ref Utf8JsonReader reader) { // Next page options aren't required, so short circuit if nothing // is found if (reader.TokenType == JsonTokenType.Null) { return(null); } // Use the generated SearchOptions parsing code using JsonDocument doc = JsonDocument.ParseValue(ref reader); return(SearchOptions.DeserializeSearchOptions(doc.RootElement)); }
#pragma warning disable CS1572 // Not all parameters will be used depending on feature flags /// <summary> /// Deserialize the SearchResults. /// </summary> /// <param name="json">A JSON stream.</param> /// <param name="serializer"> /// Optional serializer that can be used to customize the serialization /// of strongly typed models. /// </param> /// <param name="async">Whether to execute sync or async.</param> /// <param name="cancellationToken"> /// Optional <see cref="CancellationToken"/> to propagate notifications /// that the operation should be canceled. /// </param> /// <returns>Deserialized SearchResults.</returns> internal static async Task <SearchResults <T> > DeserializeAsync( Stream json, #if EXPERIMENTAL_SERIALIZER ObjectSerializer serializer, #endif bool async, CancellationToken cancellationToken) #pragma warning restore CS1572 { // Parse the JSON using JsonDocument doc = async ? await JsonDocument.ParseAsync(json, cancellationToken : cancellationToken).ConfigureAwait(false) : JsonDocument.Parse(json); JsonSerializerOptions defaultSerializerOptions = JsonSerialization.SerializerOptions; SearchResults <T> results = new SearchResults <T>(); foreach (JsonProperty prop in doc.RootElement.EnumerateObject()) { if (prop.NameEquals(Constants.ODataCountKeyJson.EncodedUtf8Bytes) && prop.Value.ValueKind != JsonValueKind.Null) { results.TotalCount = prop.Value.GetInt64(); } else if (prop.NameEquals(Constants.SearchCoverageKeyJson.EncodedUtf8Bytes) && prop.Value.ValueKind != JsonValueKind.Null) { results.Coverage = prop.Value.GetDouble(); } else if (prop.NameEquals(Constants.SearchFacetsKeyJson.EncodedUtf8Bytes)) { results.Facets = new Dictionary <string, IList <FacetResult> >(); foreach (JsonProperty facetObject in prop.Value.EnumerateObject()) { // Get the values of the facet List <FacetResult> facets = new List <FacetResult>(); foreach (JsonElement facetValue in facetObject.Value.EnumerateArray()) { Dictionary <string, object> facetValues = new Dictionary <string, object>(); long?facetCount = null; foreach (JsonProperty facetProperty in facetValue.EnumerateObject()) { if (facetProperty.NameEquals(Constants.CountKeyJson.EncodedUtf8Bytes)) { if (facetProperty.Value.ValueKind != JsonValueKind.Null) { facetCount = facetProperty.Value.GetInt64(); } } else { object value = facetProperty.Value.GetSearchObject(); facetValues[facetProperty.Name] = value; } } facets.Add(new FacetResult(facetCount, facetValues)); } // Add the facet to the results results.Facets[facetObject.Name] = facets; } } else if (prop.NameEquals(Constants.ODataNextLinkKeyJson.EncodedUtf8Bytes)) { results.NextUri = new Uri(prop.Value.GetString()); } else if (prop.NameEquals(Constants.SearchNextPageKeyJson.EncodedUtf8Bytes)) { results.NextOptions = SearchOptions.DeserializeSearchOptions(prop.Value); } else if (prop.NameEquals(Constants.ValueKeyJson.EncodedUtf8Bytes)) { foreach (JsonElement element in prop.Value.EnumerateArray()) { SearchResult <T> result = await SearchResult <T> .DeserializeAsync( element, #if EXPERIMENTAL_SERIALIZER serializer, #endif defaultSerializerOptions, async, cancellationToken) .ConfigureAwait(false); results.Values.Add(result); } } } return(results); }
internal static SearchDocumentsResult DeserializeSearchDocumentsResult(JsonElement element) { long? odataCount = default; double?searchCoverage = default; IReadOnlyDictionary <string, IList <FacetResult> > searchFacets = default; SearchOptions searchNextPageParameters = default; IReadOnlyList <SearchResult> value = default; string odataNextLink = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("@odata.count")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } odataCount = property.Value.GetInt64(); continue; } if (property.NameEquals("@search.coverage")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } searchCoverage = property.Value.GetDouble(); continue; } if (property.NameEquals("@search.facets")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } Dictionary <string, IList <FacetResult> > dictionary = new Dictionary <string, IList <FacetResult> >(); foreach (var property0 in property.Value.EnumerateObject()) { if (property0.Value.ValueKind == JsonValueKind.Null) { dictionary.Add(property0.Name, null); } else { List <FacetResult> array = new List <FacetResult>(); foreach (var item in property0.Value.EnumerateArray()) { if (item.ValueKind == JsonValueKind.Null) { array.Add(null); } else { array.Add(FacetResult.DeserializeFacetResult(item)); } } dictionary.Add(property0.Name, array); } } searchFacets = dictionary; continue; } if (property.NameEquals("@search.nextPageParameters")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } searchNextPageParameters = SearchOptions.DeserializeSearchOptions(property.Value); continue; } if (property.NameEquals("value")) { List <SearchResult> array = new List <SearchResult>(); foreach (var item in property.Value.EnumerateArray()) { if (item.ValueKind == JsonValueKind.Null) { array.Add(null); } else { array.Add(SearchResult.DeserializeSearchResult(item)); } } value = array; continue; } if (property.NameEquals("@odata.nextLink")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } odataNextLink = property.Value.GetString(); continue; } } return(new SearchDocumentsResult(odataCount, searchCoverage, searchFacets, searchNextPageParameters, value, odataNextLink)); }
internal static SearchDocumentsResult DeserializeSearchDocumentsResult(JsonElement element) { SearchDocumentsResult result = new SearchDocumentsResult(); foreach (var property in element.EnumerateObject()) { if (property.NameEquals("@odata.count")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } result.Count = property.Value.GetInt64(); continue; } if (property.NameEquals("@search.coverage")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } result.Coverage = property.Value.GetDouble(); continue; } if (property.NameEquals("@search.facets")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } result.Facets = new Dictionary <string, IList <FacetResult> >(); foreach (var property0 in property.Value.EnumerateObject()) { IList <FacetResult> value = new List <FacetResult>(); foreach (var item in property0.Value.EnumerateArray()) { value.Add(FacetResult.DeserializeFacetResult(item)); } result.Facets.Add(property0.Name, value); } continue; } if (property.NameEquals("@search.nextPageParameters")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } result.NextPageParameters = SearchOptions.DeserializeSearchOptions(property.Value); continue; } if (property.NameEquals("value")) { foreach (var item in property.Value.EnumerateArray()) { result.Results.Add(SearchResult.DeserializeSearchResult(item)); } continue; } if (property.NameEquals("@odata.nextLink")) { if (property.Value.ValueKind == JsonValueKind.Null) { continue; } result.NextLink = property.Value.GetString(); continue; } } return(result); }