Skip to content
This repository was archived by the owner on Feb 28, 2025. It is now read-only.

PHPLIB-1273: Improve $switch syntax #62

Merged
merged 5 commits into from
Feb 2, 2024
Merged
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
21 changes: 21 additions & 0 deletions generator/config/expression/case.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# $schema: ../schema.json
name: $case
link: 'https://www.mongodb.com/docs/manual/reference/operator/aggregation/switch/'
Copy link
Member

Choose a reason for hiding this comment

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

I see the interest of creating this "fake" operator for code generation. It should be consistent with OutputWindow this is the same need.

Could you create accumulator/outputWindow.yaml also?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll do so in a separate PR: the current OutputWindow type contains additional validation logic that we can't represent through the config.

type:
- switchBranch
encode: flat_object
description: |
Represents a single case in a $switch expression
arguments:
-
name: case
type:
- resolvesToBool
description: |
Can be any valid expression that resolves to a boolean. If the result is not a boolean, it is coerced to a boolean value. More information about how MongoDB evaluates expressions as either true or false can be found here.
-
name: then
type:
- expression
description: |
Can be any valid expression.
2 changes: 1 addition & 1 deletion generator/config/expression/switch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ arguments:
-
name: branches
type:
- array # of object{case:resolvesToBool, then:expression}
- array # of CaseOperator
description: |
An array of control branch documents. Each branch is a document with the following fields:
- case Can be any valid expression that resolves to a boolean. If the result is not a boolean, it is coerced to a boolean value. More information about how MongoDB evaluates expressions as either true or false can be found here.
Expand Down
4 changes: 4 additions & 0 deletions generator/config/expressions.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@
'returnType' => Type\GeometryInterface::class,
'acceptedTypes' => [Type\GeometryInterface::class, ...$bsonTypes['object']],
],
'switchBranch' => [
'returnType' => Type\SwitchBranchInterface::class,
'acceptedTypes' => [Type\SwitchBranchInterface::class, ...$bsonTypes['object']],
],

