From 42c4b04a516592c55e5b818c4908044a366b1d9b Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Sun, 11 Feb 2024 21:10:56 +0100 Subject: [PATCH 1/2] Handle aggregate function on litteral --- .../Doctrine/Query/QueryResultTypeWalker.php | 20 +++++ .../Query/QueryResultTypeWalkerTest.php | 79 +++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/src/Type/Doctrine/Query/QueryResultTypeWalker.php b/src/Type/Doctrine/Query/QueryResultTypeWalker.php index c186a5e3..ced1fad4 100644 --- a/src/Type/Doctrine/Query/QueryResultTypeWalker.php +++ b/src/Type/Doctrine/Query/QueryResultTypeWalker.php @@ -933,12 +933,32 @@ public function walkAggregateExpression($aggExpression): string switch ($aggExpression->functionName) { case 'MAX': case 'MIN': + $type = $this->unmarshalType( + $this->walkSimpleArithmeticExpression($aggExpression->pathExpression) + ); + + return $this->marshalType(TypeCombinator::addNull($type)); + case 'AVG': + $type = $this->unmarshalType( + $this->walkSimpleArithmeticExpression($aggExpression->pathExpression) + ); + + if (count($type->getConstantScalarValues()) !== 1) { + $type = TypeUtils::generalizeType($type, GeneralizePrecision::lessSpecific()); + } + + $type = TypeCombinator::union($type, $type->toFloat(), $type->toFloat()->toString()); + + return $this->marshalType(TypeCombinator::addNull($type)); + case 'SUM': $type = $this->unmarshalType( $this->walkSimpleArithmeticExpression($aggExpression->pathExpression) ); + $type = TypeUtils::generalizeType($type, GeneralizePrecision::lessSpecific()); + return $this->marshalType(TypeCombinator::addNull($type)); case 'COUNT': diff --git a/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php b/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php index 27d1acab..a2888fe8 100644 --- a/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php +++ b/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php @@ -14,6 +14,7 @@ use PHPStan\Testing\PHPStanTestCase; use PHPStan\Type\Accessory\AccessoryNumericStringType; use PHPStan\Type\Constant\ConstantArrayTypeBuilder; +use PHPStan\Type\Constant\ConstantFloatType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\ConstantTypeHelper; @@ -681,6 +682,84 @@ public function getTestData(): iterable ', ]; + yield 'aggregate on literal' => [ + $this->constantArray([ + [ + new ConstantIntegerType(1), + TypeCombinator::union( + new ConstantStringType('1'), + new ConstantIntegerType(1), + new NullType() + ), + ], + [ + new ConstantIntegerType(2), + TypeCombinator::union( + new ConstantStringType('0'), + new ConstantIntegerType(0), + new ConstantStringType('1'), + new ConstantIntegerType(1), + new NullType() + ), + ], + [ + new ConstantIntegerType(3), + TypeCombinator::union( + new ConstantStringType('1'), + new ConstantIntegerType(1), + new NullType() + ), + ], + [ + new ConstantIntegerType(4), + TypeCombinator::union( + new ConstantStringType('0'), + new ConstantIntegerType(0), + new ConstantStringType('1'), + new ConstantIntegerType(1), + new NullType() + ), + ], + [ + new ConstantIntegerType(5), + TypeCombinator::union( + new ConstantStringType('1'), + new ConstantIntegerType(1), + new ConstantStringType('1.0'), + new ConstantFloatType(1.0), + new NullType() + ), + ], + [ + new ConstantIntegerType(6), + TypeCombinator::union( + $this->intStringified(), + new FloatType(), + new NullType() + ), + ], + [ + new ConstantIntegerType(7), + TypeCombinator::addNull($this->intStringified()), + ], + [ + new ConstantIntegerType(8), + TypeCombinator::addNull($this->intStringified()), + ], + ]), + ' + SELECT MAX(1), + MAX(CASE WHEN m.intColumn = 0 THEN 1 ELSE 0 END), + MIN(1), + MIN(CASE WHEN m.intColumn = 0 THEN 1 ELSE 0 END), + AVG(1), + AVG(CASE WHEN m.intColumn = 0 THEN 1 ELSE 0 END), + SUM(1), + SUM(CASE WHEN m.intColumn = 0 THEN 1 ELSE 0 END) + FROM QueryResult\Entities\Many m + ', + ]; + yield 'literal' => [ $this->constantArray([ [ From 9c3f7aede3492f72a56d7f017a2d10ce066ea14a Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Mon, 12 Feb 2024 09:44:54 +0100 Subject: [PATCH 2/2] Simplify --- src/Type/Doctrine/Query/QueryResultTypeWalker.php | 7 ++----- tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Type/Doctrine/Query/QueryResultTypeWalker.php b/src/Type/Doctrine/Query/QueryResultTypeWalker.php index ced1fad4..14519922 100644 --- a/src/Type/Doctrine/Query/QueryResultTypeWalker.php +++ b/src/Type/Doctrine/Query/QueryResultTypeWalker.php @@ -944,11 +944,8 @@ public function walkAggregateExpression($aggExpression): string $this->walkSimpleArithmeticExpression($aggExpression->pathExpression) ); - if (count($type->getConstantScalarValues()) !== 1) { - $type = TypeUtils::generalizeType($type, GeneralizePrecision::lessSpecific()); - } - - $type = TypeCombinator::union($type, $type->toFloat(), $type->toFloat()->toString()); + $type = TypeCombinator::union($type, $type->toFloat()); + $type = TypeUtils::generalizeType($type, GeneralizePrecision::lessSpecific()); return $this->marshalType(TypeCombinator::addNull($type)); diff --git a/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php b/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php index a2888fe8..ea1e0aea 100644 --- a/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php +++ b/tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php @@ -14,7 +14,6 @@ use PHPStan\Testing\PHPStanTestCase; use PHPStan\Type\Accessory\AccessoryNumericStringType; use PHPStan\Type\Constant\ConstantArrayTypeBuilder; -use PHPStan\Type\Constant\ConstantFloatType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\ConstantTypeHelper; @@ -723,10 +722,8 @@ public function getTestData(): iterable [ new ConstantIntegerType(5), TypeCombinator::union( - new ConstantStringType('1'), - new ConstantIntegerType(1), - new ConstantStringType('1.0'), - new ConstantFloatType(1.0), + $this->intStringified(), + new FloatType(), new NullType() ), ],