Skip to content

Commit 5e6ca7a

Browse files
authored
CSHARP-5656: Support Aggregation Operator to generate random object ids (#1931)
1 parent 8f29326 commit 5e6ca7a

15 files changed

Lines changed: 335 additions & 84 deletions

File tree

src/MongoDB.Driver/Core/Misc/Feature.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class Feature
5252
private static readonly Feature __convertOperatorStringToObjectOrArray = new Feature("ConvertOperatorStringToObjectOrArray", WireVersion.Server83);
5353
private static readonly Feature __createIndexCommitQuorum = new Feature("CreateIndexCommitQuorum", WireVersion.Server44);
5454
private static readonly Feature __createIndexesUsingInsertOperations = new Feature("CreateIndexesUsingInsertOperations", WireVersion.Zero, WireVersion.Server42);
55+
private static readonly Feature __createObjectIdExpression = new Feature("CreateObjectIdExpression", WireVersion.Server83);
5556
private static readonly Feature __csfleRangeAlgorithm = new Feature("CsfleRangeAlgorithm", WireVersion.Server62);
5657
private static readonly Feature __csfle2Qev2Lookup = new Feature("csfle2Qev2Lookup", WireVersion.Server81);
5758
private static readonly Feature __csfle2Qev2RangeAlgorithm = new Feature("csfle2Qev2RangeAlgorithm", WireVersion.Server80);
@@ -248,6 +249,11 @@ public class Feature
248249
[Obsolete("This feature was removed in server version 4.2. As such, this property will be removed in a later release.")]
249250
public static Feature CreateIndexesUsingInsertOperations => __createIndexesUsingInsertOperations;
250251

252+
/// <summary>
253+
/// Represents support for the $createObjectId operator feature.
254+
/// </summary>
255+
public static Feature CreateObjectIdExpression => __createObjectIdExpression;
256+
251257
/// <summary>
252258
/// Gets the csfle range algorithm feature.
253259
/// </summary>

src/MongoDB.Driver/Linq/Linq3Implementation/Ast/AstNodeType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ internal enum AstNodeType
3838
ConstantExpression,
3939
ConvertExpression,
4040
CountStage,
41+
CreateObjectIdExpression,
4142
CurrentOpStage,
4243
CustomAccumulatorExpression,
4344
DateAddExpression,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using MongoDB.Bson;
17+
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Visitors;
18+
19+
namespace MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
20+
21+
internal sealed class AstCreateObjectIdExpression : AstExpression
22+
{
23+
public override AstNodeType NodeType => AstNodeType.CreateObjectIdExpression;
24+
25+
public override AstNode Accept(AstNodeVisitor visitor) =>
26+
visitor.VisitCreateObjectIdExpression(this);
27+
28+
public override BsonValue Render() =>
29+
new BsonDocument("$createObjectId", new BsonDocument());
30+
}

src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Expressions/AstExpression.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,9 @@ public static AstExpression Floor(AstExpression arg)
443443
return new AstUnaryExpression(AstUnaryOperator.Floor, arg);
444444
}
445445

