Merge pull request #1092 from birko/pagination-count-walker
[DDC-2794] Arbitrary Join count walkers solution
This commit is contained in:
commit
3f8865c6fb
@ -96,7 +96,8 @@ class CountOutputWalker extends SqlWalker
|
||||
throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
|
||||
}
|
||||
|
||||
$rootAlias = $from[0]->rangeVariableDeclaration->aliasIdentificationVariable;
|
||||
$fromRoot = reset($from);
|
||||
$rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable;
|
||||
$rootClass = $this->queryComponents[$rootAlias]['metadata'];
|
||||
$rootIdentifier = $rootClass->identifier;
|
||||
|
||||
|
@ -50,31 +50,26 @@ class CountWalker extends TreeWalkerAdapter
|
||||
throw new \RuntimeException('Cannot count query that uses a HAVING clause. Use the output walkers for pagination');
|
||||
}
|
||||
|
||||
$rootComponents = array();
|
||||
foreach ($this->_getQueryComponents() as $dqlAlias => $qComp) {
|
||||
$isParent = array_key_exists('parent', $qComp)
|
||||
&& $qComp['parent'] === null
|
||||
&& $qComp['nestingLevel'] == 0
|
||||
;
|
||||
if ($isParent) {
|
||||
$rootComponents[] = array($dqlAlias => $qComp);
|
||||
}
|
||||
}
|
||||
if (count($rootComponents) > 1) {
|
||||
$queryComponents = $this->_getQueryComponents();
|
||||
// Get the root entity and alias from the AST fromClause
|
||||
$from = $AST->fromClause->identificationVariableDeclarations;
|
||||
|
||||
if (count($from) > 1) {
|
||||
throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
|
||||
}
|
||||
$root = reset($rootComponents);
|
||||
$parentName = key($root);
|
||||
$parent = current($root);
|
||||
$identifierFieldName = $parent['metadata']->getSingleIdentifierFieldName();
|
||||
|
||||
$fromRoot = reset($from);
|
||||
$rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable;
|
||||
$rootClass = $queryComponents[$rootAlias]['metadata'];
|
||||
$identifierFieldName = $rootClass->getSingleIdentifierFieldName();
|
||||
|
||||
$pathType = PathExpression::TYPE_STATE_FIELD;
|
||||
if (isset($parent['metadata']->associationMappings[$identifierFieldName])) {
|
||||
if (isset($rootClass->associationMappings[$identifierFieldName])) {
|
||||
$pathType = PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;
|
||||
}
|
||||
|
||||
$pathExpression = new PathExpression(
|
||||
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName,
|
||||
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $rootAlias,
|
||||
$identifierFieldName
|
||||
);
|
||||
$pathExpression->type = $pathType;
|
||||
|
@ -122,7 +122,8 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
||||
throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
|
||||
}
|
||||
|
||||
$rootAlias = $from[0]->rangeVariableDeclaration->aliasIdentificationVariable;
|
||||
$fromRoot = reset($from);
|
||||
$rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable;
|
||||
$rootClass = $this->queryComponents[$rootAlias]['metadata'];
|
||||
$rootIdentifier = $rootClass->identifier;
|
||||
|
||||
|
@ -60,37 +60,36 @@ class LimitSubqueryWalker extends TreeWalkerAdapter
|
||||
*/
|
||||
public function walkSelectStatement(SelectStatement $AST)
|
||||
{
|
||||
$parent = null;
|
||||
$parentName = null;
|
||||
$queryComponents = $this->_getQueryComponents();
|
||||
// Get the root entity and alias from the AST fromClause
|
||||
$from = $AST->fromClause->identificationVariableDeclarations;
|
||||
$fromRoot = reset($from);
|
||||
$rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable;
|
||||
$rootClass = $queryComponents[$rootAlias]['metadata'];
|
||||
$selectExpressions = array();
|
||||
|
||||
foreach ($this->_getQueryComponents() as $dqlAlias => $qComp) {
|
||||
foreach ($queryComponents as $dqlAlias => $qComp) {
|
||||
// Preserve mixed data in query for ordering.
|
||||
if (isset($qComp['resultVariable'])) {
|
||||
$selectExpressions[] = new SelectExpression($qComp['resultVariable'], $dqlAlias);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($qComp['parent'] === null && $qComp['nestingLevel'] == 0) {
|
||||
$parent = $qComp;
|
||||
$parentName = $dqlAlias;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$identifier = $parent['metadata']->getSingleIdentifierFieldName();
|
||||
if (isset($parent['metadata']->associationMappings[$identifier])) {
|
||||
|
||||
$identifier = $rootClass->getSingleIdentifierFieldName();
|
||||
|
||||
if (isset($rootClass->associationMappings[$identifier])) {
|
||||
throw new \RuntimeException("Paginating an entity with foreign key as identifier only works when using the Output Walkers. Call Paginator#setUseOutputWalkers(true) before iterating the paginator.");
|
||||
}
|
||||
|
||||
$this->_getQuery()->setHint(
|
||||
self::IDENTIFIER_TYPE,
|
||||
Type::getType($parent['metadata']->getTypeOfField($identifier))
|
||||
Type::getType($rootClass->getTypeOfField($identifier))
|
||||
);
|
||||
|
||||
$pathExpression = new PathExpression(
|
||||
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION,
|
||||
$parentName,
|
||||
$rootAlias,
|
||||
$identifier
|
||||
);
|
||||
$pathExpression->type = PathExpression::TYPE_STATE_FIELD;
|
||||
|
@ -71,30 +71,25 @@ class WhereInWalker extends TreeWalkerAdapter
|
||||
*/
|
||||
public function walkSelectStatement(SelectStatement $AST)
|
||||
{
|
||||
$rootComponents = array();
|
||||
foreach ($this->_getQueryComponents() as $dqlAlias => $qComp) {
|
||||
$isParent = array_key_exists('parent', $qComp)
|
||||
&& $qComp['parent'] === null
|
||||
&& $qComp['nestingLevel'] == 0
|
||||
;
|
||||
if ($isParent) {
|
||||
$rootComponents[] = array($dqlAlias => $qComp);
|
||||
}
|
||||
}
|
||||
if (count($rootComponents) > 1) {
|
||||
$queryComponents = $this->_getQueryComponents();
|
||||
// Get the root entity and alias from the AST fromClause
|
||||
$from = $AST->fromClause->identificationVariableDeclarations;
|
||||
|
||||
if (count($from) > 1) {
|
||||
throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
|
||||
}
|
||||
$root = reset($rootComponents);
|
||||
$parentName = key($root);
|
||||
$parent = current($root);
|
||||
$identifierFieldName = $parent['metadata']->getSingleIdentifierFieldName();
|
||||
|
||||
$fromRoot = reset($from);
|
||||
$rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable;
|
||||
$rootClass = $queryComponents[$rootAlias]['metadata'];
|
||||
$identifierFieldName = $rootClass->getSingleIdentifierFieldName();
|
||||
|
||||
$pathType = PathExpression::TYPE_STATE_FIELD;
|
||||
if (isset($parent['metadata']->associationMappings[$identifierFieldName])) {
|
||||
if (isset($rootClass->associationMappings[$identifierFieldName])) {
|
||||
$pathType = PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;
|
||||
}
|
||||
|
||||
$pathExpression = new PathExpression(PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName, $identifierFieldName);
|
||||
$pathExpression = new PathExpression(PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $rootAlias, $identifierFieldName);
|
||||
$pathExpression->type = $pathType;
|
||||
|
||||
$count = $this->_getQuery()->getHint(self::HINT_PAGINATOR_ID_COUNT);
|
||||
|
@ -90,5 +90,21 @@ class CountWalkerTest extends PaginationTestCase
|
||||
|
||||
$query->getSql();
|
||||
}
|
||||
|
||||
/**
|
||||
* Arbitrary Join
|
||||
*/
|
||||
public function testCountQueryWithArbitraryJoin()
|
||||
{
|
||||
$query = $this->entityManager->createQuery(
|
||||
'SELECT p FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p LEFT JOIN Doctrine\Tests\ORM\Tools\Pagination\Category c WITH p.category = c');
|
||||
$query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\CountWalker'));
|
||||
$query->setHint(CountWalker::HINT_DISTINCT, true);
|
||||
$query->setFirstResult(null)->setMaxResults(null);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT count(DISTINCT b0_.id) AS sclr_0 FROM BlogPost b0_ LEFT JOIN Category c1_ ON (b0_.category_id = c1_.id)", $query->getSql()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,5 +67,36 @@ class LimitSubqueryWalkerTest extends PaginationTestCase
|
||||
$limitQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arbitrary Join
|
||||
*/
|
||||
public function testLimitSubqueryWithArbitraryJoin()
|
||||
{
|
||||
$dql = 'SELECT p, c FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN Doctrine\Tests\ORM\Tools\Pagination\Category c WITH p.category = c';
|
||||
$query = $this->entityManager->createQuery($dql);
|
||||
$limitQuery = clone $query;
|
||||
|
||||
$limitQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker'));
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT DISTINCT m0_.id AS id_0 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON (m0_.category_id = c1_.id)",
|
||||
$limitQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testLimitSubqueryWithSortWithArbitraryJoin()
|
||||
{
|
||||
$dql = 'SELECT p, c FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN Doctrine\Tests\ORM\Tools\Pagination\Category c WITH p.category = c ORDER BY p.title';
|
||||
$query = $this->entityManager->createQuery($dql);
|
||||
$limitQuery = clone $query;
|
||||
|
||||
$limitQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker'));
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT DISTINCT m0_.id AS id_0, m0_.title AS title_1 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON (m0_.category_id = c1_.id) ORDER BY m0_.title ASC",
|
||||
$limitQuery->getSql()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,5 +121,34 @@ class WhereInWalkerTest extends PaginationTestCase
|
||||
"SELECT u0_.id AS id_0, g1_.id AS id_1 FROM User u0_ INNER JOIN user_group u2_ ON u0_.id = u2_.user_id INNER JOIN groups g1_ ON g1_.id = u2_.group_id WHERE (NOT 1 = 2) AND u0_.id IN (?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arbitrary Join
|
||||
*/
|
||||
public function testWhereInQueryWithArbitraryJoin_NoWhere()
|
||||
{
|
||||
$whereInQuery = $this->entityManager->createQuery(
|
||||
'SELECT p FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p JOIN Doctrine\Tests\ORM\Tools\Pagination\Category c WITH p.category = c'
|
||||
);
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT b0_.id AS id_0, b0_.author_id AS author_id_1, b0_.category_id AS category_id_2 FROM BlogPost b0_ INNER JOIN Category c1_ ON (b0_.category_id = c1_.id) WHERE b0_.id IN (?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
|
||||
public function testWhereInQueryWithArbitraryJoin_SingleWhere()
|
||||
{
|
||||
$whereInQuery = $this->entityManager->createQuery(
|
||||
'SELECT p FROM Doctrine\Tests\ORM\Tools\Pagination\BlogPost p JOIN Doctrine\Tests\ORM\Tools\Pagination\Category c WITH p.category = c WHERE 1 = 1'
|
||||
);
|
||||
$whereInQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
|
||||
$whereInQuery->setHint(WhereInWalker::HINT_PAGINATOR_ID_COUNT, 10);
|
||||
|
||||
$this->assertEquals(
|
||||
"SELECT b0_.id AS id_0, b0_.author_id AS author_id_1, b0_.category_id AS category_id_2 FROM BlogPost b0_ INNER JOIN Category c1_ ON (b0_.category_id = c1_.id) WHERE 1 = 1 AND b0_.id IN (?)", $whereInQuery->getSql()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user