// @todo add enum values
'Granularity' => [
Expand Down
2 changes: 2 additions & 0 deletions generator/config/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"filter",
"window",
"geometry",
"switchBranch",
"resolvesToAny",
"resolvesToNumber",
"resolvesToDouble",
Expand Down Expand Up @@ -59,6 +60,7 @@
"enum": [
"array",
"object",
"flat_object",
"dollar_object",
"single",
"group"
Expand Down
1 change: 1 addition & 0 deletions generator/src/Definition/OperatorDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public function __construct(
'single' => Encode::Single,
'array' => Encode::Array,
'object' => Encode::Object,
'flat_object' => Encode::FlatObject,
'dollar_object' => Encode::DollarObject,
'group' => Encode::Group,
default => throw new UnexpectedValueException(sprintf('Unexpected "encode" value for operator "%s". Got "%s"', $name, $encode)),
Expand Down
5 changes: 4 additions & 1 deletion src/Builder/Encoder/OperatorEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function encode(mixed $value): stdClass
return $this->encodeAsArray($value);

case Encode::Object:
case Encode::FlatObject:
return $this->encodeAsObject($value);

case Encode::DollarObject:
Expand Down Expand Up @@ -107,7 +108,9 @@ private function encodeAsObject(OperatorInterface $value): stdClass
$result->{$key} = $this->recursiveEncode($val);
}

return $this->wrap($value, $result);
return $value::ENCODE === Encode::FlatObject
? $result
: $this->wrap($value, $result);
}

private function encodeAsDollarObject(OperatorInterface $value): stdClass
Expand Down
49 changes: 49 additions & 0 deletions src/Builder/Expression/CaseOperator.php

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions src/Builder/Expression/FactoryTrait.php

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Builder/Type/Encode.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ enum Encode
*/
case Object;

/**
* Same as Object, but only parameters are returned. The operator name will not be used.
*/
case FlatObject;

/**
* Parameters are encoded as an object with keys matching the parameter names prefixed with a dollar sign ($)
*/
Expand Down
14 changes: 14 additions & 0 deletions src/Builder/Type/SwitchBranchInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace MongoDB\Builder\Type;

/**
* Interface for branches in $switch operators
*
* @see https://www.mongodb.com/docs/manual/reference/operator/aggregation/switch/
*/
interface SwitchBranchInterface
{
}
6 changes: 2 additions & 4 deletions tests/Builder/Expression/ConvertOperatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
use MongoDB\Builder\Stage;
use MongoDB\Tests\Builder\PipelineTestCase;

use function MongoDB\object;

/**
* Test $convert expression
*/
Expand Down Expand Up @@ -43,7 +41,7 @@ public function testExample(): void
Stage::project(
totalPrice: Expression::switch(
branches: [
object(
Expression::case(
case: Expression::eq(
Expression::type(
Expression::fieldPath('convertedPrice'),
Expand All @@ -52,7 +50,7 @@ public function testExample(): void
),
then: 'NaN',
),
object(
Expression::case(
case: Expression::eq(
Expression::type(
Expression::fieldPath('convertedQty'),
Expand Down
12 changes: 5 additions & 7 deletions tests/Builder/Expression/IsNumberOperatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
use MongoDB\Builder\Stage;
use MongoDB\Tests\Builder\PipelineTestCase;

use function MongoDB\object;

/**
* Test $isNumber expression
*/
Expand All @@ -28,35 +26,35 @@ public function testConditionallyModifyFieldsUsingIsNumber(): void
then: Expression::fieldPath('grade'),
else: Expression::switch(
branches: [
object(
Expression::case(
case: Expression::eq(
Expression::fieldPath('grade'),
'A',
),
then: 4,
),
object(
Expression::case(
case: Expression::eq(
Expression::fieldPath('grade'),
'B',
),
then: 3,
),
object(
Expression::case(
case: Expression::eq(
Expression::fieldPath('grade'),
'C',
),
then: 2,
),
object(
Expression::case(
case: Expression::eq(
Expression::fieldPath('grade'),
'D',
),
then: 1,
),
object(
Expression::case(
case: Expression::eq(
Expression::fieldPath('grade'),
'F',
Expand Down
8 changes: 3 additions & 5 deletions tests/Builder/Expression/SwitchOperatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
use MongoDB\Builder\Stage;
use MongoDB\Tests\Builder\PipelineTestCase;

use function MongoDB\object;

/**
* Test $switch expression
*/
Expand All @@ -23,7 +21,7 @@ public function testExample(): void
name: 1,
summary: Expression::switch(
branches: [
object(
Expression::case(
case: Expression::gte(
Expression::avg(
Expression::intFieldPath('scores'),
Expand All @@ -32,7 +30,7 @@ public function testExample(): void
),
then: 'Doing great!',
),
object(
Expression::case(
case:Expression::and(
Expression::gte(
Expression::avg(
Expand All @@ -49,7 +47,7 @@ public function testExample(): void
),
then: 'Doing pretty well.',
),
object(
Expression::case(
case: Expression::lt(
Expression::avg(
Expression::intFieldPath('scores'),
Expand Down
6 changes: 2 additions & 4 deletions tests/Builder/Expression/ToBoolOperatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
use MongoDB\Builder\Stage;
use MongoDB\Tests\Builder\PipelineTestCase;

use function MongoDB\object;

/**
* Test $toBool expression
*/
Expand All @@ -22,14 +20,14 @@ public function testExample(): void
Stage::addFields(
convertedShippedFlag: Expression::switch(
branches: [
object(
Expression::case(
case: Expression::eq(
Expression::fieldPath('shipped'),
'false',
),
then: false,
),
object(
Expression::case(
case: Expression::eq(
Expression::fieldPath('shipped'),
'',
Expand Down