From 4e7f8cc50110a8cbf949731866ec425375e008f9 Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Thu, 7 May 2026 15:02:03 +0200 Subject: [PATCH 1/9] support CommandOptions in find, rearrange xmldocs a bit, add a test --- .../Collections/Collection.cs | 43 +++++++++++++----- src/DataStax.AstraDB.DataApi/Tables/Table.cs | 44 ++++++++++++++----- .../Tests/CollectionCursorTests.cs | 22 ++++++++++ 3 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs index d1f2a04..6ce8612 100644 --- a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs +++ b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs @@ -642,7 +642,7 @@ private async Task FindOneAsync(CollectionFilter filter, Co /// public CollectionFindCursor Find() { - return Find(null, null); + return Find(null, null, null); } /// @@ -657,23 +657,32 @@ public CollectionFindCursor Find() /// public CollectionFindCursor Find(CollectionFilter filter) { - return Find(filter, null); + return Find(filter, null, null); } /// /// public CollectionFindCursor Find(CollectionFindManyOptions findOptions) { - return Find(null, findOptions); + return Find(null, findOptions, null); } /// /// /// public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions) + { + return Find(filter, findOptions, null); + } + + /// + /// + /// + /// + public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions, CommandOptions commandOptions) { findOptions ??= new CollectionFindManyOptions(); - return new(findOptions.WithFilterParam(filter), null, RunFindManyAsync); + return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } /// @@ -683,7 +692,7 @@ public CollectionFindCursor Find(CollectionFilter filter, CollectionFindMa /// public CollectionFindCursor Find() where TResult : class { - return Find(null, null); + return Find(null, null, null); } /// @@ -693,7 +702,7 @@ public CollectionFindCursor Find() where TResult : class /// public CollectionFindCursor Find(CollectionFilter filter) where TResult : class { - return Find(filter, null); + return Find(filter, null, null); } /// @@ -703,16 +712,28 @@ public CollectionFindCursor Find(CollectionFilter filter /// public CollectionFindCursor Find(CollectionFindManyOptions findOptions) where TResult : class { - return Find(null, findOptions); + return Find(null, findOptions, null); } - /// - /// - /// + /// + /// + /// 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) + /// public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions) where TResult : class + { + return Find(filter, findOptions, null); + } + + /// + /// + /// 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) + /// + public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions, CommandOptions commandOptions) where TResult : class { findOptions ??= new CollectionFindManyOptions(); - return new(findOptions.WithFilterParam(filter), null, RunFindManyAsync); + return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } internal async Task> RunFindManyAsync(CollectionFindCursor cursor, string nextPageState, bool runSynchronously) where TResult : class diff --git a/src/DataStax.AstraDB.DataApi/Tables/Table.cs b/src/DataStax.AstraDB.DataApi/Tables/Table.cs index 2e51f6e..f6be6f0 100644 --- a/src/DataStax.AstraDB.DataApi/Tables/Table.cs +++ b/src/DataStax.AstraDB.DataApi/Tables/Table.cs @@ -881,7 +881,7 @@ private async Task InsertOneAsync(T row, CommandOptions co /// public TableFindCursor Find() { - return Find(null, null); + return Find(null, null, null); } /// @@ -900,14 +900,14 @@ public TableFindCursor Find() /// public TableFindCursor Find(TableFilter filter) { - return Find(filter, null); + return Find(filter, null, null); } /// /// public TableFindCursor Find(TableFindManyOptions findOptions) { - return Find(null, findOptions); + return Find(null, findOptions, null); } /// @@ -916,7 +916,17 @@ public TableFindCursor Find(TableFindManyOptions findOptions) public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions) { findOptions ??= new TableFindManyOptions(); - return new(findOptions.WithFilterParam(filter), null, RunFindManyAsync); + return Find(filter, findOptions, null); + } + + /// + /// + /// + /// + public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions, CommandOptions commandOptions) + { + findOptions ??= new TableFindManyOptions(); + return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } /// @@ -926,7 +936,7 @@ public TableFindCursor Find(TableFilter filter, TableFindManyOptions fi /// public TableFindCursor Find() where TResult : class { - return Find(null, null); + return Find(null, null, null); } /// @@ -936,7 +946,7 @@ public TableFindCursor Find() where TResult : class /// public TableFindCursor Find(TableFilter filter) where TResult : class { - return Find(filter, null); + return Find(filter, null, null); } /// @@ -946,16 +956,28 @@ public TableFindCursor Find(TableFilter filter) where TR /// public TableFindCursor Find(TableFindManyOptions findOptions) where TResult : class { - return Find(null, findOptions); + return Find(null, findOptions, null); } - /// - /// - /// + /// + /// + /// The Find alternatives that accept a TResult type parameter allow for deserializing the row as a different type + /// (most commonly used when using projection to return a subset of fields) + /// public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions) where TResult : class + { + return Find(filter, findOptions, null); + } + + /// + /// + /// The Find alternatives that accept a TResult type parameter allow for deserializing the row as a different type + /// (most commonly used when using projection to return a subset of fields) + /// + public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions, CommandOptions commandOptions) where TResult : class { findOptions ??= new TableFindManyOptions(); - return new(findOptions.WithFilterParam(filter), null, RunFindManyAsync); + return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } internal async Task> RunFindManyAsync(TableFindCursor cursor, string nextPageState, bool runSynchronously) where TResult : class diff --git a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs index ffc18dc..fbc27c9 100644 --- a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs +++ b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs @@ -2,6 +2,7 @@ using DataStax.AstraDB.DataApi.Core; using DataStax.AstraDB.DataApi.Core.Commands; using DataStax.AstraDB.DataApi.Core.Enumeration; +using DataStax.AstraDB.DataApi.Core.Query; using DataStax.AstraDB.DataApi.Core.Results; using DataStax.AstraDB.DataApi.IntegrationTests.Fixtures; using DataStax.AstraDB.DataApi.SerDes; @@ -25,6 +26,27 @@ public CollectionCursorTests(AssemblyFixture assemblyFixture, CollectionCursorFi _fixture = fixture; } + [Fact] + public async Task Test_CollectionCursor_CommandOptions() + { + var filledCollection = _fixture.FilledCollection; + + var theFilter = Builders.CollectionFilter.Gt(d => d.PInt, 2); + var theFindOptions = new CollectionFindManyOptions { + Sort = Builders.CollectionSort.Descending(d => d.PInt) + }; + var theBadToken = new CommandOptions { Token = "blibblo" }; + + var goodCur = filledCollection.Find(theFilter, theFindOptions); + var badCur = filledCollection.Find(theFilter, theFindOptions, theBadToken); + + await foreach (var item in goodCur) { /* moot */ }; + await Assert.ThrowsAsync( async () => + { + await foreach (var item in badCur) { /* moot */ } + }); + } + [Fact] public async Task Test_CollectionCursor_IdleProperties() { From c5bb9dcdaf870fcaada7c4c8c88b3709595371de Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Fri, 8 May 2026 11:42:07 +0200 Subject: [PATCH 2/9] conflate CommandOptions into FindManyOptions --- .../Collections/Collection.cs | 40 +++------ .../Core/CommandOptions.cs | 7 ++ .../Core/HttpClientOptions.cs | 12 ++- .../Core/Query/CollectionFindManyOptions.cs | 39 +++++++- .../Core/Query/IFindManyOptions.cs | 2 + .../Core/Query/TableFindManyOptions.cs | 90 +++++++++++-------- .../Core/TimeoutOptions.cs | 14 +++ src/DataStax.AstraDB.DataApi/Tables/Table.cs | 39 +++----- .../Tests/CollectionCursorTests.cs | 11 ++- 9 files changed, 153 insertions(+), 101 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs index 6ce8612..50f6d93 100644 --- a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs +++ b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs @@ -642,7 +642,7 @@ private async Task FindOneAsync(CollectionFilter filter, Co /// public CollectionFindCursor Find() { - return Find(null, null, null); + return Find(null, null); } /// @@ -657,31 +657,23 @@ public CollectionFindCursor Find() /// public CollectionFindCursor Find(CollectionFilter filter) { - return Find(filter, null, null); + return Find(filter, null); } /// /// public CollectionFindCursor Find(CollectionFindManyOptions findOptions) { - return Find(null, findOptions, null); + return Find(null, findOptions); } /// /// /// public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions) - { - return Find(filter, findOptions, null); - } - - /// - /// - /// - /// - public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions, CommandOptions commandOptions) { findOptions ??= new CollectionFindManyOptions(); + var commandOptions = findOptions.commandOptions(); return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } @@ -692,7 +684,7 @@ public CollectionFindCursor Find(CollectionFilter filter, CollectionFindMa /// public CollectionFindCursor Find() where TResult : class { - return Find(null, null, null); + return Find(null, null); } /// @@ -702,7 +694,7 @@ public CollectionFindCursor Find() where TResult : class /// public CollectionFindCursor Find(CollectionFilter filter) where TResult : class { - return Find(filter, null, null); + return Find(filter, null); } /// @@ -712,7 +704,7 @@ public CollectionFindCursor Find(CollectionFilter filter /// public CollectionFindCursor Find(CollectionFindManyOptions findOptions) where TResult : class { - return Find(null, findOptions, null); + return Find(null, findOptions); } /// @@ -721,18 +713,9 @@ public CollectionFindCursor Find(CollectionFindManyOptions< /// (most commonly used when using projection to return a subset of fields) /// public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions) where TResult : class - { - return Find(filter, findOptions, null); - } - - /// - /// - /// 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) - /// - public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions, CommandOptions commandOptions) where TResult : class { findOptions ??= new CollectionFindManyOptions(); + var commandOptions = findOptions.commandOptions(); return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } @@ -740,10 +723,11 @@ internal async Task> RunFindManyAsync(CollectionFindC { 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, TResult, FindStatusResult>(runSynchronously).ConfigureAwait(false); - + return new FindPage( response.Data.NextPageState, response.Data.Items, diff --git a/src/DataStax.AstraDB.DataApi/Core/CommandOptions.cs b/src/DataStax.AstraDB.DataApi/Core/CommandOptions.cs index ccdc791..30bf0a1 100644 --- a/src/DataStax.AstraDB.DataApi/Core/CommandOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/CommandOptions.cs @@ -48,6 +48,7 @@ public class CommandOptions /// /// The token to use for authentication /// + [JsonIgnore] public string Token { get; set; } /// @@ -55,6 +56,7 @@ public class CommandOptions /// /// Defaults to /// + [JsonIgnore] public RunMode? RunMode { get; set; } /// @@ -62,6 +64,7 @@ public class CommandOptions /// /// Defaults to /// + [JsonIgnore] public DataAPIDestination? Destination { get; set; } /// @@ -69,6 +72,7 @@ public class CommandOptions /// /// Defaults to HttpVersion: 2.0, FollowRedirects: true /// + [JsonIgnore] public HttpClientOptions HttpClientOptions { get; set; } /// @@ -77,6 +81,7 @@ public class CommandOptions /// /// See for information. /// + [JsonIgnore] public TimeoutOptions TimeoutOptions { get; set; } = new TimeoutOptions(); /// @@ -84,6 +89,7 @@ public class CommandOptions /// /// Defaults to /// + [JsonIgnore] public APIVersion? APIVersion { get; set; } internal string APIUrlBase @@ -101,6 +107,7 @@ internal string APIUrlBase /// /// An optional CancellationToken to interrupt asynchronous operations /// + [JsonIgnore] public CancellationToken? CancellationToken { get; set; } internal CancellationToken? BulkOperationCancellationToken { get; set; } diff --git a/src/DataStax.AstraDB.DataApi/Core/HttpClientOptions.cs b/src/DataStax.AstraDB.DataApi/Core/HttpClientOptions.cs index ba6e4d5..ff4f946 100644 --- a/src/DataStax.AstraDB.DataApi/Core/HttpClientOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/HttpClientOptions.cs @@ -32,4 +32,14 @@ public class HttpClientOptions /// Whether the HTTP client should follow redirects or not. /// public bool FollowRedirects { get; set; } = true; -} \ No newline at end of file + + internal HttpClientOptions Clone() + { + return new HttpClientOptions + { + HttpVersion = HttpVersion, + FollowRedirects = FollowRedirects, + }; + } + +} diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs index 1ca338d..b8d4433 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs @@ -25,7 +25,7 @@ namespace DataStax.AstraDB.DataApi.Core.Query; /// Options for finding multiple documents in a collection. /// /// The type of the document. -public class CollectionFindManyOptions : IFindManyOptions> +public class CollectionFindManyOptions : CommandOptions, IFindManyOptions> { /// The projection to apply to the results. [JsonIgnore] @@ -114,6 +114,33 @@ internal Dictionary Options } } + IFindManyOptions> IFindManyOptions>.payloadOptions() + { + return new CollectionFindManyOptions { + 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 Clone() { return new CollectionFindManyOptions @@ -125,7 +152,15 @@ internal CollectionFindManyOptions 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 }; } diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs index a635330..9385e01 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs @@ -40,4 +40,6 @@ internal interface IFindManyOptions : IFindOptions internal bool? IncludeSortVector { get; set; } internal IFindManyOptions Clone(); + + internal IFindManyOptions payloadOptions(); } diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs index 156d03e..65ba9e6 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs @@ -25,7 +25,7 @@ namespace DataStax.AstraDB.DataApi.Core.Query; /// A set of options to be used when finding rows in a table. /// /// -public class TableFindManyOptions : IFindManyOptions> +public class TableFindManyOptions : CommandOptions, IFindManyOptions> { /// The projection to apply to the results. [JsonIgnore] @@ -144,6 +144,33 @@ internal Dictionary Options } } + IFindManyOptions> IFindManyOptions>.payloadOptions() + { + return new TableFindManyOptions { + 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 TableFindManyOptions Clone() { return new TableFindManyOptions @@ -155,50 +182,37 @@ internal TableFindManyOptions 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 }; } - IFindManyOptions> IFindManyOptions>.Clone() + IFindManyOptions> IFindManyOptions>.Clone() + { + return Clone(); + } + internal TableFindManyOptions WithFilterParam(TableFilter filter) + { + if (filter == null) { - - return Clone(); - + return this; } - - - internal TableFindManyOptions WithFilterParam(TableFilter filter) - + if (Filter != null) { - - if (filter == null) - - { - - return this; - - } - - - - if (Filter != null) - - { - - throw new ArgumentException("Cannot pass a filter both within FindOptions and as stand-alone argument"); - - } - - - - var cloned = Clone(); - - cloned.Filter = filter; - - return cloned; - + throw new ArgumentException("Cannot pass a filter both within FindOptions and as stand-alone argument"); } - } \ No newline at end of file + var cloned = Clone(); + cloned.Filter = filter; + return cloned; + } +} diff --git a/src/DataStax.AstraDB.DataApi/Core/TimeoutOptions.cs b/src/DataStax.AstraDB.DataApi/Core/TimeoutOptions.cs index 098f994..46f254e 100644 --- a/src/DataStax.AstraDB.DataApi/Core/TimeoutOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/TimeoutOptions.cs @@ -94,4 +94,18 @@ public class TimeoutOptions /// The timeout for keyspace administration operations, such as creating or deleting keyspaces. /// public TimeSpan? KeyspaceAdminTimeout { get; set; } + + internal TimeoutOptions Clone() + { + return new TimeoutOptions + { + ConnectionTimeout = ConnectionTimeout, + RequestTimeout = RequestTimeout, + BulkOperationTimeout = BulkOperationTimeout, + CollectionAdminTimeout = CollectionAdminTimeout, + TableAdminTimeout = TableAdminTimeout, + DatabaseAdminTimeout = DatabaseAdminTimeout, + KeyspaceAdminTimeout = KeyspaceAdminTimeout, + }; + } } diff --git a/src/DataStax.AstraDB.DataApi/Tables/Table.cs b/src/DataStax.AstraDB.DataApi/Tables/Table.cs index f6be6f0..8e9607b 100644 --- a/src/DataStax.AstraDB.DataApi/Tables/Table.cs +++ b/src/DataStax.AstraDB.DataApi/Tables/Table.cs @@ -881,7 +881,7 @@ private async Task InsertOneAsync(T row, CommandOptions co /// public TableFindCursor Find() { - return Find(null, null, null); + return Find(null, null); } /// @@ -900,14 +900,14 @@ public TableFindCursor Find() /// public TableFindCursor Find(TableFilter filter) { - return Find(filter, null, null); + return Find(filter, null); } /// /// public TableFindCursor Find(TableFindManyOptions findOptions) { - return Find(null, findOptions, null); + return Find(null, findOptions); } /// @@ -916,16 +916,7 @@ public TableFindCursor Find(TableFindManyOptions findOptions) public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions) { findOptions ??= new TableFindManyOptions(); - return Find(filter, findOptions, null); - } - - /// - /// - /// - /// - public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions, CommandOptions commandOptions) - { - findOptions ??= new TableFindManyOptions(); + var commandOptions = findOptions.commandOptions(); return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } @@ -936,7 +927,7 @@ public TableFindCursor Find(TableFilter filter, TableFindManyOptions fi /// public TableFindCursor Find() where TResult : class { - return Find(null, null, null); + return Find(null, null); } /// @@ -946,7 +937,7 @@ public TableFindCursor Find() where TResult : class /// public TableFindCursor Find(TableFilter filter) where TResult : class { - return Find(filter, null, null); + return Find(filter, null); } /// @@ -956,7 +947,7 @@ public TableFindCursor Find(TableFilter filter) where TR /// public TableFindCursor Find(TableFindManyOptions findOptions) where TResult : class { - return Find(null, findOptions, null); + return Find(null, findOptions); } /// @@ -965,18 +956,9 @@ public TableFindCursor Find(TableFindManyOptions findOpt /// (most commonly used when using projection to return a subset of fields) /// public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions) where TResult : class - { - return Find(filter, findOptions, null); - } - - /// - /// - /// The Find alternatives that accept a TResult type parameter allow for deserializing the row as a different type - /// (most commonly used when using projection to return a subset of fields) - /// - public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions, CommandOptions commandOptions) where TResult : class { findOptions ??= new TableFindManyOptions(); + var commandOptions = findOptions.commandOptions(); return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } @@ -984,9 +966,10 @@ internal async Task> RunFindManyAsync(TableFindCursor { var options = cursor.FindOptions.Clone(); options.PageState = nextPageState; - + + var payloadOptions = options.payloadOptions(); var commandOptions = SetRowSerializationOptions(cursor.CommandOptions, false); - var command = CreateCommand("find").WithPayload(options).AddCommandOptions(commandOptions); + var command = CreateCommand("find").WithPayload(payloadOptions).AddCommandOptions(commandOptions); var response = await command.RunAsyncReturnData, TableFindStatusResult>(runSynchronously).ConfigureAwait(false); if (typeof(Row).IsAssignableFrom(typeof(TResult))) diff --git a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs index fbc27c9..5663ad2 100644 --- a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs +++ b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs @@ -32,13 +32,16 @@ public async Task Test_CollectionCursor_CommandOptions() var filledCollection = _fixture.FilledCollection; var theFilter = Builders.CollectionFilter.Gt(d => d.PInt, 2); - var theFindOptions = new CollectionFindManyOptions { + var theGoodFindOptions = new CollectionFindManyOptions { Sort = Builders.CollectionSort.Descending(d => d.PInt) }; - var theBadToken = new CommandOptions { Token = "blibblo" }; + var theBadFindOptions = new CollectionFindManyOptions { + Sort = Builders.CollectionSort.Descending(d => d.PInt), + Token = "blibblo" + }; - var goodCur = filledCollection.Find(theFilter, theFindOptions); - var badCur = filledCollection.Find(theFilter, theFindOptions, theBadToken); + var goodCur = filledCollection.Find(theFilter, theGoodFindOptions); + var badCur = filledCollection.Find(theFilter, theBadFindOptions); await foreach (var item in goodCur) { /* moot */ }; await Assert.ThrowsAsync( async () => From a44f1c184b7454ec7154fcf2a77cbf0bc3995f99 Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Fri, 8 May 2026 11:45:14 +0200 Subject: [PATCH 3/9] capitalize method name --- src/DataStax.AstraDB.DataApi/Collections/Collection.cs | 2 +- .../Core/Query/CollectionFindManyOptions.cs | 2 +- src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs | 2 +- src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs | 2 +- src/DataStax.AstraDB.DataApi/Tables/Table.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs index 50f6d93..f4723a3 100644 --- a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs +++ b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs @@ -724,7 +724,7 @@ internal async Task> RunFindManyAsync(CollectionFindC var options = cursor.FindOptions.Clone(); options.PageState = nextPageState; - var payloadOptions = options.payloadOptions(); + var payloadOptions = options.PayloadOptions(); var command = CreateCommand("find").WithPayload(payloadOptions).AddCommandOptions(cursor.CommandOptions); var response = await command.RunAsyncReturnDocumentData, TResult, FindStatusResult>(runSynchronously).ConfigureAwait(false); diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs index b8d4433..1e61253 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs @@ -114,7 +114,7 @@ internal Dictionary Options } } - IFindManyOptions> IFindManyOptions>.payloadOptions() + IFindManyOptions> IFindManyOptions>.PayloadOptions() { return new CollectionFindManyOptions { Filter = Filter, diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs index 9385e01..7122a36 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/IFindManyOptions.cs @@ -41,5 +41,5 @@ internal interface IFindManyOptions : IFindOptions internal IFindManyOptions Clone(); - internal IFindManyOptions payloadOptions(); + internal IFindManyOptions PayloadOptions(); } diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs index 65ba9e6..6056fb7 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs @@ -144,7 +144,7 @@ internal Dictionary Options } } - IFindManyOptions> IFindManyOptions>.payloadOptions() + IFindManyOptions> IFindManyOptions>.PayloadOptions() { return new TableFindManyOptions { Filter = Filter, diff --git a/src/DataStax.AstraDB.DataApi/Tables/Table.cs b/src/DataStax.AstraDB.DataApi/Tables/Table.cs index 8e9607b..ad701da 100644 --- a/src/DataStax.AstraDB.DataApi/Tables/Table.cs +++ b/src/DataStax.AstraDB.DataApi/Tables/Table.cs @@ -967,7 +967,7 @@ internal async Task> RunFindManyAsync(TableFindCursor var options = cursor.FindOptions.Clone(); options.PageState = nextPageState; - var payloadOptions = options.payloadOptions(); + var payloadOptions = options.PayloadOptions(); var commandOptions = SetRowSerializationOptions(cursor.CommandOptions, false); var command = CreateCommand("find").WithPayload(payloadOptions).AddCommandOptions(commandOptions); var response = await command.RunAsyncReturnData, TableFindStatusResult>(runSynchronously).ConfigureAwait(false); From 2be4f8dbab61bb18c09ab3955b4020002fd1ea0f Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Fri, 8 May 2026 11:54:28 +0200 Subject: [PATCH 4/9] more method capitalization lol --- src/DataStax.AstraDB.DataApi/Collections/Collection.cs | 4 ++-- .../Core/Query/CollectionFindManyOptions.cs | 2 +- .../Core/Query/TableFindManyOptions.cs | 2 +- src/DataStax.AstraDB.DataApi/Tables/Table.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs index f4723a3..7367bed 100644 --- a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs +++ b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs @@ -673,7 +673,7 @@ public CollectionFindCursor Find(CollectionFindManyOptions findOptions) public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions) { findOptions ??= new CollectionFindManyOptions(); - var commandOptions = findOptions.commandOptions(); + var commandOptions = findOptions.CommandOptions(); return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } @@ -715,7 +715,7 @@ public CollectionFindCursor Find(CollectionFindManyOptions< public CollectionFindCursor Find(CollectionFilter filter, CollectionFindManyOptions findOptions) where TResult : class { findOptions ??= new CollectionFindManyOptions(); - var commandOptions = findOptions.commandOptions(); + var commandOptions = findOptions.CommandOptions(); return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs index 1e61253..c812abd 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs @@ -128,7 +128,7 @@ IFindManyOptions> IFindManyOptions> IFindManyOptions }; } - internal CommandOptions commandOptions() + internal CommandOptions CommandOptions() { return new CommandOptions { Token = Token, diff --git a/src/DataStax.AstraDB.DataApi/Tables/Table.cs b/src/DataStax.AstraDB.DataApi/Tables/Table.cs index ad701da..8c31d86 100644 --- a/src/DataStax.AstraDB.DataApi/Tables/Table.cs +++ b/src/DataStax.AstraDB.DataApi/Tables/Table.cs @@ -916,7 +916,7 @@ public TableFindCursor Find(TableFindManyOptions findOptions) public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions) { findOptions ??= new TableFindManyOptions(); - var commandOptions = findOptions.commandOptions(); + var commandOptions = findOptions.CommandOptions(); return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } @@ -958,7 +958,7 @@ public TableFindCursor Find(TableFindManyOptions findOpt public TableFindCursor Find(TableFilter filter, TableFindManyOptions findOptions) where TResult : class { findOptions ??= new TableFindManyOptions(); - var commandOptions = findOptions.commandOptions(); + var commandOptions = findOptions.CommandOptions(); return new(findOptions.WithFilterParam(filter), commandOptions, RunFindManyAsync); } From f7db2349de8261783fd820adead8c7ff886600f6 Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Fri, 8 May 2026 23:45:33 +0200 Subject: [PATCH 5/9] post-rebase(Api->API) adjustments --- .../Core/Query/CollectionFindManyOptions.cs | 4 ++-- .../Core/Query/TableFindManyOptions.cs | 4 ++-- .../Tests/CollectionCursorTests.cs | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs index c812abd..e9b7e71 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs @@ -136,7 +136,7 @@ internal CommandOptions CommandOptions() Destination = Destination, HttpClientOptions = HttpClientOptions != null ? HttpClientOptions.Clone() : null, TimeoutOptions = TimeoutOptions != null ? TimeoutOptions.Clone() : null, - ApiVersion = ApiVersion, + APIVersion = APIVersion, CancellationToken = CancellationToken }; } @@ -159,7 +159,7 @@ internal CollectionFindManyOptions Clone() Destination = Destination, HttpClientOptions = HttpClientOptions != null ? HttpClientOptions.Clone() : null, TimeoutOptions = TimeoutOptions != null ? TimeoutOptions.Clone() : null, - ApiVersion = ApiVersion, + APIVersion = APIVersion, CancellationToken = CancellationToken }; } diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs index 4a513ce..2241433 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs @@ -166,7 +166,7 @@ internal CommandOptions CommandOptions() Destination = Destination, HttpClientOptions = HttpClientOptions != null ? HttpClientOptions.Clone() : null, TimeoutOptions = TimeoutOptions != null ? TimeoutOptions.Clone() : null, - ApiVersion = ApiVersion, + APIVersion = APIVersion, CancellationToken = CancellationToken }; } @@ -189,7 +189,7 @@ internal TableFindManyOptions Clone() Destination = Destination, HttpClientOptions = HttpClientOptions != null ? HttpClientOptions.Clone() : null, TimeoutOptions = TimeoutOptions != null ? TimeoutOptions.Clone() : null, - ApiVersion = ApiVersion, + APIVersion = APIVersion, CancellationToken = CancellationToken }; } diff --git a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs index 5663ad2..270cc8f 100644 --- a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs +++ b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionCursorTests.cs @@ -26,6 +26,8 @@ public CollectionCursorTests(AssemblyFixture assemblyFixture, CollectionCursorFi _fixture = fixture; } + // This one is skipped on HCD because in some cases a wrong token will *not* bring failure + [SkipWhenNotAstra] [Fact] public async Task Test_CollectionCursor_CommandOptions() { From 2b70fcb26c48b1ab3a865f2dc85a6327fbaa1a4c Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Sat, 9 May 2026 00:12:54 +0200 Subject: [PATCH 6/9] Make IncludeSortVector public in the C/T FindManyOptions --- .../Core/Query/CollectionFindManyOptions.cs | 6 ++++-- .../Core/Query/TableFindManyOptions.cs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs index e9b7e71..20a8e89 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/CollectionFindManyOptions.cs @@ -55,14 +55,16 @@ public class CollectionFindManyOptions : CommandOptions, IFindManyOptions + /// Whether to include the sort vector in the result or not + /// [JsonIgnore] - internal bool? IncludeSortVector { get; set; } + public bool? IncludeSortVector { get; set; } bool? IFindManyOptions>.IncludeSortVector { get => IncludeSortVector; set => IncludeSortVector = value; } internal Filter Filter { get; set; } - [JsonIgnore] internal string PageState { get; set; } string IFindOptions>.PageState { get => PageState; set => PageState = value; } diff --git a/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs index 2241433..c089e93 100644 --- a/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/Query/TableFindManyOptions.cs @@ -86,7 +86,7 @@ public class TableFindManyOptions : CommandOptions, IFindManyOptions /// [JsonIgnore] - internal bool? IncludeSortVector { get; set; } + public bool? IncludeSortVector { get; set; } bool? IFindManyOptions>.IncludeSortVector { get => IncludeSortVector; set => IncludeSortVector = value; } From 605641fc2e3d48248bbfa21f1eedebdf6f8b3e45 Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Sat, 9 May 2026 00:29:56 +0200 Subject: [PATCH 7/9] revise InsertManyOptions defaults --- src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs index 8840257..d175a7e 100644 --- a/src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs @@ -24,12 +24,12 @@ public class InsertManyOptions /// /// Default batch size. /// - public const int DefaultChunkSize = 100; + public const int DefaultChunkSize = 50; /// - /// Maximum concurrency. + /// Default concurrency for unordered insertions. /// - public const int MaxConcurrency = int.MaxValue; + public const int DefaultConcurrency = 20; private bool _Ordered = false; /// @@ -48,7 +48,7 @@ public bool Ordered /// The number of parallel processes to use while inserting documents. /// Must be set to 1 for ordered inserts. /// - public int Concurrency { get; set; } = MaxConcurrency; + public int Concurrency { get; set; } = DefaultConcurrency; /// /// The number of documents to insert in each batch. From f7fa10b856294482d7bed8239a9740a934d43b5e Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Sat, 9 May 2026 00:41:17 +0200 Subject: [PATCH 8/9] InsertManyOptions+CommandOptions conflation --- .../Collections/Collection.cs | 76 ++++++------------- .../Core/InsertManyOptions.cs | 34 ++++++++- src/DataStax.AstraDB.DataApi/Tables/Table.cs | 58 ++++---------- .../Tests/CollectionTests.cs | 32 ++++++++ .../Tests/TableTests.cs | 40 ++++++++++ 5 files changed, 143 insertions(+), 97 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs index 7367bed..a1837fc 100644 --- a/src/DataStax.AstraDB.DataApi/Collections/Collection.cs +++ b/src/DataStax.AstraDB.DataApi/Collections/Collection.cs @@ -134,39 +134,21 @@ private async Task> InsertOneAsync(T document, Co } /// - /// Synchronous version of + /// Synchronous version of /// - /// - public CollectionInsertManyResult InsertMany(List documents) + /// + public CollectionInsertManyResult InsertMany(IEnumerable documents) { - return InsertMany(documents, null, null); + return InsertMany(documents, null); } /// - /// Synchronous version of + /// Synchronous version of /// - /// - public CollectionInsertManyResult InsertMany(List documents, InsertManyOptions insertOptions) + /// + public CollectionInsertManyResult InsertMany(IEnumerable documents, InsertManyOptions insertOptions) { - return InsertMany(documents, insertOptions, null); - } - - /// - /// Synchronous version of - /// - /// - public CollectionInsertManyResult InsertMany(List documents, CommandOptions commandOptions) - { - return InsertMany(documents, null, commandOptions); - } - - /// - /// Synchronous version of - /// - /// - public CollectionInsertManyResult InsertMany(List documents, InsertManyOptions insertOptions, CommandOptions commandOptions) - { - return InsertManyAsync(documents, insertOptions, commandOptions, runSynchronously: true).ResultSync(); + return InsertManyAsync(documents, insertOptions, runSynchronously: true).ResultSync(); } /// @@ -174,44 +156,30 @@ public CollectionInsertManyResult InsertMany(List documents, InsertManyO /// /// The list of documents to insert. /// - /// Thrown if the documents list is null or empty. - /// Thrown if an error occurs during the bulk operation, + /// + /// If you need to control concurrency, chunk size, whether the insert is ordered or not, or other options, use the overload. + /// + /// Thrown if an error occurs during the bulk operation, /// with partial results returned in the property. - public Task> InsertManyAsync(List documents) - { - return InsertManyAsync(documents, new CommandOptions()); - } - - /// - /// - /// Allows specifying whether the documents should be inserted in order as well as the chunk size. - public Task> InsertManyAsync(List documents, InsertManyOptions insertOptions) - { - return InsertManyAsync(documents, insertOptions, null, runSynchronously: false); - } - - /// - /// - /// - public Task> InsertManyAsync(List documents, CommandOptions commandOptions) + public Task> InsertManyAsync(IEnumerable documents) { - return InsertManyAsync(documents, null, commandOptions, runSynchronously: false); + return InsertManyAsync(documents, null); } - /// - /// - /// - /// - public Task> InsertManyAsync(List documents, InsertManyOptions insertOptions, CommandOptions commandOptions) + /// + /// The list of documents to insert. + /// Allows specifying the insertion chunk size, ordered/unordered mode, concurrency, as well as other generic command-execution options. + public Task> InsertManyAsync(IEnumerable documents, InsertManyOptions insertOptions) { - return InsertManyAsync(documents, insertOptions, commandOptions, runSynchronously: false); + return InsertManyAsync(documents, insertOptions, runSynchronously: false); } - private async Task> InsertManyAsync(List documents, InsertManyOptions insertOptions, CommandOptions commandOptions, bool runSynchronously) + private async Task> InsertManyAsync(IEnumerable 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."); diff --git a/src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs b/src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs index d175a7e..ae10dc0 100644 --- a/src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs +++ b/src/DataStax.AstraDB.DataApi/Core/InsertManyOptions.cs @@ -19,7 +19,7 @@ namespace DataStax.AstraDB.DataApi.Core; /// /// Options for inserting multiple documents into a collection. /// -public class InsertManyOptions +public class InsertManyOptions : CommandOptions { /// /// Default batch size. @@ -54,4 +54,36 @@ public bool Ordered /// The number of documents to insert in each batch. /// 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 + }; + } + } diff --git a/src/DataStax.AstraDB.DataApi/Tables/Table.cs b/src/DataStax.AstraDB.DataApi/Tables/Table.cs index 8c31d86..9653687 100644 --- a/src/DataStax.AstraDB.DataApi/Tables/Table.cs +++ b/src/DataStax.AstraDB.DataApi/Tables/Table.cs @@ -652,21 +652,12 @@ private async Task CreateGenericIndexAsync(string indexName, string columnName, // /// - /// This is a synchronous version of + /// Synchronous version of /// - /// + /// public TableInsertManyResult InsertMany(IEnumerable rows) { - return InsertMany(rows, null as CommandOptions); - } - - /// - /// Synchronous version of - /// - /// - public TableInsertManyResult InsertMany(IEnumerable rows, CommandOptions commandOptions) - { - return InsertManyAsync(rows, null, commandOptions, true).ResultSync(); + return InsertMany(rows, null); } /// @@ -675,55 +666,38 @@ public TableInsertManyResult InsertMany(IEnumerable rows, CommandOptions comm /// public TableInsertManyResult InsertMany(IEnumerable rows, InsertManyOptions insertOptions) { - return InsertManyAsync(rows, insertOptions, null, true).ResultSync(); + return InsertManyAsync(rows, insertOptions, runSynchronously: true).ResultSync(); } /// - /// Insert multiple rows into the table. + /// Asynchronously insert multiple rows into the table. /// - /// + /// The list of rows to insert. /// /// - /// If you need to control concurrency, chunk size, or whether the insert is ordered or not, use the overload. - /// To additionally control timesouts, use the overload. + /// If you need to control concurrency, chunk size, whether the insert is ordered or not, or other options, use the overload. /// - /// Thrown if the rows collection is null or empty. - /// Thrown if an error occurs during the bulk operation, with partial results returned in the property. + /// Thrown if an error occurs during the bulk operation, + /// with partial results returned in the property. public Task InsertManyAsync(IEnumerable rows) { - return InsertManyAsync(rows, null, null, false); + return InsertManyAsync(rows, null); } /// - /// - /// - public Task InsertManyAsync(IEnumerable rows, CommandOptions commandOptions) - { - return InsertManyAsync(rows, null, commandOptions, false); - } - - /// - /// - /// + /// The list of rows to insert. + /// Allows specifying the insertion chunk size, ordered/unordered mode, concurrency, as well as other generic command-execution options. public Task InsertManyAsync(IEnumerable rows, InsertManyOptions insertOptions) { - return InsertManyAsync(rows, insertOptions, null, false); - } - - /// - /// - /// - /// - public Task InsertManyAsync(IEnumerable rows, InsertManyOptions insertOptions, CommandOptions commandOptions) - { - return InsertManyAsync(rows, insertOptions, commandOptions, false); + return InsertManyAsync(rows, insertOptions, runSynchronously: false); } - private async Task InsertManyAsync(IEnumerable rows, InsertManyOptions insertOptions, CommandOptions commandOptions, bool runSynchronously) + private async Task InsertManyAsync(IEnumerable rows, InsertManyOptions insertOptions, bool runSynchronously) { - Guard.NotNullOrEmpty(rows, nameof(rows)); + Guard.NotNull(rows, nameof(rows)); 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."); diff --git a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionTests.cs b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionTests.cs index c3983d4..e5f979d 100644 --- a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionTests.cs +++ b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionTests.cs @@ -628,6 +628,38 @@ public async Task InsertDocumentsOrderedAsync() } } + [SkipWhenNotAstra] + [Fact] + public async Task InsertManyCommandOptions() + { + var collectionName = "simpleObjects"; + try + { + List items = new List(); + for (var i = 0; i < 10; i++) + { + items.Add(new SimpleObject() + { + _id = i, + Name = $"Test Object {i}" + }); + } + ; + var collection = await fixture.Database.CreateCollectionAsync(collectionName); + + // passing generic command options: + await Assert.ThrowsAsync>( async () => + { + await collection.InsertManyAsync( + items, new InsertManyOptions() { Token = "blibbli" }); + }); + } + finally + { + await fixture.Database.DropCollectionAsync(collectionName); + } + } + [Fact] public async Task CountDocuments_NoFilter_ReturnsCorrectCount() { diff --git a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableTests.cs b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableTests.cs index 0b96aa1..d2f17f3 100644 --- a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableTests.cs +++ b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableTests.cs @@ -1,5 +1,6 @@ using DataStax.AstraDB.DataApi.Core; using DataStax.AstraDB.DataApi.Core.Query; +using DataStax.AstraDB.DataApi.Core.Results; using DataStax.AstraDB.DataApi.IntegrationTests.Fixtures; using DataStax.AstraDB.DataApi.Tables; using Microsoft.VisualBasic; @@ -56,6 +57,45 @@ public async Task InsertRows() } } + [SkipWhenNotAstra] + [Fact] + public async Task InsertManyCommandOptions() + { + var tableName = "insertRowsTest"; + try + { + var table = await fixture.Database.CreateTableAsync(tableName); + var row1 = new RowBook() + { + Title = "Computed Wilderness", + Author = "Ryan Eau", + NumberOfPages = 432, + DueDate = DateTime.UtcNow - TimeSpan.FromDays(1), + Genres = new HashSet { "History", "Biography" } + }; + var row2 = new RowBook() + { + Title = "Desert Peace", + Author = "Walter Dray", + NumberOfPages = 355, + DueDate = DateTime.UtcNow - TimeSpan.FromDays(2), + Genres = new HashSet { "Fiction" } + }; + var rows = new List { row1, row2 }; + + // passing generic command options: + await Assert.ThrowsAsync>( async () => + { + await table.InsertManyAsync( + rows, new InsertManyOptions() { Token = "blibbli" }); + }); + } + finally + { + await fixture.Database.DropTableAsync(tableName); + } + } + [Fact] public async Task InsertManyRows() { From 2a615a290fb6d2e29d799abe55b5d7e9040033a6 Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Mon, 11 May 2026 10:23:19 +0200 Subject: [PATCH 9/9] fix missing type param in exception --- .../Tests/CollectionTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionTests.cs b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionTests.cs index e5f979d..e82e105 100644 --- a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionTests.cs +++ b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/CollectionTests.cs @@ -648,7 +648,7 @@ public async Task InsertManyCommandOptions() var collection = await fixture.Database.CreateCollectionAsync(collectionName); // passing generic command options: - await Assert.ThrowsAsync>( async () => + await Assert.ThrowsAsync>>( async () => { await collection.InsertManyAsync( items, new InsertManyOptions() { Token = "blibbli" });