diff --git a/src/MongoDB.Driver/Core/Misc/Feature.cs b/src/MongoDB.Driver/Core/Misc/Feature.cs index c3b6d249961..560162bdb92 100644 --- a/src/MongoDB.Driver/Core/Misc/Feature.cs +++ b/src/MongoDB.Driver/Core/Misc/Feature.cs @@ -52,6 +52,7 @@ public class Feature private static readonly Feature __convertOperatorStringToObjectOrArray = new Feature("ConvertOperatorStringToObjectOrArray", WireVersion.Server83); private static readonly Feature __createIndexCommitQuorum = new Feature("CreateIndexCommitQuorum", WireVersion.Server44); private static readonly Feature __createIndexesUsingInsertOperations = new Feature("CreateIndexesUsingInsertOperations", WireVersion.Zero, WireVersion.Server42); + private static readonly Feature __createObjectIdExpression = new Feature("CreateObjectIdExpression", WireVersion.Server83); private static readonly Feature __csfleRangeAlgorithm = new Feature("CsfleRangeAlgorithm", WireVersion.Server62); private static readonly Feature __csfle2Qev2Lookup = new Feature("csfle2Qev2Lookup", WireVersion.Server81); private static readonly Feature __csfle2Qev2RangeAlgorithm = new Feature("csfle2Qev2RangeAlgorithm", WireVersion.Server80); @@ -248,6 +249,11 @@ public class Feature [Obsolete("This feature was removed in server version 4.2. As such, this property will be removed in a later release.")] public static Feature CreateIndexesUsingInsertOperations => __createIndexesUsingInsertOperations; + /// + /// Represents support for the $createObjectId operator feature. + /// + public static Feature CreateObjectIdExpression => __createObjectIdExpression; + /// /// Gets the csfle range algorithm feature. /// diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/AstNodeType.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/AstNodeType.cs index 48ddd2eb0a6..3af3b3af469 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/AstNodeType.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/AstNodeType.cs @@ -38,6 +38,7 @@ internal enum AstNodeType ConstantExpression, ConvertExpression, CountStage, + CreateObjectIdExpression, CurrentOpStage, CustomAccumulatorExpression, DateAddExpression, diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstCreateObjectIdExpression.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstCreateObjectIdExpression.cs new file mode 100644 index 00000000000..da128cf1961 --- /dev/null +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstCreateObjectIdExpression.cs @@ -0,0 +1,30 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MongoDB.Bson; +using MongoDB.Driver.Linq.Linq3Implementation.Ast.Visitors; + +namespace MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions; + +internal sealed class AstCreateObjectIdExpression : AstExpression +{ + public override AstNodeType NodeType => AstNodeType.CreateObjectIdExpression; + + public override AstNode Accept(AstNodeVisitor visitor) => + visitor.VisitCreateObjectIdExpression(this); + + public override BsonValue Render() => + new BsonDocument("$createObjectId", new BsonDocument()); +} diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstExpression.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstExpression.cs index ec9c44bf48e..8bbbbdb08b3 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstExpression.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstExpression.cs @@ -443,6 +443,9 @@ public static AstExpression Floor(AstExpression arg) return new AstUnaryExpression(AstUnaryOperator.Floor, arg); } + public static AstCreateObjectIdExpression CreateObjectId() + => new(); + public static AstGetFieldExpression GetField(AstExpression input, AstExpression fieldName) { return new AstGetFieldExpression(input, fieldName); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Visitors/AstNodeVisitor.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Visitors/AstNodeVisitor.cs index 72e50374a1c..e2365532fac 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Visitors/AstNodeVisitor.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Visitors/AstNodeVisitor.cs @@ -244,6 +244,9 @@ public virtual AstNode VisitCustomAccumulatorExpression(AstCustomAccumulatorExpr return node.Update(VisitAndConvert(node.InitArgs), VisitAndConvert(node.AccumulateArgs)); } + public virtual AstNode VisitCreateObjectIdExpression(AstCreateObjectIdExpression node) + => node; + public virtual AstNode VisitDateAddExpression(AstDateAddExpression node) { return node.Update(VisitAndConvert(node.StartDate), VisitAndConvert(node.Unit), VisitAndConvert(node.Amount), VisitAndConvert(node.Timezone)); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/MqlMethod.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/MqlMethod.cs index 3a6265c5d5c..de5f41c6b4f 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/MqlMethod.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/MqlMethod.cs @@ -27,6 +27,7 @@ internal static class MqlMethod private static readonly MethodInfo __constantWithRepresentation; private static readonly MethodInfo __constantWithSerializer; private static readonly MethodInfo __convert; + private static readonly MethodInfo __createObjectId; private static readonly MethodInfo __dateFromString; private static readonly MethodInfo __dateFromStringWithFormat; private static readonly MethodInfo __dateFromStringWithFormatAndTimezone; @@ -53,6 +54,7 @@ static MqlMethod() __constantWithRepresentation = ReflectionInfo.Method((object value, BsonType representation) => Mql.Constant(value, representation)); __constantWithSerializer = ReflectionInfo.Method((object value, IBsonSerializer serializer) => Mql.Constant(value, serializer)); __convert = ReflectionInfo.Method((object value, ConvertOptions options) => Mql.Convert(value, options)); + __createObjectId = ReflectionInfo.Method(() => Mql.CreateObjectId()); __dateFromString = ReflectionInfo.Method((string dateStringl) => Mql.DateFromString(dateStringl)); __dateFromStringWithFormat = ReflectionInfo.Method((string dateString, string format) => Mql.DateFromString(dateString, format)); __dateFromStringWithFormatAndTimezone = ReflectionInfo.Method((string dateString, string format, string timezone) => Mql.DateFromString(dateString, format, timezone)); @@ -110,6 +112,7 @@ static MqlMethod() public static MethodInfo ConstantWithRepresentation => __constantWithRepresentation; public static MethodInfo ConstantWithSerializer => __constantWithSerializer; public static MethodInfo Convert => __convert; + public static MethodInfo CreateObjectId => __createObjectId; public static MethodInfo DateFromString => __dateFromString; public static MethodInfo DateFromStringWithFormat => __dateFromStringWithFormat; public static MethodInfo DateFromStringWithFormatAndTimezone => __dateFromStringWithFormatAndTimezone; diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/ReflectionInfo.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/ReflectionInfo.cs index 9cc03bdf517..68afde684ee 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/ReflectionInfo.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/ReflectionInfo.cs @@ -16,106 +16,69 @@ using System; using System.Linq.Expressions; using System.Reflection; -using MongoDB.Driver.Linq.Linq3Implementation.Misc; namespace MongoDB.Driver.Linq.Linq3Implementation.Reflection { internal static class ReflectionInfo { - public static ConstructorInfo Constructor(Expression> lambda) - { - return ExtractConstructorInfoFromLambda(lambda); - } + public static ConstructorInfo Constructor(Expression> lambda) => + ExtractConstructorInfoFromLambda(lambda); - public static ConstructorInfo Constructor(Expression> lambda) - { - return ExtractConstructorInfoFromLambda(lambda); - } + public static ConstructorInfo Constructor(Expression> lambda) => + ExtractConstructorInfoFromLambda(lambda); - public static ConstructorInfo Constructor(Expression> lambda) - { - return ExtractConstructorInfoFromLambda(lambda); - } + public static ConstructorInfo Constructor(Expression> lambda) => + ExtractConstructorInfoFromLambda(lambda); - public static ConstructorInfo Constructor(Expression> lambda) - { - return ExtractConstructorInfoFromLambda(lambda); - } + public static ConstructorInfo Constructor(Expression> lambda) => + ExtractConstructorInfoFromLambda(lambda); - public static ConstructorInfo Constructor(Expression> lambda) - { - return ExtractConstructorInfoFromLambda(lambda); - } + public static ConstructorInfo Constructor(Expression> lambda) => + ExtractConstructorInfoFromLambda(lambda); - public static ConstructorInfo Constructor(Expression> lambda) - { - return ExtractConstructorInfoFromLambda(lambda); - } + public static ConstructorInfo Constructor(Expression> lambda) => + ExtractConstructorInfoFromLambda(lambda); - public static ConstructorInfo Constructor(Expression> lambda) - { - return ExtractConstructorInfoFromLambda(lambda); - } + public static ConstructorInfo Constructor(Expression> lambda) => + ExtractConstructorInfoFromLambda(lambda); - public static ConstructorInfo Constructor(Expression> lambda) - { - return ExtractConstructorInfoFromLambda(lambda); - } + public static ConstructorInfo Constructor(Expression> lambda) => + ExtractConstructorInfoFromLambda(lambda); - public static MethodInfo Method(Expression> lambda) - { - return ExtractMethodInfoFromLambda(lambda); - } + public static MethodInfo Method(Expression> lambda) => + ExtractMethodInfoFromLambda(lambda); - public static MethodInfo Method(Expression> lambda) - { - return ExtractMethodInfoFromLambda(lambda); - } + public static MethodInfo Method(Expression> lambda) => + ExtractMethodInfoFromLambda(lambda); - public static MethodInfo Method(Expression> lambda) - { - return ExtractMethodInfoFromLambda(lambda); - } + public static MethodInfo Method(Expression> lambda) => + ExtractMethodInfoFromLambda(lambda); - public static MethodInfo Method(Expression> lambda) - { - return ExtractMethodInfoFromLambda(lambda); - } + public static MethodInfo Method(Expression> lambda) => + ExtractMethodInfoFromLambda(lambda); - public static MethodInfo Method(Expression> lambda) - { - return ExtractMethodInfoFromLambda(lambda); - } + public static MethodInfo Method(Expression> lambda) => + ExtractMethodInfoFromLambda(lambda); - public static MethodInfo Method(Expression> lambda) - { - return ExtractMethodInfoFromLambda(lambda); - } + public static MethodInfo Method(Expression> lambda) => ExtractMethodInfoFromLambda(lambda); - public static MethodInfo Method(Expression> lambda) - { - return ExtractMethodInfoFromLambda(lambda); - } + public static MethodInfo Method(Expression> lambda) => + ExtractMethodInfoFromLambda(lambda); - public static MethodInfo Method(Expression> lambda) - { - return ExtractMethodInfoFromLambda(lambda); - } + public static MethodInfo Method(Expression> lambda) => + ExtractMethodInfoFromLambda(lambda); - public static PropertyInfo Property(Expression> lambda) - { - return ExtractPropertyInfoFromLambda(lambda); - } + public static MethodInfo Method(Expression> lambda) => + ExtractMethodInfoFromLambda(lambda); - public static MethodInfo IndexerGet(Expression> lambda) - { - return ExtractMethodInfoFromLambda(lambda); - } + public static PropertyInfo Property(Expression> lambda) => + ExtractPropertyInfoFromLambda(lambda); - public static MethodInfo IndexerSet(Expression> lambda) - { - return ExtractIndexerSetMethodInfoFromLambda(lambda); - } + public static MethodInfo IndexerGet(Expression> lambda) => + ExtractMethodInfoFromLambda(lambda); + + public static MethodInfo IndexerSet(Expression> lambda) => + ExtractIndexerSetMethodInfoFromLambda(lambda); // private static methods private static ConstructorInfo ExtractConstructorInfoFromLambda(LambdaExpression lambda) diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/SerializerFinders/SerializerFinderVisitMethodCall.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/SerializerFinders/SerializerFinderVisitMethodCall.cs index e8b59d5c7b1..d7679de7ce2 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/SerializerFinders/SerializerFinderVisitMethodCall.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/SerializerFinders/SerializerFinderVisitMethodCall.cs @@ -100,6 +100,7 @@ void DeduceMethodCallSerializers() case "ContainsValue": DeduceContainsValueMethodSerializers(); break; case "Convert": DeduceConvertMethodSerializers(); break; case "Create": DeduceCreateMethodSerializers(); break; + case "CreateObjectId": DeduceCreateObjectIdMethodSerializers(); break; case "DateFromString": DeduceDateFromStringMethodSerializers(); break; case "DefaultIfEmpty": DeduceDefaultIfEmptyMethodSerializers(); break; case "DegreesToRadians": DeduceDegreesToRadiansMethodSerializers(); break; @@ -1373,6 +1374,21 @@ void DeduceFieldMethodSerializers() } } + void DeduceCreateObjectIdMethodSerializers() + { + if (method.Is(MqlMethod.CreateObjectId)) + { + if (IsNotKnown(node)) + { + DeduceSerializer(node, ObjectIdSerializer.Instance); + } + } + else + { + DeduceUnknownMethodSerializer(); + } + } + void DeduceFirstOrLastOrSingleMethodsSerializers() { if (method.IsOneOf(EnumerableOrQueryableMethod.FirstOrLastOrSingleOverloads)) diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs index 0ab78e8c88e..426396718e8 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs @@ -42,6 +42,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC case "CovariancePopulation": return CovariancePopulationMethodToAggregationExpressionTranslator.Translate(context, expression); case "CovarianceSample": return CovarianceSampleMethodToAggregationExpressionTranslator.Translate(context, expression); case "Create": return CreateMethodToAggregationExpressionTranslator.Translate(context, expression); + case "CreateObjectId": return CreateObjectIdMethodToAggregationExpressionTranslator.Translate(context, expression); case "DateFromString": return DateFromStringMethodToAggregationExpressionTranslator.Translate(context, expression); case "DefaultIfEmpty": return DefaultIfEmptyMethodToAggregationExpressionTranslator.Translate(context, expression); case "DenseRank": return DenseRankMethodToAggregationExpressionTranslator.Translate(context, expression); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CreateObjectIdMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CreateObjectIdMethodToAggregationExpressionTranslator.cs new file mode 100644 index 00000000000..efacfbd20b8 --- /dev/null +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CreateObjectIdMethodToAggregationExpressionTranslator.cs @@ -0,0 +1,38 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Linq.Expressions; +using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions; +using MongoDB.Driver.Linq.Linq3Implementation.Misc; +using MongoDB.Driver.Linq.Linq3Implementation.Reflection; + +namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators; + +internal static class CreateObjectIdMethodToAggregationExpressionTranslator +{ + public static TranslatedExpression Translate(TranslationContext context, MethodCallExpression expression) + { + var method = expression.Method; + + if (method.Is(MqlMethod.CreateObjectId)) + { + var ast = AstExpression.CreateObjectId(); + var serializer = context.GetSerializer(expression); + return new TranslatedExpression(expression, ast, serializer); + } + + throw new ExpressionNotSupportedException(expression); + } +} diff --git a/src/MongoDB.Driver/Mql.cs b/src/MongoDB.Driver/Mql.cs index 550ee81c8f3..630ef1da6f5 100644 --- a/src/MongoDB.Driver/Mql.cs +++ b/src/MongoDB.Driver/Mql.cs @@ -64,6 +64,13 @@ public static TTo Convert(TFrom value, ConvertOptions options) throw CustomLinqExtensionMethodHelper.CreateNotSupportedException(); } + /// + /// Creates a new unique ObjectId using the $createObjectId aggregation operator. + /// + /// A ObjectId. + public static ObjectId CreateObjectId() => + throw CustomLinqExtensionMethodHelper.CreateNotSupportedException(); + /// /// Converts a string to a DateTime using the $dateFromString aggregation operator. /// diff --git a/tests/MongoDB.Driver.Tests/Linq/Integration/MqlCreateObjectIdTests.cs b/tests/MongoDB.Driver.Tests/Linq/Integration/MqlCreateObjectIdTests.cs new file mode 100644 index 00000000000..15e5198c7bb --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Linq/Integration/MqlCreateObjectIdTests.cs @@ -0,0 +1,137 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FluentAssertions; +using MongoDB.Bson; +using MongoDB.Driver.Core.Misc; +using MongoDB.Driver.TestHelpers; +using Xunit; + +namespace MongoDB.Driver.Tests.Linq.Integration; + +public class MqlCreateObjectIdTests : LinqIntegrationTest +{ + public MqlCreateObjectIdTests(ClassFixture fixture) + : base(fixture, server => server.Supports(Feature.CreateObjectIdExpression)) + { + } + + [Fact] + public void MqlCreateObjectId_in_where_should_work() + { + var collection = Fixture.Collection; + var queryable = collection.AsQueryable() + .Where(d => d.Id == Mql.CreateObjectId()); + + var renderedStages = Translate(collection, queryable); + AssertStages(renderedStages, "{ $match : { $expr : { $eq : ['$_id', { $createObjectId : {} }] } } }"); + + var result = queryable.ToList(); + result.Should().BeEmpty(); + } + + [Fact] + public void MqlCreateObjectId_in_select_should_work() + { + var collection = Fixture.Collection; + var queryable = collection.AsQueryable() + .Select(d => new { NewId = Mql.CreateObjectId() }); + + var renderedStages = Translate(collection, queryable); + AssertStages(renderedStages, "{ $project : { 'NewId' : { $createObjectId : {} }, '_id' : 0 } }"); + + var result = queryable.ToList(); + var firstId = result.First().NewId; + var secondId = result.Skip(1).First().NewId; + + firstId.Should().NotBe(default); + secondId.Should().NotBe(default); + firstId.Should().NotBe(secondId); + } + + [Fact] + public async Task MqlCreateObjectId_in_filter_builder_should_work() + { + var collection = Fixture.Collection; + + var filter = Builders.Filter.Where(d => d.Id == Mql.CreateObjectId()); + var result = await collection.Find(filter).ToListAsync(); + + var renderedFilter = Translate(collection, filter); + renderedFilter.Should().Be("{ $expr : { $eq : ['$_id', { $createObjectId : {} }] } }"); + result.Should().BeEmpty(); + } + + [Fact] + public async Task MqlCreateObjectId_in_projection_builder_should_work() + { + var collection = Fixture.Collection; + + var projection = Builders.Projection.Expression(c => new { NewId = Mql.CreateObjectId() }); + var result = await collection.Find(Builders.Filter.Empty).Project(projection).ToListAsync(); + + var renderedProjection = TranslateFindProjection(collection, projection, null); + renderedProjection.Should().Be("{ 'NewId' : { $createObjectId : {} }, '_id' : 0 }"); + + var firstId = result.First().NewId; + var secondId = result.Skip(1).First().NewId; + + firstId.Should().NotBe(default); + secondId.Should().NotBe(default); + firstId.Should().NotBe(secondId); + } + + [Fact] + public async Task MqlCreateObjectId_in_aggregate_should_work() + { + var collection = Fixture.Collection; + + var pipeline = new EmptyPipelineDefinition() + .Match(d => d.Id != Mql.CreateObjectId()) + .Project(d => new { NewId = Mql.CreateObjectId() }); + + var result = await collection.Aggregate(pipeline).ToListAsync(); + + var renderedPipeline = Translate(collection, pipeline, null); + AssertStages( + renderedPipeline, + "{ '$match' : { '$expr' : { '$ne' : [ '$_id', { $createObjectId : {} }] } } }", + "{ '$project' : { 'NewId' : { $createObjectId : {} }, '_id' : 0 } }"); + + var firstId = result.First().NewId; + var secondId = result.Skip(1).First().NewId; + + firstId.Should().NotBe(default); + secondId.Should().NotBe(default); + firstId.Should().NotBe(secondId); + } + + public class C + { + public ObjectId Id { get; set; } + } + + public sealed class ClassFixture : MongoCollectionFixture + { + protected override IEnumerable InitialData => + [ + new(), + new(), + ]; + } +} diff --git a/tests/MongoDB.Driver.Tests/Linq/Integration/MqlSubtypeTests.cs b/tests/MongoDB.Driver.Tests/Linq/Integration/MqlSubtypeTests.cs index f51b1eb0368..020d8567eba 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Integration/MqlSubtypeTests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Integration/MqlSubtypeTests.cs @@ -38,7 +38,7 @@ public MqlSubtypeTests(ClassFixture fixture) [InlineData(BsonBinarySubType.Vector, 2)] [InlineData(BsonBinarySubType.UuidStandard, 3)] [InlineData(null, 4)] - public void MqlSubtype_in_where(BsonBinarySubType? subtype, int expectedId) + public void MqlSubtype_in_where_should_work(BsonBinarySubType? subtype, int expectedId) { var collection = Fixture.Collection; var queryable = collection.AsQueryable() @@ -52,7 +52,7 @@ public void MqlSubtype_in_where(BsonBinarySubType? subtype, int expectedId) } [Fact] - public void MqlSubtype_in_select() + public void MqlSubtype_in_select_should_work() { var collection = Fixture.Collection; var queryable = collection.AsQueryable() @@ -66,7 +66,7 @@ public void MqlSubtype_in_select() } [Fact] - public async Task MqlSubtype_in_filter_builder() + public async Task MqlSubtype_in_filter_builder_should_work() { var collection = Fixture.Collection; @@ -79,7 +79,7 @@ public async Task MqlSubtype_in_filter_builder() } [Fact] - public async Task MqlSubtype_in_projection_builder() + public async Task MqlSubtype_in_projection_builder_should_work() { var collection = Fixture.Collection; @@ -93,7 +93,7 @@ public async Task MqlSubtype_in_projection_builder() } [Fact] - public async Task MqlSubtype_in_aggregate() + public async Task MqlSubtype_in_aggregate_should_work() { var collection = Fixture.Collection; diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/SerializerFinders/MqlTests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/SerializerFinders/MqlTests.cs index 4911d983866..b23b4fca382 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/SerializerFinders/MqlTests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/SerializerFinders/MqlTests.cs @@ -39,11 +39,14 @@ public void SerializerFinder_should_resolve_mql_methods(LambdaExpression express public static readonly object[][] TestCases = [ + [TestHelpers.MakeLambda((MyModel model) => Mql.CreateObjectId()), typeof(ObjectIdSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.DateFromString(model.DateString)), typeof(DateTimeSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.DateFromString(model.DateString, "yyyy-MM-dd")), typeof(DateTimeSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.DateFromString(model.DateString, "yyyy-MM-dd", "UTC")), typeof(DateTimeSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.DateFromString(model.DateString, "yyyy-MM-dd", "UTC", null, null)), typeof(NullableSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.Exists(model.Field)), typeof(BooleanSerializer)], + [TestHelpers.MakeLambda((MyModel model) => Mql.Hash(model.Data, MqlHashAlgorithm.SHA256)), typeof(BsonBinaryDataSerializer)], + [TestHelpers.MakeLambda((MyModel model) => Mql.HexHash(model.Data, MqlHashAlgorithm.SHA256)), typeof(StringSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.IsMissing(model.Field)), typeof(BooleanSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.IsNullOrMissing(model.Field)), typeof(BooleanSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.Sigmoid(model.Value)), typeof(DoubleSerializer)], @@ -51,8 +54,6 @@ public void SerializerFinder_should_resolve_mql_methods(LambdaExpression express [TestHelpers.MakeLambda((MyModel model) => Mql.SimilarityDotProduct(model.Vector1, model.Vector2, false)), typeof(DoubleSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.SimilarityEuclidean(model.Vector1, model.Vector2, false)), typeof(DoubleSerializer)], [TestHelpers.MakeLambda((MyModel model) => Mql.Subtype(model.Data)), typeof(NullableSerializer)], - [TestHelpers.MakeLambda((MyModel model) => Mql.Hash(model.Data, MqlHashAlgorithm.SHA256)), typeof(BsonBinaryDataSerializer)], - [TestHelpers.MakeLambda((MyModel model) => Mql.HexHash(model.Data, MqlHashAlgorithm.SHA256)), typeof(StringSerializer)] ]; private class MyModel diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CreateObjectIdMethodToAggregationExpressionTranslatorTests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CreateObjectIdMethodToAggregationExpressionTranslatorTests.cs new file mode 100644 index 00000000000..fbb62fd31ca --- /dev/null +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CreateObjectIdMethodToAggregationExpressionTranslatorTests.cs @@ -0,0 +1,42 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Linq.Expressions; +using FluentAssertions; +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators; +using Xunit; + +namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators; + +public class CreateObjectIdMethodToAggregationExpressionTranslatorTests +{ + [Fact] + public void Translate_should_produce_proper_ast() + { + var expression = TestHelpers.MakeLambda(model => Mql.CreateObjectId()); + var translationContext = TestHelpers.CreateTranslationContext(expression); + var translation = CreateObjectIdMethodToAggregationExpressionTranslator.Translate(translationContext, (MethodCallExpression)expression.Body); + + translation.Serializer.Should().BeOfType(); + translation.Ast.Render().Should().Be(BsonDocument.Parse("{ $createObjectId: { } }")); + } + + public class MyModel + { + } +} +