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 ;
@@ -292,13 +294,9 @@ public function dump(mixed ...$args)
292294 }
293295
294296 /**
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[]>
297+ * @return StageInterface[]
300298 */
301- public function toMql (): array
299+ protected function getPipeline (): array
302300 {
303301 $ columns = $ this ->columns ?? [];
304302
@@ -373,33 +371,33 @@ public function toMql(): array
373371 // Build the aggregation pipeline.
374372 $ pipeline = [];
375373 if ($ wheres ) {
376- $ pipeline [] = [ ' $match ' => $ wheres] ;
374+ $ pipeline [] = new MatchStage (... $ wheres) ;
377375 }
378376
379377 // apply unwinds for subdocument array aggregation
380378 foreach ($ unwinds as $ unwind ) {
381- $ pipeline [] = [ ' $unwind ' => ' $ ' . $ unwind] ;
379+ $ pipeline [] = new UnwindStage ( $ unwind) ;
382380 }
383381
384382 if ($ group ) {
385- $ pipeline [] = [ ' $group ' => $ group] ;
383+ $ pipeline [] = new GroupStage (... $ group) ;
386384 }
387385
388386 // Apply order and limit
389387 if ($ this ->orders ) {
390- $ pipeline [] = [ ' $sort ' => $ this ->orders ] ;
388+ $ pipeline [] = new SortStage ( $ this ->orders ) ;
391389 }
392390
393391 if ($ this ->offset ) {
394- $ pipeline [] = [ ' $skip ' => $ this ->offset ] ;
392+ $ pipeline [] = new SkipStage ( $ this ->offset ) ;
395393 }
396394
397395 if ($ this ->limit ) {
398- $ pipeline [] = [ ' $limit ' => $ this ->limit ] ;
396+ $ pipeline [] = new LimitStage ( $ this ->limit ) ;
399397 }
400398
401399 if ($ this ->projections ) {
402- $ pipeline [] = [ ' $project ' => $ this ->projections ] ;
400+ $ pipeline [] = new ProjectStage (... $ this ->projections ) ;
403401 }
404402
405403 $ options = [
@@ -457,6 +455,22 @@ public function toMql(): array
457455 $ pipeline [] = new ProjectStage (...$ projection );
458456 }
459457
458+ return $ pipeline ;
459+ }
460+
461+ /**
462+ * Return the MongoDB query to be run in the form of an element array like ['method' => [arguments]].
463+ *
464+ * Example: ['find' => [['name' => 'John Doe'], ['projection' => ['birthday' => 1]]]]
465+ *
466+ * @return array<string, mixed[]>
467+ */
468+ public function toMql (): array
469+ {
470+ $ pipeline = $ this ->getPipeline ();
471+ $ encoder = new BuilderEncoder ();
472+ $ pipeline = $ encoder ->encode (new Pipeline (...$ pipeline ));
473+
460474 $ options = ['typeMap ' => ['root ' => 'array ' , 'document ' => 'array ' ]];
461475
462476 if ($ this ->timeout ) {
@@ -468,12 +482,8 @@ public function toMql(): array
468482 }
469483
470484 $ options = array_merge ($ options , $ this ->options );
471-
472485 $ options = $ this ->inheritConnectionOptions ($ options );
473486
474- $ encoder = new BuilderEncoder ();
475- $ pipeline = $ encoder ->encode (new Pipeline (...$ pipeline ));
476-
477487 return ['aggregate ' => [$ pipeline , $ options ]];
478488 }
479489
@@ -554,9 +564,16 @@ public function generateCacheKey()
554564 return md5 (serialize (array_values ($ key )));
555565 }
556566
557- /** @inheritdoc */
558- public function aggregate ($ function , $ columns = [])
567+ /**
568+ * @return self|PipelineBuilder
569+ * @psalm-return $function === null ? PipelineBuilder : self
570+ */
571+ public function aggregate ($ function = null , $ columns = [])
559572 {
573+ if ($ function === null ) {
574+ return new PipelineBuilder ($ this ->getPipeline ());
575+ }
576+
560577 $ this ->aggregate = [
561578 'function ' => $ function ,
562579 'columns ' => $ columns ,
0 commit comments