Skip to content

Commit c49475b

Browse files
arnaud-lbondrejmirtes
authored andcommitted
Add IDENTITY() type inference support
Supports IDENTITY(a.assoc) or IDENTITY(a.assoc, 'id_field') where 'id_field' is the name of one of the id fields of the target class. Does not support IDENTITY(a.assoc) when the target id field is also an association.
1 parent 46256c9 commit c49475b

File tree

5 files changed

+166
-0
lines changed

5 files changed

+166
-0
lines changed

src/Type/Doctrine/Query/QueryResultTypeWalker.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,55 @@ public function walkFunction($function)
506506

507507
return $this->marshalType($type);
508508

509+
case $function instanceof AST\Functions\IdentityFunction:
510+
$dqlAlias = $function->pathExpression->identificationVariable;
511+
$assocField = $function->pathExpression->field;
512+
$queryComp = $this->queryComponents[$dqlAlias];
513+
$class = $queryComp['metadata'];
514+
$assoc = $class->associationMappings[$assocField];
515+
$targetClass = $this->em->getClassMetadata($assoc['targetEntity']);
516+
517+
if ($function->fieldMapping === null) {
518+
$identifierFieldNames = $targetClass->getIdentifierFieldNames();
519+
if (count($identifierFieldNames) === 0) {
520+
throw new ShouldNotHappenException();
521+
}
522+
523+
$targetFieldName = $identifierFieldNames[0];
524+
} else {
525+
$targetFieldName = $function->fieldMapping;
526+
}
527+
528+
$typeName = $targetClass->getTypeOfField($targetFieldName);
529+
if ($typeName === null) {
530+
return $this->marshalType(new MixedType());
531+
}
532+
533+
$fieldMapping = $targetClass->fieldMappings[$targetFieldName] ?? null;
534+
if ($fieldMapping === null) {
535+
return $this->marshalType(new MixedType());
536+
}
537+
538+
$joinColumn = null;
539+
540+
foreach ($assoc['joinColumns'] as $item) {
541+
if ($item['referencedColumnName'] === $fieldMapping['columnName']) {
542+
$joinColumn = $item;
543+
break;
544+
}
545+
}
546+
547+
if ($joinColumn === null) {
548+
return $this->marshalType(new MixedType());
549+
}
550+
551+
$nullable = (bool) ($joinColumn['nullable'] ?? true)
552+
|| $this->hasAggregateWithoutGroupBy();
553+
554+
$fieldType = $this->resolveDatabaseInternalType($typeName, $nullable);
555+
556+
return $this->marshalType($fieldType);
557+
509558
default:
510559
return $this->marshalType(new MixedType());
511560
}

