Skip to content

Instantly share code, notes, and snippets.

@wbrframe
Created September 5, 2019 12:52
Show Gist options
  • Save wbrframe/6ffe6292345024fb059d4693ffd346ca to your computer and use it in GitHub Desktop.
Save wbrframe/6ffe6292345024fb059d4693ffd346ca to your computer and use it in GitHub Desktop.
Doctrine custom DQL string function for PostgreSQL string_agg with supports DISTINCT and ORDER BY clause
<?php
namespace App\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Literal;
use Doctrine\ORM\Query\AST\OrderByClause;
use Doctrine\ORM\Query\AST\PathExpression;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* StringAgg.
*/
class StringAgg extends FunctionNode
{
/**
* @var PathExpression|null
*/
private $expression = null;
/**
* @var Literal|null
*/
private $delimiter = null;
/**
* @var bool
*/
private $isDistinct = false;
/**
* @var OrderByClause|null
*/
public $orderBy = null;
/**
* @param Parser $parser
*/
public function parse(Parser $parser): void
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$lexer = $parser->getLexer();
if ($lexer->isNextToken(Lexer::T_DISTINCT)) {
$parser->match(Lexer::T_DISTINCT);
$this->isDistinct = true;
}
$this->expression = $parser->PathExpression(PathExpression::TYPE_STATE_FIELD);
$parser->match(Lexer::T_COMMA);
$this->delimiter = $parser->StringPrimary();
if ($lexer->isNextToken(Lexer::T_ORDER)) {
$this->orderBy = $parser->OrderByClause();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* @param SqlWalker $sqlWalker
*
* @return string
*/
public function getSql(SqlWalker $sqlWalker): string
{
return \sprintf('string_agg(%s%s, %s%s)',
($this->isDistinct ? 'DISTINCT ' : ''),
$sqlWalker->walkPathExpression($this->expression),
$sqlWalker->walkStringPrimary($this->delimiter),
($this->orderBy ? $sqlWalker->walkOrderByClause($this->orderBy) : '')
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment