diff --git a/src/MongoDB.Driver.Core/Core/Misc/Feature.cs b/src/MongoDB.Driver.Core/Core/Misc/Feature.cs
index f8117973dc5..3c27d7ab392 100644
--- a/src/MongoDB.Driver.Core/Core/Misc/Feature.cs
+++ b/src/MongoDB.Driver.Core/Core/Misc/Feature.cs
@@ -74,6 +74,7 @@ public class Feature
private static readonly Feature __findAllowDiskUse = new Feature("FindAllowDiskUse", WireVersion.Server44);
private static readonly Feature __findAndModifyWriteConcern = new Feature("FindAndModifyWriteConcern", WireVersion.Server32);
private static readonly Feature __findCommand = new Feature("FindCommand", WireVersion.Server32);
+ private static readonly Feature __findProjectionExpressions = new Feature("FindProjectionExpressions", WireVersion.Server44);
private static readonly Feature __geoNearCommand = new Feature("GeoNearCommand", WireVersion.Zero, WireVersion.Server42);
private static readonly Feature __getField = new Feature("GetField", WireVersion.Server50);
private static readonly Feature __getMoreComment = new Feature("GetMoreComment", WireVersion.Server44);
@@ -409,6 +410,11 @@ public class Feature
[Obsolete("This property will be removed in a later release.")]
public static Feature FindCommand => __findCommand;
+ ///
+ /// Gets the find projection expressions feature.
+ ///
+ public static Feature FindProjectionExpressions => __findProjectionExpressions;
+
///
/// Gets the geoNear command feature.
///
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/LinqProviderAdapterV3.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/LinqProviderAdapterV3.cs
index 72746d808fd..e8257ccfed2 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/LinqProviderAdapterV3.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/LinqProviderAdapterV3.cs
@@ -140,8 +140,7 @@ internal override RenderedProjectionDefinition TranslateExpressionT
IBsonSerializer sourceSerializer,
IBsonSerializerRegistry serializerRegistry)
{
- // TODO: implement using LINQ3 instead of falling back to LINQ2
- return LinqProviderAdapter.V2.TranslateExpressionToFindProjection(expression, sourceSerializer, serializerRegistry);
+ return TranslateExpressionToProjection(expression, sourceSerializer, serializerRegistry, translationOptions: null);
}
internal override RenderedProjectionDefinition TranslateExpressionToGroupProjection(
diff --git a/tests/MongoDB.Driver.Tests/FindFluentTests.cs b/tests/MongoDB.Driver.Tests/FindFluentTests.cs
index bae0d79750d..af63aa98b85 100644
--- a/tests/MongoDB.Driver.Tests/FindFluentTests.cs
+++ b/tests/MongoDB.Driver.Tests/FindFluentTests.cs
@@ -24,6 +24,8 @@
using MongoDB.Driver.Linq;
using Moq;
using Xunit;
+using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
+using MongoDB.Driver.Core.Misc;
namespace MongoDB.Driver.Tests
{
@@ -303,10 +305,17 @@ public void ToCursor_should_call_collection_Find_with_expected_arguments(
}
}
- [Fact]
- public void ToString_should_return_the_correct_string()
+ [Theory]
+ [ParameterAttributeData]
+ public void ToString_should_return_the_correct_string(
+ [Values(LinqProvider.V2, LinqProvider.V3)] LinqProvider linqProvider)
{
- var subject = CreateSubject();
+ if (linqProvider == LinqProvider.V3)
+ {
+ RequireServer.Check().Supports(Feature.FindProjectionExpressions);
+ }
+
+ var subject = CreateSubject(linqProvider: linqProvider);
subject.Filter = new BsonDocument("Age", 20);
subject.Options.Collation = new Collation("en_US");
subject.Options.Comment = "awesome";
@@ -333,8 +342,12 @@ public void ToString_should_return_the_correct_string()
var str = find.ToString();
+ var expectedProjection = linqProvider == LinqProvider.V2 ?
+ "{ \"FirstName\" : 1, \"LastName\" : 1, \"_id\" : 0 }" :
+ "{ \"_v\" : { \"$concat\" : [\"$FirstName\", \" \", \"$LastName\"] }, \"_id\" : 0 }";
+
str.Should().Be(
- "find({ \"Age\" : 20 }, { \"FirstName\" : 1, \"LastName\" : 1, \"_id\" : 0 })" +
+ "find({ \"Age\" : 20 }, " + expectedProjection + ")" +
".collation({ \"locale\" : \"en_US\" })" +
".sort({ \"LastName\" : 1, \"FirstName\" : -1 })" +
".skip(2)" +
@@ -356,9 +369,9 @@ private IClientSessionHandle CreateSession(bool usingSession)
return usingSession ? Mock.Of() : null;
}
- private IFindFluent CreateSubject(IClientSessionHandle session = null, FilterDefinition filter = null, FindOptions options = null)
+ private IFindFluent CreateSubject(IClientSessionHandle session = null, FilterDefinition filter = null, FindOptions options = null, LinqProvider linqProvider = LinqProvider.V3)
{
- var clientSettings = new MongoClientSettings { LinqProvider = LinqProvider.V2 };
+ var clientSettings = new MongoClientSettings { LinqProvider = linqProvider };
var mockClient = new Mock();
mockClient.SetupGet(c => c.Settings).Returns(clientSettings);
diff --git a/tests/MongoDB.Driver.Tests/IFindFluentExtensionsTests.cs b/tests/MongoDB.Driver.Tests/IFindFluentExtensionsTests.cs
index 60bc77841cc..afdbd877a87 100644
--- a/tests/MongoDB.Driver.Tests/IFindFluentExtensionsTests.cs
+++ b/tests/MongoDB.Driver.Tests/IFindFluentExtensionsTests.cs
@@ -20,13 +20,17 @@
using FluentAssertions;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
+using MongoDB.Driver.Linq;
+using MongoDB.Driver.Tests.Linq.Linq3ImplementationTests;
using MongoDB.TestHelpers.XunitExtensions;
using Moq;
using Xunit;
namespace MongoDB.Driver.Tests
{
- public class IFindFluentExtensionsTests
+ public class IFindFluentExtensionsTests : Linq3IntegrationTest
{
// public methods
[Theory]
@@ -228,15 +232,27 @@ public void Project_should_generate_the_correct_fields_when_a_string_is_used()
AssertProjection(subject, expectedProjection);
}
- [Fact]
- public void Project_should_generate_the_correct_fields_and_assign_the_correct_result_serializer()
+ [Theory]
+ [ParameterAttributeData]
+ public void Project_should_generate_the_correct_fields_and_assign_the_correct_result_serializer(
+ [Values(LinqProvider.V2, LinqProvider.V3)] LinqProvider linqProvider)
{
- var subject = CreateSubject()
+ if (linqProvider == LinqProvider.V3)
+ {
+ RequireServer.Check().Supports(Feature.FindProjectionExpressions);
+ }
+
+ var subject = CreateSubject(linqProvider)
.Project(x => x.FirstName + " " + x.LastName);
- var expectedProjection = BsonDocument.Parse("{FirstName: 1, LastName: 1, _id: 0}");
+ var expectedProjection = linqProvider == LinqProvider.V2 ?
+ BsonDocument.Parse("{ FirstName : 1, LastName : 1, _id : 0}") :
+ BsonDocument.Parse("{ _v : { $concat : ['$FirstName', ' ', '$LastName'] }, _id : 0 }");
- AssertProjection(subject, expectedProjection);
+ AssertProjection(subject, expectedProjection, linqProvider);
+
+ var results = subject.ToList();
+ results.Should().Equal("John Doe");
}
[Theory]
@@ -435,9 +451,9 @@ public void SortByDescending_ThenByDescending_should_generate_the_correct_sort()
AssertSort(subject, expectedSort);
}
- private static void AssertProjection(IFindFluent subject, BsonDocument expectedProjection)
+ private static void AssertProjection(IFindFluent subject, BsonDocument expectedProjection, LinqProvider linqProvider = LinqProvider.V3)
{
- Assert.Equal(expectedProjection, subject.Options.Projection.Render(BsonSerializer.SerializerRegistry.GetSerializer(), BsonSerializer.SerializerRegistry).Document);
+ Assert.Equal(expectedProjection, subject.Options.Projection.Render(BsonSerializer.SerializerRegistry.GetSerializer(), BsonSerializer.SerializerRegistry, linqProvider).Document);
}
private static void AssertSort(IFindFluent subject, BsonDocument expectedSort)
@@ -445,13 +461,21 @@ private static void AssertSort(IFindFluent subject, BsonDocument
Assert.Equal(expectedSort, subject.Options.Sort.Render(BsonSerializer.SerializerRegistry.GetSerializer(), BsonSerializer.SerializerRegistry));
}
- private IFindFluent CreateSubject()
+ private IMongoCollection CreateCollection(LinqProvider linqProvider = LinqProvider.V3)
+ {
+ var collection = GetCollection(linqProvider: linqProvider);
+
+ CreateCollection(
+ collection,
+ new Person { FirstName = "John", LastName = "Doe", Age = 21 });
+
+ return collection;
+ }
+
+ private IFindFluent CreateSubject(LinqProvider linqProvider = LinqProvider.V3)
{
- var settings = new MongoCollectionSettings();
- var mockCollection = new Mock>();
- mockCollection.SetupGet(c => c.Settings).Returns(settings);
- var options = new FindOptions();
- return new FindFluent(session: null, collection: mockCollection.Object, filter: new BsonDocument(), options: options);
+ var collection = CreateCollection(linqProvider);
+ return collection.Find("{}");
}
public class Person
diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationTests/LinqProviderV3Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationTests/LinqProviderV3Tests.cs
index de37e67e1f7..ec37f9f9eb5 100644
--- a/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationTests/LinqProviderV3Tests.cs
+++ b/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationTests/LinqProviderV3Tests.cs
@@ -139,9 +139,7 @@ public void TranslateExpressionToFindProjection_should_return_expected_result()
var result = subject.TranslateExpressionToFindProjection(expression, documentSerializer, serializerRegistry);
- var expectedResult = LinqProviderAdapter.V2.TranslateExpressionToFindProjection(expression, documentSerializer, serializerRegistry);
- expectedResult.Document.Should().Be("{ X : 1, _id : 0 }");
- result.Document.Should().Be(expectedResult.Document);
+ result.Document.Should().Be("{ _v : '$X', _id : 0 }");
result.ProjectionSerializer.ValueType.Should().Be(typeof(int));
}