@@ -125,13 +125,13 @@ def test_filter_in_returns_self(self):
125125 qb = QueryBuilder ("account" )
126126 self .assertIs (qb .filter_in ("statecode" , [0 , 1 ]), qb )
127127
128- def test_filter_in_accepts_set (self ):
128+ def test_filter_in_with_set (self ):
129129 qb = QueryBuilder ("account" ).filter_in ("statecode" , {0 , 1 })
130130 result = qb .build ()["filter" ]
131131 self .assertIn ("Microsoft.Dynamics.CRM.In" , result )
132132 self .assertIn ("statecode" , result )
133133
134- def test_filter_in_accepts_tuple (self ):
134+ def test_filter_in_with_tuple (self ):
135135 qb = QueryBuilder ("account" ).filter_in ("statecode" , (0 , 1 , 2 ))
136136 self .assertEqual (
137137 qb .build ()["filter" ],
@@ -297,6 +297,19 @@ def test_filter_not_in_combined_with_other_filters(self):
297297 'statecode eq 0 and Microsoft.Dynamics.CRM.NotIn(PropertyName=\' priority\' ,PropertyValues=["1","2"])' ,
298298 )
299299
300+ def test_filter_not_in_with_set (self ):
301+ qb = QueryBuilder ("account" ).filter_not_in ("statecode" , {2 , 3 })
302+ result = qb .build ()["filter" ]
303+ self .assertIn ("Microsoft.Dynamics.CRM.NotIn" , result )
304+ self .assertIn ("statecode" , result )
305+
306+ def test_filter_not_in_with_tuple (self ):
307+ qb = QueryBuilder ("account" ).filter_not_in ("statecode" , (2 , 3 ))
308+ self .assertEqual (
309+ qb .build ()["filter" ],
310+ 'Microsoft.Dynamics.CRM.NotIn(PropertyName=\' statecode\' ,PropertyValues=["2","3"])' ,
311+ )
312+
300313
301314class TestFilterNotBetween (unittest .TestCase ):
302315 """Tests for the filter_not_between() method."""
@@ -506,6 +519,38 @@ def test_expand_mixed_strings_and_options(self):
506519 ["primarycontactid" , "Account_Tasks($select=subject)" ],
507520 )
508521
522+ def test_expand_option_chained_select_accumulates (self ):
523+ """Calling select() multiple times should accumulate columns."""
524+ from PowerPlatform .Dataverse .models .query_builder import ExpandOption
525+
526+ opt = ExpandOption ("Account_Tasks" ).select ("subject" ).select ("createdon" )
527+ self .assertEqual (
528+ opt .to_odata (),
529+ "Account_Tasks($select=subject,createdon)" ,
530+ )
531+
532+ def test_expand_option_multiple_order_by (self ):
533+ """Calling order_by() multiple times should accumulate sort clauses."""
534+ from PowerPlatform .Dataverse .models .query_builder import ExpandOption
535+
536+ opt = (
537+ ExpandOption ("Account_Tasks" ).select ("subject" ).order_by ("priority" , descending = True ).order_by ("createdon" )
538+ )
539+ self .assertEqual (
540+ opt .to_odata (),
541+ "Account_Tasks($select=subject;$orderby=priority desc,createdon)" ,
542+ )
543+
544+ def test_expand_option_filter_last_wins (self ):
545+ """Calling filter() multiple times should use the last value."""
546+ from PowerPlatform .Dataverse .models .query_builder import ExpandOption
547+
548+ opt = ExpandOption ("Account_Tasks" ).filter ("statecode eq 0" ).filter ("contains(subject,'Task')" )
549+ self .assertEqual (
550+ opt .to_odata (),
551+ "Account_Tasks($filter=contains(subject,'Task'))" ,
552+ )
553+
509554
510555class TestCount (unittest .TestCase ):
511556 """Tests for the count() method."""
@@ -556,6 +601,19 @@ def test_include_annotations_returns_self(self):
556601 qb = QueryBuilder ("account" )
557602 self .assertIs (qb .include_annotations (), qb )
558603
604+ def test_include_annotations_overrides_formatted_values (self ):
605+ """Last annotation call should win."""
606+ qb = QueryBuilder ("account" ).include_formatted_values ().include_annotations ("*" )
607+ self .assertEqual (qb .build ()["include_annotations" ], "*" )
608+
609+ def test_include_formatted_values_overrides_annotations (self ):
610+ """Last annotation call should win (reverse order)."""
611+ qb = QueryBuilder ("account" ).include_annotations ("*" ).include_formatted_values ()
612+ self .assertEqual (
613+ qb .build ()["include_annotations" ],
614+ "OData.Community.Display.V1.FormattedValue" ,
615+ )
616+
559617
560618class TestBuild (unittest .TestCase ):
561619 """Tests for the build() method."""
@@ -860,6 +918,31 @@ def test_to_dataframe_returns_dataframe(self):
860918 self .assertEqual (len (result ), 2 )
861919 self .assertListEqual (list (result .columns ), ["name" , "revenue" ])
862920
921+ def test_to_dataframe_forwards_count_and_annotations (self ):
922+ """to_dataframe() should forward count and include_annotations when set."""
923+ import pandas as pd
924+
925+ mock_query_ops = MagicMock ()
926+ mock_client = mock_query_ops ._client
927+ mock_client .dataframe .get .return_value = pd .DataFrame ()
928+
929+ qb = QueryBuilder ("account" )
930+ qb ._query_ops = mock_query_ops
931+ qb .count ().include_formatted_values ()
932+ qb .to_dataframe ()
933+
934+ mock_client .dataframe .get .assert_called_once_with (
935+ "account" ,
936+ select = None ,
937+ filter = None ,
938+ orderby = None ,
939+ top = None ,
940+ expand = None ,
941+ page_size = None ,
942+ count = True ,
943+ include_annotations = "OData.Community.Display.V1.FormattedValue" ,
944+ )
945+
863946
864947if __name__ == "__main__" :
865948 unittest .main ()
0 commit comments