<?php
namespace Fuse\Core;
use Fuse\Core\Register;
use Fuse\Exception\LogicalSearchInvalidQueryForKeyException;
use Fuse\Tools\KeyStore;
use function Fuse\Helpers\Types\{isArray, isAssoc};
function isExpression(array $query): bool
{
return isset($query[LogicalOperator::AND]) || isset($query[LogicalOperator::OR]);
}
function isPath(array $query): bool
{
return isset($query[KeyType::PATH]);
}
function isLeaf(array $query): bool
{
return isAssoc($query) && !isExpression($query);
}
/**
* @return array[][]
*
* @psalm-return array{$and: list<array>}
*/
function convertToExplicit(array $query): array
{
return [
LogicalOperator::AND => array_map(fn ($key) => [$key => $query[$key]], array_keys($query)),
];
}
function parseNext(array $query, array $options, bool $auto): array
{
$keys = array_keys($query);
$isQueryPath = isPath($query);
if (!$isQueryPath && sizeof($keys) > 1 && !isExpression($query)) {
return parseNext(convertToExplicit($query), $options, $auto);
}
if (isLeaf($query)) {
$key = $isQueryPath ? $query[KeyType::PATH] : $keys[0];
$pattern = $isQueryPath ? $query[KeyType::PATTERN] : $query[$key];
if (!is_string($pattern)) {
throw new LogicalSearchInvalidQueryForKeyException($key);
}
$obj = [
'keyId' => KeyStore::createKeyId($key),
'pattern' => $pattern,
];
if ($auto) {
$obj['searcher'] = Register::createSearcher($pattern, $options);
}
return $obj;
}
$node = [
'children' => [],
'operator' => $keys[0],
];
foreach ($keys as $key) {
$value = $query[$key];
if (isArray($value)) {
foreach ($value as $item) {
$node['children'][] = parseNext($item, $options, $auto);
}
}
}
return $node;
}
// When `auto` is `true`, the parse function will infer and initialize and add
// the appropriate `Searcher` instance
function parse(array $query, array $options, array $additionalOptions = []): array
{
$auto = $additionalOptions['auto'] ?? true;
if (!isExpression($query)) {
$query = convertToExplicit($query);
}
return parseNext($query, $options, $auto);
}
|