Skip to content

Commit bd0383d

Browse files
committed
CSHARP-1366: added $sample stage operator.
1 parent 5f5e819 commit bd0383d

File tree

9 files changed

+164
-0
lines changed

9 files changed

+164
-0
lines changed

src/MongoDB.Driver.Tests/Linq/MongoQueryableTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,16 @@ public void OrderBy_ThenBy_ThenByDescending_with_redundant_fields_in_different_d
564564
act.ShouldThrow<NotSupportedException>();
565565
}
566566

567+
[Test]
568+
public void Sample()
569+
{
570+
var query = CreateQuery().Sample(100);
571+
572+
Assert(query,
573+
2,
574+
"{ $sample: { size: 100 } }");
575+
}
576+
567577
[Test]
568578
public void Select_identity()
569579
{

src/MongoDB.Driver/Linq/Expressions/ExtensionExpressionType.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ internal enum ExtensionExpressionType
2727
GroupByWithResultSelector,
2828
Intersect,
2929
OrderBy,
30+
Sample,
3031
Select,
3132
SelectMany,
3233
Skip,

src/MongoDB.Driver/Linq/Expressions/ExtensionExpressionVisitor.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ protected internal virtual ResultOperator VisitResultOperator(ResultOperator res
132132
return resultOperator.Update(this);
133133
}
134134

135+
protected internal virtual Expression VisitSample(SampleExpression node)
136+
{
137+
return node.Update(
138+
Visit(node.Source),
139+
Visit(node.Count));
140+
}
141+
135142
protected internal virtual Expression VisitSelect(SelectExpression node)
136143
{
137144
return node.Update(
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* Copyright 2015 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;
17+
using System.Linq.Expressions;
18+
using MongoDB.Driver.Core.Misc;
19+
20+
namespace MongoDB.Driver.Linq.Expressions
21+
{
22+
internal sealed class SampleExpression : ExtensionExpression, ISourcedExpression
23+
{
24+
private readonly Expression _count;
25+
private readonly Expression _source;
26+
27+
public SampleExpression(Expression source, Expression count)
28+
{
29+
_source = Ensure.IsNotNull(source, nameof(source));
30+
_count = Ensure.IsNotNull(count, nameof(count));
31+
}
32+
33+
public override ExtensionExpressionType ExtensionType
34+
{
35+
get { return ExtensionExpressionType.Sample; }
36+
}
37+
38+
public Expression Count
39+
{
40+
get { return _count; }
41+
}
42+
43+
public Expression Source
44+
{
45+
get { return _source; }
46+
}
47+
48+
public override Type Type
49+
{
50+
get { return _source.Type; }
51+
}
52+
53+
public override string ToString()
54+
{
55+
return string.Format("{0}.Sample({1})", _source.ToString(), _count.ToString());
56+
}
57+
58+
public SampleExpression Update(Expression source, Expression count)
59+
{
60+
if (source != _source ||
61+
count != _count)
62+
{
63+
return new SampleExpression(source, count);
64+
}
65+
66+
return this;
67+
}
68+
69+
protected internal override Expression Accept(ExtensionExpressionVisitor visitor)
70+
{
71+
return visitor.VisitSample(this);
72+
}
73+
}
74+
}

src/MongoDB.Driver/Linq/MongoQueryable.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,25 @@ public static IOrderedMongoQueryable<TSource> OrderByDescending<TSource, TKey>(t
748748
return (IOrderedMongoQueryable<TSource>)Queryable.OrderByDescending(source, keySelector);
749749
}
750750

751+
/// <summary>
752+
/// Returns a sample of the elements in the <paramref name="source"/>.
753+
/// </summary>
754+
/// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
755+
/// <param name="source">An <see cref="IMongoQueryable{TSource}" /> to return a sample of.</param>
756+
/// <param name="count">The number of elements in the sample.</param>
757+
/// <returns>
758+
/// A sample of the elements in the <paramref name="source"/>.
759+
/// </returns>
760+
public static IMongoQueryable<TSource> Sample<TSource>(this IQueryable<TSource> source, long count)
761+
{
762+
return (IMongoQueryable<TSource>)source.Provider.CreateQuery<TSource>(
763+
Expression.Call(
764+
null,
765+
GetMethodInfo(Sample, source, count),
766+
source.Expression,
767+
Expression.Constant(count)));
768+
}
769+
751770
/// <summary>
752771
/// Projects each element of a sequence into a new form by incorporating the
753772
/// element's index.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* Copyright 2015 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.Collections.Generic;
17+
using System.Linq;
18+
using System.Linq.Expressions;
19+
using System.Reflection;
20+
using MongoDB.Driver.Linq.Expressions;
21+
22+
namespace MongoDB.Driver.Linq.Processors.Pipeline.MethodCallBinders
23+
{
24+
internal sealed class SampleBinder : IMethodCallBinder<PipelineBindingContext>
25+
{
26+
public static IEnumerable<MethodInfo> GetSupportedMethods()
27+
{
28+
return MethodHelper.GetEnumerableAndQueryableMethodDefinitions(nameof(MongoQueryable.Sample));
29+
}
30+
31+
public Expression Bind(PipelineExpression pipeline, PipelineBindingContext bindingContext, MethodCallExpression node, IEnumerable<Expression> arguments)
32+
{
33+
return new PipelineExpression(
34+
new SampleExpression(
35+
pipeline.Source,
36+
arguments.Single()),
37+
pipeline.Projector);
38+
}
39+
}
40+
}

src/MongoDB.Driver/Linq/Processors/Pipeline/PipelineBinder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static PipelineBinder()
3939
__methodCallBinder.Register(new MinBinder(), MinBinder.GetSupportedMethods());
4040
__methodCallBinder.Register(new OfTypeBinder(), OfTypeBinder.GetSupportedMethods());
4141
__methodCallBinder.Register(new OrderByBinder(), OrderByBinder.GetSupportedMethods());
42+
__methodCallBinder.Register(new SampleBinder(), SampleBinder.GetSupportedMethods());
4243
__methodCallBinder.Register(new SelectBinder(), SelectBinder.GetSupportedMethods());
4344
__methodCallBinder.Register(new SelectManyBinder(), SelectManyBinder.GetSupportedMethods());
4445
__methodCallBinder.Register(new SingleBinder(), SingleBinder.GetSupportedMethods());

src/MongoDB.Driver/Linq/Translators/QueryableTranslator.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ private void Translate(Expression node)
7676
case ExtensionExpressionType.Pipeline:
7777
TranslatePipeline((PipelineExpression)node);
7878
return;
79+
case ExtensionExpressionType.Sample:
80+
TranslateSample((SampleExpression)node);
81+
return;
7982
case ExtensionExpressionType.Select:
8083
TranslateSelect((SelectExpression)node);
8184
return;
@@ -192,6 +195,13 @@ private void TranslatePipeline(PipelineExpression node)
192195
_resultTransformer = node.ResultOperator as IResultTransformer;
193196
}
194197

198+
private void TranslateSample(SampleExpression node)
199+
{
200+
Translate(node.Source);
201+
202+
_stages.Add(new BsonDocument("$sample", new BsonDocument("size", (long)((ConstantExpression)node.Count).Value)));
203+
}
204+
195205
private void TranslateSelect(SelectExpression node)
196206
{
197207
Translate(node.Source);

src/MongoDB.Driver/MongoDB.Driver.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
<Compile Include="Linq\Expressions\OrderByClause.cs" />
115115
<Compile Include="Linq\Expressions\ExceptExpression.cs" />
116116
<Compile Include="Linq\Expressions\IntersectExpression.cs" />
117+
<Compile Include="Linq\Expressions\SampleExpression.cs" />
117118
<Compile Include="Linq\Expressions\UnionExpression.cs" />
118119
<Compile Include="Linq\Expressions\WhereExpression.cs" />
119120
<Compile Include="Linq\Expressions\ISerializationExpression.cs" />
@@ -177,6 +178,7 @@
177178
<Compile Include="Linq\Processors\Pipeline\MethodCallBinders\GroupByWithResultSelectorBinder.cs" />
178179
<Compile Include="Linq\Processors\Pipeline\MethodCallBinders\StandardDeviationSampleBinder.cs" />
179180
<Compile Include="Linq\Processors\Pipeline\MethodCallBinders\StandardDeviationPopulationBinder.cs" />
181+
<Compile Include="Linq\Processors\Pipeline\MethodCallBinders\SampleBinder.cs" />
180182
<Compile Include="Linq\Processors\Pipeline\MethodCallBinders\ThenByBinder.cs" />
181183
<Compile Include="Linq\Processors\Pipeline\MethodCallBinders\OrderByBinder.cs" />
182184
<Compile Include="Linq\Processors\Pipeline\MethodCallBinders\SelectManyBinder.cs" />

0 commit comments

Comments
 (0)