From bdb480e495feecad62d1e90305572c6100297af8 Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Fri, 10 Apr 2026 18:29:09 +0200 Subject: [PATCH 1/3] enable options to index creation on maps --- .../Tables/TableIndexBuilder.cs | 80 ++++++++++++------- .../Tables/TableMapIndexDefinition.cs | 6 ++ .../Tests/TableIndexesTests.cs | 72 ++++++++++++++++- 3 files changed, 127 insertions(+), 31 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Tables/TableIndexBuilder.cs b/src/DataStax.AstraDB.DataApi/Tables/TableIndexBuilder.cs index f3b4546..3e16d45 100644 --- a/src/DataStax.AstraDB.DataApi/Tables/TableIndexBuilder.cs +++ b/src/DataStax.AstraDB.DataApi/Tables/TableIndexBuilder.cs @@ -24,9 +24,12 @@ namespace DataStax.AstraDB.DataApi.Tables; public class TableIndexBuilder { /// - /// Create a default index. + /// Create a default table index. /// - /// + /// Whether the index should be case sensitive + /// Whether the index should normalize the text + /// Whether the index should use ASCII conversion + /// An index definition for use in a CreateIndex method call. public TableIndexDefinition Index(bool caseSensitive = true, bool normalize = false, bool ascii = false) { return new TableIndexDefinition @@ -42,27 +45,48 @@ public TableIndexDefinition Index(bool caseSensitive = true, bool normalize = fa /// /// Create a table index for a map column. /// - /// - /// + /// A value specifying how the map is indexed (keys, values or entries). + /// An index definition for use in a CreateIndex method call. public TableIndexDefinition Map(MapIndexType mapIndexType) { return new TableMapIndexDefinition(mapIndexType); } /// - /// Create a text index using the default analyzer. + /// Create a table index for a map column. + /// + /// A value specifying how the map is indexed (keys, values or entries). + /// Whether the index should be case sensitive + /// Whether the index should normalize the text + /// Whether the index should use ASCII conversion + /// An index definition for use in a CreateIndex method call. + public TableIndexDefinition Map(MapIndexType mapIndexType, bool caseSensitive = true, bool normalize = false, bool ascii = false) + { + return new TableMapIndexDefinition ( + mapIndexType, + new TableIndexOptions { + CaseSensitive = caseSensitive, + Normalize = normalize, + Ascii = ascii + } + ); + } + + /// + /// Create a table text index using the default analyzer. /// - /// + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text() { return new TableTextIndexDefinition(); } /// - /// Create a text index using a specific analyzer. + /// Create a table text index using a specific analyzer. + /// See https://docs.datastax.com/en/astra-db-serverless/databases/analyzers.html#supported-built-in-analyzers /// - /// - /// + /// A value specifying a preset indexing method. + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text(TextAnalyzer analyzer) { return new TableTextIndexDefinition() @@ -74,11 +98,11 @@ public TableTextIndexDefinition Text(TextAnalyzer analyzer) } /// - /// Create a text index using a specific analyzer by name, for example a language-specific analyzer. + /// Create a table text index using a specific analyzer by name, for example a language-specific analyzer. /// See https://docs.datastax.com/en/astra-db-serverless/databases/analyzers.html#supported-built-in-analyzers /// - /// - /// + /// A string value specifying a preset indexing method. + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text(string analyzer) { return new TableTextIndexDefinition() @@ -90,10 +114,11 @@ public TableTextIndexDefinition Text(string analyzer) } /// - /// Create a text index using custom analyzer options. + /// Create a table text index using custom analyzer options. + /// See https://docs.datastax.com/en/astra-db-serverless/databases/analyzers.html#supported-built-in-analyzers /// - /// - /// + /// An object defining the analyzer options for the indexing. + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text(AnalyzerOptions analyzerOptions) { return new TableTextIndexDefinition() @@ -105,10 +130,11 @@ public TableTextIndexDefinition Text(AnalyzerOptions analyzerOptions) } /// - /// Create a text index with free-form analyzer options. + /// Create a table text index using custom, free-form analyzer options. + /// See https://docs.datastax.com/en/astra-db-serverless/databases/analyzers.html#supported-built-in-analyzers /// - /// - /// + /// A free-form object defining the analyzer options for the indexing. + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text(object analyzer) { return new TableTextIndexDefinition() @@ -120,40 +146,40 @@ public TableTextIndexDefinition Text(object analyzer) } /// - /// Create a vector index. + /// Create a table vector index. /// - /// + /// An index definition for use in a CreateIndex method call. public TableVectorIndexDefinition Vector() { return Vector(null, null); } /// - /// Create a vector index. + /// Create a table vector index. /// - /// Optional similarity metric to use for vector searches on this index - /// + /// Similarity metric to use for vector searches on this index + /// An index definition for use in a CreateIndex method call. public TableVectorIndexDefinition Vector(SimilarityMetric metric) { return Vector(metric, null); } /// - /// Create a vector index. + /// Create a table vector index. /// /// Allows enabling certain vector optimizations on the index by specifying the source model for your vectors - /// + /// An index definition for use in a CreateIndex method call. public TableVectorIndexDefinition Vector(string sourceModel) { return Vector(null, sourceModel); } /// - /// Create a vector index. + /// Create a table vector index. /// /// Similarity metric to use for vector searches on this index /// Allows enabling certain vector optimizations on the index by specifying the source model for your vectors. Pass a null for server default. - /// + /// An index definition for use in a CreateIndex method call. public TableVectorIndexDefinition Vector(SimilarityMetric? metric, string sourceModel) { return new TableVectorIndexDefinition diff --git a/src/DataStax.AstraDB.DataApi/Tables/TableMapIndexDefinition.cs b/src/DataStax.AstraDB.DataApi/Tables/TableMapIndexDefinition.cs index 509d399..e85e4c2 100644 --- a/src/DataStax.AstraDB.DataApi/Tables/TableMapIndexDefinition.cs +++ b/src/DataStax.AstraDB.DataApi/Tables/TableMapIndexDefinition.cs @@ -49,6 +49,12 @@ internal TableMapIndexDefinition(MapIndexType indexType) IndexType = indexType; } + internal TableMapIndexDefinition(MapIndexType indexType, TableIndexOptions options) + { + IndexType = indexType; + Options = options; + } + /// /// The column to index. /// diff --git a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs index 8f51cfc..9038b1b 100644 --- a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs +++ b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs @@ -260,9 +260,9 @@ public async Task CreateIndexTests_MapIndex_EntriesExplicitly() } [Fact] - public async Task CreateIndexTests_MapIndex_Keys() + public async Task CreateIndexTests_MapIndex_KeysNoOptions() { - var tableName = "tableIndexesTest_MapIndex_Keys"; + var tableName = "CreateIndexTests_MapIndex_KeysNoOptions"; string indexName = "map_k_idx"; try @@ -286,9 +286,41 @@ public async Task CreateIndexTests_MapIndex_Keys() } [Fact] - public async Task CreateIndexTests_MapIndex_Values() + public async Task CreateIndexTests_MapIndex_KeysWithOptions() { - var tableName = "tableIndexesTest_MapIndex_Values"; + var tableName = "CreateIndexTests_MapIndex_KeysWithOptions"; + string indexName = "map_k_idx"; + + try + { + var table = await fixture.Database.CreateTableAsync(tableName); + + await table.CreateIndexAsync(indexName, (b) => b.StringMap, + Builders.TableIndex.Map(MapIndexType.Keys, true, true, true)); + // compare: {"createIndex":{"name":"map_k_idx","definition":{"column":{"StringMap":"$keys"},"options":{"caseSensitive":true,"normalize":true,"ascii":true}}}} + + var result = await table.ListIndexesAsync(); + var foundIndex = result.Indexes.Single(i => i.Name == indexName); + Assert.NotNull(foundIndex); + Assert.IsType(foundIndex.Definition); + Assert.Equal(new Dictionary { ["StringMap"] = "$keys" }, foundIndex.Definition.Column); + var indexDefinition = (TableIndexDefinition)foundIndex.Definition; + Assert.NotNull(indexDefinition.Options); + Assert.True(indexDefinition.Options.CaseSensitive); + Assert.True(indexDefinition.Options.Normalize); + Assert.True(indexDefinition.Options.Ascii); + + } + finally + { + await fixture.Database.DropTableAsync(tableName); + } + } + + [Fact] + public async Task CreateIndexTests_MapIndex_ValuesNoOptions() + { + var tableName = "CreateIndexTests_MapIndex_ValuesNoOptions"; string indexName = "map_v_idx"; try @@ -311,6 +343,38 @@ public async Task CreateIndexTests_MapIndex_Values() } } + [Fact] + public async Task CreateIndexTests_MapIndex_ValuesWithOptions() + { + var tableName = "tableIndexesTest_MapIndex_Values"; + string indexName = "map_v_idx"; + + try + { + var table = await fixture.Database.CreateTableAsync(tableName); + + await table.CreateIndexAsync(indexName, (b) => b.StringMap, + Builders.TableIndex.Map(MapIndexType.Values, true, true, true)); + // compare: {"createIndex":{"name":"map_v_idx","definition":{"column":{"StringMap":"$values"},"options":{"caseSensitive":true,"normalize":true,"ascii":true}}}} + + var result = await table.ListIndexesAsync(); + var foundIndex = result.Indexes.Single(i => i.Name == indexName); + Assert.NotNull(foundIndex); + Assert.IsType(foundIndex.Definition); + Assert.Equal(new Dictionary { ["StringMap"] = "$values" }, foundIndex.Definition.Column); + var indexDefinition = (TableIndexDefinition)foundIndex.Definition; + Assert.NotNull(indexDefinition.Options); + Assert.True(indexDefinition.Options.CaseSensitive); + Assert.True(indexDefinition.Options.Normalize); + Assert.True(indexDefinition.Options.Ascii); + + } + finally + { + await fixture.Database.DropTableAsync(tableName); + } + } + [Fact] public async Task CreateIndexTests_VectorIndex_NoOptions() { From 357bf0e5b70aea186de480bebf28c198144349f1 Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Fri, 10 Apr 2026 18:56:22 +0200 Subject: [PATCH 2/3] switch to named parameters within the TableIndexOptions for index creation; adjust xmldocs to zero warnings --- .../Tables/TableIndexBuilder.cs | 56 +++++++++---------- .../Tests/TableIndexesTests.cs | 36 +++++++++--- 2 files changed, 55 insertions(+), 37 deletions(-) diff --git a/src/DataStax.AstraDB.DataApi/Tables/TableIndexBuilder.cs b/src/DataStax.AstraDB.DataApi/Tables/TableIndexBuilder.cs index 3e16d45..1ec874d 100644 --- a/src/DataStax.AstraDB.DataApi/Tables/TableIndexBuilder.cs +++ b/src/DataStax.AstraDB.DataApi/Tables/TableIndexBuilder.cs @@ -26,18 +26,17 @@ public class TableIndexBuilder /// /// Create a default table index. /// - /// Whether the index should be case sensitive - /// Whether the index should normalize the text - /// Whether the index should use ASCII conversion - /// An index definition for use in a CreateIndex method call. - public TableIndexDefinition Index(bool caseSensitive = true, bool normalize = false, bool ascii = false) + /// A specification for the indexing options. Pass null for defaults + /// An index definition for use in a CreateIndex method call. + public TableIndexDefinition Index(TableIndexOptions options = null) { return new TableIndexDefinition { - Options = new TableIndexOptions { - CaseSensitive = caseSensitive, - Normalize = normalize, - Ascii = ascii + Options = options ?? new TableIndexOptions + { + CaseSensitive = true, + Normalize = false, + Ascii = false } }; } @@ -46,7 +45,7 @@ public TableIndexDefinition Index(bool caseSensitive = true, bool normalize = fa /// Create a table index for a map column. /// /// A value specifying how the map is indexed (keys, values or entries). - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableIndexDefinition Map(MapIndexType mapIndexType) { return new TableMapIndexDefinition(mapIndexType); @@ -56,18 +55,17 @@ public TableIndexDefinition Map(MapIndexType mapIndexType) /// Create a table index for a map column. /// /// A value specifying how the map is indexed (keys, values or entries). - /// Whether the index should be case sensitive - /// Whether the index should normalize the text - /// Whether the index should use ASCII conversion - /// An index definition for use in a CreateIndex method call. - public TableIndexDefinition Map(MapIndexType mapIndexType, bool caseSensitive = true, bool normalize = false, bool ascii = false) + /// A specification for the indexing options. Pass null for defaults + /// An index definition for use in a CreateIndex method call. + public TableIndexDefinition Map(MapIndexType mapIndexType, TableIndexOptions options = null) { - return new TableMapIndexDefinition ( + return new TableMapIndexDefinition( mapIndexType, - new TableIndexOptions { - CaseSensitive = caseSensitive, - Normalize = normalize, - Ascii = ascii + options ?? new TableIndexOptions + { + CaseSensitive = true, + Normalize = false, + Ascii = false } ); } @@ -75,7 +73,7 @@ public TableIndexDefinition Map(MapIndexType mapIndexType, bool caseSensitive = /// /// Create a table text index using the default analyzer. /// - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text() { return new TableTextIndexDefinition(); @@ -86,7 +84,7 @@ public TableTextIndexDefinition Text() /// See https://docs.datastax.com/en/astra-db-serverless/databases/analyzers.html#supported-built-in-analyzers /// /// A value specifying a preset indexing method. - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text(TextAnalyzer analyzer) { return new TableTextIndexDefinition() @@ -102,7 +100,7 @@ public TableTextIndexDefinition Text(TextAnalyzer analyzer) /// See https://docs.datastax.com/en/astra-db-serverless/databases/analyzers.html#supported-built-in-analyzers /// /// A string value specifying a preset indexing method. - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text(string analyzer) { return new TableTextIndexDefinition() @@ -118,7 +116,7 @@ public TableTextIndexDefinition Text(string analyzer) /// See https://docs.datastax.com/en/astra-db-serverless/databases/analyzers.html#supported-built-in-analyzers /// /// An object defining the analyzer options for the indexing. - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text(AnalyzerOptions analyzerOptions) { return new TableTextIndexDefinition() @@ -134,7 +132,7 @@ public TableTextIndexDefinition Text(AnalyzerOptions analyzerOptions) /// See https://docs.datastax.com/en/astra-db-serverless/databases/analyzers.html#supported-built-in-analyzers /// /// A free-form object defining the analyzer options for the indexing. - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableTextIndexDefinition Text(object analyzer) { return new TableTextIndexDefinition() @@ -148,7 +146,7 @@ public TableTextIndexDefinition Text(object analyzer) /// /// Create a table vector index. /// - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableVectorIndexDefinition Vector() { return Vector(null, null); @@ -158,7 +156,7 @@ public TableVectorIndexDefinition Vector() /// Create a table vector index. /// /// Similarity metric to use for vector searches on this index - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableVectorIndexDefinition Vector(SimilarityMetric metric) { return Vector(metric, null); @@ -168,7 +166,7 @@ public TableVectorIndexDefinition Vector(SimilarityMetric metric) /// Create a table vector index. /// /// Allows enabling certain vector optimizations on the index by specifying the source model for your vectors - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableVectorIndexDefinition Vector(string sourceModel) { return Vector(null, sourceModel); @@ -179,7 +177,7 @@ public TableVectorIndexDefinition Vector(string sourceModel) /// /// Similarity metric to use for vector searches on this index /// Allows enabling certain vector optimizations on the index by specifying the source model for your vectors. Pass a null for server default. - /// An index definition for use in a CreateIndex method call. + /// An index definition for use in a CreateIndex method call. public TableVectorIndexDefinition Vector(SimilarityMetric? metric, string sourceModel) { return new TableVectorIndexDefinition diff --git a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs index 9038b1b..e9967b9 100644 --- a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs +++ b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs @@ -183,10 +183,16 @@ public async Task CreateIndexTests_WithOptions_WithBuilder() { var table = await fixture.Database.CreateTableAsync(tableName); string indexName = "category_idx"; - var indexDefinition = new TableIndexDefinition() { Options = new TableIndexOptions { Ascii = true, CaseSensitive = true, Normalize = true } }; - await table.CreateIndexAsync(indexName, (b) => b.Category, Builders.TableIndex.Index(true, true, true)); - // compare: {"createIndex":{"name":"category_idx","definition":{"column":"category","options":{"ascii":true,"caseSensitive":true,"normalize":true}}}} + await table.CreateIndexAsync(indexName, (b) => b.Category, + Builders.TableIndex.Index(new TableIndexOptions + { + CaseSensitive = true, + Normalize = true, + Ascii = true + } + )); + // compare: {"createIndex":{"name":"category_idx","definition":{"options":{"caseSensitive":true,"normalize":true,"ascii":true},"column":"category"}}} var result = await table.ListIndexesAsync(); var foundIndex = result.Single(i => i.Name == indexName); @@ -296,7 +302,13 @@ public async Task CreateIndexTests_MapIndex_KeysWithOptions() var table = await fixture.Database.CreateTableAsync(tableName); await table.CreateIndexAsync(indexName, (b) => b.StringMap, - Builders.TableIndex.Map(MapIndexType.Keys, true, true, true)); + Builders.TableIndex.Map(MapIndexType.Keys, new TableIndexOptions + { + CaseSensitive = true, + Normalize = true, + Ascii = true + } + )); // compare: {"createIndex":{"name":"map_k_idx","definition":{"column":{"StringMap":"$keys"},"options":{"caseSensitive":true,"normalize":true,"ascii":true}}}} var result = await table.ListIndexesAsync(); @@ -353,8 +365,15 @@ public async Task CreateIndexTests_MapIndex_ValuesWithOptions() { var table = await fixture.Database.CreateTableAsync(tableName); - await table.CreateIndexAsync(indexName, (b) => b.StringMap, - Builders.TableIndex.Map(MapIndexType.Values, true, true, true)); + await table.CreateIndexAsync( + indexName, (b) => b.StringMap, + Builders.TableIndex.Map(MapIndexType.Values, new TableIndexOptions + { + CaseSensitive = true, + Normalize = true, + Ascii = true + } + )); // compare: {"createIndex":{"name":"map_v_idx","definition":{"column":{"StringMap":"$values"},"options":{"caseSensitive":true,"normalize":true,"ascii":true}}}} var result = await table.ListIndexesAsync(); @@ -712,8 +731,9 @@ await table.CreateTextIndexAsync(indexName, (b) => b.Name, Builders.TableIndex.T } - // [SkipWhenAstra] // TODO: reinstate this attribute once 115 is merged - [Fact(Skip="Run manually on HCD after some CQL setup!")] + [SkipWhenAstra] + // [Fact(Skip="Run manually on HCD after some CQL setup!")] + [Fact] public async Task ListIndexesTests_UnknownUnsupportedCQLIndex() { var tableName = "table_with_unsupported_index"; From a4a4ee8152bdc2b7d11248d50aaa5e20e0bbbe8b Mon Sep 17 00:00:00 2001 From: Stefano Lottini <236640031+sl-at-ibm@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:03:21 +0200 Subject: [PATCH 3/3] align to pr 137 (return type of ListIndexes simplified) --- .../Tests/TableIndexesTests.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs index e9967b9..07a5482 100644 --- a/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs +++ b/test/DataStax.AstraDB.DataApi.IntegrationTests/Tests/TableIndexesTests.cs @@ -312,7 +312,7 @@ await table.CreateIndexAsync(indexName, (b) => b.StringMap, // compare: {"createIndex":{"name":"map_k_idx","definition":{"column":{"StringMap":"$keys"},"options":{"caseSensitive":true,"normalize":true,"ascii":true}}}} var result = await table.ListIndexesAsync(); - var foundIndex = result.Indexes.Single(i => i.Name == indexName); + var foundIndex = result.Single(i => i.Name == indexName); Assert.NotNull(foundIndex); Assert.IsType(foundIndex.Definition); Assert.Equal(new Dictionary { ["StringMap"] = "$keys" }, foundIndex.Definition.Column); @@ -377,7 +377,7 @@ await table.CreateIndexAsync( // compare: {"createIndex":{"name":"map_v_idx","definition":{"column":{"StringMap":"$values"},"options":{"caseSensitive":true,"normalize":true,"ascii":true}}}} var result = await table.ListIndexesAsync(); - var foundIndex = result.Indexes.Single(i => i.Name == indexName); + var foundIndex = result.Single(i => i.Name == indexName); Assert.NotNull(foundIndex); Assert.IsType(foundIndex.Definition); Assert.Equal(new Dictionary { ["StringMap"] = "$values" }, foundIndex.Definition.Column); @@ -732,8 +732,7 @@ await table.CreateTextIndexAsync(indexName, (b) => b.Name, Builders.TableIndex.T } [SkipWhenAstra] - // [Fact(Skip="Run manually on HCD after some CQL setup!")] - [Fact] + [Fact(Skip="Run manually on HCD after some CQL setup!")] public async Task ListIndexesTests_UnknownUnsupportedCQLIndex() { var tableName = "table_with_unsupported_index";