< Summary

Class:Azure.Search.Documents.SearchClient
Assembly:Azure.Search.Documents
File(s):C:\Git\azure-sdk-for-net\sdk\search\Azure.Search.Documents\src\SearchClient.cs
Covered lines:374
Uncovered lines:31
Coverable lines:405
Total lines:1908
Line coverage:92.3% (374 of 405)
Covered branches:57
Total branches:58
Branch coverage:98.2% (57 of 58)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
get_Endpoint()-100%100%
get_ServiceName()-100%100%
get_IndexName()-100%100%
get_Serializer()-100%100%
get_Pipeline()-100%100%
get_ClientDiagnostics()-100%100%
get_Version()-100%100%
get_Protocol()-100%100%
.ctor()-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
GetDocumentCount(...)-100%100%
GetDocumentCountAsync()-100%100%
GetDocument(...)-100%100%
GetDocumentAsync()-100%100%
GetDocumentInternal()-95.65%90%
Search(...)-100%100%
SearchAsync()-100%100%
SearchInternal()-100%100%
SearchInternal()-100%100%
Suggest(...)-100%100%
SuggestAsync()-100%100%
SuggestInternal()-100%100%
Autocomplete(...)-100%100%
AutocompleteAsync()-100%100%
AutocompleteInternal()-100%100%
IndexDocuments(...)-100%100%
IndexDocumentsAsync()-100%100%
IndexDocumentsInternal()-100%100%
UploadDocuments(...)-70%100%
UploadDocumentsAsync()-72.73%100%
MergeDocuments(...)-70%100%
MergeDocumentsAsync()-72.73%100%
MergeOrUploadDocuments(...)-70%100%
MergeOrUploadDocumentsAsync()-72.73%100%
DeleteDocuments(...)-70%100%
DeleteDocumentsAsync()-72.73%100%
DeleteDocuments(...)-70%100%
DeleteDocumentsAsync()-72.73%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\search\Azure.Search.Documents\src\SearchClient.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Text.Json;
 8using System.Threading;
 9using System.Threading.Tasks;
 10using Azure.Core;
 11using Azure.Core.Pipeline;
 12#if EXPERIMENTAL_SERIALIZER
 13using Azure.Core.Serialization;
 14#endif
 15using Azure.Search.Documents.Indexes;
 16using Azure.Search.Documents.Models;
 17
 18namespace Azure.Search.Documents
 19{
 20    /// <summary>
 21    /// Azure Cognitive Search client that can be used to query an index and
 22    /// upload, merge, or delete documents.
 23    /// </summary>
 24    public class SearchClient
 25    {
 26        /// <summary>
 27        /// Gets the URI endpoint of the Search Service.  This is likely
 28        /// to be similar to "https://{search_service}.search.windows.net".
 29        /// </summary>
 30        /// <remarks>
 31        /// This is not the URI of the Search Index.  You could construct that
 32        /// URI with "{Endpoint}/indexes/{IndexName}" if needed.
 33        /// </remarks>
 10434        public virtual Uri Endpoint { get; }
 35
 36        /// <summary>
 37        /// The name of the Search Service, lazily obtained from the
 38        /// <see cref="Endpoint"/>.
 39        /// </summary>
 40        private string _serviceName = null;
 41
 42        /// <summary>
 43        /// Gets the name of the Search Service.
 44        /// </summary>
 45        public virtual string ServiceName =>
 446            _serviceName ??= Endpoint.GetSearchServiceName();
 47
 48        /// <summary>
 49        /// Gets the name of the Search Index.
 50        /// </summary>
 34851        public virtual string IndexName { get; }
 52
 53#if EXPERIMENTAL_SERIALIZER
 54        /// <summary>
 55        /// Gets an <see cref="ObjectSerializer"/> that can be used to
 56        /// customize the serialization of strongly typed models.
 57        /// </summary>
 25258        private ObjectSerializer Serializer { get; }
 59#endif
 60
 61        /// <summary>
 62        /// Gets the authenticated <see cref="HttpPipeline"/> used for sending
 63        /// requests to the Search Service.
 64        /// </summary>
 60965        private HttpPipeline Pipeline { get; }
 66
 67        /// <summary>
 68        /// Gets the <see cref="Azure.Core.Pipeline.ClientDiagnostics"/> used
 69        /// to provide tracing support for the client library.
 70        /// </summary>
 61671        private ClientDiagnostics ClientDiagnostics { get; }
 72
 73        /// <summary>
 74        /// Gets the REST API version of the Search Service to use when making
 75        /// requests.
 76        /// </summary>
 34477        private SearchClientOptions.ServiceVersion Version { get; }
 78
 79        /// <summary>
 80        /// Gets the generated document operations to make requests.
 81        /// </summary>
 24582        private DocumentsRestClient Protocol { get; }
 83
 84        #region ctors
 85        /// <summary>
 86        /// Initializes a new instance of the SearchClient class for
 87        /// mocking.
 88        /// </summary>
 47689        protected SearchClient() { }
 90
 91        /// <summary>
 92        /// Initializes a new instance of the SearchClient class for
 93        /// querying an index and uploading, merging, or deleting documents.
 94        /// </summary>
 95        /// <param name="endpoint">
 96        /// Required.  The URI endpoint of the Search Service.  This is likely
 97        /// to be similar to "https://{search_service}.search.windows.net".
 98        /// The URI must use HTTPS.
 99        /// </param>
 100        /// <param name="indexName">
 101        /// Required.  The name of the Search Index.
 102        /// </param>
 103        /// <param name="credential">
 104        /// Required.  The API key credential used to authenticate requests
 105        /// against the search service.  You need to use an admin key to
 106        /// modify the documents in a Search Index.  See
 107        /// <see href="https://docs.microsoft.com/azure/search/search-security-api-keys">Create and manage api-keys for 
 108        /// for more information about API keys in Azure Cognitive Search.
 109        /// </param>
 110        /// <exception cref="ArgumentNullException">
 111        /// Thrown when the <paramref name="endpoint"/>,
 112        /// <paramref name="indexName"/>, or <paramref name="credential"/> is
 113        /// null.
 114        /// </exception>
 115        /// <exception cref="ArgumentException">
 116        /// Thrown when the <paramref name="endpoint"/> is not using HTTPS or
 117        /// the <paramref name="indexName"/> is empty.
 118        /// </exception>
 119        public SearchClient(
 120            Uri endpoint,
 121            string indexName,
 122            AzureKeyCredential credential) :
 18123            this(endpoint, indexName, credential, null)
 124        {
 8125        }
 126
 127        /// <summary>
 128        /// Initializes a new instance of the SearchClient class for
 129        /// querying an index and uploading, merging, or deleting documents.
 130        /// </summary>
 131        /// <param name="endpoint">
 132        /// Required.  The URI endpoint of the Search Service.  This is likely
 133        /// to be similar to "https://{search_service}.search.windows.net".
 134        /// The URI must use HTTPS.
 135        /// </param>
 136        /// <param name="indexName">
 137        /// Required.  The name of the Search Index.
 138        /// </param>
 139        /// <param name="credential">
 140        /// Required.  The API key credential used to authenticate requests
 141        /// against the search service.  You need to use an admin key to
 142        /// modify the documents in a Search Index.  See
 143        /// <see href="https://docs.microsoft.com/azure/search/search-security-api-keys">Create and manage api-keys for 
 144        /// for more information about API keys in Azure Cognitive Search.
 145        /// </param>
 146        /// <param name="options">
 147        /// Client configuration options for connecting to Azure Cognitive
 148        /// Search.
 149        /// </param>
 150        /// <exception cref="ArgumentNullException">
 151        /// Thrown when the <paramref name="endpoint"/>,
 152        /// <paramref name="indexName"/>, or <paramref name="credential"/> is
 153        /// null.
 154        /// </exception>
 155        /// <exception cref="ArgumentException">
 156        /// Thrown when the <paramref name="endpoint"/> is not using HTTPS or
 157        /// the <paramref name="indexName"/> is empty.
 158        /// </exception>
 178159        public SearchClient(
 178160            Uri endpoint,
 178161            string indexName,
 178162            AzureKeyCredential credential,
 178163            SearchClientOptions options)
 164        {
 178165            Argument.AssertNotNull(endpoint, nameof(endpoint));
 176166            endpoint.AssertHttpsScheme(nameof(endpoint));
 174167            Argument.AssertNotNullOrEmpty(indexName, nameof(indexName));
 170168            Argument.AssertNotNull(credential, nameof(credential));
 169
 168170            options ??= new SearchClientOptions();
 168171            Endpoint = endpoint;
 168172            IndexName = indexName;
 173#if EXPERIMENTAL_SERIALIZER
 168174            Serializer = options.Serializer;
 175#endif
 168176            ClientDiagnostics = new ClientDiagnostics(options);
 168177            Pipeline = options.Build(credential);
 168178            Version = options.Version;
 179
 168180            Protocol = new DocumentsRestClient(
 168181                ClientDiagnostics,
 168182                Pipeline,
 168183                endpoint.ToString(),
 168184                IndexName,
 168185                null,
 168186                Version.ToVersionString());
 168187        }
 188
 189#pragma warning disable CS1573 // Not all parameters will be used depending on feature flags
 190        /// <summary>
 191        /// Initializes a new instance of the SearchClient class from a
 192        /// <see cref="SearchIndexClient"/>.
 193        /// </summary>
 194        /// <param name="endpoint">
 195        /// Required.  The URI endpoint of the Search Service.  This is likely
 196        /// to be similar to "https://{search_service}.search.windows.net".
 197        /// The URI must use HTTPS.
 198        /// </param>
 199        /// <param name="indexName">
 200        /// Required.  The name of the Search Index.
 201        /// </param>
 202        /// <param name="pipeline">
 203        /// The authenticated <see cref="HttpPipeline"/> used for sending
 204        /// requests to the Search Service.
 205        /// </param>
 206        /// <param name="diagnostics">
 207        /// The <see cref="Azure.Core.Pipeline.ClientDiagnostics"/> used to
 208        /// provide tracing support for the client library.
 209        /// </param>
 210        /// <param name="version">
 211        /// The REST API version of the Search Service to use when making
 212        /// requests.
 213        /// </param>
 80214        internal SearchClient(
 80215            Uri endpoint,
 80216            string indexName,
 80217#if EXPERIMENTAL_SERIALIZER
 80218            ObjectSerializer serializer,
 80219#endif
 80220            HttpPipeline pipeline,
 80221            ClientDiagnostics diagnostics,
 80222            SearchClientOptions.ServiceVersion version)
 223        #pragma warning restore CS1573
 224        {
 225            Debug.Assert(endpoint != null);
 226            Debug.Assert(string.Equals(endpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase));
 227            Debug.Assert(!string.IsNullOrEmpty(indexName));
 228            Debug.Assert(pipeline != null);
 229            Debug.Assert(diagnostics != null);
 230            Debug.Assert(
 231                SearchClientOptions.ServiceVersion.V2020_06_30 <= version &&
 232                version <= SearchClientOptions.LatestVersion);
 233
 80234            Endpoint = endpoint;
 80235            IndexName = indexName;
 236#if EXPERIMENTAL_SERIALIZER
 80237            Serializer = serializer;
 238#endif
 80239            ClientDiagnostics = diagnostics;
 80240            Pipeline = pipeline;
 80241            Version = version;
 242
 80243            Protocol = new DocumentsRestClient(
 80244                ClientDiagnostics,
 80245                Pipeline,
 80246                endpoint.ToString(),
 80247                IndexName,
 80248                null,
 80249                Version.ToVersionString());
 80250        }
 251        #endregion ctors
 252
 253        #region GetDocumentCount
 254        /// <summary>
 255        /// Retrieves a count of the number of documents in this search index.
 256        /// </summary>
 257        /// <param name="cancellationToken">
 258        /// Optional <see cref="CancellationToken"/> to propagate notifications
 259        /// that the operation should be canceled.
 260        /// </param>
 261        /// <returns>The number of documents in the search index.</returns>
 262        /// <exception cref="RequestFailedException">
 263        /// Thrown when a failure is returned by the Search Service.
 264        /// </exception>
 265        public virtual Response<long> GetDocumentCount(
 266            CancellationToken cancellationToken = default)
 267        {
 20268            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(GetDocumentCoun
 20269            scope.Start();
 270            try
 271            {
 20272                return Protocol.Count(
 20273                    cancellationToken);
 274            }
 1275            catch (Exception ex)
 276            {
 1277                scope.Failed(ex);
 1278                throw;
 279            }
 19280        }
 281
 282        /// <summary>
 283        /// Retrieves a count of the number of documents in this search index.
 284        /// </summary>
 285        /// <param name="cancellationToken">
 286        /// Optional <see cref="CancellationToken"/> to propagate notifications
 287        /// that the operation should be canceled.
 288        /// </param>
 289        /// <returns>The number of documents in the search index.</returns>
 290        /// <exception cref="RequestFailedException">
 291        /// Thrown when a failure is returned by the Search Service.
 292        /// </exception>
 293        public virtual async Task<Response<long>> GetDocumentCountAsync(
 294            CancellationToken cancellationToken = default)
 295        {
 20296            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(GetDocumentCoun
 20297            scope.Start();
 298            try
 299            {
 20300                return await Protocol.CountAsync(
 20301                    cancellationToken)
 20302                    .ConfigureAwait(false);
 303            }
 1304            catch (Exception ex)
 305            {
 1306                scope.Failed(ex);
 1307                throw;
 308            }
 19309        }
 310        #endregion GetDocumentCount
 311
 312        #region GetDocument
 313        /// <summary>
 314        /// Retrieves a document from Azure Cognitive Search.  This is useful
 315        /// when a user clicks on a specific search result, and you want to
 316        /// look up specific details about that document. You can only get one
 317        /// document at a time.  Use Search to get multiple documents in a
 318        /// single request.
 319        /// <see href="https://docs.microsoft.com/rest/api/searchservice/lookup-document">Lookup Document</see>
 320        /// </summary>
 321        /// <typeparam name="T">
 322        /// The .NET type that maps to the index schema. Instances of this type
 323        /// can be retrieved as documents from the index.
 324        /// </typeparam>
 325        /// <param name="key">
 326        /// Required.  An string value that uniquely identifies each document
 327        /// in the index.  The key is sometimes referred to as a document ID.
 328        /// See
 329        /// <see href="https://docs.microsoft.com/rest/api/searchservice/naming-rules">Naming rules</see>
 330        /// for the rules for constructing valid document keys.
 331        /// </param>
 332        /// <param name="options">
 333        /// Options to customize the operation's behavior.
 334        /// </param>
 335        /// <param name="cancellationToken">
 336        /// Optional <see cref="CancellationToken"/> to propagate notifications
 337        /// that the operation should be canceled.
 338        /// </param>
 339        /// <returns>
 340        /// The document corresponding to the <paramref name="key"/>.
 341        /// </returns>
 342        /// <exception cref="RequestFailedException">
 343        /// Thrown when a failure is returned by the Search Service.
 344        /// </exception>
 345        /// <remarks>
 346        /// The generic overloads of the <see cref="GetDocument"/> and
 347        /// <see cref="GetDocumentAsync"/> methods support mapping of Azure
 348        /// Search field types to .NET types via the type parameter
 349        /// <typeparamref name="T"/>.  Note that all search field types except
 350        /// collections are nullable, so we recommend using nullable types for
 351        /// the properties of <typeparamref name="T"/>. See
 352        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 353        /// for more information.
 354        /// </remarks>
 355        public virtual Response<T> GetDocument<T>(
 356            string key,
 357            GetDocumentOptions options = null,
 358            CancellationToken cancellationToken = default) =>
 29359            GetDocumentInternal<T>(
 29360                key,
 29361                options,
 29362                async: false,
 29363                cancellationToken)
 29364                .EnsureCompleted();
 365
 366        /// <summary>
 367        /// Retrieves a document from Azure Cognitive Search.  This is useful
 368        /// when a user clicks on a specific search result, and you want to
 369        /// look up specific details about that document. You can only get one
 370        /// document at a time.  Use Search to get multiple documents in a
 371        /// single request.
 372        /// <see href="https://docs.microsoft.com/rest/api/searchservice/lookup-document">Lookup Document</see>
 373        /// </summary>
 374        /// <typeparam name="T">
 375        /// The .NET type that maps to the index schema. Instances of this type
 376        /// can be retrieved as documents from the index.
 377        /// </typeparam>
 378        /// <param name="key">
 379        /// Required.  An string value that uniquely identifies each document
 380        /// in the index.  The key is sometimes referred to as a document ID.
 381        /// See
 382        /// <see href="https://docs.microsoft.com/rest/api/searchservice/naming-rules">Naming rules</see>
 383        /// for the rules for constructing valid document keys.
 384        /// </param>
 385        /// <param name="options">
 386        /// Options to customize the operation's behavior.
 387        /// </param>
 388        /// <param name="cancellationToken">
 389        /// Optional <see cref="CancellationToken"/> to propagate notifications
 390        /// that the operation should be canceled.
 391        /// </param>
 392        /// <returns>
 393        /// The document corresponding to the <paramref name="key"/>.
 394        /// </returns>
 395        /// <exception cref="RequestFailedException">
 396        /// Thrown when a failure is returned by the Search Service.
 397        /// </exception>
 398        /// <remarks>
 399        /// The <see cref="GetDocument"/> and <see cref="GetDocumentAsync"/>
 400        /// methods support mapping of Azure Search field types to .NET types
 401        /// via the type parameter <typeparamref name="T"/>.  Note that all
 402        /// search field types except collections are nullable, so we recommend
 403        /// using nullable types for the properties of <typeparamref name="T"/>.
 404        /// The type mapping is as follows:
 405        /// <list type="table">
 406        /// <listheader>
 407        /// <term>Search field type</term>
 408        /// <description>.NET type</description>
 409        /// </listheader>
 410        /// <item>
 411        /// <term>Edm.String</term>
 412        /// <description><see cref="String"/> (string in C# and F#)</description>
 413        /// </item>
 414        /// <item>
 415        /// <term>Edm.Boolean</term>
 416        /// <description><see cref="Nullable{Boolean}"/> (bool? in C#,\
 417        /// Nullable&lt;bool&gt; in F#)</description>
 418        /// </item>
 419        /// <item>
 420        /// <term>Edm.Double</term>
 421        /// <description><see cref="Nullable{Double}"/> (double? in C#,
 422        /// Nullable&lt;float&gt; in F#)</description>
 423        /// </item>
 424        /// <item>
 425        /// <term>Edm.Int32</term>
 426        /// <description><see cref="Nullable{Int32}"/> (int? in C#,
 427        /// Nullable&lt;int&gt; in F#)</description>
 428        /// </item>
 429        /// <item>
 430        /// <term>Edm.Int64</term>
 431        /// <description><see cref="Nullable{Int64}"/> (long? in C#,
 432        /// Nullable&lt;int64&gt; in F#)</description>
 433        /// </item>
 434        /// <item>
 435        /// <term>Edm.DateTimeOffset</term>
 436        /// <description>
 437        /// <see cref="Nullable{DateTimeOffset}"/> (DateTimeOffset? in
 438        /// C#, Nullable&lt;DateTimeOffset&gt; in F#) or
 439        /// System.Nullable&lt;System.DateTime&gt; (DateTime? in C#,
 440        /// Nullable&lt;DateTime&gt; in F#). Both types work, although we
 441        /// recommend using DateTimeOffset.  When retrieving documents,
 442        /// DateTime values will always be in UTC. When indexing documents,
 443        /// DateTime values are interpreted as follows:
 444        /// <list type="table">
 445        /// <item>
 446        /// <term>UTC DateTime</term>
 447        /// <description>Sent as-is to the index.</description>
 448        /// </item>
 449        /// <item>
 450        /// <term>Local DateTime</term>
 451        /// <description>Converted to UTC before being sent to the index.
 452        /// </description>
 453        /// </item>
 454        /// <item>
 455        /// <term>DateTime with unspecified time zone</term>
 456        /// <description>Assumed to be UTC and sent as-is to the index.
 457        /// </description>
 458        /// </item>
 459        /// </list>
 460        /// </description>
 461        /// </item>
 462        /// <item>
 463        /// <term>Edm.GeographyPoint</term>
 464        /// <description> Azure.Core.Spatial.PointGeometry
 465        /// </description>
 466        /// </item>
 467        /// <item>
 468        /// <term>Edm.ComplexType</term>
 469        /// <description>
 470        /// Any type that can be deserialized from the JSON objects in the
 471        /// complex field.  This can be a value type or a reference type, but
 472        /// we recommend using a reference type since complex fields are
 473        /// nullable in Azure Cognitive Search.
 474        /// </description>
 475        /// </item>
 476        /// <item>
 477        /// <term>Collection(Edm.String)</term>
 478        /// <description><see cref="IEnumerable{String}"/> (seq&lt;string&gt;
 479        /// in F#)</description>
 480        /// </item>
 481        /// <item>
 482        /// <term>Collection(Edm.Boolean)</term>
 483        /// <description><see cref="IEnumerable{Boolean}"/> (seq&lt;bool&gt; in
 484        /// F#)</description>
 485        /// </item>
 486        /// <item>
 487        /// <term>Collection(Edm.Double)</term>
 488        /// <description><see cref="IEnumerable{Double}"/> (seq&lt;float&gt; in
 489        /// F#)</description>
 490        /// </item>
 491        /// <item>
 492        /// <term>Collection(Edm.Int32)</term>
 493        /// <description><see cref="IEnumerable{Int32}"/> (seq&lt;int&gt; in
 494        /// F#)</description>
 495        /// </item>
 496        /// <item>
 497        /// <term>Collection(Edm.Int64)</term>
 498        /// <description><see cref="IEnumerable{Int64}"/> (seq&lt;int64&gt; in
 499        /// F#)</description>
 500        /// </item>
 501        /// <item>
 502        /// <term>Collection(Edm.DateTimeOffset)</term>
 503        /// <description>
 504        /// <see cref="IEnumerable{DateTimeOffset}"/> or
 505        /// <see cref="IEnumerable{DateTime}"/> (seq&lt;DateTimeOffset&gt; or
 506        /// seq&lt;DateTime&gt; in F#). Both types work, although we recommend
 507        /// using <see cref="IEnumerable{DateTimeOffset}"/>.  See the notes
 508        /// above on Edm.DateTimeOffset for details.
 509        /// </description>
 510        /// </item>
 511        /// <item>
 512        /// <term>Collection(Edm.GeographyPoint)</term>
 513        /// <description>sequence of Azure.Core.Spatial.PointGeometry
 514        /// (seq&lt;PointGeometry&gt; in F#)</description>
 515        /// </item>
 516        /// <item>
 517        /// <term>Collection(Edm.ComplexType)</term>
 518        /// <description>
 519        /// <see cref="IEnumerable{T}"/> (seq&lt;T&gt; in F#) where T is any
 520        /// type that can be deserialized from the JSON objects in the complex
 521        /// collection field. This can be a value type or a reference type.
 522        /// </description>
 523        /// </item>
 524        /// </list>
 525        /// You can also use the dynamic <see cref="SearchDocument"/> as your
 526        /// <typeparamref name="T"/> and we will attempt to map JSON types in
 527        /// the response payload to .NET types. This mapping does not
 528        /// have the benefit of precise type information from the index, so the
 529        /// mapping is not always correct. In particular, be aware of the
 530        /// following cases:
 531        /// <list type="bullet">
 532        /// <item>
 533        /// <description>
 534        /// Any numeric value without a decimal point will be deserialized to
 535        /// a <see cref="Int32"/> (int in C#, int32 in F#) if it can be
 536        /// converted or a <see cref="Int64"/> (long in C#, int64 in F#)
 537        /// otherwise.
 538        /// </description>
 539        /// </item>
 540        /// <item>
 541        /// <description>
 542        /// Special double-precision floating point values such as NaN and
 543        /// Infinity will be deserialized as type <see cref="String"/> rather
 544        /// than <see cref="Double"/>, even if they are in arrays with regular
 545        /// floating point values.
 546        /// </description>
 547        /// </item>
 548        /// <item>
 549        /// <description>
 550        /// Any Edm.DateTimeOffset field will be deserialized as a
 551        /// <see cref="DateTimeOffset"/>, not <see cref="DateTime"/>.
 552        /// </description>
 553        /// </item>
 554        /// <item>
 555        /// <description>
 556        /// Any empty JSON array will be deserialized as an array of
 557        /// <see cref="Object"/> (object[] in C#, obj[] in F#).
 558        /// </description>
 559        /// </item>
 560        /// <item>
 561        /// <description>
 562        /// Complex fields will be recursively deserialized into instances of
 563        /// type <see cref="SearchDocument"/>.  Similarly, complex collection
 564        /// fields will be deserialized into arrays of such instances.
 565        /// </description>
 566        /// </item>
 567        /// </list>
 568        /// </remarks>
 569        public virtual async Task<Response<T>> GetDocumentAsync<T>(
 570            string key,
 571            GetDocumentOptions options = null,
 572            CancellationToken cancellationToken = default) =>
 27573            await GetDocumentInternal<T>(
 27574                key,
 27575                options,
 27576                async: true,
 27577                cancellationToken)
 27578                .ConfigureAwait(false);
 579
 580        private async Task<Response<T>> GetDocumentInternal<T>(
 581            string key,
 582            GetDocumentOptions options,
 583            bool async,
 584            CancellationToken cancellationToken)
 585        {
 0586            if (key == null) { throw new ArgumentNullException(nameof(key)); }
 56587            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(GetDocument)}")
 56588            scope.Start();
 589            try
 590            {
 56591                using HttpMessage message = Protocol.CreateGetRequest(key, options?.SelectedFieldsOrNull);
 56592                if (async)
 593                {
 27594                    await Pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false);
 595                }
 596                else
 597                {
 29598                    Pipeline.Send(message, cancellationToken);
 599                }
 56600                switch (message.Response.Status)
 601                {
 602                    case 200:
 603                    {
 51604                        T value = await message.Response.ContentStream.DeserializeAsync<T>(
 51605#if EXPERIMENTAL_SERIALIZER
 51606                            Serializer,
 51607#endif
 51608                            async,
 51609                            cancellationToken)
 51610                            .ConfigureAwait(false);
 51611                        return Response.FromValue(value, message.Response);
 612                    }
 613                    default:
 5614                        throw async ?
 5615                            await ClientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(f
 5616                            ClientDiagnostics.CreateRequestFailedException(message.Response);
 617                }
 618            }
 5619            catch (Exception e)
 620            {
 5621                scope.Failed(e);
 5622                throw;
 623            }
 51624        }
 625        #endregion Get
 626
 627        #region Search
 628        /// <summary>
 629        /// Searches for documents in the search index.
 630        /// <see href="https://docs.microsoft.com/rest/api/searchservice/search-documents">Search Documents</see>
 631        /// </summary>
 632        /// <typeparam name="T">
 633        /// The .NET type that maps to the index schema. Instances of this type
 634        /// can be retrieved as documents from the index.
 635        /// </typeparam>
 636        /// <param name="searchText">
 637        /// A full-text search query expression;  Use "*" or omit this
 638        /// parameter to match all documents.  See
 639        /// <see href="https://docs.microsoft.com/azure/search/query-simple-syntax">Simple query syntax in Azure Cogniti
 640        /// for more information about search query syntax.
 641        /// </param>
 642        /// <param name="options">
 643        /// Options that allow specifying filtering, sorting, faceting, paging,
 644        /// and other search query behaviors.
 645        /// </param>
 646        /// <param name="cancellationToken">
 647        /// Optional <see cref="CancellationToken"/> to propagate notifications
 648        /// that the operation should be canceled.
 649        /// </param>
 650        /// <returns>
 651        /// Response containing the documents matching the query.
 652        /// </returns>
 653        /// <exception cref="RequestFailedException">
 654        /// Thrown when a failure is returned by the Search Service.
 655        /// </exception>
 656        /// <remarks>
 657        /// <para>
 658        /// Search and SearchAsync methods support mapping of search field
 659        /// types to .NET types via the type parameter T.  You can provide your
 660        /// own type <typeparamref name="T"/> or use the dynamic
 661        /// <see cref="SearchDocument"/>. See
 662        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 663        /// for more details on the type mapping.
 664        /// </para>
 665        /// <para>
 666        /// Azure Cognitive Search might not be able to include all results in
 667        /// a single response in which case <see cref="SearchResults{T}.GetResults"/>
 668        /// will automatically continue making additional requests as you
 669        /// enumerate through the results.  You can also process the results a
 670        /// page at a time with the <see cref="Pageable{T}.AsPages(string, int?)"/>
 671        /// method.
 672        /// </para>
 673        /// </remarks>
 674        public virtual Response<SearchResults<T>> Search<T>(
 675            string searchText,
 676            SearchOptions options = null,
 677            CancellationToken cancellationToken = default) =>
 37678            SearchInternal<T>(
 37679                searchText,
 37680                options,
 37681                async: false,
 37682                cancellationToken)
 37683                .EnsureCompleted();
 684
 685        /// <summary>
 686        /// Searches for documents in the search index.
 687        /// <see href="https://docs.microsoft.com/rest/api/searchservice/search-documents">Search Documents</see>
 688        /// </summary>
 689        /// <typeparam name="T">
 690        /// The .NET type that maps to the index schema. Instances of this type
 691        /// can be retrieved as documents from the index.
 692        /// </typeparam>
 693        /// <param name="searchText">
 694        /// A full-text search query expression;  Use "*" or omit this
 695        /// parameter to match all documents.  See
 696        /// <see href="https://docs.microsoft.com/azure/search/query-simple-syntax">Simple query syntax in Azure Cogniti
 697        /// for more information about search query syntax.
 698        /// </param>
 699        /// <param name="options">
 700        /// Options that allow specifying filtering, sorting, faceting, paging,
 701        /// and other search query behaviors.
 702        /// </param>
 703        /// <param name="cancellationToken">
 704        /// Optional <see cref="CancellationToken"/> to propagate notifications
 705        /// that the operation should be canceled.
 706        /// </param>
 707        /// <returns>
 708        /// Response containing the documents matching the query.
 709        /// </returns>
 710        /// <exception cref="RequestFailedException">
 711        /// Thrown when a failure is returned by the Search Service.
 712        /// </exception>
 713        /// <remarks>
 714        /// <para>
 715        /// Search and SearchAsync methods support mapping of search field
 716        /// types to .NET types via the type parameter T.  You can provide your
 717        /// own type <typeparamref name="T"/> or use the dynamic
 718        /// <see cref="SearchDocument"/>. See
 719        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 720        /// for more details on the type mapping.
 721        /// </para>
 722        /// <para>
 723        /// Azure Cognitive Search might not be able to include all results in
 724        /// a single response in which case
 725        /// <see cref="SearchResults{T}.GetResultsAsync"/> will automatically
 726        /// continue making additional requests as you enumerate through the
 727        /// results.  You can also process the results a page at a time with
 728        /// the <see cref="AsyncPageable{T}.AsPages(string, int?)"/> method.
 729        /// </para>
 730        /// </remarks>
 731        public async virtual Task<Response<SearchResults<T>>> SearchAsync<T>(
 732            string searchText,
 733            SearchOptions options = null,
 734            CancellationToken cancellationToken = default) =>
 50735            await SearchInternal<T>(
 50736                searchText,
 50737                options,
 50738                async: true,
 50739                cancellationToken)
 50740                .ConfigureAwait(false);
 741
 742        private async Task<Response<SearchResults<T>>> SearchInternal<T>(
 743            string searchText,
 744            SearchOptions options,
 745            bool async,
 746            CancellationToken cancellationToken = default)
 747        {
 87748            if (options != null && searchText != null)
 749            {
 60750                options = options.Clone();
 60751                options.SearchText = searchText;
 752            }
 27753            else if (options == null)
 754            {
 11755                options = new SearchOptions() { SearchText = searchText };
 756            }
 87757            return await SearchInternal<T>(
 87758                options,
 87759                $"{nameof(SearchClient)}.{nameof(Search)}",
 87760                async,
 87761                cancellationToken)
 87762                .ConfigureAwait(false);
 83763        }
 764
 765        private async Task<Response<SearchResults<T>>> SearchInternal<T>(
 766            SearchOptions options,
 767            string operationName,
 768            bool async,
 769            CancellationToken cancellationToken = default)
 770        {
 771            Debug.Assert(options != null);
 87772            using DiagnosticScope scope = ClientDiagnostics.CreateScope(operationName);
 87773            scope.Start();
 774            try
 775            {
 87776                using HttpMessage message = Protocol.CreateSearchPostRequest(options);
 87777                if (async)
 778                {
 50779                    await Pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false);
 780                }
 781                else
 782                {
 37783                    Pipeline.Send(message, cancellationToken);
 784                }
 87785                switch (message.Response.Status)
 786                {
 787                    case 200:
 788                    {
 789                        // Deserialize the results
 83790                        SearchResults<T> results = await SearchResults<T>.DeserializeAsync(
 83791                            message.Response.ContentStream,
 83792#if EXPERIMENTAL_SERIALIZER
 83793                            Serializer,
 83794#endif
 83795                            async,
 83796                            cancellationToken)
 83797                            .ConfigureAwait(false);
 798
 799                        // Cache the client and raw response so we can abstract
 800                        // away server-side paging
 83801                        results.ConfigurePaging(this, message.Response);
 802
 83803                        return Response.FromValue(results, message.Response);
 804                    }
 805                    default:
 4806                        throw async ?
 4807                            await ClientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(f
 4808                            ClientDiagnostics.CreateRequestFailedException(message.Response);
 809                }
 810            }
 4811            catch (Exception e)
 812            {
 4813                scope.Failed(e);
 4814                throw;
 815            }
 83816        }
 817        #endregion Search
 818
 819        #region Suggest
 820        /// <summary>
 821        /// Executes a "search-as-you-type" query consisting of a partial text
 822        /// input (three character minimum).  It returns matching text found in
 823        /// suggester-aware fields.  Azure Cognitive Search looks for matching
 824        /// values in fields that are predefined in a Suggester.  For example,
 825        /// if you enable suggestions on a city field, typing "sea" produces
 826        /// documents containing "Seattle", "Sea Tac", and "Seaside" (all
 827        /// actual city names) for that field.
 828        /// <see href="https://docs.microsoft.com/rest/api/searchservice/suggestions">Suggestions</see>
 829        /// </summary>
 830        /// <typeparam name="T">
 831        /// The .NET type that maps to the index schema. Instances of this type
 832        /// can be retrieved as documents from the index.
 833        /// </typeparam>
 834        /// <param name="searchText">
 835        /// The search text to use to suggest documents. Must be at least 1
 836        /// character, and no more than 100 characters.
 837        /// </param>
 838        /// <param name="suggesterName">
 839        /// The name of the suggester as specified in the suggesters collection
 840        /// that's part of the index definition.
 841        /// </param>
 842        /// <param name="options">
 843        /// Options for filtering, sorting, and other suggestions query
 844        /// behaviors.
 845        /// </param>
 846        /// <param name="cancellationToken">
 847        /// Optional <see cref="CancellationToken"/> to propagate notifications
 848        /// that the operation should be canceled.
 849        /// </param>
 850        /// <returns>
 851        /// Response containing suggestion query results from an index.
 852        /// </returns>
 853        /// <exception cref="RequestFailedException">
 854        /// Thrown when a failure is returned by the Search Service.
 855        /// </exception>
 856        /// <remarks>
 857        /// Suggest and SuggestAsync methods support mapping of search field
 858        /// types to .NET types via the type parameter T.  You can provide your
 859        /// own type <typeparamref name="T"/> or use the dynamic
 860        /// <see cref="SearchDocument"/>. See
 861        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 862        /// for more details on the type mapping.
 863        /// </remarks>
 864        public virtual Response<SuggestResults<T>> Suggest<T>(
 865            string searchText,
 866            string suggesterName,
 867            SuggestOptions options = null,
 868            CancellationToken cancellationToken = default) =>
 13869            SuggestInternal<T>(
 13870                searchText,
 13871                suggesterName,
 13872                options,
 13873                async: false,
 13874                cancellationToken)
 13875                .EnsureCompleted();
 876
 877        /// <summary>
 878        /// Executes a "search-as-you-type" query consisting of a partial text
 879        /// input (three character minimum).  It returns matching text found in
 880        /// suggester-aware fields.  Azure Cognitive Search looks for matching
 881        /// values in fields that are predefined in a Suggester.  For example,
 882        /// if you enable suggestions on a city field, typing "sea" produces
 883        /// documents containing "Seattle", "Sea Tac", and "Seaside" (all
 884        /// actual city names) for that field.
 885        /// <see href="https://docs.microsoft.com/rest/api/searchservice/suggestions">Suggestions</see>
 886        /// </summary>
 887        /// <typeparam name="T">
 888        /// The .NET type that maps to the index schema. Instances of this type
 889        /// can be retrieved as documents from the index.
 890        /// </typeparam>
 891        /// <param name="searchText">
 892        /// The search text to use to suggest documents. Must be at least 1
 893        /// character, and no more than 100 characters.
 894        /// </param>
 895        /// <param name="suggesterName">
 896        /// The name of the suggester as specified in the suggesters collection
 897        /// that's part of the index definition.
 898        /// </param>
 899        /// <param name="options">
 900        /// Options for filtering, sorting, and other suggestions query
 901        /// behaviors.
 902        /// </param>
 903        /// <param name="cancellationToken">
 904        /// Optional <see cref="CancellationToken"/> to propagate notifications
 905        /// that the operation should be canceled.
 906        /// </param>
 907        /// <returns>
 908        /// Response containing suggestion query results from an index.
 909        /// </returns>
 910        /// <exception cref="RequestFailedException">
 911        /// Thrown when a failure is returned by the Search Service.
 912        /// </exception>
 913        /// <remarks>
 914        /// Suggest and SuggestAsync methods support mapping of search field
 915        /// types to .NET types via the type parameter T.  You can provide your
 916        /// own type <typeparamref name="T"/> or use the dynamic
 917        /// <see cref="SearchDocument"/>. See
 918        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 919        /// for more details on the type mapping.
 920        /// </remarks>
 921        public virtual async Task<Response<SuggestResults<T>>> SuggestAsync<T>(
 922            string searchText,
 923            string suggesterName,
 924            SuggestOptions options = null,
 925            CancellationToken cancellationToken = default) =>
 13926            await SuggestInternal<T>(
 13927                searchText,
 13928                suggesterName,
 13929                options,
 13930                async: true,
 13931                cancellationToken)
 13932                .ConfigureAwait(false);
 933
 934        private async Task<Response<SuggestResults<T>>> SuggestInternal<T>(
 935            string searchText,
 936            string suggesterName,
 937            SuggestOptions options,
 938            bool async,
 939            CancellationToken cancellationToken = default)
 940        {
 26941            options = options != null ? options.Clone() : new SuggestOptions();
 26942            options.SearchText = searchText;
 26943            options.SuggesterName = suggesterName;
 944
 26945            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(Suggest)}");
 26946            scope.Start();
 947            try
 948            {
 26949                using HttpMessage message = Protocol.CreateSuggestPostRequest(options);
 26950                if (async)
 951                {
 13952                    await Pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false);
 953                }
 954                else
 955                {
 13956                    Pipeline.Send(message, cancellationToken);
 957                }
 26958                switch (message.Response.Status)
 959                {
 960                    case 200:
 961                    {
 22962                        SuggestResults<T> suggestions = await SuggestResults<T>.DeserializeAsync(
 22963                            message.Response.ContentStream,
 22964#if EXPERIMENTAL_SERIALIZER
 22965                            Serializer,
 22966#endif
 22967                            async,
 22968                            cancellationToken)
 22969                            .ConfigureAwait(false);
 22970                        return Response.FromValue(suggestions, message.Response);
 971                    }
 972                    default:
 4973                        throw async ?
 4974                            await ClientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(f
 4975                            ClientDiagnostics.CreateRequestFailedException(message.Response);
 976                }
 977            }
 4978            catch (Exception e)
 979            {
 4980                scope.Failed(e);
 4981                throw;
 982            }
 22983        }
 984        #endregion Suggest
 985
 986        #region Autocomplete
 987        /// <summary>
 988        /// Suggests query terms based on input text and matching documents in
 989        /// the search index.
 990        /// <see href="https://docs.microsoft.com/rest/api/searchservice/autocomplete">Autocomplete</see>
 991        /// </summary>
 992        /// <param name="searchText">
 993        /// The search text on which to base autocomplete results.
 994        /// </param>
 995        /// <param name="suggesterName">
 996        /// The name of the suggester as specified in the suggesters collection
 997        /// that's part of the index definition.
 998        /// </param>
 999        /// <param name="options">
 1000        /// Options that allow specifying autocomplete behaviors, like fuzzy
 1001        /// matching.
 1002        /// </param>
 1003        /// <param name="cancellationToken">
 1004        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1005        /// that the operation should be canceled.
 1006        /// </param>
 1007        /// <returns>The result of Autocomplete query.</returns>
 1008        /// <exception cref="RequestFailedException">
 1009        /// Thrown when a failure is returned by the Search Service.
 1010        /// </exception>
 1011        public virtual Response<AutocompleteResults> Autocomplete(
 1012            string searchText,
 1013            string suggesterName,
 1014            AutocompleteOptions options = null,
 1015            CancellationToken cancellationToken = default)
 1016        {
 181017            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(Autocomplete)}"
 181018            scope.Start();
 1019            try
 1020            {
 181021                return AutocompleteInternal(
 181022                    searchText,
 181023                    suggesterName,
 181024                    options,
 181025                    async: false,
 181026                    cancellationToken)
 181027                    .EnsureCompleted();
 1028            }
 21029            catch (Exception ex)
 1030            {
 21031                scope.Failed(ex);
 21032                throw;
 1033            }
 161034        }
 1035
 1036        /// <summary>
 1037        /// Suggests query terms based on input text and matching documents in
 1038        /// the search index.
 1039        /// <see href="https://docs.microsoft.com/rest/api/searchservice/autocomplete">Autocomplete</see>
 1040        /// </summary>
 1041        /// <param name="searchText">
 1042        /// The search text on which to base autocomplete results.
 1043        /// </param>
 1044        /// <param name="suggesterName">
 1045        /// The name of the suggester as specified in the suggesters collection
 1046        /// that's part of the index definition.
 1047        /// </param>
 1048        /// <param name="options">
 1049        /// Options that allow specifying autocomplete behaviors, like fuzzy
 1050        /// matching.
 1051        /// </param>
 1052        /// <param name="cancellationToken">
 1053        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1054        /// that the operation should be canceled.
 1055        /// </param>
 1056        /// <returns>The result of Autocomplete query.</returns>
 1057        /// <exception cref="RequestFailedException">
 1058        /// Thrown when a failure is returned by the Search Service.
 1059        /// </exception>
 1060        public virtual async Task<Response<AutocompleteResults>> AutocompleteAsync(
 1061            string searchText,
 1062            string suggesterName,
 1063            AutocompleteOptions options = null,
 1064            CancellationToken cancellationToken = default)
 1065        {
 181066            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(Autocomplete)}"
 181067            scope.Start();
 1068            try
 1069            {
 181070                return await AutocompleteInternal(
 181071                    searchText,
 181072                    suggesterName,
 181073                    options,
 181074                    async: true,
 181075                    cancellationToken)
 181076                    .ConfigureAwait(false);
 1077            }
 21078            catch (Exception ex)
 1079            {
 21080                scope.Failed(ex);
 21081                throw;
 1082            }
 161083        }
 1084
 1085        private async Task<Response<AutocompleteResults>> AutocompleteInternal(
 1086            string searchText,
 1087            string suggesterName,
 1088            AutocompleteOptions options,
 1089            bool async,
 1090            CancellationToken cancellationToken)
 1091        {
 361092            options = options != null ? options.Clone() : new AutocompleteOptions();
 361093            options.SearchText = searchText;
 361094            options.SuggesterName = suggesterName;
 1095
 361096            return async ?
 361097                await Protocol.AutocompletePostAsync(options, cancellationToken).ConfigureAwait(false) :
 361098                Protocol.AutocompletePost(options, cancellationToken);
 321099        }
 1100        #endregion Autocomplete
 1101
 1102        #region IndexDocuments
 1103        /// <summary>
 1104        /// Sends a batch of upload, merge, and/or delete actions to the search
 1105        /// index.
 1106        /// <see href="https://docs.microsoft.com/rest/api/searchservice/addupdate-or-delete-documents">Add, Update or D
 1107        /// </summary>
 1108        /// <typeparam name="T">
 1109        /// The .NET type that maps to the index schema. Instances of this type
 1110        /// can be retrieved as documents from the index.
 1111        /// </typeparam>
 1112        /// <param name="batch">
 1113        /// The batch of document index actions.
 1114        /// </param>
 1115        /// <param name="options">
 1116        /// Options that allow specifying document indexing behavior.
 1117        /// </param>
 1118        /// <param name="cancellationToken">
 1119        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1120        /// that the operation should be canceled.
 1121        /// </param>
 1122        /// <returns>
 1123        /// Response containing the status of operations for all actions in the
 1124        /// batch of actions.
 1125        /// </returns>
 1126        /// <exception cref="RequestFailedException">
 1127        /// Thrown when a failure is returned by the Search Service.
 1128        /// </exception>
 1129        /// <remarks>
 1130        /// <para>
 1131        /// The generic overloads of the IndexDocuments and IndexDocumentsAsync
 1132        /// methods support mapping of search field types to .NET types via the
 1133        /// type parameter T. See
 1134        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1135        /// for more details on the type mapping.
 1136        /// </para>
 1137        /// <para>
 1138        /// By default, an exception will only be thrown if the entire request
 1139        /// fails.  Individual failures are described in the
 1140        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1141        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1142        /// individual <see cref="RequestFailedException"/>s wrapped into an
 1143        /// <see cref="AggregateException"/> that's thrown on partial failure.
 1144        /// </para>
 1145        /// </remarks>
 1146        public virtual Response<IndexDocumentsResult> IndexDocuments<T>(
 1147            IndexDocumentsBatch<T> batch,
 1148            IndexDocumentsOptions options = null,
 1149            CancellationToken cancellationToken = default) =>
 491150            IndexDocumentsInternal<T>(
 491151                batch,
 491152                options,
 491153                async: false,
 491154                cancellationToken)
 491155                .EnsureCompleted();
 1156
 1157        /// <summary>
 1158        /// Sends a batch of upload, merge, and/or delete actions to the search
 1159        /// index.
 1160        /// <see href="https://docs.microsoft.com/rest/api/searchservice/addupdate-or-delete-documents">Add, Update or D
 1161        /// </summary>
 1162        /// <typeparam name="T">
 1163        /// The .NET type that maps to the index schema. Instances of this type
 1164        /// can be retrieved as documents from the index.
 1165        /// </typeparam>
 1166        /// <param name="batch">
 1167        /// The batch of document index actions.
 1168        /// </param>
 1169        /// <param name="options">
 1170        /// Options that allow specifying document indexing behavior.
 1171        /// </param>
 1172        /// <param name="cancellationToken">
 1173        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1174        /// that the operation should be canceled.
 1175        /// </param>
 1176        /// <returns>
 1177        /// Response containing the status of operations for all actions in the
 1178        /// batch of actions.
 1179        /// </returns>
 1180        /// <exception cref="RequestFailedException">
 1181        /// Thrown when a failure is returned by the Search Service.
 1182        /// </exception>
 1183        /// <remarks>
 1184        /// <para>
 1185        /// The generic overloads of the IndexDocuments and IndexDocumentsAsync
 1186        /// methods support mapping of search field types to .NET types via the
 1187        /// type parameter T. See
 1188        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1189        /// for more details on the type mapping.
 1190        /// </para>
 1191        /// <para>
 1192        /// By default, an exception will only be thrown if the entire request
 1193        /// fails.  Individual failures are described in the
 1194        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1195        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1196        /// individual <see cref="RequestFailedException"/>s wrapped into an
 1197        /// <see cref="AggregateException"/> that's thrown on partial failure.
 1198        /// </para>
 1199        /// </remarks>>
 1200        public async virtual Task<Response<IndexDocumentsResult>> IndexDocumentsAsync<T>(
 1201            IndexDocumentsBatch<T> batch,
 1202            IndexDocumentsOptions options = null,
 1203            CancellationToken cancellationToken = default) =>
 471204            await IndexDocumentsInternal<T>(
 471205                batch,
 471206                options,
 471207                async: true,
 471208                cancellationToken)
 471209                .ConfigureAwait(false);
 1210
 1211        private async Task<Response<IndexDocumentsResult>> IndexDocumentsInternal<T>(
 1212            IndexDocumentsBatch<T> batch,
 1213            IndexDocumentsOptions options,
 1214            bool async,
 1215            CancellationToken cancellationToken = default)
 1216        {
 961217            Argument.AssertNotNull(batch, nameof(batch));
 1218
 961219            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(IndexDocuments)
 961220            scope.Start();
 1221            try
 1222            {
 1223                // Create the message
 961224                using HttpMessage message = Pipeline.CreateMessage();
 1225                {
 961226                    Request request = message.Request;
 961227                    request.Method = RequestMethod.Post;
 961228                    RawRequestUriBuilder uri = new RawRequestUriBuilder();
 961229                    uri.AppendRaw(Endpoint.ToString(), false);
 961230                    uri.AppendRaw("/indexes('", false);
 961231                    uri.AppendRaw(IndexName, true);
 961232                    uri.AppendRaw("')", false);
 961233                    uri.AppendPath("/docs/search.index", false);
 961234                    uri.AppendQuery("api-version", Version.ToVersionString(), true);
 961235                    request.Uri = uri;
 961236                    request.Headers.Add("Accept", "application/json; odata.metadata=none");
 961237                    request.Headers.Add("Content-Type", "application/json");
 961238                    Utf8JsonRequestContent content = new Utf8JsonRequestContent();
 961239                    await batch.SerializeAsync(
 961240                        content.JsonWriter,
 961241#if EXPERIMENTAL_SERIALIZER
 961242                        Serializer,
 961243#endif
 961244                        JsonSerialization.SerializerOptions,
 961245                        async,
 961246                        cancellationToken)
 961247                        .ConfigureAwait(false);
 961248                    request.Content = content;
 961249                }
 1250
 1251                // Send the request
 961252                if (async)
 1253                {
 471254                    await Pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false);
 1255                }
 1256                else
 1257                {
 491258                    Pipeline.Send(message, cancellationToken);
 1259                }
 1260
 1261                // Parse the response
 961262                switch (message.Response.Status)
 1263                {
 1264                    case 200:
 1265                    case 207: // Process partial failures the same as successes
 1266                    {
 1267                        // Parse the results
 931268                        using JsonDocument document = async ?
 931269                            await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).Co
 931270                            JsonDocument.Parse(message.Response.ContentStream, default);
 931271                        IndexDocumentsResult value = IndexDocumentsResult.DeserializeIndexDocumentsResult(document.RootE
 1272
 1273                        // Optionally throw an exception if any individual
 1274                        // write failed
 931275                        if (options?.ThrowOnAnyError == true)
 1276                        {
 61277                            List<RequestFailedException> failures = new List<RequestFailedException>();
 61278                            List<string> failedKeys = new List<string>();
 361279                            foreach (IndexingResult result in value.Results)
 1280                            {
 121281                                if (!result.Succeeded)
 1282                                {
 81283                                    failedKeys.Add(result.Key);
 81284                                    var ex = new RequestFailedException(result.Status, result.ErrorMessage);
 81285                                    ex.Data["Key"] = result.Key;
 81286                                    failures.Add(ex);
 1287                                }
 1288                            }
 61289                            if (failures.Count > 0)
 1290                            {
 61291                                throw new AggregateException(
 61292                                    $"Failed to index document(s): " + string.Join(", ", failedKeys) + ".",
 61293                                    failures);
 1294                            }
 1295                        }
 1296
 1297                        // TODO: #10593 - Ensure input and output document
 1298                        // order is in sync while batching (this is waiting on
 1299                        // both our broader batching story and adding something
 1300                        // on the client that can potentially indicate the Key
 1301                        // column since we have no way to tell that at present.)
 1302
 871303                        return Response.FromValue(value, message.Response);
 1304                    }
 1305                    default:
 31306                        throw async ?
 31307                            await ClientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(f
 31308                            ClientDiagnostics.CreateRequestFailedException(message.Response);
 1309                }
 1310            }
 91311            catch (Exception e)
 1312            {
 91313                scope.Failed(e);
 91314                throw;
 1315            }
 871316        }
 1317        #endregion IndexDocuments
 1318
 1319        #region Index Documents Conveniences
 1320        /// <summary>
 1321        /// Upload documents to the index as a batch.
 1322        /// </summary>
 1323        /// <typeparam name="T">
 1324        /// The .NET type that maps to the index schema. Instances of this type
 1325        /// can be retrieved as documents from the index.
 1326        /// </typeparam>
 1327        /// <param name="documents">The documents to upload.</param>
 1328        /// <param name="options">
 1329        /// Options that allow specifying document indexing behavior.
 1330        /// </param>
 1331        /// <param name="cancellationToken">
 1332        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1333        /// that the operation should be canceled.
 1334        /// </param>
 1335        /// <returns>
 1336        /// Response containing the status of operations for all actions in the
 1337        /// batch of actions.
 1338        /// </returns>
 1339        /// <exception cref="RequestFailedException">
 1340        /// Thrown when a failure is returned by the Search Service.
 1341        /// </exception>
 1342        /// <remarks>
 1343        /// <para>
 1344        /// The generic overloads of the UploadDocuments and UploadDocumentsAsync
 1345        /// methods support mapping of search field types to .NET types via the
 1346        /// type parameter T. See
 1347        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1348        /// for more details on the type mapping.
 1349        /// </para>
 1350        /// <para>
 1351        /// By default, an exception will only be thrown if the entire request
 1352        /// fails.  Individual failures are described in the
 1353        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1354        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1355        /// exceptions thrown on partial failure.
 1356        /// </para>
 1357        /// </remarks>
 1358        public virtual Response<IndexDocumentsResult> UploadDocuments<T>(
 1359            IEnumerable<T> documents,
 1360            IndexDocumentsOptions options = null,
 1361            CancellationToken cancellationToken = default)
 1362        {
 21363            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(UploadDocuments
 21364            scope.Start();
 1365            try
 1366            {
 21367                return IndexDocuments<T>(
 21368                    IndexDocumentsBatch.Upload<T>(documents),
 21369                    options,
 21370                    cancellationToken);
 1371            }
 01372            catch (Exception ex)
 1373            {
 01374                scope.Failed(ex);
 01375                throw;
 1376            }
 21377        }
 1378
 1379        /// <summary>
 1380        /// Upload documents to the index as a batch.
 1381        /// </summary>
 1382        /// <typeparam name="T">
 1383        /// The .NET type that maps to the index schema. Instances of this type
 1384        /// can be retrieved as documents from the index.
 1385        /// </typeparam>
 1386        /// <param name="documents">The documents to upload.</param>
 1387        /// <param name="options">
 1388        /// Options that allow specifying document indexing behavior.
 1389        /// </param>
 1390        /// <param name="cancellationToken">
 1391        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1392        /// that the operation should be canceled.
 1393        /// </param>
 1394        /// <returns>
 1395        /// Response containing the status of operations for all actions in the
 1396        /// batch of actions.
 1397        /// </returns>
 1398        /// <exception cref="RequestFailedException">
 1399        /// Thrown when a failure is returned by the Search Service.
 1400        /// </exception>
 1401        /// <remarks>
 1402        /// <para>
 1403        /// The generic overloads of the UploadDocuments and UploadDocumentsAsync
 1404        /// methods support mapping of search field types to .NET types via the
 1405        /// type parameter T. See
 1406        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1407        /// for more details on the type mapping.
 1408        /// </para>
 1409        /// <para>
 1410        /// By default, an exception will only be thrown if the entire request
 1411        /// fails.  Individual failures are described in the
 1412        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1413        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1414        /// exceptions thrown on partial failure.
 1415        /// </para>
 1416        /// </remarks>
 1417        public virtual async Task<Response<IndexDocumentsResult>> UploadDocumentsAsync<T>(
 1418            IEnumerable<T> documents,
 1419            IndexDocumentsOptions options = null,
 1420            CancellationToken cancellationToken = default)
 1421        {
 11422            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(UploadDocuments
 11423            scope.Start();
 1424            try
 1425            {
 11426                return await IndexDocumentsAsync<T>(
 11427                    IndexDocumentsBatch.Upload<T>(documents),
 11428                    options,
 11429                    cancellationToken)
 11430                    .ConfigureAwait(false);
 1431            }
 01432            catch (Exception ex)
 1433            {
 01434                scope.Failed(ex);
 01435                throw;
 1436            }
 11437        }
 1438
 1439        /// <summary>
 1440        /// Merge documents to the index as a batch.
 1441        /// </summary>
 1442        /// <typeparam name="T">
 1443        /// The .NET type that maps to the index schema. Instances of this type
 1444        /// can be retrieved as documents from the index.
 1445        /// </typeparam>
 1446        /// <param name="documents">The documents to upload.</param>
 1447        /// <param name="options">
 1448        /// Options that allow specifying document indexing behavior.
 1449        /// </param>
 1450        /// <param name="cancellationToken">
 1451        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1452        /// that the operation should be canceled.
 1453        /// </param>
 1454        /// <returns>
 1455        /// Response containing the status of operations for all actions in the
 1456        /// batch of actions.
 1457        /// </returns>
 1458        /// <exception cref="RequestFailedException">
 1459        /// Thrown when a failure is returned by the Search Service.
 1460        /// </exception>
 1461        /// <remarks>
 1462        /// <para>
 1463        /// The generic overloads of the MergeDocuments and MergeDocumentsAsync
 1464        /// methods support mapping of search field types to .NET types via the
 1465        /// type parameter T. See
 1466        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1467        /// for more details on the type mapping.
 1468        /// </para>
 1469        /// <para>
 1470        /// By default, an exception will only be thrown if the entire request
 1471        /// fails.  Individual failures are described in the
 1472        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1473        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1474        /// exceptions thrown on partial failure.
 1475        /// </para>
 1476        /// </remarks>
 1477        public virtual Response<IndexDocumentsResult> MergeDocuments<T>(
 1478            IEnumerable<T> documents,
 1479            IndexDocumentsOptions options = null,
 1480            CancellationToken cancellationToken = default)
 1481        {
 11482            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(MergeDocuments)
 11483            scope.Start();
 1484            try
 1485            {
 11486                return IndexDocuments<T>(
 11487                    IndexDocumentsBatch.Merge<T>(documents),
 11488                    options,
 11489                    cancellationToken);
 1490            }
 01491            catch (Exception ex)
 1492            {
 01493                scope.Failed(ex);
 01494                throw;
 1495            }
 11496        }
 1497
 1498        /// <summary>
 1499        /// Merge documents to the index as a batch.
 1500        /// </summary>
 1501        /// <typeparam name="T">
 1502        /// The .NET type that maps to the index schema. Instances of this type
 1503        /// can be retrieved as documents from the index.
 1504        /// </typeparam>
 1505        /// <param name="documents">The documents to upload.</param>
 1506        /// <param name="options">
 1507        /// Options that allow specifying document indexing behavior.
 1508        /// </param>
 1509        /// <param name="cancellationToken">
 1510        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1511        /// that the operation should be canceled.
 1512        /// </param>
 1513        /// <returns>
 1514        /// Response containing the status of operations for all actions in the
 1515        /// batch of actions.
 1516        /// </returns>
 1517        /// <exception cref="RequestFailedException">
 1518        /// Thrown when a failure is returned by the Search Service.
 1519        /// </exception>
 1520        /// <remarks>
 1521        /// <para>
 1522        /// The generic overloads of the MergeDocuments and MergeDocumentsAsync
 1523        /// methods support mapping of search field types to .NET types via the
 1524        /// type parameter T. See
 1525        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1526        /// for more details on the type mapping.
 1527        /// </para>
 1528        /// <para>
 1529        /// By default, an exception will only be thrown if the entire request
 1530        /// fails.  Individual failures are described in the
 1531        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1532        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1533        /// exceptions thrown on partial failure.
 1534        /// </para>
 1535        /// </remarks>
 1536        public virtual async Task<Response<IndexDocumentsResult>> MergeDocumentsAsync<T>(
 1537            IEnumerable<T> documents,
 1538            IndexDocumentsOptions options = null,
 1539            CancellationToken cancellationToken = default)
 1540        {
 11541            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(MergeDocuments)
 11542            scope.Start();
 1543            try
 1544            {
 11545                return await IndexDocumentsAsync<T>(
 11546                    IndexDocumentsBatch.Merge<T>(documents),
 11547                    options,
 11548                    cancellationToken)
 11549                    .ConfigureAwait(false);
 1550            }
 01551            catch (Exception ex)
 1552            {
 01553                scope.Failed(ex);
 01554                throw;
 1555            }
 11556        }
 1557
 1558        /// <summary>
 1559        /// Merge or upload documents to the index as a batch.
 1560        /// </summary>
 1561        /// <typeparam name="T">
 1562        /// The .NET type that maps to the index schema. Instances of this type
 1563        /// can be retrieved as documents from the index.
 1564        /// </typeparam>
 1565        /// <param name="documents">The documents to upload.</param>
 1566        /// <param name="options">
 1567        /// Options that allow specifying document indexing behavior.
 1568        /// </param>
 1569        /// <param name="cancellationToken">
 1570        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1571        /// that the operation should be canceled.
 1572        /// </param>
 1573        /// <returns>
 1574        /// Response containing the status of operations for all actions in the
 1575        /// batch of actions.
 1576        /// </returns>
 1577        /// <exception cref="RequestFailedException">
 1578        /// Thrown when a failure is returned by the Search Service.
 1579        /// </exception>
 1580        /// <remarks>
 1581        /// <para>
 1582        /// The generic overloads of the MergeOrUploadDocuments and
 1583        /// MergeOrUploadDocumentsAsync methods support mapping of search field
 1584        /// types to .NET types via the type parameter T. See
 1585        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1586        /// for more details on the type mapping.
 1587        /// </para>
 1588        /// <para>
 1589        /// By default, an exception will only be thrown if the entire request
 1590        /// fails.  Individual failures are described in the
 1591        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1592        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1593        /// exceptions thrown on partial failure.
 1594        /// </para>
 1595        /// </remarks>
 1596        public virtual Response<IndexDocumentsResult> MergeOrUploadDocuments<T>(
 1597            IEnumerable<T> documents,
 1598            IndexDocumentsOptions options = null,
 1599            CancellationToken cancellationToken = default)
 1600        {
 11601            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(MergeOrUploadDo
 11602            scope.Start();
 1603            try
 1604            {
 11605                return IndexDocuments<T>(
 11606                    IndexDocumentsBatch.MergeOrUpload<T>(documents),
 11607                    options,
 11608                    cancellationToken);
 1609            }
 01610            catch (Exception ex)
 1611            {
 01612                scope.Failed(ex);
 01613                throw;
 1614            }
 11615        }
 1616
 1617        /// <summary>
 1618        /// Merge or upload documents to the index as a batch.
 1619        /// </summary>
 1620        /// <typeparam name="T">
 1621        /// The .NET type that maps to the index schema. Instances of this type
 1622        /// can be retrieved as documents from the index.
 1623        /// </typeparam>
 1624        /// <param name="documents">The documents to upload.</param>
 1625        /// <param name="options">
 1626        /// Options that allow specifying document indexing behavior.
 1627        /// </param>
 1628        /// <param name="cancellationToken">
 1629        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1630        /// that the operation should be canceled.
 1631        /// </param>
 1632        /// <returns>
 1633        /// Response containing the status of operations for all actions in the
 1634        /// batch of actions.
 1635        /// </returns>
 1636        /// <exception cref="RequestFailedException">
 1637        /// Thrown when a failure is returned by the Search Service.
 1638        /// </exception>
 1639        /// <remarks>
 1640        /// <para>
 1641        /// The generic overloads of the MergeOrUploadDocuments and
 1642        /// MergeOrUploadDocumentsAsync methods support mapping of search field
 1643        /// types to .NET types via the type parameter T. See
 1644        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1645        /// for more details on the type mapping.
 1646        /// </para>
 1647        /// <para>
 1648        /// By default, an exception will only be thrown if the entire request
 1649        /// fails.  Individual failures are described in the
 1650        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1651        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1652        /// exceptions thrown on partial failure.
 1653        /// </para>
 1654        /// </remarks>
 1655        public virtual async Task<Response<IndexDocumentsResult>> MergeOrUploadDocumentsAsync<T>(
 1656            IEnumerable<T> documents,
 1657            IndexDocumentsOptions options = null,
 1658            CancellationToken cancellationToken = default)
 1659        {
 11660            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(MergeOrUploadDo
 11661            scope.Start();
 1662            try
 1663            {
 11664                return await IndexDocumentsAsync<T>(
 11665                    IndexDocumentsBatch.MergeOrUpload<T>(documents),
 11666                    options,
 11667                    cancellationToken)
 11668                    .ConfigureAwait(false);
 1669            }
 01670            catch (Exception ex)
 1671            {
 01672                scope.Failed(ex);
 01673                throw;
 1674            }
 11675        }
 1676
 1677        /// <summary>
 1678        /// Delete documents from the index as a batch.
 1679        /// </summary>
 1680        /// <typeparam name="T">
 1681        /// The .NET type that maps to the index schema. Instances of this type
 1682        /// can be retrieved as documents from the index.
 1683        /// </typeparam>
 1684        /// <param name="documents">The documents to upload.</param>
 1685        /// <param name="options">
 1686        /// Options that allow specifying document indexing behavior.
 1687        /// </param>
 1688        /// <param name="cancellationToken">
 1689        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1690        /// that the operation should be canceled.
 1691        /// </param>
 1692        /// <returns>
 1693        /// Response containing the status of operations for all actions in the
 1694        /// batch of actions.
 1695        /// </returns>
 1696        /// <exception cref="RequestFailedException">
 1697        /// Thrown when a failure is returned by the Search Service.
 1698        /// </exception>
 1699        /// <remarks>
 1700        /// <para>
 1701        /// The generic overloads of the DeleteDocuments and DeleteDocumentsAsync
 1702        /// methods support mapping of search field types to .NET types via the
 1703        /// type parameter T. See
 1704        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1705        /// for more details on the type mapping.
 1706        /// </para>
 1707        /// <para>
 1708        /// By default, an exception will only be thrown if the entire request
 1709        /// fails.  Individual failures are described in the
 1710        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1711        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1712        /// exceptions thrown on partial failure.
 1713        /// </para>
 1714        /// </remarks>
 1715        public virtual Response<IndexDocumentsResult> DeleteDocuments<T>(
 1716            IEnumerable<T> documents,
 1717            IndexDocumentsOptions options = null,
 1718            CancellationToken cancellationToken = default)
 1719        {
 11720            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(DeleteDocuments
 11721            scope.Start();
 1722            try
 1723            {
 11724                return IndexDocuments<T>(
 11725                    IndexDocumentsBatch.Delete<T>(documents),
 11726                    options,
 11727                    cancellationToken);
 1728            }
 01729            catch (Exception ex)
 1730            {
 01731                scope.Failed(ex);
 01732                throw;
 1733            }
 11734        }
 1735
 1736        /// <summary>
 1737        /// Delete documents from the index as a batch.
 1738        /// </summary>
 1739        /// <typeparam name="T">
 1740        /// The .NET type that maps to the index schema. Instances of this type
 1741        /// can be retrieved as documents from the index.
 1742        /// </typeparam>
 1743        /// <param name="documents">The documents to upload.</param>
 1744        /// <param name="options">
 1745        /// Options that allow specifying document indexing behavior.
 1746        /// </param>
 1747        /// <param name="cancellationToken">
 1748        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1749        /// that the operation should be canceled.
 1750        /// </param>
 1751        /// <returns>
 1752        /// Response containing the status of operations for all actions in the
 1753        /// batch of actions.
 1754        /// </returns>
 1755        /// <exception cref="RequestFailedException">
 1756        /// Thrown when a failure is returned by the Search Service.
 1757        /// </exception>
 1758        /// <remarks>
 1759        /// <para>
 1760        /// The generic overloads of the DeleteDocuments and DeleteDocumentsAsync
 1761        /// methods support mapping of search field types to .NET types via the
 1762        /// type parameter T. See
 1763        /// <see cref="GetDocumentAsync{T}(string, GetDocumentOptions, CancellationToken)"/>
 1764        /// for more details on the type mapping.
 1765        /// </para>
 1766        /// <para>
 1767        /// By default, an exception will only be thrown if the entire request
 1768        /// fails.  Individual failures are described in the
 1769        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1770        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1771        /// exceptions thrown on partial failure.
 1772        /// </para>
 1773        /// </remarks>
 1774        public virtual async Task<Response<IndexDocumentsResult>> DeleteDocumentsAsync<T>(
 1775            IEnumerable<T> documents,
 1776            IndexDocumentsOptions options = null,
 1777            CancellationToken cancellationToken = default)
 1778        {
 11779            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(DeleteDocuments
 11780            scope.Start();
 1781            try
 1782            {
 11783                return await IndexDocumentsAsync<T>(
 11784                    IndexDocumentsBatch.Delete<T>(documents),
 11785                    options,
 11786                    cancellationToken)
 11787                    .ConfigureAwait(false);
 1788            }
 01789            catch (Exception ex)
 1790            {
 01791                scope.Failed(ex);
 01792                throw;
 1793            }
 11794        }
 1795
 1796        /// <summary>
 1797        /// Delete documents from the index as a batch given only their keys.
 1798        /// </summary>
 1799        /// <param name="keyName">
 1800        /// The name of the key field that uniquely identifies documents in
 1801        /// the index.
 1802        /// </param>
 1803        /// <param name="keyValues">
 1804        /// The keys of the documents to delete.
 1805        /// </param>
 1806        /// <param name="options">
 1807        /// Options that allow specifying document indexing behavior.
 1808        /// </param>
 1809        /// <param name="cancellationToken">
 1810        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1811        /// that the operation should be canceled.
 1812        /// </param>
 1813        /// <returns>
 1814        /// Response containing the status of operations for all actions in the
 1815        /// batch of actions.
 1816        /// </returns>
 1817        /// <exception cref="RequestFailedException">
 1818        /// Thrown when a failure is returned by the Search Service.
 1819        /// </exception>
 1820        /// <remarks>
 1821        /// <para>
 1822        /// By default, an exception will only be thrown if the entire request
 1823        /// fails.  Individual failures are described in the
 1824        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1825        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1826        /// exceptions thrown on partial failure.
 1827        /// </para>
 1828        /// </remarks>
 1829        public virtual Response<IndexDocumentsResult> DeleteDocuments(
 1830            string keyName,
 1831            IEnumerable<string> keyValues,
 1832            IndexDocumentsOptions options = null,
 1833            CancellationToken cancellationToken = default)
 1834        {
 11835            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(DeleteDocuments
 11836            scope.Start();
 1837            try
 1838            {
 11839                return IndexDocuments(
 11840                    IndexDocumentsBatch.Delete(keyName, keyValues),
 11841                    options,
 11842                    cancellationToken);
 1843            }
 01844            catch (Exception ex)
 1845            {
 01846                scope.Failed(ex);
 01847                throw;
 1848            }
 11849        }
 1850
 1851        /// <summary>
 1852        /// Delete documents from the index as a batch given only their keys.
 1853        /// </summary>
 1854        /// <param name="keyName">
 1855        /// The name of the key field that uniquely identifies documents in
 1856        /// the index.
 1857        /// </param>
 1858        /// <param name="keyValues">
 1859        /// The keys of the documents to delete.
 1860        /// </param>
 1861        /// <param name="options">
 1862        /// Options that allow specifying document indexing behavior.
 1863        /// </param>
 1864        /// <param name="cancellationToken">
 1865        /// Optional <see cref="CancellationToken"/> to propagate notifications
 1866        /// that the operation should be canceled.
 1867        /// </param>
 1868        /// <returns>
 1869        /// Response containing the status of operations for all actions in the
 1870        /// batch of actions.
 1871        /// </returns>
 1872        /// <exception cref="RequestFailedException">
 1873        /// Thrown when a failure is returned by the Search Service.
 1874        /// </exception>
 1875        /// <remarks>
 1876        /// <para>
 1877        /// By default, an exception will only be thrown if the entire request
 1878        /// fails.  Individual failures are described in the
 1879        /// <see cref="IndexDocumentsResult.Results"/> collection.  You can set
 1880        /// <see cref="IndexDocumentsOptions.ThrowOnAnyError"/> if you want
 1881        /// exceptions thrown on partial failure.
 1882        /// </para>
 1883        /// </remarks>
 1884        public virtual async Task<Response<IndexDocumentsResult>> DeleteDocumentsAsync(
 1885            string keyName,
 1886            IEnumerable<string> keyValues,
 1887            IndexDocumentsOptions options = null,
 1888            CancellationToken cancellationToken = default)
 1889        {
 11890            using DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(SearchClient)}.{nameof(DeleteDocuments
 11891            scope.Start();
 1892            try
 1893            {
 11894                return await IndexDocumentsAsync(
 11895                    IndexDocumentsBatch.Delete(keyName, keyValues),
 11896                    options,
 11897                    cancellationToken)
 11898                    .ConfigureAwait(false);
 1899            }
 01900            catch (Exception ex)
 1901            {
 01902                scope.Failed(ex);
 01903                throw;
 1904            }
 11905        }
 1906        #endregion Index Documents Conveniences
 1907    }
 1908}