-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Workflow] Add tip on how to add a WHERE constraint on a multi-state marking store #20086
base: 5.4
Are you sure you want to change the base?
Conversation
Ping @lyrixx in case you can review this proposal. Thanks! |
`scienta/doctrine-json-functions` and enable the `JSON_CONTAINS_PATH` doctrine | ||
function. Then you can filter for a current place as follows: | ||
``$qb->andWhere("JSON_CONTAINS_PATH(item.currentPlaces, 'one', '$.draft') <> 0")`` | ||
(where `draft` is the place to be checked) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if it works.
I personally use:
private function filterByMarking(QueryBuilder $queryBuilder, array $markings, bool $and = false): void
{
$entityAlias = $queryBuilder->getRootAliases()[0];
$contains = [];
foreach ($markings as $marking) {
$contains[] = $queryBuilder->expr()->eq(sprintf(
'JSON_CONTAINS(%s.marking, %s)',
$entityAlias,
$queryBuilder->expr()->literal(json_encode([$marking => 1], \JSON_THROW_ON_ERROR)),
), 1);
}
if ($and) {
$queryBuilder->andWhere($queryBuilder->expr()->andX(...$contains));
} else {
$queryBuilder->andWhere($queryBuilder->expr()->orX(...$contains));
}
$queryBuilder->andWhere($queryBuilder->expr()->isNotNull("{$entityAlias}.marking"));
}
With this class
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;
class JsonContains extends FunctionNode
{
private const string FUNCTION_NAME = 'JSON_CONTAINS';
public ?Node $jsonDocExpr = null;
public ?Node $jsonValExpr = null;
public ?Node $jsonPathExpr = null;
public function getSql(SqlWalker $sqlWalker): string
{
$jsonDoc = $sqlWalker->walkStringPrimary($this->jsonDocExpr);
$jsonVal = $sqlWalker->walkStringPrimary($this->jsonValExpr);
$jsonPath = '';
if ($this->jsonPathExpr) {
$jsonPath = ', ' . $sqlWalker->walkStringPrimary($this->jsonPathExpr);
}
return sprintf('%s(%s, %s)', self::FUNCTION_NAME, $jsonDoc, "{$jsonVal}{$jsonPath}");
}
public function parse(Parser $parser): void
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->jsonDocExpr = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->jsonValExpr = $parser->StringPrimary();
if ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$this->jsonPathExpr = $parser->StringPrimary();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
Anyway, before merging this PR, item.currentPlaces
, one
, and $.draft
must be explained
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, PostgreSQL and mariadb have different option to deal with JSON
I think JSON CONTAINS and JSON_CONTAINS PATH in these usages are functional equivalent in these cases but I wonder what is more performant :-) |
Filtering a single state marking store might be straightforward (i.e.,
WHERE currentPlaces = :place
).I found filtering on a multiple state marking store with JSON schema more challenging (because of the key-value structure as well).
Also, JSON functions are not default to Doctrine and not standardized among databases.