Nie wiem, czy ja coś robie źle, czy faktycznie z Doctrinem trzeba się tak szaprać. Chciałem zrobić mniej więcej cos takiego:
SELECT COALESCE((SELECT JSON_AGG(id) FROM customers), '[]') FROM ...
$related_customers = .... ->getDQL();
$qb = $this->_em->createQueryBuilder()
->select(...)
->addSelect("coalesce(($related_customers), '[]') AS related_customers")
Niestety użycie subquery w połączeniu z coalesce
nie zostało przewidziane. No to co, zaczynam grzebać w parserze w poszukiwaniu rozwiązania.
Na szybkości zmodyfikowałem metodę CoalesceExpression, żeby mi przeparsowała to (Parser.php):
public function CoalesceExpression()
{
$this->match(Lexer::T_COALESCE);
$this->match(Lexer::T_OPEN_PARENTHESIS);
// Process ScalarExpressions (1..N)
$scalarExpressions = array();
if($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
$expr = $this->SimpleSelectExpression();
$scalarExpressions[] = $expr;
} else {
$scalarExpressions[] = $this->ScalarExpression();
}
while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
$this->match(Lexer::T_COMMA);
if($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
$expr = $this->SimpleSelectExpression();
$scalarExpressions[] = $expr;
} else {
$scalarExpressions[] = $this->ScalarExpression();
}
}
$this->match(Lexer::T_CLOSE_PARENTHESIS);
return new AST\CoalesceExpression($scalarExpressions);
}
Niestety to nie wystarczy, bo Doctrine mi na siłę aliasuje wszytko... no to co, może tak (SqlWalker.php):
public function walkSimpleSelectExpression($simpleSelectExpression) {
// ...
case ($expr instanceof AST\Subselect):
if($expr->no_alias) {
$sql .= '(' . $this->walkSubselect($expr) . ')';
break;
}
Great success. Z tym że coś mi się nie chce wierzyć, że trzeba się z tym tak mordować. Już nawet nie chodzi o słuszność tego zapytania, tylko dziwi mnie dlaczego coś co jest valid sql nie działa. Tak samo byłem zdziwiony, że nie ma gotowego JSON_AGG
, lub JSON_BUILD_OBJECT