446+
public static AstCreateObjectIdExpression CreateObjectId()
447+
=> new();
448+
446449
public static AstGetFieldExpression GetField(AstExpression input, AstExpression fieldName)
447450
{
448451
return new AstGetFieldExpression(input, fieldName);

src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Visitors/AstNodeVisitor.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ public virtual AstNode VisitCustomAccumulatorExpression(AstCustomAccumulatorExpr
244244
return node.Update(VisitAndConvert(node.InitArgs), VisitAndConvert(node.AccumulateArgs));
245245
}
246246

247+
public virtual AstNode VisitCreateObjectIdExpression(AstCreateObjectIdExpression node)
248+
=> node;
249+
247250
public virtual AstNode VisitDateAddExpression(AstDateAddExpression node)
248251
{
249252
return node.Update(VisitAndConvert(node.StartDate), VisitAndConvert(node.Unit), VisitAndConvert(node.Amount), VisitAndConvert(node.Timezone));

src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/MqlMethod.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ internal static class MqlMethod
2727
private static readonly MethodInfo __constantWithRepresentation;
2828
private static readonly MethodInfo __constantWithSerializer;
2929
private static readonly MethodInfo __convert;
30+
private static readonly MethodInfo __createObjectId;
3031
private static readonly MethodInfo __dateFromString;
3132
private static readonly MethodInfo __dateFromStringWithFormat;
3233
private static readonly MethodInfo __dateFromStringWithFormatAndTimezone;
@@ -53,6 +54,7 @@ static MqlMethod()
5354
__constantWithRepresentation = ReflectionInfo.Method((object value, BsonType representation) => Mql.Constant(value, representation));
5455
__constantWithSerializer = ReflectionInfo.Method((object value, IBsonSerializer<object> serializer) => Mql.Constant(value, serializer));
5556
__convert = ReflectionInfo.Method((object value, ConvertOptions<object> options) => Mql.Convert(value, options));
57+
__createObjectId = ReflectionInfo.Method(() => Mql.CreateObjectId());
5658
__dateFromString = ReflectionInfo.Method((string dateStringl) => Mql.DateFromString(dateStringl));
5759
__dateFromStringWithFormat = ReflectionInfo.Method((string dateString, string format) => Mql.DateFromString(dateString, format));
5860
__dateFromStringWithFormatAndTimezone = ReflectionInfo.Method((string dateString, string format, string timezone) => Mql.DateFromString(dateString, format, timezone));
@@ -110,6 +112,7 @@ static MqlMethod()
110112
public static MethodInfo ConstantWithRepresentation => __constantWithRepresentation;
111113
public static MethodInfo ConstantWithSerializer => __constantWithSerializer;
112114
public static MethodInfo Convert => __convert;
115+
public static MethodInfo CreateObjectId => __createObjectId;
113116
public static MethodInfo DateFromString => __dateFromString;
114117
public static MethodInfo DateFromStringWithFormat => __dateFromStringWithFormat;
115118
public static MethodInfo DateFromStringWithFormatAndTimezone => __dateFromStringWithFormatAndTimezone;

src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/ReflectionInfo.cs

Lines changed: 40 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -16,106 +16,69 @@
1616
using System;
1717
using System.Linq.Expressions;
1818
using System.Reflection;
19-
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
2019

2120
namespace MongoDB.Driver.Linq.Linq3Implementation.Reflection
2221
{
2322
internal static class ReflectionInfo
2423
{
25-
public static ConstructorInfo Constructor<TObject>(Expression<Func<TObject>> lambda)
26-
{
27-
return ExtractConstructorInfoFromLambda(lambda);
28-
}
24+
public static ConstructorInfo Constructor<TObject>(Expression<Func<TObject>> lambda) =>
25+
ExtractConstructorInfoFromLambda(lambda);
2926

30-
public static ConstructorInfo Constructor<T1, TObject>(Expression<Func<T1, TObject>> lambda)
31-
{
32-
return ExtractConstructorInfoFromLambda(lambda);
33-
}
27+
public static ConstructorInfo Constructor<T1, TObject>(Expression<Func<T1, TObject>> lambda) =>
28+
ExtractConstructorInfoFromLambda(lambda);
3429

35-
public static ConstructorInfo Constructor<T1, T2, TObject>(Expression<Func<T1, T2, TObject>> lambda)
36-
{
37-
return ExtractConstructorInfoFromLambda(lambda);
38-
}
30+
public static ConstructorInfo Constructor<T1, T2, TObject>(Expression<Func<T1, T2, TObject>> lambda) =>
31+
ExtractConstructorInfoFromLambda(lambda);
3932

40-
public static ConstructorInfo Constructor<T1, T2, T3, TObject>(Expression<Func<T1, T2, T3, TObject>> lambda)
41-
{
42-
return ExtractConstructorInfoFromLambda(lambda);
43-
}
33+
public static ConstructorInfo Constructor<T1, T2, T3, TObject>(Expression<Func<T1, T2, T3, TObject>> lambda) =>
34+
ExtractConstructorInfoFromLambda(lambda);
4435

45-
public static ConstructorInfo Constructor<T1, T2, T3, T4, TObject>(Expression<Func<T1, T2, T3, T4, TObject>> lambda)
46-
{
47-
return ExtractConstructorInfoFromLambda(lambda);
48-
}
36+
public static ConstructorInfo Constructor<T1, T2, T3, T4, TObject>(Expression<Func<T1, T2, T3, T4, TObject>> lambda) =>
37+
ExtractConstructorInfoFromLambda(lambda);
4938

50-
public static ConstructorInfo Constructor<T1, T2, T3, T4, T5, TObject>(Expression<Func<T1, T2, T3, T4, T5, TObject>> lambda)
51-
{
52-
return ExtractConstructorInfoFromLambda(lambda);
53-
}
39+
public static ConstructorInfo Constructor<T1, T2, T3, T4, T5, TObject>(Expression<Func<T1, T2, T3, T4, T5, TObject>> lambda) =>
40+
ExtractConstructorInfoFromLambda(lambda);
5441

55-
public static ConstructorInfo Constructor<T1, T2, T3, T4, T5, T6, TObject>(Expression<Func<T1, T2, T3, T4, T5, T6, TObject>> lambda)
56-
{
57-
return ExtractConstructorInfoFromLambda(lambda);
58-
}
42+
public static ConstructorInfo Constructor<T1, T2, T3, T4, T5, T6, TObject>(Expression<Func<T1, T2, T3, T4, T5, T6, TObject>> lambda) =>
43+
ExtractConstructorInfoFromLambda(lambda);
5944

60-
public static ConstructorInfo Constructor<T1, T2, T3, T4, T5, T6, T7, TObject>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TObject>> lambda)
61-
{
62-
return ExtractConstructorInfoFromLambda(lambda);
63-
}
45+
public static ConstructorInfo Constructor<T1, T2, T3, T4, T5, T6, T7, TObject>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TObject>> lambda) =>
46+
ExtractConstructorInfoFromLambda(lambda);
6447

65-
public static MethodInfo Method<T1, TResult>(Expression<Func<T1, TResult>> lambda)
66-
{
67-
return ExtractMethodInfoFromLambda(lambda);
68-
}
48+
public static MethodInfo Method<TResult>(Expression<Func<TResult>> lambda) =>
49+
ExtractMethodInfoFromLambda(lambda);
6950

70-
public static MethodInfo Method<T1, T2, TResult>(Expression<Func<T1, T2, TResult>> lambda)
71-
{
72-
return ExtractMethodInfoFromLambda(lambda);
73-
}
51+
public static MethodInfo Method<T1, TResult>(Expression<Func<T1, TResult>> lambda) =>
52+
ExtractMethodInfoFromLambda(lambda);
7453

75-
public static MethodInfo Method<T1, T2, T3, TResult>(Expression<Func<T1, T2, T3, TResult>> lambda)
76-
{
77-
return ExtractMethodInfoFromLambda(lambda);
78-
}
54+
public static MethodInfo Method<T1, T2, TResult>(Expression<Func<T1, T2, TResult>> lambda) =>
55+
ExtractMethodInfoFromLambda(lambda);
7956

80-
public static MethodInfo Method<T1, T2, T3, T4, TResult>(Expression<Func<T1, T2, T3, T4, TResult>> lambda)
81-
{
82-
return ExtractMethodInfoFromLambda(lambda);
83-
}
57+
public static MethodInfo Method<T1, T2, T3, TResult>(Expression<Func<T1, T2, T3, TResult>> lambda) =>
58+
ExtractMethodInfoFromLambda(lambda);
8459

85-
public static MethodInfo Method<T1, T2, T3, T4, T5, TResult>(Expression<Func<T1, T2, T3, T4, T5, TResult>> lambda)
86-
{
87-
return ExtractMethodInfoFromLambda(lambda);
88-
}
60+
public static MethodInfo Method<T1, T2, T3, T4, TResult>(Expression<Func<T1, T2, T3, T4, TResult>> lambda) =>
61+
ExtractMethodInfoFromLambda(lambda);
8962

90-
public static MethodInfo Method<T1, T2, T3, T4, T5, T6, TResult>(Expression<Func<T1, T2, T3, T4, T5, T6, TResult>> lambda)
91-
{
92-
return ExtractMethodInfoFromLambda(lambda);
93-
}
63+
public static MethodInfo Method<T1, T2, T3, T4, T5, TResult>(Expression<Func<T1, T2, T3, T4, T5, TResult>> lambda) => ExtractMethodInfoFromLambda(lambda);
9464

95-
public static MethodInfo Method<T1, T2, T3, T4, T5, T6, T7, TResult>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TResult>> lambda)
96-
{
97-
return ExtractMethodInfoFromLambda(lambda);
98-
}
65+
public static MethodInfo Method<T1, T2, T3, T4, T5, T6, TResult>(Expression<Func<T1, T2, T3, T4, T5, T6, TResult>> lambda) =>
66+
ExtractMethodInfoFromLambda(lambda);
9967

100-
public static MethodInfo Method<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>> lambda)
101-
{
102-
return ExtractMethodInfoFromLambda(lambda);
103-
}
68+
public static MethodInfo Method<T1, T2, T3, T4, T5, T6, T7, TResult>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TResult>> lambda) =>
69+
ExtractMethodInfoFromLambda(lambda);
10470

