Skip to content

Commit b9c01c7

Browse files
committed
CSHARP-1424: Add support for creating partial filtered indexes.
1 parent 19eadab commit b9c01c7

File tree

8 files changed

+161
-6
lines changed

8 files changed

+161
-6
lines changed

src/MongoDB.Driver.Core.Tests/Core/Operations/CreateIndexRequestTests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public void constructor_should_initialize_subject()
6161
subject.AdditionalOptions.Should().BeNull();
6262
subject.Background.Should().NotHaveValue();
6363
subject.Name.Should().BeNull();
64+
subject.PartialFilterExpression.Should().BeNull();
6465
subject.Sparse.Should().NotHaveValue();
6566
subject.ExpireAfter.Should().NotHaveValue();
6667
subject.Unique.Should().NotHaveValue();
@@ -260,6 +261,24 @@ public void CreateIndexDocument_should_return_expected_result_when_min_has_value
260261
result.Should().Be(expectedResult);
261262
}
262263

264+
[Test]
265+
public void CreateIndexDocument_should_return_expected_result_when_partialFilterExpression_has_value()
266+
{
267+
var keys = new BsonDocument("x", 1);
268+
var subject = new CreateIndexRequest(keys);
269+
subject.PartialFilterExpression = new BsonDocument("x", new BsonDocument("$gt", 0));
270+
var expectedResult = new BsonDocument
271+
{
272+
{ "key", keys },
273+
{ "name", "x_1" },
274+
{ "partialFilterExpression", subject.PartialFilterExpression }
275+
};
276+
277+
var result = subject.CreateIndexDocument();
278+
279+
result.Should().Be(expectedResult);
280+
}
281+
263282
[Test]
264283
public void CreateIndexDocument_should_return_expected_result_when_sparse_has_value()
265284
{
@@ -427,6 +446,18 @@ public void Keys_get_should_return_expected_result()
427446
result.Should().Be(keys);
428447
}
429448

