24
24
using MongoDB . Bson . Serialization . Serializers ;
25
25
using MongoDB . Driver . Core . Misc ;
26
26
using MongoDB . Driver . GeoJsonObjectModel ;
27
- using MongoDB . Driver . Linq ;
28
- using MongoDB . Driver . Linq . Linq3Implementation . Ast . Expressions ;
29
27
using MongoDB . Driver . Linq . Linq3Implementation . Ast . Filters ;
30
28
using MongoDB . Driver . Linq . Linq3Implementation . Ast . Optimizers ;
29
+ using MongoDB . Driver . Linq . Linq3Implementation . Misc ;
31
30
using MongoDB . Driver . Linq . Linq3Implementation . Translators ;
32
31
33
32
namespace MongoDB . Driver
@@ -473,6 +472,30 @@ public FilterDefinition<TDocument> BitsAnySet(Expression<Func<TDocument, object>
473
472
return BitsAnySet ( new ExpressionFieldDefinition < TDocument > ( field ) , bitmask ) ;
474
473
}
475
474
475
+ /// <summary>
476
+ /// Creates an element match filter for an array value.
477
+ /// </summary>
478
+ /// <remarks>TDocument must implement IEnumerable{TITem} when using this overload of ElemMatch.</remarks>
479
+ /// <param name="impliedElementFilter">The implied element filter.</param>
480
+ /// <returns>An element match filter.</returns>
481
+ public FilterDefinition < TDocument > ElemMatch < TItem > ( FilterDefinition < TItem > impliedElementFilter )
482
+ // where TDocument : IEnumerable<TItem> (can only be checked at runtime)
483
+ {
484
+ return new ElementMatchFilterDefinition < TDocument , TItem > ( impliedElementFilter ) ;
485
+ }
486
+
487
+ /// <summary>
488
+ /// Creates an element match filter for an array value.
489
+ /// </summary>
490
+ /// <remarks>TDocument must implement IEnumerable{TITem} when using this overload of ElemMatch.</remarks>
491
+ /// <param name="impliedElementFilter">The implied element filter.</param>
492
+ /// <returns>An element match filter.</returns>
493
+ public FilterDefinition < TDocument > ElemMatch < TItem > ( Expression < Func < TItem , bool > > impliedElementFilter )
494
+ // where TDocument : IEnumerable<TItem> (can only be checked at runtime)
495
+ {
496
+ return ElemMatch ( new ExpressionFilterDefinition < TItem > ( impliedElementFilter ) ) ;
497
+ }
498
+
476
499
/// <summary>
477
500
/// Creates an element match filter for an array field.
478
501
/// </summary>
@@ -481,6 +504,7 @@ public FilterDefinition<TDocument> BitsAnySet(Expression<Func<TDocument, object>
481
504
/// <param name="filter">The filter.</param>
482
505
/// <returns>An element match filter.</returns>
483
506
public FilterDefinition < TDocument > ElemMatch < TItem > ( FieldDefinition < TDocument > field , FilterDefinition < TItem > filter )
507
+ // where TField : IEnumerable<TItem> (can only be checked at runtime)
484
508
{
485
509
return new ElementMatchFilterDefinition < TDocument , TItem > ( field , filter ) ;
486
510
}
@@ -493,6 +517,7 @@ public FilterDefinition<TDocument> ElemMatch<TItem>(FieldDefinition<TDocument> f
493
517
/// <param name="filter">The filter.</param>
494
518
/// <returns>An element match filter.</returns>
495
519
public FilterDefinition < TDocument > ElemMatch < TItem > ( Expression < Func < TDocument , IEnumerable < TItem > > > field , FilterDefinition < TItem > filter )
520
+ // where TField : IEnumerable<TItem> (can only be checked at runtime)
496
521
{
497
522
return ElemMatch ( new ExpressionFieldDefinition < TDocument > ( field ) , filter ) ;
498
523
}
@@ -1852,24 +1877,49 @@ internal sealed class ElementMatchFilterDefinition<TDocument, TItem> : FilterDef
1852
1877
private readonly FieldDefinition < TDocument > _field ;
1853
1878
private readonly FilterDefinition < TItem > _filter ;
1854
1879
1880
+ public ElementMatchFilterDefinition ( FilterDefinition < TItem > filter )
1881
+ // where TDocument : IEnumerable<TItem> (can only be checked at runtime)
1882
+ {
1883
+ _filter = filter ;
1884
+
1885
+ // TODO: CSHARP-5517 validate type constraint
1886
+ }
1887
+
1855
1888
public ElementMatchFilterDefinition ( FieldDefinition < TDocument > field , FilterDefinition < TItem > filter )
1889
+ // where TField : IEnumerable<TItem> (checked in Render)
1856
1890
{
1857
1891
_field = Ensure . IsNotNull ( field , nameof ( field ) ) ;
1858
1892
_filter = filter ;
1893
+
1894
+ // TODO: CSHARP-5517 validate type constraint
1859
1895
}
1860
1896
1861
1897
public override BsonDocument Render ( RenderArgs < TDocument > args )
1862
1898
{
1863
- var renderedField = _field . Render ( args ) ;
1899
+ string fieldName = null ;
1900
+ IBsonSerializer enumerableSerializer ;
1901
+
1902
+ if ( _field == null )
1903
+ {
1904
+ enumerableSerializer = args . DocumentSerializer ; // note that TDocument : IEnumerable<TItem>
1905
+ }
1906
+ else
1907
+ {
1908
+ var renderedField = _field . Render ( args ) ;
1909
+ fieldName = renderedField . FieldName ;
1910
+ enumerableSerializer = renderedField . FieldSerializer ; // note that TField : IEnumerable<TItem>
1911
+ }
1864
1912
1865
1913
IBsonSerializer < TItem > itemSerializer ;
1866
- if ( renderedField . FieldSerializer != null )
1914
+ if ( enumerableSerializer != null )
1867
1915
{
1868
- var arraySerializer = renderedField . FieldSerializer as IBsonArraySerializer ;
1916
+ var arraySerializer = enumerableSerializer as IBsonArraySerializer ;
1869
1917
BsonSerializationInfo itemSerializationInfo ;
1870
1918
if ( arraySerializer == null || ! arraySerializer . TryGetItemSerializationInfo ( out itemSerializationInfo ) )
1871
1919
{
1872
- var message = string . Format ( "The serializer for field '{0}' must implement IBsonArraySerializer and provide item serialization info." , renderedField . FieldName ) ;
1920
+ var message = fieldName == null ?
1921
+ $ "The serializer '{ enumerableSerializer . GetType ( ) } ' must implement IBsonArraySerializer and provide item serialization info." :
1922
+ $ "The serializer for field '{ fieldName } ' must implement IBsonArraySerializer and provide item serialization info.";
1873
1923
throw new InvalidOperationException ( message ) ;
1874
1924
}
1875
1925
itemSerializer = ( IBsonSerializer < TItem > ) itemSerializationInfo . Serializer ;
@@ -1880,8 +1930,11 @@ public override BsonDocument Render(RenderArgs<TDocument> args)
1880
1930
}
1881
1931
1882
1932
var renderedFilter = _filter . Render ( args . WithNewDocumentType ( itemSerializer ) with { RenderForElemMatch = true } ) ;
1933
+ var renderedElemMatchOperation = new BsonDocument ( "$elemMatch" , renderedFilter ) ;
1883
1934
1884
- return new BsonDocument ( renderedField . FieldName , new BsonDocument ( "$elemMatch" , renderedFilter ) ) ;
1935
+ return fieldName == null ?
1936
+ renderedElemMatchOperation :
1937
+ new BsonDocument ( fieldName , renderedElemMatchOperation ) ;
1885
1938
}
1886
1939
}
1887
1940
0 commit comments