3232use MongoDB \Builder \Stage \ReplaceRootStage ;
3333use MongoDB \Builder \Stage \SkipStage ;
3434use MongoDB \Builder \Stage \SortStage ;
35+ use MongoDB \Builder \Stage \UnwindStage ;
36+ use MongoDB \Builder \Type \StageInterface ;
3537use MongoDB \Builder \Variable ;
3638use MongoDB \Driver \Cursor ;
3739use Override ;
@@ -291,14 +293,8 @@ public function dump(mixed ...$args)
291293 return $ this ;
292294 }
293295
294- /**
295- * Return the MongoDB query to be run in the form of an element array like ['method' => [arguments]].
296- *
297- * Example: ['find' => [['name' => 'John Doe'], ['projection' => ['birthday' => 1]]]]
298- *
299- * @return array<string, mixed[]>
300- */
301- public function toMql (): array
296+ /** @return StageInterface[] */
297+ protected function getPipeline (): array
302298 {
303299 $ columns = $ this ->columns ?? [];
304300
@@ -373,33 +369,33 @@ public function toMql(): array
373369 // Build the aggregation pipeline.
374370 $ pipeline = [];
375371 if ($ wheres ) {
376- $ pipeline [] = [ ' $match ' => $ wheres] ;
372+ $ pipeline [] = new MatchStage (... $ wheres) ;
377373 }
378374
379375 // apply unwinds for subdocument array aggregation
380376 foreach ($ unwinds as $ unwind ) {
381- $ pipeline [] = [ ' $unwind ' => ' $ ' . $ unwind] ;
377+ $ pipeline [] = new UnwindStage ( $ unwind) ;
382378 }
383379
384380 if ($ group ) {
385- $ pipeline [] = [ ' $group ' => $ group] ;
381+ $ pipeline [] = new GroupStage (... $ group) ;
386382 }
387383
388384 // Apply order and limit
389385 if ($ this ->orders ) {
390- $ pipeline [] = [ ' $sort ' => $ this ->orders ] ;
386+ $ pipeline [] = new SortStage ( $ this ->orders ) ;
391387 }
392388
393389 if ($ this ->offset ) {
394- $ pipeline [] = [ ' $skip ' => $ this ->offset ] ;
390+ $ pipeline [] = new SkipStage ( $ this ->offset ) ;
395391 }
396392
397393 if ($ this ->limit ) {
398- $ pipeline [] = [ ' $limit ' => $ this ->limit ] ;
394+ $ pipeline [] = new LimitStage ( $ this ->limit ) ;
399395 }
400396
401397 if ($ this ->projections ) {
402- $ pipeline [] = [ ' $project ' => $ this ->projections ] ;
398+ $ pipeline [] = new ProjectStage (... $ this ->projections ) ;
403399 }
404400
405401 $ options = [
@@ -457,6 +453,22 @@ public function toMql(): array
457453 $ pipeline [] = new ProjectStage (...$ projection );
458454 }
459455
456+ return $ pipeline ;
457+ }
458+
459+ /**
460+ * Return the MongoDB query to be run in the form of an element array like ['method' => [arguments]].
461+ *
462+ * Example: ['find' => [['name' => 'John Doe'], ['projection' => ['birthday' => 1]]]]
463+ *
464+ * @return array<string, mixed[]>
465+ */
466+ public function toMql (): array
467+ {
468+ $ pipeline = $ this ->getPipeline ();
469+ $ encoder = new BuilderEncoder ();
470+ $ pipeline = $ encoder ->encode (new Pipeline (...$ pipeline ));
471+
460472 $ options = ['typeMap ' => ['root ' => 'array ' , 'document ' => 'array ' ]];
461473
462474 if ($ this ->timeout ) {
@@ -468,12 +480,8 @@ public function toMql(): array
468480 }
469481
470482 $ options = array_merge ($ options , $ this ->options );
471-
472483 $ options = $ this ->inheritConnectionOptions ($ options );
473484
474- $ encoder = new BuilderEncoder ();
475- $ pipeline = $ encoder ->encode (new Pipeline (...$ pipeline ));
476-
477485 return ['aggregate ' => [$ pipeline , $ options ]];
478486 }
479487
@@ -554,9 +562,16 @@ public function generateCacheKey()
554562 return md5 (serialize (array_values ($ key )));
555563 }
556564
557- /** @inheritdoc */
558- public function aggregate ($ function , $ columns = [])
565+ /**
566+ * @return self|PipelineBuilder
567+ * @psalm-return $function === null ? PipelineBuilder : self
568+ */
569+ public function aggregate ($ function = null , $ columns = [])
559570 {
571+ if ($ function === null ) {
572+ return new PipelineBuilder ($ this ->getPipeline ());
573+ }
574+
560575 $ this ->aggregate = [
561576 'function ' => $ function ,
562577 'columns ' => $ columns ,
0 commit comments