Allow flipping of subqueries

This commit is contained in:
Sobuno
2025-01-03 00:07:57 +01:00
parent a62916a63d
commit 0c955efa8b
3 changed files with 34 additions and 17 deletions

View File

@@ -23,10 +23,10 @@ declare(strict_types=1);
namespace FireflyIII\Providers; namespace FireflyIII\Providers;
use FireflyIII\Support\Search\GdbotsQueryParser; use FireflyIII\Support\Search\QueryParser\GdbotsQueryParser;
use FireflyIII\Support\Search\OperatorQuerySearch; use FireflyIII\Support\Search\OperatorQuerySearch;
use FireflyIII\Support\Search\QueryParser; use FireflyIII\Support\Search\QueryParser\QueryParser;
use FireflyIII\Support\Search\QueryParserInterface; use FireflyIII\Support\Search\QueryParser\QueryParserInterface;
use FireflyIII\Support\Search\SearchInterface; use FireflyIII\Support\Search\SearchInterface;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;

View File

@@ -150,7 +150,7 @@ class OperatorQuerySearch implements SearchInterface
} }
app('log')->debug(sprintf('Found %d node(s) at top-level', count($parsedQuery->getNodes()))); app('log')->debug(sprintf('Found %d node(s) at top-level', count($parsedQuery->getNodes())));
$this->handleSearchNode($parsedQuery); $this->handleSearchNode($parsedQuery, $parsedQuery->isProhibited(false));
// add missing information // add missing information
$this->collector->withBillInformation(); $this->collector->withBillInformation();
@@ -164,21 +164,21 @@ class OperatorQuerySearch implements SearchInterface
* *
* @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/ */
private function handleSearchNode(Node $node): void private function handleSearchNode(Node $node, $flipProhibitedFlag): void
{ {
app('log')->debug(sprintf('Now in handleSearchNode(%s)', get_class($node))); app('log')->debug(sprintf('Now in handleSearchNode(%s)', get_class($node)));
switch (true) { switch (true) {
case $node instanceof StringNode: case $node instanceof StringNode:
$this->handleStringNode($node); $this->handleStringNode($node, $flipProhibitedFlag);
break; break;
case $node instanceof FieldNode: case $node instanceof FieldNode:
$this->handleFieldNode($node); $this->handleFieldNode($node, $flipProhibitedFlag);
break; break;
case $node instanceof NodeGroup: case $node instanceof NodeGroup:
$this->handleNodeGroup($node); $this->handleNodeGroup($node, $flipProhibitedFlag);
break; break;
default: default:
@@ -187,20 +187,24 @@ class OperatorQuerySearch implements SearchInterface
} }
} }
private function handleNodeGroup(NodeGroup $node): void private function handleNodeGroup(NodeGroup $node, $flipProhibitedFlag): void
{ {
//TODO: Handle Subquery prohibition, i.e. flip all prohibition flags inside the subquery $prohibited = $node->isProhibited($flipProhibitedFlag);
foreach ($node->getNodes() as $subNode) { foreach ($node->getNodes() as $subNode) {
$this->handleSearchNode($subNode); $this->handleSearchNode($subNode, $prohibited);
} }
} }
private function handleStringNode(StringNode $node): void private function handleStringNode(StringNode $node, $flipProhibitedFlag): void
{ {
$string = (string) $node->getValue(); $string = (string) $node->getValue();
if($node->isProhibited()) {
$prohibited = $node->isProhibited($flipProhibitedFlag);
if($prohibited) {
app('log')->debug(sprintf('Exclude string "%s" from search string', $string)); app('log')->debug(sprintf('Exclude string "%s" from search string', $string));
$this->prohibitedWords[] = $string; $this->prohibitedWords[] = $string;
} else { } else {
@@ -212,11 +216,11 @@ class OperatorQuerySearch implements SearchInterface
/** /**
* @throws FireflyException * @throws FireflyException
*/ */
private function handleFieldNode(FieldNode $node): void private function handleFieldNode(FieldNode $node, $flipProhibitedFlag): void
{ {
$operator = strtolower($node->getOperator()); $operator = strtolower($node->getOperator());
$value = $node->getValue(); $value = $node->getValue();
$prohibited = $node->isProhibited(); $prohibited = $node->isProhibited($flipProhibitedFlag);
$context = config(sprintf('search.operators.%s.needs_context', $operator)); $context = config(sprintf('search.operators.%s.needs_context', $operator));

View File

@@ -11,8 +11,21 @@ abstract class Node
{ {
protected bool $prohibited; protected bool $prohibited;
public function isProhibited(): bool /**
* Returns the prohibited status of the node, optionally inverted based on flipFlag
*
* Flipping is used when a node is inside a NodeGroup that has a prohibited status itself, causing inversion of the query parts inside
*
* @param bool $flipFlag When true, inverts the prohibited status
* @return bool The (potentially inverted) prohibited status
*/
public function isProhibited(bool $flipFlag): bool
{ {
return $this->prohibited; if ($flipFlag === true) {
return !$this->prohibited;
} else {
return $this->prohibited;
}
} }
} }