449+
[Test]
450+
public void PartialFilterExpression_get_and_set_should_work()
451+
{
452+
var subject = new CreateIndexRequest(new BsonDocument("x", 1));
453+
var value = new BsonDocument("x", new BsonDocument("$gt", 0));
454+
455+
subject.PartialFilterExpression = value;
456+
var result = subject.PartialFilterExpression;
457+
458+
result.Should().Be(value);
459+
}
460+
430461
[Test]
431462
public void Sparse_get_and_set_should_work(
432463
[Values(null, false, true)]

src/MongoDB.Driver.Core.Tests/Core/Operations/CreateIndexesOperationTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,24 @@ public void Execute_should_work_when_creating_two_indexes(
105105
indexes.Select(index => index["name"].AsString).Should().BeEquivalentTo(new[] { "_id_", "x_1", "y_1" });
106106
}
107107

108+
[Test]
109+
[RequiresServer("DropCollection", MinimumVersion = "3.1.1")]
110+
public void Execute_should_work_when_partialFilterExpression_is_has_value(
111+
[Values(false, true)]
112+
bool async)
113+
{
114+
var requests = new[] { new CreateIndexRequest(new BsonDocument("x", 1)) { PartialFilterExpression = new BsonDocument("x", new BsonDocument("$gt", 0)) } };
115+
var subject = new CreateIndexesOperation(_collectionNamespace, requests, _messageEncoderSettings);
116+
117+
var result = ExecuteOperation(subject, async);
118+
119+
result["ok"].ToBoolean().Should().BeTrue();
120+
121+
var indexes = ListIndexes(async);
122+
var index = indexes.Single(i => i["name"].AsString == "x_1");
123+
index["partialFilterExpression"].AsBsonDocument.Should().Be(requests[0].PartialFilterExpression);
124+
}
125+
108126
[Test]
109127
[RequiresServer("DropCollection")]
110128
public void Execute_should_work_when_sparse_is_true(

src/MongoDB.Driver.Core.Tests/Core/Operations/CreateIndexesUsingCommandOperationTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,24 @@ public void Execute_should_work_when_creating_two_indexes(
141141
indexes.Select(index => index["name"].AsString).Should().BeEquivalentTo(new[] { "_id_", "x_1", "y_1" });
142142
}
143143

144+
[Test]
145+
[RequiresServer("DropCollection", MinimumVersion = "3.1.1")]
146+
public void Execute_should_work_when_partialFilterExpression_has_value(
147+
[Values(false, true)]
148+
bool async)
149+
{
150+
var requests = new[] { new CreateIndexRequest(new BsonDocument("x", 1)) { PartialFilterExpression = new BsonDocument("x", new BsonDocument("$gt", 0)) } };
151+
var subject = new CreateIndexesUsingCommandOperation(_collectionNamespace, requests, _messageEncoderSettings);
152+
153+
var result = ExecuteOperation(subject, async);
154+
155+
result["ok"].ToBoolean().Should().BeTrue();
156+
157+
var indexes = ListIndexes(async);
158+
var index = indexes.Single(i => i["name"].AsString == "x_1");
159+
index["partialFilterExpression"].AsBsonDocument.Should().Be(requests[0].PartialFilterExpression);
160+
}
161+
144162
[Test]
145163
[RequiresServer("DropCollection", MinimumVersion = "2.7.6")]
146164
public void Execute_should_work_when_sparse_is_true(

src/MongoDB.Driver.Core/Core/Operations/CreateIndexRequest.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class CreateIndexRequest
3838
private double? _max;
3939
private double? _min;
4040
private string _name;
41+
private BsonDocument _partialFilterExpression;
4142
private bool? _sparse;
4243
private int? _sphereIndexVersion;
4344
private BsonDocument _storageEngine;
@@ -188,6 +189,18 @@ public string Name
188189
set { _name = value; }
189190
}
190191

192+
/// <summary>
193+
/// Gets or sets the partial filter expression.
194+
/// </summary>
195+
/// <value>
196+
/// The partial filter expression.
197+
/// </value>
198+
public BsonDocument PartialFilterExpression
199+
{
200+
get { return _partialFilterExpression; }
201+
set { _partialFilterExpression = value; }
202+
}
203+
191204
/// <summary>
192205
/// Gets or sets a value indicating whether the index is a sparse index.
193206
/// </summary>
@@ -298,6 +311,7 @@ internal BsonDocument CreateIndexDocument()
298311
{ "language_override", () => _languageOverride, _languageOverride != null },
299312
{ "max", () => _max.Value, _max.HasValue },
300313
{ "min", () => _min.Value, _min.HasValue },
314+
{ "partialFilterExpression", _partialFilterExpression, _partialFilterExpression != null },
301315
{ "sparse", () => _sparse.Value, _sparse.HasValue },
302316
{ "2dsphereIndexVersion", () => _sphereIndexVersion.Value, _sphereIndexVersion.HasValue },
303317
{ "storageEngine", () => _storageEngine, _storageEngine != null },

src/MongoDB.Driver.Tests/MongoCollectionImplTests.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -723,9 +723,11 @@ public async Task FindOneAndUpdateAsync_with_Projection_As_should_execute_correc
723723
public async Task Indexes_CreateOneAsync_should_execute_the_CreateIndexesOperation()
724724
{
725725
var keys = new BsonDocument("x", 1);
726+
var partialFilterExpression = Builders<BsonDocument>.Filter.Gt("x", 0);
727+
var renderedPartialFilterExpression = new BsonDocument("x", new BsonDocument("$gt", 0));
726728
var weights = new BsonDocument("y", 1);
727729
var storageEngine = new BsonDocument("awesome", true);
728-
var options = new CreateIndexOptions
730+
var options = new CreateIndexOptions<BsonDocument>
729731
{
730732
Background = true,
731733
Bits = 10,
@@ -736,6 +738,7 @@ public async Task Indexes_CreateOneAsync_should_execute_the_CreateIndexesOperati
736738
Max = 30,
737739
Min = 40,
738740
Name = "awesome",
741+
PartialFilterExpression = partialFilterExpression,
739742
Sparse = false,
740743
SphereIndexVersion = 50,
741744
StorageEngine = storageEngine,
@@ -766,6 +769,7 @@ public async Task Indexes_CreateOneAsync_should_execute_the_CreateIndexesOperati
766769
request.Max.Should().Be(options.Max);
767770
request.Min.Should().Be(options.Min);
768771
request.Name.Should().Be(options.Name);
772+
request.PartialFilterExpression.Should().Be(renderedPartialFilterExpression);
769773
request.Sparse.Should().Be(options.Sparse);
770774
request.SphereIndexVersion.Should().Be(options.SphereIndexVersion);
771775
request.StorageEngine.Should().Be(storageEngine);
@@ -781,9 +785,11 @@ public async Task Indexes_CreateManyAsync_should_execute_the_CreateIndexesOperat
781785
{
782786
var keys = new BsonDocument("x", 1);
783787
var keys2 = new BsonDocument("z", 1);
788+
var partialFilterExpression = Builders<BsonDocument>.Filter.Gt("x", 0);
789+
var renderedPartialFilterExpression = new BsonDocument("x", new BsonDocument("$gt", 0));
784790
var weights = new BsonDocument("y", 1);
785791
var storageEngine = new BsonDocument("awesome", true);
786-
var options = new CreateIndexOptions
792+
var options = new CreateIndexOptions<BsonDocument>
787793
{
788794
Background = true,
789795
Bits = 10,
@@ -794,6 +800,7 @@ public async Task Indexes_CreateManyAsync_should_execute_the_CreateIndexesOperat
794800
Max = 30,
795801
Min = 40,
796802
Name = "awesome",
803+
PartialFilterExpression = partialFilterExpression,
797804
Sparse = false,
798805
SphereIndexVersion = 50,
799806
StorageEngine = storageEngine,
@@ -828,6 +835,7 @@ public async Task Indexes_CreateManyAsync_should_execute_the_CreateIndexesOperat
828835
request1.Max.Should().Be(options.Max);
829836
request1.Min.Should().Be(options.Min);
830837
request1.Name.Should().Be(options.Name);
838+
request1.PartialFilterExpression.Should().Be(renderedPartialFilterExpression);
831839
request1.Sparse.Should().Be(options.Sparse);
832840
request1.SphereIndexVersion.Should().Be(options.SphereIndexVersion);
833841
request1.StorageEngine.Should().Be(storageEngine);
@@ -849,6 +857,7 @@ public async Task Indexes_CreateManyAsync_should_execute_the_CreateIndexesOperat
849857
request2.Max.Should().NotHaveValue();
850858
request2.Min.Should().NotHaveValue(); ;
851859
request2.Name.Should().BeNull();
860+
request2.PartialFilterExpression.Should().BeNull();
852861
request2.Sparse.Should().NotHaveValue(); ;
853862
request2.SphereIndexVersion.Should().NotHaveValue();
854863
request2.StorageEngine.Should().BeNull();

src/MongoDB.Driver/CreateIndexModel.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace MongoDB.Driver
3030
public sealed class CreateIndexModel<TDocument>
3131
{
3232
private readonly IndexKeysDefinition<TDocument> _keys;
33-
private readonly CreateIndexOptions _options;
33+
private readonly CreateIndexOptions<TDocument> _options;
3434

3535
/// <summary>
3636
/// Initializes a new instance of the <see cref="CreateIndexModel{TDocument}"/> class.
@@ -40,7 +40,7 @@ public sealed class CreateIndexModel<TDocument>
4040
public CreateIndexModel(IndexKeysDefinition<TDocument> keys, CreateIndexOptions options = null)
4141
{
4242
_keys = Ensure.IsNotNull(keys, nameof(keys));
43-
_options = options;
43+
_options = CreateIndexOptions<TDocument>.CoercedFrom(options);
4444
}
4545

4646
/// <summary>
@@ -54,7 +54,7 @@ public IndexKeysDefinition<TDocument> Keys
5454
/// <summary>
5555
/// Gets the options.
5656
/// </summary>
57-
public CreateIndexOptions Options
57+
public CreateIndexOptions<TDocument> Options
5858
{
5959
get { return _options; }
6060
}

src/MongoDB.Driver/CreateIndexOptions.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
using System;
1717
using MongoDB.Bson;
18+
using MongoDB.Driver.Core.Misc;
1819

1920
namespace MongoDB.Driver
2021
{
@@ -186,4 +187,65 @@ public BsonDocument Weights
186187
set { _weights = value; }
187188
}
188189
}
190+
191+
/// <summary>
192+
/// Options for creating an index.
193+
/// </summary>
194+
/// <typeparam name="TDocument">The type of the document.</typeparam>
195+
public class CreateIndexOptions<TDocument> : CreateIndexOptions
196+
{
197+
#region static
198+
// public static methods
199+
/// <summary>
200+
/// Coerces a generic <see cref="CreateIndexOptions{TDocument}"/> from a non-generic <see cref="CreateIndexOptions"/> value.
201+
/// </summary>
202+
/// <param name="options">The options.</param>
203+
/// <returns>A generic <see cref="CreateIndexOptions{TDocument}"/> .</returns>
204+
public static CreateIndexOptions<TDocument> CoercedFrom(CreateIndexOptions options)
205+
{
206+
if (options == null)
207+
{
208+
return null;
209+
}
210+
211+
if (options.GetType() == typeof(CreateIndexOptions))
212+
{
213+
return new CreateIndexOptions<TDocument>
214+
{
215+
Background = options.Background,
216+
Bits = options.Bits,
217+
BucketSize = options.BucketSize,
218+
DefaultLanguage = options.DefaultLanguage,
219+
ExpireAfter = options.ExpireAfter,
220+
LanguageOverride = options.LanguageOverride,
221+
Max = options.Max,
222+
Min = options.Min,
223+
Name = options.Name,
224+
Sparse = options.Sparse,
225+
SphereIndexVersion = options.SphereIndexVersion,
226+
StorageEngine = options.StorageEngine,
227+
TextIndexVersion = options.TextIndexVersion,
228+
Unique = options.Unique,
229+
Version = options.Version,
230+
Weights = options.Weights
231+
};
232+
}
233+
234+
return (CreateIndexOptions<TDocument>)options;
235+
}
236+
#endregion
237+
238+
// private fields
239+
private FilterDefinition<TDocument> _partialFilterExpression;
240+
241+
// public properties
242+
/// <summary>
243+
/// Gets or sets the partial filter expression.
244+
/// </summary>
245+
public FilterDefinition<TDocument> PartialFilterExpression
246+
{
247+
get { return _partialFilterExpression; }
248+
set { _partialFilterExpression = value; }
249+
}
250+
}
189251
}

src/MongoDB.Driver/MongoCollectionImpl.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,8 +583,10 @@ public override MongoCollectionSettings Settings
583583

584584
var requests = models.Select(m =>
585585
{
586+
var options = m.Options ?? new CreateIndexOptions<TDocument>();
586587
var keysDocument = m.Keys.Render(_collection._documentSerializer, _collection._settings.SerializerRegistry);
587-
var options = m.Options ?? new CreateIndexOptions();
588+
var renderedPartialFilterExpression = options.PartialFilterExpression == null ? null : options.PartialFilterExpression.Render(_collection._documentSerializer, _collection._settings.SerializerRegistry);
589+
588590
return new CreateIndexRequest(keysDocument)
589591
{
590592
Name = options.Name,
@@ -596,6 +598,7 @@ public override MongoCollectionSettings Settings
596598
LanguageOverride = options.LanguageOverride,
597599
Max = options.Max,
598600
Min = options.Min,
601+
PartialFilterExpression = renderedPartialFilterExpression,
599602
Sparse = options.Sparse,
600603
SphereIndexVersion = options.SphereIndexVersion,
601604
StorageEngine = options.StorageEngine,

0 commit comments

Comments
 (0)