Skip to content

Commit

Permalink
Static analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
GromNaN committed Sep 29, 2023
1 parent 1084b1a commit a3eef39
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 19 deletions.
6 changes: 5 additions & 1 deletion psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
<code>$query</code>
<code>$result</code>
<code>$result[]</code>
<code>$stage</code>
<code>$val</code>
<code>$val</code>
</MixedAssignment>
Expand All @@ -83,6 +82,11 @@
<code><![CDATA[$mergedDriver['platform']]]></code>
</MixedAssignment>
</file>
<file src="src/Codec/EncodeIfSupported.php">
<InvalidReturnType>
<code>($value is NativeType ? BSONType : $value)</code>
</InvalidReturnType>
</file>
<file src="src/Collection.php">
<MixedArgumentTypeCoercion>
<code>$options</code>
Expand Down
2 changes: 1 addition & 1 deletion src/Builder/BuilderEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function encode($value): stdClass|array|string
// A pipeline is encoded as a list of stages
if ($value instanceof Pipeline) {
$encoded = [];
foreach ($value->stages as $stage) {
foreach ($value->getIterator() as $stage) {
$encoded[] = $this->encodeIfSupported($stage);
}

Expand Down
30 changes: 24 additions & 6 deletions src/Builder/Pipeline.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,40 @@

namespace MongoDB\Builder;

use ArrayIterator;
use IteratorAggregate;
use MongoDB\Builder\Stage\StageInterface;
use MongoDB\Exception\InvalidArgumentException;
use Traversable;

use function array_is_list;
use function array_merge;

class Pipeline
/** @template-implements IteratorAggregate<StageInterface> */
class Pipeline implements IteratorAggregate
{
public array $stages;
/** @var StageInterface[] */
private array $stages = [];

public function __construct(
StageInterface ...$stages
) {
public function __construct(StageInterface ...$stages)
{
$this->add(...$stages);
}

/** @return $this */
public function add(StageInterface ...$stages): static
{
if (! array_is_list($stages)) {
throw new InvalidArgumentException('Expected $stages argument to be a list, got an associative array.');
}

$this->stages = $stages;
$this->stages = array_merge($this->stages, $stages);

return $this;
}

public function getIterator(): Traversable
{
return new ArrayIterator($this->stages);
}
}
23 changes: 14 additions & 9 deletions tests/Builder/BuilderCodecTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@
use function array_walk;
use function is_array;

/**
* @todo This annotation is not enough as this PHP file needs to use named arguments, that can't compile on PHP 7.4
* @requires PHP 8.0
*/
class BuilderCodecTest extends TestCase
{
/** @see https://www.mongodb.com/docs/manual/reference/operator/aggregation/match/#equality-match */
public function testPipeline(): void
{
$pipeline = new Pipeline(
Stage::match(Aggregation::eq('$foo', 1)),
Stage::match(Aggregation::ne('$foo', 2)),
// @todo array is accepted by the stage class, but we expect an object. The driver accepts both.
Stage::match((object) ['author' => 'dave']),
Stage::limit(1),
);

$expected = [
['$match' => ['$eq' => ['$foo', 1]]],
['$match' => ['$ne' => ['$foo', 2]]],
['$match' => ['author' => 'dave']],
['$limit' => 1],
];

Expand Down Expand Up @@ -70,15 +74,16 @@ public function testPerformCount(): void
* @see https://www.mongodb.com/docs/manual/reference/operator/aggregation/filter/#examples
* @dataProvider provideAggregationFilterLimit
*/
public function testAggregationFilter($limit, $expectedLimit): void
public function testAggregationFilter(?int $limit, array $expectedLimit): void
{
$pipeline = new Pipeline(
Stage::project([
'items' => Aggregation::filter(
input: Expression::arrayFieldPath('items'),
cond: Aggregation::gte(Expression::variable('item.price'), 100),
as: 'item',
limit: $limit,
// @todo use named argument once we can require PHP 8
Expression::arrayFieldPath('items'),
Aggregation::gte(Expression::variable('item.price'), 100),
'item',
$limit,
),
]),
);
Expand Down
11 changes: 9 additions & 2 deletions tests/PedantryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,22 @@
use function realpath;
use function str_contains;
use function str_replace;
use function str_starts_with;
use function strcasecmp;
use function strlen;
use function substr;
use function usort;

use const DIRECTORY_SEPARATOR;
use const PHP_VERSION_ID;

/**
* Pedantic tests that have nothing to do with functional correctness.
*/
class PedantryTest extends TestCase
{
/** @dataProvider provideProjectClassNames */
public function testMethodsAreOrderedAlphabeticallyByVisibility($className): void
public function testMethodsAreOrderedAlphabeticallyByVisibility(string $className): void
{
$class = new ReflectionClass($className);
$methods = $class->getMethods();
Expand Down Expand Up @@ -56,7 +58,7 @@ public function testMethodsAreOrderedAlphabeticallyByVisibility($className): voi
$this->assertEquals($sortedMethods, $methods);
}

public function provideProjectClassNames()
public static function provideProjectClassNames(): array
{
$classNames = [];
$srcDir = realpath(__DIR__ . '/../src/');
Expand All @@ -74,6 +76,11 @@ public function provideProjectClassNames()
}

$className = 'MongoDB\\' . str_replace(DIRECTORY_SEPARATOR, '\\', substr($file->getRealPath(), strlen($srcDir) + 1, -4));

if (PHP_VERSION_ID < 80000 && str_starts_with($className, 'MongoDB\\Builder\\')) {
continue;
}

$classNames[$className][] = $className;
}

Expand Down

0 comments on commit a3eef39

Please sign in to comment.