Skip to content

Commit 8fc0764

Browse files
committed
CSHARP-3225: Implement SetWindowFields stage.
1 parent 00ac83e commit 8fc0764

File tree

53 files changed

+6769
-15
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+6769
-15
lines changed

src/MongoDB.Driver/AggregateExpressionDefinition.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using MongoDB.Bson.Serialization;
2020
using MongoDB.Driver.Core.Misc;
2121
using MongoDB.Driver.Linq;
22+
using MongoDB.Driver.Linq.Linq3Implementation.Translators;
2223

2324
namespace MongoDB.Driver
2425
{
@@ -113,6 +114,7 @@ public override BsonValue Render(IBsonSerializer<TSource> sourceSerializer, IBso
113114
public sealed class ExpressionAggregateExpressionDefinition<TSource, TResult> : AggregateExpressionDefinition<TSource, TResult>
114115
{
115116
// private fields
117+
private readonly TranslationContextData _contextData;
116118
private readonly Expression<Func<TSource, TResult>> _expression;
117119
private readonly ExpressionTranslationOptions _translationOptions;
118120

@@ -122,17 +124,23 @@ public sealed class ExpressionAggregateExpressionDefinition<TSource, TResult> :
122124
/// </summary>
123125
/// <param name="expression">The expression.</param>
124126
/// <param name="translationOptions">The translation options.</param>
125-
public ExpressionAggregateExpressionDefinition(Expression<Func<TSource, TResult>> expression, ExpressionTranslationOptions translationOptions)
127+
/// <param name="contextData">Any optional data for the TranslationContext.</param>
128+
public ExpressionAggregateExpressionDefinition(
129+
Expression<Func<TSource, TResult>> expression,
130+
ExpressionTranslationOptions translationOptions,
131+
TranslationContextData contextData = null)
126132
{
127133
_expression = Ensure.IsNotNull(expression, nameof(expression));
128134
_translationOptions = translationOptions; // can be null
135+
_contextData = contextData; // can be null
129136
}
130137

131138
// public methods
132139
/// <inheritdoc/>
133140
public override BsonValue Render(IBsonSerializer<TSource> sourceSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider)
134141
{
135-
return linqProvider.GetAdapter().TranslateExpressionToAggregateExpression(_expression, sourceSerializer, serializerRegistry, _translationOptions);
142+
var contextData = _contextData?.With("SerializerRegistry", serializerRegistry);
143+
return linqProvider.GetAdapter().TranslateExpressionToAggregateExpression(_expression, sourceSerializer, serializerRegistry, _translationOptions, contextData);
136144
}
137145
}
138146
}

src/MongoDB.Driver/AggregateFluent.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,27 @@ public override IAggregateFluent<TNewResult> ReplaceWith<TNewResult>(AggregateEx
222222
return WithPipeline(_pipeline.ReplaceWith(newRoot));
223223
}
224224

225+
public override IAggregateFluent<BsonDocument> SetWindowFields<TWindowFields>(
226+
AggregateExpressionDefinition<ISetWindowFieldsPartition<TResult>, TWindowFields> output)
227+
{
228+
return WithPipeline(_pipeline.SetWindowFields(output));
229+
}
230+
231+
public override IAggregateFluent<BsonDocument> SetWindowFields<TPartitionBy, TWindowFields>(
232+
AggregateExpressionDefinition<TResult, TPartitionBy> partitionBy,
233+
AggregateExpressionDefinition<ISetWindowFieldsPartition<TResult>, TWindowFields> output)
234+
{
235+
return WithPipeline(_pipeline.SetWindowFields(partitionBy, output));
236+
}
237+
238+
public override IAggregateFluent<BsonDocument> SetWindowFields<TPartitionBy, TWindowFields>(
239+
AggregateExpressionDefinition<TResult, TPartitionBy> partitionBy,
240+
SortDefinition<TResult> sortBy,
241+
AggregateExpressionDefinition<ISetWindowFieldsPartition<TResult>, TWindowFields> output)
242+
{
243+
return WithPipeline(_pipeline.SetWindowFields(partitionBy, sortBy, output));
244+
}
245+
225246
public override IAggregateFluent<TResult> Skip(int skip)
226247
{
227248
return WithPipeline(_pipeline.Skip(skip));

src/MongoDB.Driver/AggregateFluentBase.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,30 @@ public virtual IAggregateFluent<TNewResult> ReplaceWith<TNewResult>(AggregateExp
197197
throw new NotImplementedException();
198198
}
199199

200+
/// <inheritdoc />
201+
public virtual IAggregateFluent<BsonDocument> SetWindowFields<TWindowFields>(
202+
AggregateExpressionDefinition<ISetWindowFieldsPartition<TResult>, TWindowFields> output)
203+
{
204+
throw new NotImplementedException();
205+
}
206+
207+
/// <inheritdoc />
208+
public virtual IAggregateFluent<BsonDocument> SetWindowFields<TPartitionBy, TWindowFields>(
209+
AggregateExpressionDefinition<TResult, TPartitionBy> partitionBy,
210+
AggregateExpressionDefinition<ISetWindowFieldsPartition<TResult>, TWindowFields> output)
211+
{
212+
throw new NotImplementedException();
213+
}
214+
215+
/// <inheritdoc />
216+
public virtual IAggregateFluent<BsonDocument> SetWindowFields<TPartitionBy, TWindowFields>(
217+
AggregateExpressionDefinition<TResult, TPartitionBy> partitionBy,
218+
SortDefinition<TResult> sort,
219+
AggregateExpressionDefinition<ISetWindowFieldsPartition<TResult>, TWindowFields> output)
220+
{
221+
throw new NotImplementedException();
222+
}
223+
200224
/// <inheritdoc />
201225
public abstract IAggregateFluent<TResult> Skip(int skip);
202226

src/MongoDB.Driver/DocumentsWindow.cs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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.Driver.Core.Misc;
17+
18+
namespace MongoDB.Driver
19+
{
20+
/// <summary>
21+
/// Represents a documents window for a SetWindowFields window method.
22+
/// </summary>
23+
public sealed class DocumentsWindow : SetWindowFieldsWindow
24+
{
25+
#region static
26+
private static readonly KeywordDocumentsWindowBoundary __current = new KeywordDocumentsWindowBoundary("current");
27+
private static readonly KeywordDocumentsWindowBoundary __unbounded = new KeywordDocumentsWindowBoundary("unbounded");
28+
29+
/// <summary>
30+
/// Returns a "current" documents window boundary.
31+
/// </summary>
32+
public static KeywordDocumentsWindowBoundary Current => __current;
33+
34+
/// <summary>
35+
/// Returns an "unbounded" documents window boundary.
36+
/// </summary>
37+
public static KeywordDocumentsWindowBoundary Unbounded => __unbounded;
38+
39+
/// <summary>
40+
/// Creates a documents window.
41+
/// </summary>
42+
/// <param name="lowerBoundary">The lower boundary.</param>
43+
/// <param name="upperBoundary">The upper boundary.</param>
44+
/// <returns>A documents window.</returns>
45+
public static DocumentsWindow Create(int lowerBoundary, int upperBoundary)
46+
{
47+
return new DocumentsWindow(new PositionDocumentsWindowBoundary(lowerBoundary), new PositionDocumentsWindowBoundary(upperBoundary));
48+
}
49+
50+
/// <summary>
51+
/// Creates a documents window.
52+
/// </summary>
53+
/// <param name="lowerBoundary">The lower boundary.</param>
54+
/// <param name="upperBoundary">The upper boundary.</param>
55+
/// <returns>A documents window.</returns>
56+
public static DocumentsWindow Create(int lowerBoundary, KeywordDocumentsWindowBoundary upperBoundary)
57+
{
58+
return new DocumentsWindow(new PositionDocumentsWindowBoundary(lowerBoundary), upperBoundary);
59+
}
60+
61+
/// <summary>
62+
/// Creates a documents window.
63+
/// </summary>
64+
/// <param name="lowerBoundary">The lower boundary.</param>
65+
/// <param name="upperBoundary">The upper boundary.</param>
66+
/// <returns>A documents window.</returns>
67+
public static DocumentsWindow Create(KeywordDocumentsWindowBoundary lowerBoundary, int upperBoundary)
68+
{
69+
return new DocumentsWindow(lowerBoundary, new PositionDocumentsWindowBoundary(upperBoundary));
70+
}
71+
72+
/// <summary>
73+
/// Creates a documents window.
74+
/// </summary>
75+
/// <param name="lowerBoundary">The lower boundary.</param>
76+
/// <param name="upperBoundary">The upper boundary.</param>
77+
/// <returns>A documents window.</returns>
78+
public static DocumentsWindow Create(KeywordDocumentsWindowBoundary lowerBoundary, KeywordDocumentsWindowBoundary upperBoundary)
79+
{
80+
return new DocumentsWindow(lowerBoundary, upperBoundary);
81+
}
82+
#endregion
83+
84+
private readonly DocumentsWindowBoundary _lowerBoundary;
85+
private readonly DocumentsWindowBoundary _upperBoundary;
86+
87+
/// <summary>
88+
/// Initializes an instance of DocumentsWindow.
89+
/// </summary>
90+
/// <param name="lowerBoundary">The lower boundary.</param>
91+
/// <param name="upperBoundary">The upper boundary.</param>
92+
internal DocumentsWindow(DocumentsWindowBoundary lowerBoundary, DocumentsWindowBoundary upperBoundary)
93+
{
94+
_lowerBoundary = Ensure.IsNotNull(lowerBoundary, nameof(lowerBoundary));
95+
_upperBoundary = Ensure.IsNotNull(upperBoundary, nameof(upperBoundary));
96+
}
97+
98+
/// <summary>
99+
/// The lower boundary.
100+
/// </summary>
101+
public DocumentsWindowBoundary LowerBoundary => _lowerBoundary;
102+
103+
/// <summary>
104+
/// The upper boundary.
105+
/// </summary>
106+
public DocumentsWindowBoundary UpperBoundary => _upperBoundary;
107+
108+
/// <inheritdoc/>
109+
public override string ToString() => $"documents : [{_lowerBoundary}, {_upperBoundary}]";
110+
}
111+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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.Core.Misc;
18+
19+
namespace MongoDB.Driver
20+
{
21+
/// <summary>
22+
/// Represents a boundary for a documents window in SetWindowFields.
23+
/// </summary>
24+
public abstract class DocumentsWindowBoundary
25+
{
26+
internal DocumentsWindowBoundary() { } // disallow user defined subclasses
27+
internal abstract BsonValue Render();
28+
}
29+
30+
/// <summary>
31+
/// Represents a keyword boundary for a document window in SetWindowFields (i.e. "unbounded" or "current").
32+
/// </summary>
33+
public sealed class KeywordDocumentsWindowBoundary : DocumentsWindowBoundary
34+
{
35+
private readonly string _keyword;
36+
37+
internal KeywordDocumentsWindowBoundary(string keyword)
38+
{
39+
_keyword = Ensure.IsNotNullOrEmpty(keyword, nameof(keyword));
40+
}
41+
42+
/// <summary>
43+
/// The keyword.
44+
/// </summary>
45+
public string Keyword => _keyword;
46+
47+
/// <inheritdoc/>
48+
public override string ToString() => $"\"{_keyword}\"";
49+
50+
internal override BsonValue Render() => _keyword;
51+
}
52+
53+
/// <summary>
54+
/// Represents a position boundary for a document window in SetWindowFields.
55+
/// </summary>
56+
public sealed class PositionDocumentsWindowBoundary : DocumentsWindowBoundary
57+
{
58+
private readonly int _position;
59+
60+
/// <summary>
61+
/// Initializes a new instance of PositionDocumentsWindowBoundary.
62+
/// </summary>
63+
/// <param name="position">The position.</param>
64+
internal PositionDocumentsWindowBoundary(int position)
65+
{
66+
_position = position;
67+
}
68+
69+
/// <summary>
70+
/// The position.
71+
/// </summary>
72+
public int Position => _position;
73+
74+
/// <inheritdoc/>
75+
public override string ToString() => _position.ToString();
76+
77+
internal override BsonValue Render() => _position;
78+
}
79+
}

src/MongoDB.Driver/IAggregateFluent.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,41 @@ IAggregateFluent<TNewResult> Lookup<TForeignDocument, TAsElement, TAs, TNewResul
320320
/// <returns>The fluent aggregate interface.</returns>
321321
IAggregateFluent<TNewResult> ReplaceWith<TNewResult>(AggregateExpressionDefinition<TResult, TNewResult> newRoot);
322322

323+
/// <summary>
324+
/// Appends a $setWindowFields to the pipeline.
325+
/// </summary>
326+
/// <typeparam name="TWindowFields">The type of the added window fields.</typeparam>
327+
/// <param name="output">The window fields definition.</param>
328+
/// <returns></returns>
329+
IAggregateFluent<BsonDocument> SetWindowFields<TWindowFields>(
330+
AggregateExpressionDefinition<ISetWindowFieldsPartition<TResult>, TWindowFields> output);
331+
332+
/// <summary>
333+
/// Appends a $setWindowFields to the pipeline.
334+
/// </summary>
335+
/// <typeparam name="TPartitionBy">The type of the value to partition by.</typeparam>
336+
/// <typeparam name="TWindowFields">The type of the added window fields.</typeparam>
337+
/// <param name="partitionBy">The partitionBy definition.</param>
338+
/// <param name="output">The window fields definition.</param>
339+
/// <returns></returns>
340+
IAggregateFluent<BsonDocument> SetWindowFields<TPartitionBy, TWindowFields>(
341+
AggregateExpressionDefinition<TResult, TPartitionBy> partitionBy,
342+
AggregateExpressionDefinition<ISetWindowFieldsPartition<TResult>, TWindowFields> output);
343+
344+
/// <summary>
345+
/// Appends a $setWindowFields to the pipeline.
346+
/// </summary>
347+
/// <typeparam name="TPartitionBy">The type of the value to partition by.</typeparam>
348+
/// <typeparam name="TWindowFields">The type of the added window fields.</typeparam>
349+
/// <param name="partitionBy">The partitionBy definition.</param>
350+
/// <param name="sortBy">The sortBy definition.</param>
351+
/// <param name="output">The window fields definition.</param>
352+
/// <returns></returns>
353+
IAggregateFluent<BsonDocument> SetWindowFields<TPartitionBy, TWindowFields>(
354+
AggregateExpressionDefinition<TResult, TPartitionBy> partitionBy,
355+
SortDefinition<TResult> sortBy,
356+
AggregateExpressionDefinition<ISetWindowFieldsPartition<TResult>, TWindowFields> output);
357+
323358
/// <summary>
324359
/// Appends a skip stage to the pipeline.
325360
/// </summary>

src/MongoDB.Driver/IAggregateFluentExtensions.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,62 @@ public static IAggregateFluent<TNewResult> ReplaceWith<TResult, TNewResult>(
520520
return aggregate.AppendStage(PipelineStageDefinitionBuilder.ReplaceWith(newRoot));
521521
}
522522

523+
/// <summary>
524+
/// Appends a $setWindowFields to the pipeline.
525+
/// </summary>
526+
/// <typeparam name="TResult">The type of the result.</typeparam>
527+
/// <typeparam name="TWindowFields">The type of the added window fields.</typeparam>
528+
/// <param name="aggregate">The aggregate.</param>
529+
/// <param name="output">The window fields expression.</param>
530+
/// <returns>The fluent aggregate interface.</returns>
531+
public static IAggregateFluent<BsonDocument> SetWindowFields<TResult, TWindowFields>(
532+
this IAggregateFluent<TResult> aggregate,
533+
Expression<Func<ISetWindowFieldsPartition<TResult>, TWindowFields>> output)
534+
{
535+
Ensure.IsNotNull(aggregate, nameof(aggregate));
536+
return aggregate.AppendStage(PipelineStageDefinitionBuilder.SetWindowFields(output));
537+
}
538+
539+
/// <summary>
540+
/// Appends a $setWindowFields to the pipeline.
541+
/// </summary>
542+
/// <typeparam name="TResult">The type of the result.</typeparam>
543+
/// <typeparam name="TPartitionBy">The type of the value to partition by.</typeparam>
544+
/// <typeparam name="TWindowFields">The type of the added window fields.</typeparam>
545+
/// <param name="aggregate">The aggregate.</param>
546+
/// <param name="partitionBy">The partitionBy expression.</param>
547+
/// <param name="output">The window fields expression.</param>
548+
/// <returns>The fluent aggregate interface.</returns>
549+
public static IAggregateFluent<BsonDocument> SetWindowFields<TResult, TPartitionBy, TWindowFields>(
550+
this IAggregateFluent<TResult> aggregate,
551+
Expression<Func<TResult, TPartitionBy>> partitionBy,
552+
Expression<Func<ISetWindowFieldsPartition<TResult>, TWindowFields>> output)
553+
{
554+
Ensure.IsNotNull(aggregate, nameof(aggregate));
555+
return aggregate.AppendStage(PipelineStageDefinitionBuilder.SetWindowFields(partitionBy, output));
556+
}
557+
558+
/// <summary>
559+
/// Appends a $setWindowFields to the pipeline.
560+
/// </summary>
561+
/// <typeparam name="TResult">The type of the result.</typeparam>
562+
/// <typeparam name="TPartitionBy">The type of the value to partition by.</typeparam>
563+
/// <typeparam name="TWindowFields">The type of the added window fields.</typeparam>
564+
/// <param name="aggregate">The aggregate.</param>
565+
/// <param name="partitionBy">The partitionBy expression.</param>
566+
/// <param name="sortBy">The sortBy expression.</param>
567+
/// <param name="output">The window fields expression.</param>
568+
/// <returns>The fluent aggregate interface.</returns>
569+
public static IAggregateFluent<BsonDocument> SetWindowFields<TResult, TPartitionBy, TWindowFields>(
570+
this IAggregateFluent<TResult> aggregate,
571+
Expression<Func<TResult, TPartitionBy>> partitionBy,
572+
SortDefinition<TResult> sortBy,
573+
Expression<Func<ISetWindowFieldsPartition<TResult>, TWindowFields>> output)
574+
{
575+
Ensure.IsNotNull(aggregate, nameof(aggregate));
576+
return aggregate.AppendStage(PipelineStageDefinitionBuilder.SetWindowFields(partitionBy, sortBy, output));
577+
}
578+
523579
/// <summary>
524580
/// Appends an ascending sort stage to the pipeline.
525581
/// </summary>

0 commit comments

Comments
 (0)