init
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace Lucent\Query;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class Filter
|
||||
{
|
||||
private array $operatorsList;
|
||||
|
||||
public function __construct(
|
||||
public array $arguments = [],
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public function add(array $arguments): Filter
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
private function formatArguments(array $arguments): array
|
||||
{
|
||||
return (array)collect($arguments)->reduce(fn($c, $v, $k) => $this->formatArgument($c, $v, $k), []);
|
||||
}
|
||||
|
||||
private function formatArgument(array $arguments, mixed $value, string $filter): array
|
||||
{
|
||||
|
||||
$operator = $this->detectOperator($filter);
|
||||
$field = $this->detectField($filter, $operator);
|
||||
$formattedValue = match ($operator) {
|
||||
"eq" => $this->formatText($value),
|
||||
"ne" => $this->formatText($value),
|
||||
"eqnum" => $this->formatNumber($value),
|
||||
"nenum" => $this->formatNumber($value),
|
||||
"object" => $this->formatText($value),
|
||||
"in" => $this->formatListString($value),
|
||||
"nin" => $this->formatListString($value),
|
||||
"innum" => $this->formatListNum($value),
|
||||
"ninnum" => $this->formatListNum($value),
|
||||
"eqtrue" => true,
|
||||
"eqfalse" => false,
|
||||
"netrue" => true,
|
||||
"nefalse" => false,
|
||||
"regex" => "%{$value}%",
|
||||
"gt" => \is_numeric($value) ? floatval($value) : $value,
|
||||
"gte" => \is_numeric($value) ? floatval($value) : $value,
|
||||
"lt" => \is_numeric($value) ? floatval($value) : $value,
|
||||
"lte" => \is_numeric($value) ? floatval($value) : $value,
|
||||
"null" => null,
|
||||
"nnull" => null,
|
||||
"exists" => true,
|
||||
"nexists" => false,
|
||||
default => $value,
|
||||
};
|
||||
|
||||
|
||||
$matchedOperator = $this->operatorsList[$operator];
|
||||
$arguments[] = [
|
||||
"field" => str_replace(".", "->", $field),
|
||||
"operator" => $matchedOperator->db,
|
||||
"value" => $formattedValue
|
||||
];
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
private function formatText(string $value): string
|
||||
{
|
||||
return trim($value);
|
||||
}
|
||||
|
||||
private function formatNumber(string $value): float
|
||||
{
|
||||
return \floatval($value);
|
||||
}
|
||||
|
||||
|
||||
private function formatListString(mixed $value): array
|
||||
{
|
||||
if (\is_string($value)) {
|
||||
$value = explode(",", $value);
|
||||
}
|
||||
|
||||
return \array_map(fn($v) => $this->formatText($v), $value);
|
||||
}
|
||||
|
||||
private function formatListNum(mixed $value): array
|
||||
{
|
||||
if (\is_string($value)) {
|
||||
$value = explode(",", $value);
|
||||
}
|
||||
|
||||
return \array_map(fn($v) => $this->formatNumber($v), $value);
|
||||
}
|
||||
|
||||
|
||||
private function detectOperator(string $filter): string
|
||||
{
|
||||
$exploded = \explode("_", $filter);
|
||||
$candidate = end($exploded);
|
||||
$operatorsListNames = collect($this->operatorsList)->map(fn($o) => $o->name)->toArray();
|
||||
|
||||
if (\in_array($candidate, $operatorsListNames)) {
|
||||
return $candidate;
|
||||
}
|
||||
return 'eq';
|
||||
}
|
||||
|
||||
private function detectField(string $filter, string $operator): string
|
||||
{
|
||||
$exploded = \explode("_", $filter);
|
||||
$candidate = array_pop($exploded);
|
||||
|
||||
if ($candidate == $operator) {
|
||||
return \implode("_", $exploded);
|
||||
}
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
|
||||
private function formatReferences(Query $query): array
|
||||
{
|
||||
[$arguments, $referenceArguments] = $this->separateMainFromReferenceArguments();
|
||||
if (empty($referenceArguments)) {
|
||||
return [$arguments, []];
|
||||
};
|
||||
|
||||
$subqueries = collect($referenceArguments)->reduce(function ($c, $v, $k) {
|
||||
$keyWithoutRef = str_replace("children.", "", $k);
|
||||
[$field] = explode(".", $keyWithoutRef);
|
||||
$referenceField = str_replace($field . ".", "", $keyWithoutRef);
|
||||
$c[$field][$referenceField] = $v;
|
||||
return $c;
|
||||
}, []);
|
||||
|
||||
|
||||
$sourceIds = collect($subqueries)->reduce(function ($c, $subquery, $k) use ($query) {
|
||||
|
||||
$graph = $query->filter($subquery)->run();
|
||||
|
||||
if (!$graph->hasResults()) {
|
||||
return $c;
|
||||
}
|
||||
|
||||
$targetIds = collect($graph->records)->pluck("id");
|
||||
$sourceIds = DB::table("edges")->whereIn("target", $targetIds)->where("field", $k)->get()->pluck("source");
|
||||
return array_merge($c, $sourceIds->toArray());
|
||||
}, []);
|
||||
|
||||
return [$arguments, [
|
||||
"field" => "id",
|
||||
"operator" => "in",
|
||||
"value" => $sourceIds
|
||||
]];
|
||||
}
|
||||
|
||||
private function separateMainFromReferenceArguments(): array
|
||||
{
|
||||
return collect($this->arguments)->partition(function ($v, $k) {
|
||||
if (!str_starts_with($k, "children.")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
|
||||
public function run(Query $query): array
|
||||
{
|
||||
[$argumentsWithoutReferences, $referencesFilter] = $this->formatReferences($query);
|
||||
|
||||
$this->operatorsList = Operator::list();
|
||||
$formattedArguments = $this->formatArguments($argumentsWithoutReferences);
|
||||
if (!empty($referencesFilter)) {
|
||||
$formattedArguments[] = $referencesFilter;
|
||||
}
|
||||
return $formattedArguments;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user