Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve query and aggregator classes #2702

Open
wants to merge 2 commits into
base: 2.10.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions lib/Doctrine/ODM/MongoDB/Aggregation/Aggregation.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Iterator\CachingIterator;
use Doctrine\ODM\MongoDB\Iterator\HydratingIterator;
use Doctrine\ODM\MongoDB\Iterator\IterableResult;
use Doctrine\ODM\MongoDB\Iterator\Iterator;
use Doctrine\ODM\MongoDB\Iterator\UnrewindableIterator;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use Iterator as SPLIterator;
use IteratorAggregate;
use MongoDB\Collection;
use MongoDB\Driver\CursorInterface;

use function array_merge;
use function assert;

/** @phpstan-import-type PipelineExpression from Builder */
final class Aggregation implements IteratorAggregate
final class Aggregation implements IterableResult
{
/**
* @param array<string, mixed> $pipeline
Expand All @@ -30,6 +30,26 @@ public function __construct(private DocumentManager $dm, private ?ClassMetadata
{
}

public function execute(): Iterator
{
return $this->getIterator();
}

/**
* Execute the query and return the first result.
*
* @return array<string, mixed>|object|null
*/
public function getSingleResult(): mixed
{
$clone = clone $this;

// Limit the pipeline to a single result for efficiency
$this->pipeline[] = ['$limit' => 1];

return $clone->getIterator()->current() ?: null;
}

public function getIterator(): Iterator
{
// Force cursor to be used
Expand Down
5 changes: 4 additions & 1 deletion lib/Doctrine/ODM/MongoDB/Aggregation/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Doctrine\ODM\MongoDB\Aggregation\Stage\Sort;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Iterator\IterableResult;
use Doctrine\ODM\MongoDB\Iterator\Iterator;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use Doctrine\ODM\MongoDB\Persisters\DocumentPersister;
Expand Down Expand Up @@ -246,8 +247,10 @@ public function geoNear($x, $y = null): Stage\GeoNear
* Returns an aggregation object for the current pipeline
*
* @param array<string, mixed> $options
*
* @return Aggregation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted that this is necessary for static analysis and autocompletion, but we don't use it as return type to allow mocking more easily.

*/
public function getAggregation(array $options = []): Aggregation
public function getAggregation(array $options = []): IterableResult
{
$class = $this->hydrationClass ? $this->dm->getClassMetadata($this->hydrationClass) : null;

Expand Down
32 changes: 32 additions & 0 deletions lib/Doctrine/ODM/MongoDB/Iterator/IterableResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Doctrine\ODM\MongoDB\Iterator;

use BadMethodCallException;
use IteratorAggregate;

interface IterableResult extends IteratorAggregate
{
/**
* Executes the operation and returns a result if available; null otherwise
*/
public function execute(): mixed;

/**
* Executes the operation and returns a result iterator. If the operation
* did not yield an iterator, this method will throw
*
* @throws BadMethodCallException if the operation did not yield an iterator.
*/
public function getIterator(): Iterator;

/**
* Returns the first result only from the operation
*
* Note that the behaviour of fetching the first result is dependent on the
* implementation. A separate operation might be involved.
*/
public function getSingleResult(): mixed;
}
5 changes: 4 additions & 1 deletion lib/Doctrine/ODM/MongoDB/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use BadMethodCallException;
use Doctrine\ODM\MongoDB\Aggregation\Stage\Sort;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Iterator\IterableResult;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use GeoJson\Geometry\Geometry;
use GeoJson\Geometry\Point;
Expand Down Expand Up @@ -659,8 +660,10 @@ public function getNewObj(): array
* Gets the Query executable.
*
* @param array<string, mixed> $options
*
* @return Query
*/
public function getQuery(array $options = []): Query
public function getQuery(array $options = []): IterableResult
{
$documentPersister = $this->dm->getUnitOfWork()->getDocumentPersister($this->class->name);

Expand Down
10 changes: 5 additions & 5 deletions lib/Doctrine/ODM/MongoDB/Query/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Iterator\CachingIterator;
use Doctrine\ODM\MongoDB\Iterator\HydratingIterator;
use Doctrine\ODM\MongoDB\Iterator\IterableResult;
use Doctrine\ODM\MongoDB\Iterator\Iterator;
use Doctrine\ODM\MongoDB\Iterator\PrimingIterator;
use Doctrine\ODM\MongoDB\Iterator\UnrewindableIterator;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use Doctrine\ODM\MongoDB\MongoDBException;
use Doctrine\ODM\MongoDB\UnitOfWork;
use InvalidArgumentException;
use IteratorAggregate;
use MongoDB\Collection;
use MongoDB\DeleteResult;
use MongoDB\Driver\ReadPreference;
Expand Down Expand Up @@ -63,7 +63,7 @@
* @phpstan-import-type Hints from UnitOfWork
* @phpstan-import-type SortMeta from Sort
*/
final class Query implements IteratorAggregate
final class Query implements IterableResult
{
public const TYPE_FIND = 1;
public const TYPE_FIND_AND_UPDATE = 2;
Expand Down Expand Up @@ -200,7 +200,7 @@ public function debug(?string $name = null)
*
* @throws MongoDBException
*/
public function execute()
public function execute(): mixed
{
$results = $this->runQuery();

Expand Down Expand Up @@ -298,7 +298,7 @@ public function getQuery(): array
*
* @return array<string, mixed>|object|null
*/
public function getSingleResult()
public function getSingleResult(): mixed
{
$clonedQuery = clone $this;
$clonedQuery->query['limit'] = 1;
Expand Down Expand Up @@ -355,7 +355,7 @@ public function setRewindable(bool $rewindable = true): void
/**
* Execute the query and return its results as an array.
*
* @see IteratorAggregate::toArray()
* @see Iterator::toArray()
*
* @return mixed[]
*/
Expand Down