Skip to content
97 changes: 35 additions & 62 deletions src/DataStax.AstraDB.DataApi/Collections/Collection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,84 +134,52 @@ private async Task<CollectionInsertOneResult<TId>> InsertOneAsync(T document, Co
}

/// <summary>
/// Synchronous version of <see cref="InsertManyAsync(List{T})"/>
/// Synchronous version of <see cref="InsertManyAsync(IEnumerable{T})"/>
/// </summary>
/// <inheritdoc cref="InsertManyAsync(List{T})"/>
public CollectionInsertManyResult<TId> InsertMany(List<T> documents)
/// <inheritdoc cref="InsertManyAsync(IEnumerable{T})"/>
public CollectionInsertManyResult<TId> InsertMany(IEnumerable<T> documents)
{
return InsertMany(documents, null, null);
return InsertMany(documents, null);
}

/// <summary>
/// Synchronous version of <see cref="InsertManyAsync(List{T}, InsertManyOptions)"/>
/// Synchronous version of <see cref="InsertManyAsync(IEnumerable{T}, InsertManyOptions)"/>
/// </summary>
/// <inheritdoc cref="InsertManyAsync(List{T}, InsertManyOptions)"/>
public CollectionInsertManyResult<TId> InsertMany(List<T> documents, InsertManyOptions insertOptions)
/// <inheritdoc cref="InsertManyAsync(IEnumerable{T}, InsertManyOptions)"/>
public CollectionInsertManyResult<TId> InsertMany(IEnumerable<T> documents, InsertManyOptions insertOptions)
{
return InsertMany(documents, insertOptions, null);
}

/// <summary>
/// Synchronous version of <see cref="InsertManyAsync(List{T}, CommandOptions)"/>
/// </summary>
/// <inheritdoc cref="InsertManyAsync(List{T}, CommandOptions)"/>
public CollectionInsertManyResult<TId> InsertMany(List<T> documents, CommandOptions commandOptions)
{
return InsertMany(documents, null, commandOptions);
}

/// <summary>
/// Synchronous version of <see cref="InsertManyAsync(List{T}, InsertManyOptions, CommandOptions)"/>
/// </summary>
/// <inheritdoc cref="InsertManyAsync(List{T}, InsertManyOptions, CommandOptions)"/>
public CollectionInsertManyResult<TId> InsertMany(List<T> documents, InsertManyOptions insertOptions, CommandOptions commandOptions)
{
return InsertManyAsync(documents, insertOptions, commandOptions, runSynchronously: true).ResultSync();
return InsertManyAsync(documents, insertOptions, runSynchronously: true).ResultSync();
}

/// <summary>
/// Asynchronously insert multiple documents into the collection.
/// </summary>
/// <param name="documents">The list of documents to insert.</param>
/// <returns></returns>
/// <throws cref="ArgumentException">Thrown if the documents list is null or empty.</throws>
/// <throws cref="BulkOperationException{T}">Thrown if an error occurs during the bulk operation,
/// <remarks>
/// If you need to control concurrency, chunk size, whether the insert is ordered or not, or other options, use the <see cref="InsertManyAsync(IEnumerable{T}, InsertManyOptions)"/> overload.
/// </remarks>
/// <throws cref="BulkOperationException{T}">Thrown if an error occurs during the bulk operation,
/// with partial results returned in the <see cref="BulkOperationException{T}.PartialResult"/> property.</throws>
public Task<CollectionInsertManyResult<TId>> InsertManyAsync(List<T> documents)
{
return InsertManyAsync(documents, new CommandOptions());
}

/// <inheritdoc cref="InsertManyAsync(List{T})"/>
/// <param name="documents"></param>
/// <param name="insertOptions">Allows specifying whether the documents should be inserted in order as well as the chunk size.</param>
public Task<CollectionInsertManyResult<TId>> InsertManyAsync(List<T> documents, InsertManyOptions insertOptions)
public Task<CollectionInsertManyResult<TId>> InsertManyAsync(IEnumerable<T> documents)
{
return InsertManyAsync(documents, insertOptions, null, runSynchronously: false);
return InsertManyAsync(documents, null);
}