105-
public static PropertyInfo Property<TObject, TProperty>(Expression<Func<TObject, TProperty>> lambda)
106-
{
107-
return ExtractPropertyInfoFromLambda(lambda);
108-
}
71+
public static MethodInfo Method<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>> lambda) =>
72+
ExtractMethodInfoFromLambda(lambda);
10973

110-
public static MethodInfo IndexerGet<TObject, TIndex, TValue>(Expression<Func<TObject, TIndex, TValue>> lambda)
111-
{
112-
return ExtractMethodInfoFromLambda(lambda);
113-
}
74+
public static PropertyInfo Property<TObject, TProperty>(Expression<Func<TObject, TProperty>> lambda) =>
75+
ExtractPropertyInfoFromLambda(lambda);
11476

115-
public static MethodInfo IndexerSet<TObject, TIndex, TValue>(Expression<Func<TObject, TIndex, TValue>> lambda)
116-
{
117-
return ExtractIndexerSetMethodInfoFromLambda(lambda);
118-
}
77+
public static MethodInfo IndexerGet<TObject, TIndex, TValue>(Expression<Func<TObject, TIndex, TValue>> lambda) =>
78+
ExtractMethodInfoFromLambda(lambda);
79+
80+
public static MethodInfo IndexerSet<TObject, TIndex, TValue>(Expression<Func<TObject, TIndex, TValue>> lambda) =>
81+
ExtractIndexerSetMethodInfoFromLambda(lambda);
11982

