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

Support new aggregation pipeline stages in builder #2513

Merged
merged 23 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1f289a3
Add $densify stage to aggregation pipeline builder
alcaeus Mar 14, 2023
b10aed7
Add $fill stage to aggregation pipeline builder
alcaeus Mar 14, 2023
4da931e
Add $merge stage to aggregation pipeline builder
alcaeus Mar 14, 2023
8643261
Add $replaceWith stage to aggregation pipeline builder
alcaeus Mar 14, 2023
3c1ee8d
Add $set stage to aggregation pipeline builder
alcaeus Mar 14, 2023
6a3dd48
Add $unset stage to aggregation pipeline builder
alcaeus Mar 14, 2023
f1bd9a7
Add $unionWith stage to aggregation pipeline builder
alcaeus Mar 14, 2023
e35e5d8
Use templates for Builder::addStage
alcaeus Mar 15, 2023
4fe0c0f
Add template covariance error to psalm baseline
alcaeus Mar 22, 2023
c1117f2
Remove unnecessary abstraction for $addFields and $set
alcaeus Mar 23, 2023
6f72a6a
Use array_fields for lists in variadic arguments
alcaeus Mar 23, 2023
cc4abd9
Improve wording when field name is required in Expr classes
alcaeus Mar 23, 2023
227186b
Add missing type to whenMatched option
alcaeus Mar 23, 2023
acfe974
Update type for let option
alcaeus Mar 23, 2023
0568e90
Use ? syntax for nullable type
alcaeus Mar 23, 2023
7cd1777
Rename test methods to hide copy/paste
alcaeus Mar 23, 2023
f831285
Test all range options for $densify
alcaeus Mar 23, 2023
742d27c
Test complex values and sort for $fill
alcaeus Mar 23, 2023
b8c6aff
Test reusing same builder for $merge
alcaeus Mar 23, 2023
e517015
Simplify creation of UTCDateTime instances in tests
alcaeus Mar 23, 2023
77d5827
Allow expressions as partition in $fill stage
alcaeus Mar 23, 2023
67847c5
Define psalm types for most pipeline stages
alcaeus Mar 23, 2023
3596a4c
Improve handling of required options as typed arguments
alcaeus Mar 24, 2023
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
Prev Previous commit
Next Next commit
Add $replaceWith stage to aggregation pipeline builder
  • Loading branch information
alcaeus committed Mar 17, 2023
commit 86432610395b8f8c05abd18fd8d0506ae80dd048
21 changes: 21 additions & 0 deletions lib/Doctrine/ODM/MongoDB/Aggregation/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,27 @@ public function replaceRoot($expression = null): Stage\ReplaceRoot
return $stage;
}

/**
* Replaces the input document with the specified document. The operation
* replaces all existing fields in the input document, including the _id
* field. With $replaceWith, you can promote an embedded document to the
* top-level. You can also specify a new document as the replacement.
*
* The $replaceWith stage is an alias for $replaceRoot.
*
* @see https://www.mongodb.com/docs/rapid/reference/operator/aggregation/replaceWith/
*
* @param string|mixed[]|Expr|null $expression Optional. A replacement expression that
* resolves to a document.
*/
public function replaceWith($expression = null): Stage\ReplaceWith
{
$stage = new Stage\ReplaceWith($this, $this->dm, $this->class, $expression);
$this->addStage($stage);

return $stage;
}

/**
* Controls if resulting iterator should be wrapped with CachingIterator.
*/
Expand Down
18 changes: 18 additions & 0 deletions lib/Doctrine/ODM/MongoDB/Aggregation/Stage.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,24 @@ public function replaceRoot($expression = null): Stage\ReplaceRoot
return $this->builder->replaceRoot($expression);
}

/**
* Replaces the input document with the specified document. The operation
* replaces all existing fields in the input document, including the _id
* field. With $replaceWith, you can promote an embedded document to the
* top-level. You can also specify a new document as the replacement.
*
* The $replaceWith stage is an alias for $replaceRoot.
*
* @see https://www.mongodb.com/docs/rapid/reference/operator/aggregation/replaceWith/
*
* @param string|mixed[]|Expr|null $expression Optional. A replacement expression that
* resolves to a document.
*/
public function replaceWith($expression = null): Stage\ReplaceWith
{
return $this->builder->replaceWith($expression);
}

/**
* Controls if resulting iterator should be wrapped with CachingIterator.
*/
Expand Down
17 changes: 17 additions & 0 deletions lib/Doctrine/ODM/MongoDB/Aggregation/Stage/ReplaceWith.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Doctrine\ODM\MongoDB\Aggregation\Stage;

class ReplaceWith extends ReplaceRoot
{
public function getExpression(): array
{
$expression = parent::getExpression();

return [
'$replaceWith' => $expression['$replaceRoot']['newRoot'],
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

namespace Doctrine\ODM\MongoDB\Tests\Aggregation\Stage;

use DateTimeImmutable;
use Doctrine\ODM\MongoDB\Tests\BaseTest;
use Documents\CmsComment;
use Documents\User;
use MongoDB\BSON\UTCDateTime;

class ReplaceWithTest extends BaseTest
{
public function testTypeConversion(): void
{
$builder = $this->dm->createAggregationBuilder(User::class);

$dateTime = new DateTimeImmutable('2000-01-01T00:00Z');
$mongoDate = new UTCDateTime((int) $dateTime->format('Uv'));
$stage = $builder
->replaceWith()
->field('isToday')
->eq('$createdAt', $dateTime);

self::assertEquals(
[
'$replaceWith' => (object) [
'isToday' => ['$eq' => ['$createdAt', $mongoDate]],
],
],
$stage->getExpression(),
);
}

public function testTypeConversionWithDirectExpression(): void
{
$builder = $this->dm->createAggregationBuilder(User::class);

$dateTime = new DateTimeImmutable('2000-01-01T00:00Z');
$mongoDate = new UTCDateTime((int) $dateTime->format('Uv'));
$stage = $builder
->replaceWith(
$builder->expr()
->field('isToday')
->eq('$createdAt', $dateTime),
);

self::assertEquals(
[
'$replaceWith' => (object) [
'isToday' => ['$eq' => ['$createdAt', $mongoDate]],
],
],
$stage->getExpression(),
);
}

public function testFieldNameConversion(): void
{
$builder = $this->dm->createAggregationBuilder(CmsComment::class);

$stage = $builder
->replaceWith()
->field('someField')
->concat('$authorIp', 'foo');

self::assertEquals(
[
'$replaceWith' => (object) [
'someField' => ['$concat' => ['$ip', 'foo']],
],
],
$stage->getExpression(),
);
}

public function testFieldNameConversionWithDirectExpression(): void
{
$builder = $this->dm->createAggregationBuilder(CmsComment::class);

$stage = $builder
->replaceWith('$authorIp');

self::assertEquals(
['$replaceWith' => '$ip'],
$stage->getExpression(),
);
}
}