/// <inheritdoc cref="InsertManyAsync(List{T})"/>
/// <param name="documents"></param>
/// <param name="commandOptions"></param>
public Task<CollectionInsertManyResult<TId>> InsertManyAsync(List<T> documents, CommandOptions commandOptions)
{
return InsertManyAsync(documents, null, commandOptions, runSynchronously: false);
}

/// <inheritdoc cref="InsertManyAsync(List{T}, InsertManyOptions)"/>
/// <param name="documents"></param>
/// <param name="insertOptions"></param>
/// <param name="commandOptions"></param>
public Task<CollectionInsertManyResult<TId>> InsertManyAsync(List<T> documents, InsertManyOptions insertOptions, CommandOptions commandOptions)
/// <inheritdoc cref="InsertManyAsync(IEnumerable{T})"/>
/// <param name="documents">The list of documents to insert.</param>
/// <param name="insertOptions">Allows specifying the insertion chunk size, ordered/unordered mode, concurrency, as well as other generic command-execution options.</param>
public Task<CollectionInsertManyResult<TId>> InsertManyAsync(IEnumerable<T> documents, InsertManyOptions insertOptions)
{
return InsertManyAsync(documents, insertOptions, commandOptions, runSynchronously: false);
return InsertManyAsync(documents, insertOptions, runSynchronously: false);
}

private async Task<CollectionInsertManyResult<TId>> InsertManyAsync(List<T> documents, InsertManyOptions insertOptions, CommandOptions commandOptions, bool runSynchronously)
private async Task<CollectionInsertManyResult<TId>> InsertManyAsync(IEnumerable<T> documents, InsertManyOptions insertOptions, bool runSynchronously)
{
Guard.NotNullOrEmpty(documents, nameof(documents));
Guard.NotNull(documents, nameof(documents));

if (insertOptions == null) insertOptions = new InsertManyOptions();
var commandOptions = insertOptions.CommandOptions();
if (insertOptions.Concurrency > 1 && insertOptions.Ordered)
{
throw new ArgumentException("Cannot run ordered insert_many concurrently.");
Expand Down Expand Up @@ -673,7 +641,8 @@ public CollectionFindCursor<T> Find(CollectionFindManyOptions<T> findOptions)
public CollectionFindCursor<T> Find(CollectionFilter<T> filter, CollectionFindManyOptions<T> findOptions)
{
findOptions ??= new CollectionFindManyOptions<T>();
return new(findOptions.WithFilterParam(filter), null, RunFindManyAsync);
var commandOptions = findOptions.CommandOptions();
return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync);
}

/// <inheritdoc cref="Find()" path="/summary"/>
Expand Down Expand Up @@ -706,23 +675,27 @@ public CollectionFindCursor<T, TResult> Find<TResult>(CollectionFindManyOptions<
return Find<TResult>(null, findOptions);
}

/// <inheritdoc cref="Find{TResult}(CollectionFilter{T})"/>
/// <param name="filter"></param>
/// <param name="findOptions"></param>
/// <inheritdoc cref="Find(CollectionFilter{T}, CollectionFindManyOptions{T})"/>
/// <remarks>
/// The Find alternatives that accept a TResult type parameter allow for deserializing the document as a different type
/// (most commonly used when using projection to return a subset of fields)
/// </remarks>
public CollectionFindCursor<T, TResult> Find<TResult>(CollectionFilter<T> filter, CollectionFindManyOptions<T> findOptions) where TResult : class
{
findOptions ??= new CollectionFindManyOptions<T>();
return new(findOptions.WithFilterParam(filter), null, RunFindManyAsync);
var commandOptions = findOptions.CommandOptions();
return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync);
}