tests/Type/Doctrine/Query/QueryResultTypeWalkerTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,29 @@ public function getTestData(): array
11521152
FROM QueryResult\Entities\Many m
11531153
',
11541154
],
1155+
'identity function' => [
1156+
$this->constantArray([
1157+
[new ConstantIntegerType(1), TypeCombinator::addNull($this->numericStringOrInt())],
1158+
[new ConstantIntegerType(2), $this->numericStringOrInt()],
1159+
[new ConstantIntegerType(3), TypeCombinator::addNull($this->numericStringOrInt())],
1160+
[new ConstantIntegerType(4), TypeCombinator::addNull(new StringType())],
1161+
[new ConstantIntegerType(5), TypeCombinator::addNull(new StringType())],
1162+
[new ConstantIntegerType(6), TypeCombinator::addNull($this->numericStringOrInt())],
1163+
[new ConstantIntegerType(7), TypeCombinator::addNull(new MixedType())],
1164+
[new ConstantIntegerType(8), TypeCombinator::addNull($this->numericStringOrInt())],
1165+
]),
1166+
'
1167+
SELECT IDENTITY(m.oneNull),
1168+
IDENTITY(m.one),
1169+
IDENTITY(m.oneDefaultNullability),
1170+
IDENTITY(m.compoundPk),
1171+
IDENTITY(m.compoundPk, \'id\'),
1172+
IDENTITY(m.compoundPk, \'version\'),
1173+
IDENTITY(m.compoundPkAssoc),
1174+
IDENTITY(m.compoundPkAssoc, \'version\')
1175+
FROM QueryResult\Entities\Many m
1176+
',
1177+
],
11551178
'select nullable association' => [
11561179
$this->constantArray([
11571180
[new ConstantIntegerType(1), TypeCombinator::addNull($this->numericStringOrInt())],
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace QueryResult\Entities;
4+
5+
use Doctrine\Common\Collections\Collection;
6+
use Doctrine\ORM\Mapping\Column;
7+
use Doctrine\ORM\Mapping\Embedded as ORMEmbedded;
8+
use Doctrine\ORM\Mapping\Entity;
9+
use Doctrine\ORM\Mapping\Id;
10+
use Doctrine\ORM\Mapping\JoinColumn;
11+
use Doctrine\ORM\Mapping\ManyToOne;
12+
use Doctrine\ORM\Mapping\OneToMany;
13+
use QueryResult\Entities\One;
14+
15+
/**
16+
* @Entity
17+
*/
18+
class CompoundPk
19+
{
20+
/**
21+
* @Column(type="string")
22+
* @Id
23+
*
24+
* @var string
25+
*/
26+
public $id;
27+
28+
/**
29+
* @Column(type="integer")
30+
* @Id
31+
*
32+
* @var int
33+
*/
34+
public $version;
35+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace QueryResult\Entities;
4+
5+
use Doctrine\Common\Collections\Collection;
6+
use Doctrine\ORM\Mapping\Column;
7+
use Doctrine\ORM\Mapping\Embedded as ORMEmbedded;
8+
use Doctrine\ORM\Mapping\Entity;
9+
use Doctrine\ORM\Mapping\Id;
10+
use Doctrine\ORM\Mapping\JoinColumn;
11+
use Doctrine\ORM\Mapping\ManyToOne;
12+
use Doctrine\ORM\Mapping\OneToMany;
13+
use QueryResult\Entities\One;
14+
15+
/**
16+
* @Entity
17+
*/
18+
class CompoundPkAssoc
19+
{
20+
/**
21+
* @ManyToOne(targetEntity="QueryResult\Entities\One")
22+
* @JoinColumn(nullable=false)
23+
* @Id
24+
*
25+
* @var One
26+
*/
27+
public $one;
28+
29+
/**
30+
* @Column(type="integer")
31+
* @Id
32+
*
33+
* @var int
34+
*/
35+
public $version;
36+
}

tests/Type/Doctrine/data/QueryResult/Entities/Many.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Doctrine\ORM\Mapping\Entity;
77
use Doctrine\ORM\Mapping\Id;
88
use Doctrine\ORM\Mapping\JoinColumn;
9+
use Doctrine\ORM\Mapping\JoinColumns;
910
use Doctrine\ORM\Mapping\ManyToOne;
1011

1112
/**
@@ -78,4 +79,26 @@ class Many
7879
* @var One|null
7980
*/
8081
public $oneDefaultNullability;
82+
83+
/**
84+
* @ManyToOne(targetEntity="QueryResult\Entities\CompoundPk")
85+
* @JoinColumns({
86+
* @JoinColumn(name="compoundPk_id", referencedColumnName="id"),
87+
* @JoinColumn(name="compoundPk_version", referencedColumnName="version")
88+
* })
89+
*
90+
* @var CompoundPk|null
91+
*/
92+
public $compoundPk;
93+
94+
/**
95+
* @ManyToOne(targetEntity="QueryResult\Entities\CompoundPkAssoc")
96+
* @JoinColumns({
97+
* @JoinColumn(name="compoundPk_one", referencedColumnName="one_id"),
98+
* @JoinColumn(name="compoundPk_version", referencedColumnName="version")
99+
* })
100+
*
101+
* @var CompoundPkAssoc|null
102+
*/
103+
public $compoundPkAssoc;
81104
}

0 commit comments

Comments
 (0)