|
|
|
@ -18,21 +18,19 @@ use OCP\Files\Search\ISearchOperator;
|
|
|
|
|
*/
|
|
|
|
|
class MergeDistributiveOperations extends ReplacingOptimizerStep {
|
|
|
|
|
public function processOperator(ISearchOperator &$operator): bool {
|
|
|
|
|
if (
|
|
|
|
|
$operator instanceof SearchBinaryOperator &&
|
|
|
|
|
$this->isAllSameBinaryOperation($operator->getArguments())
|
|
|
|
|
) {
|
|
|
|
|
if ($operator instanceof SearchBinaryOperator) {
|
|
|
|
|
// either 'AND' or 'OR'
|
|
|
|
|
$topLevelType = $operator->getType();
|
|
|
|
|
|
|
|
|
|
// split the arguments into groups that share a first argument
|
|
|
|
|
// (we already know that all arguments are binary operators with at least 1 child)
|
|
|
|
|
$groups = $this->groupBinaryOperatorsByChild($operator->getArguments(), 0);
|
|
|
|
|
$outerOperations = array_map(function (array $operators) use ($topLevelType) {
|
|
|
|
|
// no common operations, no need to change anything
|
|
|
|
|
if (count($operators) === 1) {
|
|
|
|
|
return $operators[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for groups with size >1 we know they are binary operators with at least 1 child
|
|
|
|
|
/** @var ISearchBinaryOperator $firstArgument */
|
|
|
|
|
$firstArgument = $operators[0];
|
|
|
|
|
|
|
|
|
@ -72,46 +70,25 @@ class MergeDistributiveOperations extends ReplacingOptimizerStep {
|
|
|
|
|
return parent::processOperator($operator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check that a list of operators is all the same type of (non-empty) binary operators
|
|
|
|
|
*
|
|
|
|
|
* @param ISearchOperator[] $operators
|
|
|
|
|
* @return bool
|
|
|
|
|
* @psalm-assert-if-true SearchBinaryOperator[] $operators
|
|
|
|
|
*/
|
|
|
|
|
private function isAllSameBinaryOperation(array $operators): bool {
|
|
|
|
|
$operation = null;
|
|
|
|
|
foreach ($operators as $operator) {
|
|
|
|
|
if (!$operator instanceof SearchBinaryOperator) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!$operator->getArguments()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ($operation === null) {
|
|
|
|
|
$operation = $operator->getType();
|
|
|
|
|
} else {
|
|
|
|
|
if ($operation !== $operator->getType()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Group a list of binary search operators that have a common argument
|
|
|
|
|
*
|
|
|
|
|
* @param SearchBinaryOperator[] $operators
|
|
|
|
|
* @return SearchBinaryOperator[][]
|
|
|
|
|
* Non-binary operators, or empty binary operators will each get their own 1-sized group
|
|
|
|
|
*
|
|
|
|
|
* @param ISearchOperator[] $operators
|
|
|
|
|
* @return ISearchOperator[][]
|
|
|
|
|
*/
|
|
|
|
|
private function groupBinaryOperatorsByChild(array $operators, int $index = 0): array {
|
|
|
|
|
$result = [];
|
|
|
|
|
foreach ($operators as $operator) {
|
|
|
|
|
/** @var SearchBinaryOperator|SearchComparison $child */
|
|
|
|
|
$child = $operator->getArguments()[$index];
|
|
|
|
|
$childKey = (string) $child;
|
|
|
|
|
$result[$childKey][] = $operator;
|
|
|
|
|
if ($operator instanceof ISearchBinaryOperator && count($operator->getArguments()) > 0) {
|
|
|
|
|
/** @var SearchBinaryOperator|SearchComparison $child */
|
|
|
|
|
$child = $operator->getArguments()[$index];
|
|
|
|
|
$childKey = (string)$child;
|
|
|
|
|
$result[$childKey][] = $operator;
|
|
|
|
|
} else {
|
|
|
|
|
$result[] = [$operator];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return array_values($result);
|
|
|
|
|
}
|
|
|
|
|