"MEMBER OF" support for JSON columns #9506
-
Hello there, I recently stubbled upon Tobias Petry's tweet about using The problem is I don't manage to make it work with the DQL translation. Consider: #[ORM\Entity]
class Foo {
// ...
/**
* @var array<int>
*/
#[ORM\Column(type: 'json')]
public array $tags;
} Doing this $em
->createQueryBuilder()
->select('f')
->from(Foo::class, 'f')
->setMaxResults(1)
->where(':tag MEMBER OF f.tags')
->setParameter('tag', 2)
->getQuery()
->getOneOrNullResult(); Produces the following error:
It looks that Doctrine's I currently use scienta/doctrine-json-functions with |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
You are correct. DQL does not support inspecting JSON fields. Part of the problem is not every database supported by the ORM implements a native JSON data type. And those who do usually use a self-invented sytax for JSON operations. It is certainly doable to build JSON support into DQL. But I don't expect it to be an easy task. Do you want to work on it? |
Beta Was this translation helpful? Give feedback.
-
Hey again! 👋 Just asking a little help as I tried to implement this as a DQL function instead, i.e:
Looks pretty simple by doing this: use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
final class JsonMemberOf extends FunctionNode
{
/**
* @var array<Node>
*/
protected array $expressions = [];
public function parse(Parser $parser): void
{
$lexer = $parser->getLexer();
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->expressions[] = $parser->ArithmeticPrimary(); // @phpstan-ignore-line
// @phpstan-ignore-next-line
while (\count($this->expressions) < 2 && Lexer::T_CLOSE_PARENTHESIS !== $lexer->lookahead['type']) {
$parser->match(Lexer::T_COMMA);
$this->expressions[] = $parser->ArithmeticPrimary(); // @phpstan-ignore-line
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(SqlWalker $sqlWalker): string
{
$arguments = [];
foreach ($this->expressions as $expression) {
$arguments[] = $expression->dispatch($sqlWalker);
}
$value = $arguments[1];
$field = $arguments[0];
return \sprintf('%d MEMBER OF (%s)', $value, $field);
}
} It seems to work, except I'm kinda enforced to write
The problem is, even if I get the same results, MySQL conditions written as Thanks! |
Beta Was this translation helpful? Give feedback.
You are correct. DQL does not support inspecting JSON fields. Part of the problem is not every database supported by the ORM implements a native JSON data type. And those who do usually use a self-invented sytax for JSON operations.
It is certainly doable to build JSON support into DQL. But I don't expect it to be an easy task. Do you want to work on it?