Skip to content

Commit 4496c7b

Browse files
committed
Test custom TypedExpression
1 parent bbbe5ec commit 4496c7b

File tree

4 files changed

+102
-2
lines changed

4 files changed

+102
-2
lines changed

src/Type/Doctrine/Query/QueryResultTypeWalker.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,7 @@ public function walkSelectExpression($selectExpression): string
11221122
if ($expr instanceof TypedExpression) {
11231123
$type = TypeCombinator::intersect( // e.g. count is typed as int, but we infer int<0, max>
11241124
$type,
1125-
$this->resolveDoctrineType(DbalType::lookupName($expr->getReturnType()), null, $this->canBeNull($type))
1125+
$this->resolveDoctrineType(DbalType::lookupName($expr->getReturnType()), null, TypeCombinator::containsNull($type))
11261126
);
11271127
} else {
11281128
// Expressions default to Doctrine's StringType, whose

tests/Platform/QueryResultTypeWalkerFetchTypeMatrixTest.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
use PHPStan\Type\VerbosityLevel;
4646
use PHPUnit\Framework\Constraint\IsEqual;
4747
use PHPUnit\Framework\Constraint\IsIdentical;
48+
use Platform\TypedExpressionBooleanPiFunction;
4849
use SQLite3;
4950
use Throwable;
5051
use function floor;
@@ -2956,9 +2957,40 @@ public static function provideCases(): iterable
29562957
},
29572958
];
29582959

2960+
yield 'INT_PI()' => [
2961+
'data' => self::dataDefault(),
2962+
'select' => 'SELECT INT_PI() FROM %s t',
2963+
'mysql' => self::int(),
2964+
'sqlite' => self::int(),
2965+
'pdo_pgsql' => self::int(),
2966+
'pgsql' => self::int(),
2967+
'mysqlResult' => 3,
2968+
'sqliteResult' => 3,
2969+
'pdoPgsqlResult' => 3,
2970+
'pgsqlResult' => 3,
2971+
'shouldStringify' => static function (): bool {
2972+
return false;
2973+
},
2974+
];
2975+
2976+
yield 'BOOL_PI()' => [
2977+
'data' => self::dataDefault(),
2978+
'select' => 'SELECT BOOL_PI() FROM %s t',
2979+
'mysql' => self::bool(),
2980+
'sqlite' => self::bool(),
2981+
'pdo_pgsql' => self::bool(),
2982+
'pgsql' => self::bool(),
2983+
'mysqlResult' => true,
2984+
'sqliteResult' => true,
2985+
'pdoPgsqlResult' => true,
2986+
'pgsqlResult' => true,
2987+
'shouldStringify' => static function (): bool {
2988+
return false;
2989+
},
2990+
];
2991+
29592992
// TODO would col_numeric_string differ from col_string results ?
29602993
// TODO dbal/orm versions
2961-
// TODO custom TypedExpression
29622994
// TODO unknown driver to return mixed everywhere
29632995
// TODO double check all inferred unions
29642996
// TODO check else branches & default behaviour (other drivers)
@@ -3070,6 +3102,8 @@ private function getQuery(
30703102
$config->setSecondLevelCacheEnabled(false);
30713103
$config->setMetadataCache(new ArrayCachePool());
30723104
$config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), [__DIR__ . '/Entity']));
3105+
$config->addCustomStringFunction('INT_PI', TypedExpressionIntegerPiFunction::class);
3106+
$config->addCustomStringFunction('BOOL_PI', TypedExpressionBooleanPiFunction::class);
30733107
$entityManager = new EntityManager($connection, $config);
30743108

30753109
$schemaTool = new SchemaTool($entityManager);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Platform;
4+
5+
use Doctrine\DBAL\Types\Type;
6+
use Doctrine\DBAL\Types\Types;
7+
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
8+
use Doctrine\ORM\Query\AST\TypedExpression;
9+
use Doctrine\ORM\Query\Parser;
10+
use Doctrine\ORM\Query\SqlWalker;
11+
use Doctrine\ORM\Query\TokenType;
12+
13+
class TypedExpressionBooleanPiFunction extends FunctionNode implements TypedExpression
14+
{
15+
16+
public function getSql(SqlWalker $sqlWalker): string
17+
{
18+
return 'PI()';
19+
}
20+
21+
public function parse(Parser $parser): void
22+
{
23+
$parser->match(TokenType::T_IDENTIFIER);
24+
$parser->match(TokenType::T_OPEN_PARENTHESIS);
25+
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
26+
}
27+
28+
public function getReturnType(): Type
29+
{
30+
return Type::getType(Types::BOOLEAN);
31+
}
32+
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Platform;
4+
5+
use Doctrine\DBAL\Types\Type;
6+
use Doctrine\DBAL\Types\Types;
7+
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
8+
use Doctrine\ORM\Query\AST\TypedExpression;
9+
use Doctrine\ORM\Query\Parser;
10+
use Doctrine\ORM\Query\SqlWalker;
11+
use Doctrine\ORM\Query\TokenType;
12+
13+
class TypedExpressionIntegerPiFunction extends FunctionNode implements TypedExpression
14+
{
15+
16+
public function getSql(SqlWalker $sqlWalker): string
17+
{
18+
return 'PI()';
19+
}
20+
21+
public function parse(Parser $parser): void
22+
{
23+
$parser->match(TokenType::T_IDENTIFIER);
24+
$parser->match(TokenType::T_OPEN_PARENTHESIS);
25+
$parser->match(TokenType::T_CLOSE_PARENTHESIS);
26+
}
27+
28+
public function getReturnType(): Type
29+
{
30+
return Type::getType(Types::INTEGER);
31+
}
32+
33+
}

0 commit comments

Comments
 (0)