Skip to content

Commit 37059c3

Browse files
committed
QueryResultTypeWalker: fix nullability checks over unknown type
1 parent b09104d commit 37059c3

File tree

4 files changed

+57
-12
lines changed

4 files changed

+57
-12
lines changed

Diff for: src/Type/Doctrine/Query/QueryResultTypeWalker.php

+17-12
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ public function walkFunction($function): string
374374
new FloatType()
375375
);
376376

377-
if (TypeCombinator::containsNull($exprType)) {
377+
if ($this->canBeNull($exprType)) {
378378
$type = TypeCombinator::addNull($type);
379379
}
380380

@@ -386,7 +386,7 @@ public function walkFunction($function): string
386386
$secondExprType = $this->unmarshalType($function->secondArithmetic->dispatch($this));
387387

388388
$type = IntegerRangeType::fromInterval(0, null);
389-
if (TypeCombinator::containsNull($firstExprType) || TypeCombinator::containsNull($secondExprType)) {
389+
if ($this->canBeNull($firstExprType) || $this->canBeNull($secondExprType)) {
390390
$type = TypeCombinator::addNull($type);
391391
}
392392

@@ -397,7 +397,7 @@ public function walkFunction($function): string
397397

398398
foreach ($function->concatExpressions as $expr) {
399399
$type = $this->unmarshalType($expr->dispatch($this));
400-
$hasNull = $hasNull || TypeCombinator::containsNull($type);
400+
$hasNull = $hasNull || $this->canBeNull($type);
401401
}
402402

403403
$type = new StringType();
@@ -418,7 +418,7 @@ public function walkFunction($function): string
418418
$intervalExprType = $this->unmarshalType($function->intervalExpression->dispatch($this));
419419

420420
$type = new StringType();
421-
if (TypeCombinator::containsNull($dateExprType) || TypeCombinator::containsNull($intervalExprType)) {
421+
if ($this->canBeNull($dateExprType) || $this->canBeNull($intervalExprType)) {
422422
$type = TypeCombinator::addNull($type);
423423
}
424424

@@ -432,7 +432,7 @@ public function walkFunction($function): string
432432
new IntegerType(),
433433
new FloatType()
434434
);
435-
if (TypeCombinator::containsNull($date1ExprType) || TypeCombinator::containsNull($date2ExprType)) {
435+
if ($this->canBeNull($date1ExprType) || $this->canBeNull($date2ExprType)) {
436436
$type = TypeCombinator::addNull($type);
437437
}
438438

@@ -442,7 +442,7 @@ public function walkFunction($function): string
442442
$stringPrimaryType = $this->unmarshalType($function->stringPrimary->dispatch($this));
443443

444444
$type = IntegerRangeType::fromInterval(0, null);
445-
if (TypeCombinator::containsNull($stringPrimaryType)) {
445+
if ($this->canBeNull($stringPrimaryType)) {
446446
$type = TypeCombinator::addNull($type);
447447
}
448448

@@ -453,7 +453,7 @@ public function walkFunction($function): string
453453
$secondExprType = $this->unmarshalType($this->walkStringPrimary($function->secondStringPrimary));
454454

455455
$type = IntegerRangeType::fromInterval(0, null);
456-
if (TypeCombinator::containsNull($firstExprType) || TypeCombinator::containsNull($secondExprType)) {
456+
if ($this->canBeNull($firstExprType) || $this->canBeNull($secondExprType)) {
457457
$type = TypeCombinator::addNull($type);
458458
}
459459

@@ -465,7 +465,7 @@ public function walkFunction($function): string
465465
$stringPrimaryType = $this->unmarshalType($function->stringPrimary->dispatch($this));
466466

467467
$type = new StringType();
468-
if (TypeCombinator::containsNull($stringPrimaryType)) {
468+
if ($this->canBeNull($stringPrimaryType)) {
469469
$type = TypeCombinator::addNull($type);
470470
}
471471

@@ -476,7 +476,7 @@ public function walkFunction($function): string
476476
$secondExprType = $this->unmarshalType($this->walkSimpleArithmeticExpression($function->secondSimpleArithmeticExpression));
477477

478478
$type = IntegerRangeType::fromInterval(0, null);
479-
if (TypeCombinator::containsNull($firstExprType) || TypeCombinator::containsNull($secondExprType)) {
479+
if ($this->canBeNull($firstExprType) || $this->canBeNull($secondExprType)) {
480480
$type = TypeCombinator::addNull($type);
481481
}
482482

@@ -491,7 +491,7 @@ public function walkFunction($function): string
491491
$exprType = $this->unmarshalType($this->walkSimpleArithmeticExpression($function->simpleArithmeticExpression));
492492

493493
$type = new FloatType();
494-
if (TypeCombinator::containsNull($exprType)) {
494+
if ($this->canBeNull($exprType)) {
495495
$type = TypeCombinator::addNull($type);
496496
}
497497

@@ -508,7 +508,7 @@ public function walkFunction($function): string
508508
}
509509

510510
$type = new StringType();
511-
if (TypeCombinator::containsNull($stringType) || TypeCombinator::containsNull($firstExprType) || TypeCombinator::containsNull($secondExprType)) {
511+
if ($this->canBeNull($stringType) || $this->canBeNull($firstExprType) || $this->canBeNull($secondExprType)) {
512512
$type = TypeCombinator::addNull($type);
513513
}
514514

@@ -639,7 +639,7 @@ public function walkCoalesceExpression($coalesceExpression): string
639639
}
640640

641641
$type = $this->unmarshalType($expression->dispatch($this));
642-
$allTypesContainNull = $allTypesContainNull && TypeCombinator::containsNull($type);
642+
$allTypesContainNull = $allTypesContainNull && $this->canBeNull($type);
643643

644644
$expressionTypes[] = $type;
645645
}
@@ -1399,6 +1399,11 @@ private function resolveDatabaseInternalType(string $typeName, ?string $enumType
13991399
return $type;
14001400
}
14011401

1402+
private function canBeNull(Type $type): bool
1403+
{
1404+
return !$type->accepts(new NullType(), true)->no();
1405+
}
1406+
14021407
private function toNumericOrNull(Type $type): Type
14031408
{
14041409
return TypeTraverser::map($type, static function (Type $type, callable $traverse): Type {

Diff for: tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php

+16
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use DateTime;
88
use DateTimeImmutable;
99
use Doctrine\Common\Collections\ArrayCollection;
10+
use Doctrine\DBAL\Types\Type as DbalType;
1011
use Doctrine\ORM\EntityManagerInterface;
1112
use Doctrine\ORM\Mapping\Column;
1213
use Doctrine\ORM\Tools\SchemaTool;
@@ -43,6 +44,7 @@
4344
use QueryResult\EntitiesEnum\IntEnum;
4445
use QueryResult\EntitiesEnum\StringEnum;
4546
use Throwable;
47+
use Type\Doctrine\data\QueryResult\CustomIntType;
4648
use function array_merge;
4749
use function array_shift;
4850
use function assert;
@@ -75,6 +77,10 @@ public static function setUpBeforeClass(): void
7577
$em = require __DIR__ . '/../data/QueryResult/entity-manager.php';
7678
self::$em = $em;
7779

80+
if (!DbalType::hasType(CustomIntType::NAME)) {
81+
DbalType::addType(CustomIntType::NAME, CustomIntType::class);
82+
}
83+
7884
$schemaTool = new SchemaTool($em);
7985
$classes = $em->getMetadataFactory()->getAllMetadata();
8086
$schemaTool->createSchema($classes);
@@ -1221,6 +1227,16 @@ public function getTestData(): iterable
12211227
',
12221228
];
12231229

1230+
yield 'abs function with mixed' => [
1231+
$this->constantArray([
1232+
[new ConstantIntegerType(1), TypeCombinator::addNull($this->unumericStringified())],
1233+
]),
1234+
'
1235+
SELECT ABS(o.mixedColumn)
1236+
FROM QueryResult\Entities\One o
1237+
',
1238+
];
1239+
12241240
yield 'bit_and function' => [
12251241
$this->constantArray([
12261242
[new ConstantIntegerType(1), $this->uintStringified()],
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Type\Doctrine\data\QueryResult;
4+
5+
use Doctrine\DBAL\Types\IntegerType;
6+
7+
class CustomIntType extends IntegerType
8+
{
9+
10+
public const NAME = 'custom_int';
11+
12+
public function getName(): string
13+
{
14+
return self::NAME;
15+
}
16+
17+
}

Diff for: tests/Type/Doctrine/data/QueryResult/Entities/One.php

+7
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ class One
7474
*/
7575
public $embedded;
7676

77+
/**
78+
* @Column(type="custom_int", nullable=true)
79+
*
80+
* @var mixed
81+
*/
82+
public $mixedColumn;
83+
7784
public function __construct()
7885
{
7986
$this->subOne = new SubOne();

0 commit comments

Comments
 (0)