@@ -486,6 +486,122 @@ public function test_hash_rows_with_different_order() : void
486486 );
487487 }
488488
489+ public function test_head () : void
490+ {
491+ $ rows = rows (
492+ row (int_entry ('id ' , 1 )),
493+ row (int_entry ('id ' , 2 )),
494+ row (int_entry ('id ' , 3 )),
495+ row (int_entry ('id ' , 4 )),
496+ row (int_entry ('id ' , 5 )),
497+ );
498+
499+ $ head = $ rows ->head (3 );
500+
501+ self ::assertCount (3 , $ head );
502+ self ::assertSame (1 , $ head [0 ]->valueOf ('id ' ));
503+ self ::assertSame (2 , $ head [1 ]->valueOf ('id ' ));
504+ self ::assertSame (3 , $ head [2 ]->valueOf ('id ' ));
505+ }
506+
507+ public function test_head_on_empty_rows () : void
508+ {
509+ $ head = (rows ())->head (5 );
510+
511+ self ::assertCount (0 , $ head );
512+ }
513+
514+ public function test_head_preserves_partitions () : void
515+ {
516+ $ rows = rows_partitioned (
517+ [
518+ row (int_entry ('id ' , 1 ), str_entry ('group ' , 'a ' )),
519+ row (int_entry ('id ' , 2 ), str_entry ('group ' , 'a ' )),
520+ row (int_entry ('id ' , 3 ), str_entry ('group ' , 'a ' )),
521+ ],
522+ [partition ('group ' , 'a ' )]
523+ );
524+
525+ $ head = $ rows ->head (2 );
526+
527+ self ::assertEquals (partitions (partition ('group ' , 'a ' )), $ head ->partitions ());
528+ self ::assertCount (2 , $ head );
529+ }
530+
531+ public function test_head_with_count_larger_than_available () : void
532+ {
533+ $ rows = rows (
534+ row (int_entry ('id ' , 1 )),
535+ row (int_entry ('id ' , 2 )),
536+ row (int_entry ('id ' , 3 )),
537+ );
538+
539+ $ head = $ rows ->head (10 );
540+
541+ self ::assertCount (3 , $ head );
542+ self ::assertSame (1 , $ head [0 ]->valueOf ('id ' ));
543+ self ::assertSame (2 , $ head [1 ]->valueOf ('id ' ));
544+ self ::assertSame (3 , $ head [2 ]->valueOf ('id ' ));
545+ }
546+
547+ public function test_head_with_negative_count () : void
548+ {
549+ $ this ->expectException (InvalidArgumentException::class);
550+ $ this ->expectExceptionMessage ('Count must be greater than or equal to 0 ' );
551+
552+ $ rows = rows (
553+ row (int_entry ('id ' , 1 )),
554+ row (int_entry ('id ' , 2 )),
555+ row (int_entry ('id ' , 3 )),
556+ );
557+
558+ $ rows ->head (-1 );
559+ }
560+
561+ public function test_head_with_zero_count () : void
562+ {
563+ $ rows = rows (
564+ row (int_entry ('id ' , 1 )),
565+ row (int_entry ('id ' , 2 )),
566+ row (int_entry ('id ' , 3 )),
567+ );
568+
569+ $ head = $ rows ->head (0 );
570+
571+ self ::assertCount (0 , $ head );
572+ }
573+
574+ public function test_last () : void
575+ {
576+ $ rows = rows (
577+ row (int_entry ('id ' , 1 )),
578+ row (int_entry ('id ' , 2 )),
579+ row (int_entry ('id ' , 3 )),
580+ );
581+
582+ $ lastRow = $ rows ->last ();
583+
584+ self ::assertNotNull ($ lastRow );
585+ self ::assertSame (3 , $ lastRow ->valueOf ('id ' ));
586+ }
587+
588+ public function test_last_on_empty_rows () : void
589+ {
590+ $ lastRow = (rows ())->last ();
591+
592+ self ::assertNull ($ lastRow );
593+ }
594+
595+ public function test_last_on_single_row () : void
596+ {
597+ $ rows = rows (row (int_entry ('id ' , 42 )));
598+
599+ $ lastRow = $ rows ->last ();
600+
601+ self ::assertNotNull ($ lastRow );
602+ self ::assertSame (42 , $ lastRow ->valueOf ('id ' ));
603+ }
604+
489605 public function test_merge_empty_rows_with_partitioned_rows () : void
490606 {
491607 $ rows1 = rows (row (int_entry ('id ' , 1 ), str_entry ('group ' , 'a ' )))->partitionBy (ref ('group ' ))[0 ];
@@ -1006,6 +1122,108 @@ public function test_sorts_entries_in_all_rows() : void
10061122 );
10071123 }
10081124
1125+ public function test_tail () : void
1126+ {
1127+ $ rows = rows (
1128+ row (int_entry ('id ' , 1 )),
1129+ row (int_entry ('id ' , 2 )),
1130+ row (int_entry ('id ' , 3 )),
1131+ row (int_entry ('id ' , 4 )),
1132+ row (int_entry ('id ' , 5 )),
1133+ );
1134+
1135+ $ tail = $ rows ->tail (3 );
1136+
1137+ self ::assertCount (3 , $ tail );
1138+ self ::assertSame (3 , $ tail [0 ]->valueOf ('id ' ));
1139+ self ::assertSame (4 , $ tail [1 ]->valueOf ('id ' ));
1140+ self ::assertSame (5 , $ tail [2 ]->valueOf ('id ' ));
1141+ }
1142+
1143+ public function test_tail_maintains_correct_order () : void
1144+ {
1145+ $ rows = rows (
1146+ row (int_entry ('id ' , 1 )),
1147+ row (int_entry ('id ' , 2 )),
1148+ row (int_entry ('id ' , 3 )),
1149+ row (int_entry ('id ' , 4 )),
1150+ row (int_entry ('id ' , 5 )),
1151+ );
1152+
1153+ $ tail = $ rows ->tail (2 );
1154+
1155+ self ::assertCount (2 , $ tail );
1156+ self ::assertSame (4 , $ tail [0 ]->valueOf ('id ' ));
1157+ self ::assertSame (5 , $ tail [1 ]->valueOf ('id ' ));
1158+ }
1159+
1160+ public function test_tail_on_empty_rows () : void
1161+ {
1162+ $ tail = (rows ())->tail (5 );
1163+
1164+ self ::assertCount (0 , $ tail );
1165+ }
1166+
1167+ public function test_tail_preserves_partitions () : void
1168+ {
1169+ $ rows = rows_partitioned (
1170+ [
1171+ row (int_entry ('id ' , 1 ), str_entry ('group ' , 'a ' )),
1172+ row (int_entry ('id ' , 2 ), str_entry ('group ' , 'a ' )),
1173+ row (int_entry ('id ' , 3 ), str_entry ('group ' , 'a ' )),
1174+ ],
1175+ [partition ('group ' , 'a ' )]
1176+ );
1177+
1178+ $ tail = $ rows ->tail (2 );
1179+
1180+ self ::assertEquals (partitions (partition ('group ' , 'a ' )), $ tail ->partitions ());
1181+ self ::assertCount (2 , $ tail );
1182+ }
1183+
1184+ public function test_tail_with_count_larger_than_available () : void
1185+ {
1186+ $ rows = rows (
1187+ row (int_entry ('id ' , 1 )),
1188+ row (int_entry ('id ' , 2 )),
1189+ row (int_entry ('id ' , 3 )),
1190+ );
1191+
1192+ $ tail = $ rows ->tail (10 );
1193+
1194+ self ::assertCount (3 , $ tail );
1195+ self ::assertSame (1 , $ tail [0 ]->valueOf ('id ' ));
1196+ self ::assertSame (2 , $ tail [1 ]->valueOf ('id ' ));
1197+ self ::assertSame (3 , $ tail [2 ]->valueOf ('id ' ));
1198+ }
1199+
1200+ public function test_tail_with_negative_count () : void
1201+ {
1202+ $ this ->expectException (InvalidArgumentException::class);
1203+ $ this ->expectExceptionMessage ('Count must be greater than or equal to 0 ' );
1204+
1205+ $ rows = rows (
1206+ row (int_entry ('id ' , 1 )),
1207+ row (int_entry ('id ' , 2 )),
1208+ row (int_entry ('id ' , 3 )),
1209+ );
1210+
1211+ $ rows ->tail (-1 );
1212+ }
1213+
1214+ public function test_tail_with_zero_count () : void
1215+ {
1216+ $ rows = rows (
1217+ row (int_entry ('id ' , 1 )),
1218+ row (int_entry ('id ' , 2 )),
1219+ row (int_entry ('id ' , 3 )),
1220+ );
1221+
1222+ $ tail = $ rows ->tail (0 );
1223+
1224+ self ::assertCount (0 , $ tail );
1225+ }
1226+
10091227 public function test_take () : void
10101228 {
10111229 $ rows = rows (
0 commit comments