Skip to content

Commit 3661126

Browse files
committed
CSHARP-1368: added $slice expression support.
1 parent 5b920c1 commit 3661126

File tree

7 files changed

+150
-0
lines changed

7 files changed

+150
-0
lines changed

Docs/reference/content/reference/driver/expressions.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,21 @@ p => p.FavoriteNumbers.Count();
788788
{ $size: '$FavoriteNumbers' }
789789
```
790790

791+
#### $slice
792+
793+
```csharp
794+
p => p.FavoriteNumbers.Take(2)
795+
```
796+
```json
797+
{ $slice: ['$FavoriteNumbers', 2] }
798+
```
799+
```csharp
800+
p => p.FavoriteNumbers.Skip(3).Take(2)
801+
```
802+
```json
803+
{ $slice: ['$FavoriteNumbers', 3, 2] }
804+
```
805+
791806
#### $sum
792807

793808
```csharp

src/MongoDB.Driver.Tests/Linq/Translators/AggregateProjectTranslatorTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,28 @@ public async Task Should_translate_subtract_3_numbers()
948948
result.Value.Result.Should().Be(-23);
949949
}
950950

951+
[Test]
952+
[RequiresServer(MinimumVersion = "3.1.7")]
953+
public async Task Should_translate_slice_with_2_arguments()
954+
{
955+
var result = await Project(x => new { Result = x.M.Take(2) });
956+
957+
result.Projection.Should().Be("{ Result: { \"$slice\": [\"$M\", 2] }, _id: 0 }");
958+
959+
result.Value.Result.Should().BeEquivalentTo(2, 4);
960+
}
961+
962+
[Test]
963+
[RequiresServer(MinimumVersion = "3.1.7")]
964+
public async Task Should_translate_slice_with_3_arguments()
965+
{
966+
var result = await Project(x => new { Result = x.M.Skip(1).Take(2) });
967+
968+
result.Projection.Should().Be("{ Result: { \"$slice\": [\"$M\", 1, 2] }, _id: 0 }");
969+
970+
result.Value.Result.Should().BeEquivalentTo(4, 5);
971+
}
972+
951973
[Test]
952974
[RequiresServer(MinimumVersion = "3.1.7")]
953975
public async Task Should_translate_sum()

src/MongoDB.Driver/Linq/Processors/EmbeddedPipeline/EmbeddedPipelineBinder.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ static EmbeddedPipelineBinder()
4141
infoBinder.Register(new MaxBinder(), MaxBinder.GetSupportedMethods());
4242
infoBinder.Register(new MinBinder(), MinBinder.GetSupportedMethods());
4343
infoBinder.Register(new SelectBinder(), SelectBinder.GetSupportedMethods());
44+
infoBinder.Register(new SkipBinder(), SkipBinder.GetSupportedMethods());
4445
infoBinder.Register(new SumBinder(), SumBinder.GetSupportedMethods());
46+
infoBinder.Register(new TakeBinder(), TakeBinder.GetSupportedMethods());
4547
infoBinder.Register(new ToArrayBinder(), ToArrayBinder.GetSupportedMethods());
4648
infoBinder.Register(new ToHashSetBinder(), ToHashSetBinder.GetSupportedMethods());
4749
infoBinder.Register(new ToListBinder(), ToListBinder.GetSupportedMethods());
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.EmbeddedPipeline.MethodCallBinders
23+
{
24+
internal sealed class SkipBinder : IMethodCallBinder<EmbeddedPipelineBindingContext>
25+
{
26+
public static IEnumerable<MethodInfo> GetSupportedMethods()
27+
{
28+
return MethodHelper.GetEnumerableAndQueryableMethodDefinitions("Skip");
29+
}
30+
31+
public Expression Bind(PipelineExpression pipeline, EmbeddedPipelineBindingContext bindingContext, MethodCallExpression node, IEnumerable<Expression> arguments)
32+
{
33+
return new PipelineExpression(
34+
new SkipExpression(
35+
pipeline.Source,
36+
arguments.Single()),
37+
pipeline.Projector);
38+
}
39+
}
40+
}
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.EmbeddedPipeline.MethodCallBinders
23+
{
24+
internal sealed class TakeBinder : IMethodCallBinder<EmbeddedPipelineBindingContext>
25+
{
26+
public static IEnumerable<MethodInfo> GetSupportedMethods()
27+
{
28+
return MethodHelper.GetEnumerableAndQueryableMethodDefinitions("Take");
29+
}
30+
31+
public Expression Bind(PipelineExpression pipeline, EmbeddedPipelineBindingContext bindingContext, MethodCallExpression node, IEnumerable<Expression> arguments)
32+
{
33+
return new PipelineExpression(
34+
new TakeExpression(
35+
pipeline.Source,
36+
arguments.Single()),
37+
pipeline.Projector);
38+
}
39+
}
40+
}

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ private BsonValue TranslateValue(Expression node)
118118
return TranslatePipeline((PipelineExpression)node);
119119
case ExtensionExpressionType.Select:
120120
return TranslateSelect((SelectExpression)node);
121+
case ExtensionExpressionType.Skip:
122+
return TranslateSkip((SkipExpression)node);
123+
case ExtensionExpressionType.Take:
124+
return TranslateTake((TakeExpression)node);
121125
case ExtensionExpressionType.Union:
122126
return TranslateUnion((UnionExpression)node);
123127
case ExtensionExpressionType.Where:
@@ -426,6 +430,31 @@ private BsonValue TranslateSelect(SelectExpression node)
426430
});
427431
}
428432

433+
private BsonValue TranslateSkip(SkipExpression node)
434+
{
435+
var message = "$project or $group only supports Skip when immediately followed by a Take.";
436+
throw new NotSupportedException(message);
437+
}
438+
439+
private BsonValue TranslateTake(TakeExpression node)
440+
{
441+
var arguments = new BsonArray();
442+
var skipNode = node.Source as SkipExpression;
443+
if (skipNode != null)
444+
{
445+
arguments.Add(TranslateValue(skipNode.Source));
446+
arguments.Add(TranslateValue(skipNode.Count));
447+
}
448+
else
449+
{
450+
arguments.Add(TranslateValue(node.Source));
451+
}
452+
453+
arguments.Add(TranslateValue(node.Count));
454+
455+
return new BsonDocument("$slice", arguments);
456+
}
457+
429458
private BsonValue TranslateUnion(UnionExpression node)
430459
{
431460
return new BsonDocument("$setUnion", new BsonArray(new[]

src/MongoDB.Driver/MongoDB.Driver.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@
148148
<Compile Include="Linq\Processors\EmbeddedPipeline\EmbeddedPipelineBindingContext.cs" />
149149
<Compile Include="Linq\Processors\EmbeddedPipeline\MethodCallBinders\AllBinder.cs" />
150150
<Compile Include="Linq\Processors\EmbeddedPipeline\MethodCallBinders\ConcatBinder.cs" />
151+
<Compile Include="Linq\Processors\EmbeddedPipeline\MethodCallBinders\SkipBinder.cs" />
152+
<Compile Include="Linq\Processors\EmbeddedPipeline\MethodCallBinders\TakeBinder.cs" />
151153
<Compile Include="Linq\Processors\EmbeddedPipeline\MethodCallBinders\ToHashSetBinder.cs" />
152154
<Compile Include="Linq\Processors\EmbeddedPipeline\MethodCallBinders\UnionBinder.cs" />
153155
<Compile Include="Linq\Processors\EmbeddedPipeline\MethodCallBinders\IntersectBinder.cs" />

0 commit comments

Comments
 (0)