@@ -256,6 +256,22 @@ public static ProjectionDefinition<TDocument> SearchMeta<TDocument>(
256256 return builder . Combine ( projection , builder . SearchMeta ( field ) ) ;
257257 }
258258
259+ /// <summary>
260+ /// Combines an existing projection with an array slice projection.
261+ /// </summary>
262+ /// <typeparam name="TDocument">The type of the document.</typeparam>
263+ /// <param name="projection">The projection.</param>
264+ /// <param name="field">The field.</param>
265+ /// <param name="limit">The limit.</param>
266+ /// <returns>
267+ /// A combined projection.
268+ /// </returns>
269+ public static ProjectionDefinition < TDocument > Slice < TDocument > ( this ProjectionDefinition < TDocument > projection , FieldDefinition < TDocument > field , int limit )
270+ {
271+ var builder = Builders < TDocument > . Projection ;
272+ return builder . Combine ( projection , builder . Slice ( field , limit ) ) ;
273+ }
274+
259275 /// <summary>
260276 /// Combines an existing projection with an array slice projection.
261277 /// </summary>
@@ -267,12 +283,28 @@ public static ProjectionDefinition<TDocument> SearchMeta<TDocument>(
267283 /// <returns>
268284 /// A combined projection.
269285 /// </returns>
270- public static ProjectionDefinition < TDocument > Slice < TDocument > ( this ProjectionDefinition < TDocument > projection , FieldDefinition < TDocument > field , int skip , int ? limit = null )
286+ public static ProjectionDefinition < TDocument > Slice < TDocument > ( this ProjectionDefinition < TDocument > projection , FieldDefinition < TDocument > field , int skip , int limit )
271287 {
272288 var builder = Builders < TDocument > . Projection ;
273289 return builder . Combine ( projection , builder . Slice ( field , skip , limit ) ) ;
274290 }
275291
292+ /// <summary>
293+ /// Combines an existing projection with an array slice projection.
294+ /// </summary>
295+ /// <typeparam name="TDocument">The type of the document.</typeparam>
296+ /// <param name="projection">The projection.</param>
297+ /// <param name="field">The field.</param>
298+ /// <param name="limit">The limit.</param>
299+ /// <returns>
300+ /// A combined projection.
301+ /// </returns>
302+ public static ProjectionDefinition < TDocument > Slice < TDocument > ( this ProjectionDefinition < TDocument > projection , Expression < Func < TDocument , object > > field , int limit )
303+ {
304+ var builder = Builders < TDocument > . Projection ;
305+ return builder . Combine ( projection , builder . Slice ( field , limit ) ) ;
306+ }
307+
276308 /// <summary>
277309 /// Combines an existing projection with an array slice projection.
278310 /// </summary>
@@ -284,7 +316,7 @@ public static ProjectionDefinition<TDocument> Slice<TDocument>(this ProjectionDe
284316 /// <returns>
285317 /// A combined projection.
286318 /// </returns>
287- public static ProjectionDefinition < TDocument > Slice < TDocument > ( this ProjectionDefinition < TDocument > projection , Expression < Func < TDocument , object > > field , int skip , int ? limit = null )
319+ public static ProjectionDefinition < TDocument > Slice < TDocument > ( this ProjectionDefinition < TDocument > projection , Expression < Func < TDocument , object > > field , int skip , int limit )
288320 {
289321 var builder = Builders < TDocument > . Projection ;
290322 return builder . Combine ( projection , builder . Slice ( field , skip , limit ) ) ;
@@ -520,6 +552,19 @@ public ProjectionDefinition<TSource> SearchMeta(Expression<Func<TSource, object>
520552 return SearchMeta ( new ExpressionFieldDefinition < TSource > ( field ) ) ;
521553 }
522554
555+ /// <summary>
556+ /// Creates an array slice projection.
557+ /// </summary>
558+ /// <param name="field">The field.</param>
559+ /// <param name="limit">The limit.</param>
560+ /// <returns>
561+ /// An array slice projection.
562+ /// </returns>
563+ public ProjectionDefinition < TSource > Slice ( FieldDefinition < TSource > field , int limit )
564+ {
565+ return new SliceProjectionDefinition < TSource > ( field , limit ) ;
566+ }
567+
523568 /// <summary>
524569 /// Creates an array slice projection.
525570 /// </summary>
@@ -529,10 +574,22 @@ public ProjectionDefinition<TSource> SearchMeta(Expression<Func<TSource, object>
529574 /// <returns>
530575 /// An array slice projection.
531576 /// </returns>
532- public ProjectionDefinition < TSource > Slice ( FieldDefinition < TSource > field , int skip , int ? limit = null )
577+ public ProjectionDefinition < TSource > Slice ( FieldDefinition < TSource > field , int skip , int limit )
533578 {
534- var value = limit . HasValue ? ( BsonValue ) new BsonArray { skip , limit . Value } : skip ;
535- return new SingleFieldProjectionDefinition < TSource > ( field , new BsonDocument ( "$slice" , value ) ) ;
579+ return new SliceProjectionDefinition < TSource > ( field , skip , limit ) ;
580+ }
581+
582+ /// <summary>
583+ /// Creates an array slice projection.
584+ /// </summary>
585+ /// <param name="field">The field.</param>
586+ /// <param name="limit">The limit.</param>
587+ /// <returns>
588+ /// An array slice projection.
589+ /// </returns>
590+ public ProjectionDefinition < TSource > Slice ( Expression < Func < TSource , object > > field , int limit )
591+ {
592+ return Slice ( new ExpressionFieldDefinition < TSource > ( field ) , limit ) ;
536593 }
537594
538595 /// <summary>
@@ -544,7 +601,7 @@ public ProjectionDefinition<TSource> Slice(FieldDefinition<TSource> field, int s
544601 /// <returns>
545602 /// An array slice projection.
546603 /// </returns>
547- public ProjectionDefinition < TSource > Slice ( Expression < Func < TSource , object > > field , int skip , int ? limit = null )
604+ public ProjectionDefinition < TSource > Slice ( Expression < Func < TSource , object > > field , int skip , int limit )
548605 {
549606 return Slice ( new ExpressionFieldDefinition < TSource > ( field ) , skip , limit ) ;
550607 }
@@ -560,12 +617,22 @@ public CombinedProjectionDefinition(IEnumerable<ProjectionDefinition<TSource>> p
560617 }
561618
562619 public override BsonDocument Render ( IBsonSerializer < TSource > sourceSerializer , IBsonSerializerRegistry serializerRegistry , LinqProvider linqProvider )
620+ {
621+ return Render ( projection => projection . Render ( sourceSerializer , serializerRegistry , linqProvider ) ) ;
622+ }
623+
624+ internal override BsonDocument RenderForFind ( IBsonSerializer < TSource > sourceSerializer , IBsonSerializerRegistry serializerRegistry , LinqProvider linqProvider )
625+ {
626+ return Render ( projection => projection . RenderForFind ( sourceSerializer , serializerRegistry , linqProvider ) ) ;
627+ }
628+
629+ private BsonDocument Render ( Func < ProjectionDefinition < TSource > , BsonDocument > renderer )
563630 {
564631 var document = new BsonDocument ( ) ;
565632
566633 foreach ( var projection in _projections )
567634 {
568- var renderedProjection = projection . Render ( sourceSerializer , serializerRegistry , linqProvider ) ;
635+ var renderedProjection = renderer ( projection ) ;
569636
570637 foreach ( var element in renderedProjection . Elements )
571638 {
@@ -650,4 +717,53 @@ public override BsonDocument Render(IBsonSerializer<TSource> sourceSerializer, I
650717 return new BsonDocument ( renderedField . FieldName , _value ) ;
651718 }
652719 }
720+
721+ internal sealed class SliceProjectionDefinition < TSource > : ProjectionDefinition < TSource >
722+ {
723+ private readonly FieldDefinition < TSource > _field ;
724+ private readonly BsonValue _limit ;
725+ private readonly BsonValue _skip ;
726+
727+ public SliceProjectionDefinition ( FieldDefinition < TSource > field , BsonValue limit )
728+ {
729+ _field = Ensure . IsNotNull ( field , nameof ( field ) ) ;
730+ _limit = Ensure . IsNotNull ( limit , nameof ( limit ) ) ;
731+ }
732+
733+ public SliceProjectionDefinition ( FieldDefinition < TSource > field , BsonValue skip , BsonValue limit )
734+ {
735+ _field = Ensure . IsNotNull ( field , nameof ( field ) ) ;
736+ _skip = skip ; // can be null
737+ _limit = Ensure . IsNotNull ( limit , nameof ( limit ) ) ;
738+ }
739+
740+ public override BsonDocument Render ( IBsonSerializer < TSource > sourceSerializer , IBsonSerializerRegistry serializerRegistry , LinqProvider linqProvider )
741+ {
742+ return Render ( sourceSerializer , serializerRegistry , linqProvider , RenderArgs ) ;
743+ }
744+
745+ internal override BsonDocument RenderForFind ( IBsonSerializer < TSource > sourceSerializer , IBsonSerializerRegistry serializerRegistry , LinqProvider linqProvider )
746+ {
747+ return Render ( sourceSerializer , serializerRegistry , linqProvider , RenderArgsForFind ) ;
748+ }
749+
750+ private BsonDocument Render ( IBsonSerializer < TSource > sourceSerializer , IBsonSerializerRegistry serializerRegistry , LinqProvider linqProvider , Func < string , BsonValue > argsRenderer )
751+ {
752+ var renderedField = _field . Render ( sourceSerializer , serializerRegistry , linqProvider ) ;
753+ var sliceArgs = argsRenderer ( renderedField . FieldName ) ;
754+ return new BsonDocument ( renderedField . FieldName , new BsonDocument ( "$slice" , sliceArgs ) ) ;
755+ }
756+
757+ private BsonValue RenderArgs ( string fieldName )
758+ {
759+ return _skip == null ?
760+ new BsonArray { "$" + fieldName , _limit } :
761+ new BsonArray { "$" + fieldName , _skip , _limit } ;
762+ }
763+
764+ private BsonValue RenderArgsForFind ( string fieldName )
765+ {
766+ return _skip == null ? _limit : new BsonArray { _skip , _limit } ;
767+ }
768+ }
653769}
0 commit comments