12083
// private static methods
12184
private static ConstructorInfo ExtractConstructorInfoFromLambda(LambdaExpression lambda)

src/MongoDB.Driver/Linq/Linq3Implementation/SerializerFinders/SerializerFinderVisitMethodCall.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ void DeduceMethodCallSerializers()
100100
case "ContainsValue": DeduceContainsValueMethodSerializers(); break;
101101
case "Convert": DeduceConvertMethodSerializers(); break;
102102
case "Create": DeduceCreateMethodSerializers(); break;
103+
case "CreateObjectId": DeduceCreateObjectIdMethodSerializers(); break;
103104
case "DateFromString": DeduceDateFromStringMethodSerializers(); break;
104105
case "DefaultIfEmpty": DeduceDefaultIfEmptyMethodSerializers(); break;
105106
case "DegreesToRadians": DeduceDegreesToRadiansMethodSerializers(); break;
@@ -1373,6 +1374,21 @@ void DeduceFieldMethodSerializers()
13731374
}
13741375
}
13751376

1377+
void DeduceCreateObjectIdMethodSerializers()
1378+
{
1379+
if (method.Is(MqlMethod.CreateObjectId))
1380+
{
1381+
if (IsNotKnown(node))
1382+
{
1383+
DeduceSerializer(node, ObjectIdSerializer.Instance);
1384+
}
1385+
}
1386+
else
1387+
{
1388+
DeduceUnknownMethodSerializer();
1389+
}
1390+
}
1391+
13761392
void DeduceFirstOrLastOrSingleMethodsSerializers()
13771393
{
13781394
if (method.IsOneOf(EnumerableOrQueryableMethod.FirstOrLastOrSingleOverloads))

src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC
4242
case "CovariancePopulation": return CovariancePopulationMethodToAggregationExpressionTranslator.Translate(context, expression);
4343
case "CovarianceSample": return CovarianceSampleMethodToAggregationExpressionTranslator.Translate(context, expression);
4444
case "Create": return CreateMethodToAggregationExpressionTranslator.Translate(context, expression);
45+
case "CreateObjectId": return CreateObjectIdMethodToAggregationExpressionTranslator.Translate(context, expression);
4546
case "DateFromString": return DateFromStringMethodToAggregationExpressionTranslator.Translate(context, expression);
4647
case "DefaultIfEmpty": return DefaultIfEmptyMethodToAggregationExpressionTranslator.Translate(context, expression);
4748
case "DenseRank": return DenseRankMethodToAggregationExpressionTranslator.Translate(context, expression);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System.Linq.Expressions;
17+
using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
18+
using MongoDB.Driver.Linq.Linq3Implementation.Misc;
19+
using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
20+
21+
namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators;
22+
23+
internal static class CreateObjectIdMethodToAggregationExpressionTranslator
24+
{
25+
public static TranslatedExpression Translate(TranslationContext context, MethodCallExpression expression)
26+
{
27+
var method = expression.Method;
28+
29+
if (method.Is(MqlMethod.CreateObjectId))
30+
{
31+
var ast = AstExpression.CreateObjectId();
32+
var serializer = context.GetSerializer(expression);
33+
return new TranslatedExpression(expression, ast, serializer);
34+
}
35+
36+
throw new ExpressionNotSupportedException(expression);
37+
}
38+
}

0 commit comments

Comments
 (0)