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; } }