internal async Task<FindPage<TResult>> RunFindManyAsync<TResult>(CollectionFindCursor<T, TResult> cursor, string nextPageState, bool runSynchronously) where TResult : class
{
var options = cursor.FindOptions.Clone();
options.PageState = nextPageState;

var command = CreateCommand("find").WithPayload(options).AddCommandOptions(cursor.CommandOptions);

var payloadOptions = options.PayloadOptions();
var command = CreateCommand("find").WithPayload(payloadOptions).AddCommandOptions(cursor.CommandOptions);
var response = await command.RunAsyncReturnDocumentData<APIFindResult<TResult>, TResult, FindStatusResult>(runSynchronously).ConfigureAwait(false);

return new FindPage<TResult>(
response.Data.NextPageState,
response.Data.Items,
Expand Down
7 changes: 7 additions & 0 deletions src/DataStax.AstraDB.DataApi/Core/CommandOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,31 @@ public class CommandOptions
/// <summary>
/// The token to use for authentication
/// </summary>
[JsonIgnore]
public string Token { get; set; }

/// <summary>
/// The execution mode for database operations.
///
/// Defaults to <see cref="Core.RunMode.Normal"/>
/// </summary>
[JsonIgnore]
public RunMode? RunMode { get; set; }

/// <summary>
/// The destination datastore.
///
/// Defaults to <see cref="DataAPIDestination.ASTRA"/>
/// </summary>
[JsonIgnore]
public DataAPIDestination? Destination { get; set; }

/// <summary>
/// Options for the HTTP client
///
/// Defaults to HttpVersion: 2.0, FollowRedirects: true
/// </summary>
[JsonIgnore]
public HttpClientOptions HttpClientOptions { get; set; }

/// <summary>
Expand All @@ -77,13 +81,15 @@ public class CommandOptions
/// <remarks>
/// See <see cref="TimeoutOptions"/> for information.
/// </remarks>
[JsonIgnore]
public TimeoutOptions TimeoutOptions { get; set; } = new TimeoutOptions();

/// <summary>
/// API version to connect to
///
/// Defaults to <see cref="APIVersion.V1"/>
/// </summary>
[JsonIgnore]
public APIVersion? APIVersion { get; set; }

internal string APIUrlBase
Expand All @@ -101,6 +107,7 @@ internal string APIUrlBase
/// <summary>
/// An optional CancellationToken to interrupt asynchronous operations
/// </summary>
[JsonIgnore]
public CancellationToken? CancellationToken { get; set; }

internal CancellationToken? BulkOperationCancellationToken { get; set; }
Expand Down
12 changes: 11 additions & 1 deletion src/DataStax.AstraDB.DataApi/Core/HttpClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,14 @@ public class HttpClientOptions
/// Whether the HTTP client should follow redirects or not.
/// </summary>
public bool FollowRedirects { get; set; } = true;
}

internal HttpClientOptions Clone()
{
return new HttpClientOptions
{
HttpVersion = HttpVersion,
FollowRedirects = FollowRedirects,
};
}

}
42 changes: 37 additions & 5 deletions src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ namespace DataStax.AstraDB.DataApi.Core;
/// <summary>
/// Options for inserting multiple documents into a collection.
/// </summary>
public class InsertManyOptions
public class InsertManyOptions : CommandOptions
{
/// <summary>
/// Default batch size.
/// </summary>
public const int DefaultChunkSize = 100;
public const int DefaultChunkSize = 50;

/// <summary>
/// Maximum concurrency.
/// Default concurrency for unordered insertions.
/// </summary>
public const int MaxConcurrency = int.MaxValue;
public const int DefaultConcurrency = 20;

private bool _Ordered = false;
/// <summary>
Expand All @@ -48,10 +48,42 @@ public bool Ordered
/// The number of parallel processes to use while inserting documents.
/// Must be set to 1 for ordered inserts.
/// </summary>
public int Concurrency { get; set; } = MaxConcurrency;
public int Concurrency { get; set; } = DefaultConcurrency;

/// <summary>
/// The number of documents to insert in each batch.
/// </summary>
public int ChunkSize { get; set; } = DefaultChunkSize;

internal CommandOptions CommandOptions()
{
return new CommandOptions {
Token = Token,
RunMode = RunMode,
Destination = Destination,
HttpClientOptions = HttpClientOptions != null ? HttpClientOptions.Clone() : null,
TimeoutOptions = TimeoutOptions != null ? TimeoutOptions.Clone() : null,
APIVersion = APIVersion,
CancellationToken = CancellationToken
};
}

internal InsertManyOptions Clone()
{
return new InsertManyOptions
{
Ordered = Ordered,
Concurrency = Concurrency,
ChunkSize = ChunkSize,
// CommandOptions properties:
Token = Token,
RunMode = RunMode,
Destination = Destination,
HttpClientOptions = HttpClientOptions != null ? HttpClientOptions.Clone() : null,
TimeoutOptions = TimeoutOptions != null ? TimeoutOptions.Clone() : null,
APIVersion = APIVersion,
CancellationToken = CancellationToken
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace DataStax.AstraDB.DataApi.Core.Query;
/// Options for finding multiple documents in a collection.
/// </summary>
/// <typeparam name="T">The type of the document.</typeparam>
public class CollectionFindManyOptions<T> : IFindManyOptions<T, CollectionSortBuilder<T>>
public class CollectionFindManyOptions<T> : CommandOptions, IFindManyOptions<T, CollectionSortBuilder<T>>
{
/// <summary>The projection to apply to the results.</summary>
[JsonIgnore]
Expand Down Expand Up @@ -55,14 +55,16 @@ public class CollectionFindManyOptions<T> : IFindManyOptions<T, CollectionSortBu
[JsonIgnore]
public int? Limit { get; set; }

/// <summary>
/// Whether to include the sort vector in the result or not
/// </summary>
[JsonIgnore]
internal bool? IncludeSortVector { get; set; }
public bool? IncludeSortVector { get; set; }

bool? IFindManyOptions<T, CollectionSortBuilder<T>>.IncludeSortVector { get => IncludeSortVector; set => IncludeSortVector = value; }

internal Filter<T> Filter { get; set; }

[JsonIgnore]
internal string PageState { get; set; }

string IFindOptions<T, CollectionSortBuilder<T>>.PageState { get => PageState; set => PageState = value; }
Expand Down Expand Up @@ -114,6 +116,33 @@ internal Dictionary<string, object> Options
}
}

IFindManyOptions<T, CollectionSortBuilder<T>> IFindManyOptions<T, CollectionSortBuilder<T>>.PayloadOptions()
{
return new CollectionFindManyOptions<T> {
Filter = Filter,
InitialPageState = InitialPageState,
Skip = Skip,
Limit = Limit,
IncludeSortVector = IncludeSortVector,
IncludeSimilarity = IncludeSimilarity,
Projection = Projection != null ? Projection.Clone() : null,
Sort = Sort != null ? Sort.Clone() : null,
};
}

internal CommandOptions CommandOptions()
{
return new CommandOptions {
Token = Token,
RunMode = RunMode,
Destination = Destination,
HttpClientOptions = HttpClientOptions != null ? HttpClientOptions.Clone() : null,
TimeoutOptions = TimeoutOptions != null ? TimeoutOptions.Clone() : null,
APIVersion = APIVersion,
CancellationToken = CancellationToken
};
}

internal CollectionFindManyOptions<T> Clone()
{
return new CollectionFindManyOptions<T>
Expand All @@ -125,7 +154,15 @@ internal CollectionFindManyOptions<T> Clone()
IncludeSortVector = IncludeSortVector,
IncludeSimilarity = IncludeSimilarity,
Projection = Projection != null ? Projection.Clone() : null,
Sort = Sort != null ? Sort.Clone() : null
Sort = Sort != null ? Sort.Clone() : null,
// CommandOptions properties:
Token = Token,
RunMode = RunMode,
Destination = Destination,
HttpClientOptions = HttpClientOptions != null ? HttpClientOptions.Clone() : null,
TimeoutOptions = TimeoutOptions != null ? TimeoutOptions.Clone() : null,
APIVersion = APIVersion,
CancellationToken = CancellationToken
};
}

Expand Down
2 changes: 2 additions & 0 deletions src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ internal interface IFindManyOptions<T, TSort> : IFindOptions<T, TSort>
internal bool? IncludeSortVector { get; set; }

internal IFindManyOptions<T, TSort> Clone();

internal IFindManyOptions<T, TSort> PayloadOptions();
}
Loading
Loading