diff --git a/front/js/svelte/content/tools/AppliedFilter.svelte b/front/js/svelte/content/tools/AppliedFilter.svelte index b64d165..c8e89d5 100644 --- a/front/js/svelte/content/tools/AppliedFilter.svelte +++ b/front/js/svelte/content/tools/AppliedFilter.svelte @@ -12,7 +12,6 @@ export let inModal; export let modalUrl; export let graph; - let filter = { label: "", operator: "", @@ -58,9 +57,11 @@ const filterRecord = extractFilterRecord(graph, value); function extractFilterRecord(graph, value) { + if (!filter.isReference) { return null; } + console.log(graph) return graph.records.find(r => r.id === value); } @@ -82,7 +83,7 @@ {#if filter.isReference && filterRecord} {filter.label} is {previewTitle(channel.schemas, filterRecord)} {:else} - {filter.label} {operators.find((o) => o.name === filter.operator)?.symbol ?? ""} {value} + {filter.label} {operators.find((o) => o.name === filter.operator)?.symbol ?? ""} {operators.find((o) => o.name === filter.operator)?.hasValue ? value : ""} {/if} {/each} @@ -214,8 +220,8 @@ required /> - diff --git a/front/views/auth/login.blade.php b/front/views/auth/login.blade.php index 7e40667..5bcb84d 100644 --- a/front/views/auth/login.blade.php +++ b/front/views/auth/login.blade.php @@ -10,6 +10,7 @@

Enter Lucent

+ @csrf

Submit your email address and you will receive a login link to your email

Don't forget to check your spam folder

diff --git a/src/Http/Controller/RecordController.php b/src/Http/Controller/RecordController.php index 9ff8a27..60a6178 100644 --- a/src/Http/Controller/RecordController.php +++ b/src/Http/Controller/RecordController.php @@ -8,7 +8,7 @@ use Lucent\Account\AccountService; use Lucent\Account\AuthService; use Lucent\Channel\ChannelService; use Lucent\LucentException; -use Lucent\Query\Operator; +use Lucent\Query\Operator\OperatorRegistry; use Lucent\Query\Query; use Lucent\Record\InputData\EdgeInputData; use Lucent\Record\InputData\RecordInputData; @@ -25,13 +25,14 @@ use function Lucent\Response\ok; class RecordController extends Controller { public function __construct( - private readonly RecordService $recordService, - private readonly AccountService $accountService, - private readonly AuthService $authService, - private readonly ChannelService $channelService, - private readonly Svelte $svelte, - private readonly Query $query, - private readonly Manager $recordManager + private readonly RecordService $recordService, + private readonly AccountService $accountService, + private readonly AuthService $authService, + private readonly ChannelService $channelService, + private readonly Svelte $svelte, + private readonly Query $query, + private readonly Manager $recordManager, + private readonly OperatorRegistry $operatorRegistry ) { } @@ -79,7 +80,6 @@ class RecordController extends Controller $records = $graph->getRootRecords()->toArray(); - $data = [ "schemas" => $this->channelService->channel->schemas, "schema" => $schema, @@ -87,7 +87,7 @@ class RecordController extends Controller "records" => $records, "graph" => toArray($graph), "systemFields" => array_values(System::list()), - "operators" => array_values(Operator::list()), + "operators" => $this->operatorRegistry->all(), "sortParam" => $sort, "sortField" => $schema->fields->merge(array_values(System::list()))->firstWhere(fn($field) => $field->name === $sort || "-" . $field->name === $sort || "data." . $field->name === $sort || "-data." . $field->name === $sort), "limit" => $limit, @@ -302,7 +302,7 @@ class RecordController extends Controller id: $request->input("record.id"), data: $request->input("record.data"), status: Status::from($request->input("record.status")), - edges: array_map(EdgeInputData::fromArray(...), $request->input("edges") ?? []), + edges: array_map(EdgeInputData::fromArray(...), $request->input("edges") ?? []), ); } diff --git a/src/Query/BuilderConverter/BuilderConverter.php b/src/Query/BuilderConverter/BuilderConverter.php new file mode 100644 index 0000000..ec499e2 --- /dev/null +++ b/src/Query/BuilderConverter/BuilderConverter.php @@ -0,0 +1,13 @@ +operator->converter)($argument); + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/Equals.php b/src/Query/BuilderConverter/Equals.php new file mode 100644 index 0000000..e54a4ad --- /dev/null +++ b/src/Query/BuilderConverter/Equals.php @@ -0,0 +1,29 @@ +where($this->argument->field, $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere($this->argument->field, $this->formatValue()); + } + + private function formatValue(): string + { + return trim($this->argument->value); + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/EqualsFalse.php b/src/Query/BuilderConverter/EqualsFalse.php new file mode 100644 index 0000000..7add416 --- /dev/null +++ b/src/Query/BuilderConverter/EqualsFalse.php @@ -0,0 +1,26 @@ +where($this->argument->field, false); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere($this->argument->field, false); + } + + +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/EqualsNumber.php b/src/Query/BuilderConverter/EqualsNumber.php new file mode 100644 index 0000000..786d347 --- /dev/null +++ b/src/Query/BuilderConverter/EqualsNumber.php @@ -0,0 +1,31 @@ +where($this->argument->field, $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere($this->argument->field, $this->formatValue()); + } + + private function formatValue(): int|float + { + $value = trim($this->argument->value); + return str_contains($value, ".") ? floatval($value) : intval($value); + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/EqualsTrue.php b/src/Query/BuilderConverter/EqualsTrue.php new file mode 100644 index 0000000..7c08d5b --- /dev/null +++ b/src/Query/BuilderConverter/EqualsTrue.php @@ -0,0 +1,25 @@ +where($this->argument->field, true); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere($this->argument->field, true); + } + +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/Exists.php b/src/Query/BuilderConverter/Exists.php new file mode 100644 index 0000000..eb36c53 --- /dev/null +++ b/src/Query/BuilderConverter/Exists.php @@ -0,0 +1,25 @@ +whereNot($this->argument->field, "")->whereNotNull($this->argument->field); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->whereNot($this->argument->field, "")->whereNotNull($this->argument->field); + } + +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/Filter.php b/src/Query/BuilderConverter/Filter.php new file mode 100644 index 0000000..a96f92f --- /dev/null +++ b/src/Query/BuilderConverter/Filter.php @@ -0,0 +1,25 @@ +whereJsonContains($this->argument->field, [$this->argument->value]); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereJsonContains($this->argument->field, [$this->argument->value]); + } + +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/GreaterThan.php b/src/Query/BuilderConverter/GreaterThan.php new file mode 100644 index 0000000..5527cb8 --- /dev/null +++ b/src/Query/BuilderConverter/GreaterThan.php @@ -0,0 +1,35 @@ +where($this->argument->field, ">", $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere($this->argument->field, ">", $this->formatValue()); + } + + private function formatValue(): int|float + { + $value = trim($this->argument->value); + if (is_numeric($value)) { + return str_contains($value, ".") ? floatval($value) : intval($value); + } + return $value; + + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/GreaterThanEquals.php b/src/Query/BuilderConverter/GreaterThanEquals.php new file mode 100644 index 0000000..809cf7f --- /dev/null +++ b/src/Query/BuilderConverter/GreaterThanEquals.php @@ -0,0 +1,35 @@ +where($this->argument->field, ">=", $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere($this->argument->field, ">=", $this->formatValue()); + } + + private function formatValue(): int|float + { + $value = trim($this->argument->value); + if (is_numeric($value)) { + return str_contains($value, ".") ? floatval($value) : intval($value); + } + return $value; + + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/IBuilderConverter.php b/src/Query/BuilderConverter/IBuilderConverter.php new file mode 100644 index 0000000..5996a4a --- /dev/null +++ b/src/Query/BuilderConverter/IBuilderConverter.php @@ -0,0 +1,13 @@ +whereIn($this->argument->field, $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereIn($this->argument->field, $this->formatValue()); + } + + private function formatValue(): array + { + $value = $this->argument->value; + if (is_string($value)) { + $value = explode(",", $value); + } + return array_map(fn($v) => trim($v), $value); + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/InNum.php b/src/Query/BuilderConverter/InNum.php new file mode 100644 index 0000000..28205ab --- /dev/null +++ b/src/Query/BuilderConverter/InNum.php @@ -0,0 +1,39 @@ +whereIn($this->argument->field, $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereIn($this->argument->field, $this->formatValue()); + } + + private function formatValue(): array + { + $value = $this->argument->value; + if (is_string($value)) { + $value = explode(",", $value); + } + return array_map(fn($v) => $this->formatNumber($v), $value); + } + + private function formatNumber(string $value): float|int + { + $value = trim($value); + return str_contains($value, ".") ? floatval($value) : intval($value); + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/IsNull.php b/src/Query/BuilderConverter/IsNull.php new file mode 100644 index 0000000..9ed096d --- /dev/null +++ b/src/Query/BuilderConverter/IsNull.php @@ -0,0 +1,25 @@ +whereNull($this->argument->field); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereNull($this->argument->field); + } + +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/LessThan.php b/src/Query/BuilderConverter/LessThan.php new file mode 100644 index 0000000..aefea3e --- /dev/null +++ b/src/Query/BuilderConverter/LessThan.php @@ -0,0 +1,35 @@ +where($this->argument->field, "<", $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere($this->argument->field, "<", $this->formatValue()); + } + + private function formatValue(): int|float + { + $value = trim($this->argument->value); + if (is_numeric($value)) { + return str_contains($value, ".") ? floatval($value) : intval($value); + } + return $value; + + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/LessThanEquals.php b/src/Query/BuilderConverter/LessThanEquals.php new file mode 100644 index 0000000..000c63d --- /dev/null +++ b/src/Query/BuilderConverter/LessThanEquals.php @@ -0,0 +1,35 @@ +where($this->argument->field, "<=", $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere($this->argument->field, "<=", $this->formatValue()); + } + + private function formatValue(): int|float + { + $value = trim($this->argument->value); + if (is_numeric($value)) { + return str_contains($value, ".") ? floatval($value) : intval($value); + } + return $value; + + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/NotEquals.php b/src/Query/BuilderConverter/NotEquals.php new file mode 100644 index 0000000..2fa8441 --- /dev/null +++ b/src/Query/BuilderConverter/NotEquals.php @@ -0,0 +1,29 @@ +whereNot($this->argument->field, $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereNot($this->argument->field, $this->formatValue()); + } + + private function formatValue(): string + { + return trim($this->argument->value); + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/NotEqualsFalse.php b/src/Query/BuilderConverter/NotEqualsFalse.php new file mode 100644 index 0000000..e30507c --- /dev/null +++ b/src/Query/BuilderConverter/NotEqualsFalse.php @@ -0,0 +1,26 @@ +whereNot($this->argument->field, false); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereNot($this->argument->field, false); + } + + +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/NotEqualsNumber.php b/src/Query/BuilderConverter/NotEqualsNumber.php new file mode 100644 index 0000000..dcac9d9 --- /dev/null +++ b/src/Query/BuilderConverter/NotEqualsNumber.php @@ -0,0 +1,30 @@ +whereNot($this->argument->field, $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereNot($this->argument->field, $this->formatValue()); + } + + private function formatValue(): int|float + { + $value = trim($this->argument->value); + return str_contains($value, ".") ? floatval($value) : intval($value); + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/NotEqualsTrue.php b/src/Query/BuilderConverter/NotEqualsTrue.php new file mode 100644 index 0000000..f1618db --- /dev/null +++ b/src/Query/BuilderConverter/NotEqualsTrue.php @@ -0,0 +1,25 @@ +whereNot($this->argument->field, true); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereNot($this->argument->field, true); + } + +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/NotExists.php b/src/Query/BuilderConverter/NotExists.php new file mode 100644 index 0000000..54159a7 --- /dev/null +++ b/src/Query/BuilderConverter/NotExists.php @@ -0,0 +1,25 @@ +where(fn($b) => $b->where($this->argument->field, "")->orWhereNull($this->argument->field)); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere(fn($b) => $b->where($this->argument->field, "")->orWhereNull($this->argument->field)); + } + +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/NotIn.php b/src/Query/BuilderConverter/NotIn.php new file mode 100644 index 0000000..825bca3 --- /dev/null +++ b/src/Query/BuilderConverter/NotIn.php @@ -0,0 +1,33 @@ +whereNotIn($this->argument->field, $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereNotIn($this->argument->field, $this->formatValue()); + } + + private function formatValue(): array + { + $value = $this->argument->value; + if (is_string($value)) { + $value = explode(",", $value); + } + return array_map(fn($v) => trim($v), $value); + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/NotInNum.php b/src/Query/BuilderConverter/NotInNum.php new file mode 100644 index 0000000..597a90b --- /dev/null +++ b/src/Query/BuilderConverter/NotInNum.php @@ -0,0 +1,39 @@ +whereNotIn($this->argument->field, $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereNotIn($this->argument->field, $this->formatValue()); + } + + private function formatValue(): array + { + $value = $this->argument->value; + if (is_string($value)) { + $value = explode(",", $value); + } + return array_map(fn($v) => $this->formatNumber($v), $value); + } + + private function formatNumber(string $value): float|int + { + $value = trim($value); + return str_contains($value, ".") ? floatval($value) : intval($value); + } +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/NotNull.php b/src/Query/BuilderConverter/NotNull.php new file mode 100644 index 0000000..ca36879 --- /dev/null +++ b/src/Query/BuilderConverter/NotNull.php @@ -0,0 +1,25 @@ +whereNotNull($this->argument->field); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhereNotNull($this->argument->field); + } + +} \ No newline at end of file diff --git a/src/Query/BuilderConverter/Regex.php b/src/Query/BuilderConverter/Regex.php new file mode 100644 index 0000000..b20b6be --- /dev/null +++ b/src/Query/BuilderConverter/Regex.php @@ -0,0 +1,30 @@ +where($this->argument->field, "like", $this->formatValue()); + } + + public function toOrQueryBuilder(Builder $builder): Builder + { + return $builder->orWhere($this->argument->field, "like", $this->formatValue()); + } + + private function formatValue(): string + { + return "%" . strtolower(trim($this->argument->value)) . "%"; + } +} \ No newline at end of file diff --git a/src/Query/Filter/Argument.php b/src/Query/Filter/Argument.php index aa8d844..337e6c4 100644 --- a/src/Query/Filter/Argument.php +++ b/src/Query/Filter/Argument.php @@ -2,11 +2,15 @@ namespace Lucent\Query\Filter; +use Lucent\Query\Operator\Operator; + class Argument { public function __construct( - public string $field, - public string $operator, - public mixed $value, - ){} + public string $field, + public Operator $operator, + public mixed $value, + ) + { + } } \ No newline at end of file diff --git a/src/Query/FilterParser.php b/src/Query/FilterParser.php index cbcaa41..77aac36 100644 --- a/src/Query/FilterParser.php +++ b/src/Query/FilterParser.php @@ -5,19 +5,26 @@ namespace Lucent\Query; use Illuminate\Contracts\Foundation\Application; use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\DB; +use Lucent\Query\BuilderConverter\BuilderConverter; use Lucent\Query\Filter\AndFilter; use Lucent\Query\Filter\Argument; use Lucent\Query\Filter\Filter; use Lucent\Query\Filter\OrFilter; +use Lucent\Query\Operator\In; +use Lucent\Query\Operator\OperatorDetector; +use function explode; final class FilterParser { - public function __construct(public Application $app) + public function __construct( + public Application $app, + public BuilderConverter $builderConverter, + public OperatorDetector $operatorDetector, + ) { } - /** * @param array $arguments * @return array @@ -25,105 +32,11 @@ final class FilterParser private function formatArguments(array $arguments): array { return collect($arguments)->reduce(function ($c, $v, $k) { - $c[] = $this->formatArgument($v, $k); + $c[] = $this->operatorDetector->detect($v, $k); return $c; }, []); } - private function formatArgument(mixed $value, string $filter): Argument - { - - $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" => "%" . strtolower($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 = Operator::list()[$operator]; - return new Argument( - field: str_replace(".", "->", $field), - operator: $matchedOperator->db, - value: $formattedValue - ); - } - - 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(Operator::list())->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(array $referenceArguments): Argument { $subqueries = collect($referenceArguments)->reduce(function ($c, $v, $k) { @@ -151,7 +64,7 @@ final class FilterParser return new Argument( field: "id", - operator: "in", + operator: In::make(), value: $sourceIds ); @@ -174,7 +87,6 @@ final class FilterParser private function parseArguments(Filter $arguments): array { [$normalArguments, $referenceArguments] = $this->separateMainFromReferenceArguments($arguments); - $formattedArguments = $this->formatArguments($normalArguments); if (!empty($referenceArguments)) { $formattedArguments[] = $this->formatReferences($referenceArguments); @@ -198,26 +110,8 @@ final class FilterParser */ private function parseAnd(Builder $builder, array $arguments): Builder { - foreach ($arguments as $argument) { - if ($argument->operator == "in") { - $builder->whereIn($argument->field, $argument->value); - } else if ($argument->operator == "nin") { - $builder->whereNotIn($argument->field, $argument->value); - } else if ($argument->operator == "exists") { - $builder->where($argument->field, "!=", ""); - $builder->where($argument->field, "!=", null); - } elseif ($argument->operator == "filter") { - $builder->whereJsonContains($argument->field, [$argument->value]); - // target result - // filter[data.previousNames_object]=previousNames&filter[previousNames.name_eq]=alpha&filter[previousNames.id_eqnum]=24 - // $query->whereJsonContains("data->previousNames", [["name" => "alpha", "id" => 24]]); - // $query->whereJsonContains($filter["field"], [$objectFilters]); - } else { - $builder->where($argument->field, $argument->operator, $argument->value); - } - } - - return $builder; + return collect($arguments) + ->reduce(fn($cBuilder, Argument $arg) => $this->builderConverter->for($arg)->toAndQueryBuilder($cBuilder), $builder); } /** @@ -225,27 +119,10 @@ final class FilterParser */ private function parseOr(Builder $builder, array $arguments): Builder { - $builder->where(function (Builder $orBuilder) use ($arguments) { - foreach ($arguments as $argument) { - if ($argument->operator == "in") { - $orBuilder->orWhereIn($argument->field, $argument->value); - } else if ($argument->operator == "nin") { - $orBuilder->orWhereNotIn($argument->field, $argument->value); - } else if ($argument->operator == "exists") { - $orBuilder->where($argument->field, "!=", ""); - $orBuilder->where($argument->field, "!=", null); - } elseif ($argument->operator == "filter") { - $orBuilder->whereJsonContains($argument->field, [$argument->value]); - // target result - // filter[data.previousNames_object]=previousNames&filter[previousNames.name_eq]=alpha&filter[previousNames.id_eqnum]=24 - // $query->whereJsonContains("data->previousNames", [["name" => "alpha", "id" => 24]]); - // $query->whereJsonContains($filter["field"], [$objectFilters]); - } else { - $orBuilder->orWhere($argument->field, $argument->operator, $argument->value); - } - } + return $builder->where(function (Builder $orBuilder) use ($arguments) { + return collect($arguments) + ->reduce(fn($cBuilder, Argument $arg) => $this->builderConverter->for($arg)->toOrQueryBuilder($cBuilder), $orBuilder); }); - return $builder; } diff --git a/src/Query/Operator.php b/src/Query/Operator.php deleted file mode 100644 index ddf94f0..0000000 --- a/src/Query/Operator.php +++ /dev/null @@ -1,186 +0,0 @@ - - */ - public static function list(): array - { - - return [ - "regex" => new Operator( - name: "regex", - label: "Search", - symbol: "~", - db: 'like', - uis: ["id", "text", "textarea", "url", "color", "date", "datetime"], - ), - "eq" => new Operator( - name: "eq", - label: "Equals", - symbol: "is", - db: '=', - uis: ["id", "text", "textarea", "url", "color", "date", "datetime", "reference"], - ), - "ne" => new Operator( - name: "ne", - label: "Not Equals", - symbol: "is not", - db: '!=', - uis: ["id", "text", "textarea", "url", "color", "date", "datetime"], - ), - "eqnum" => new Operator( - name: "eqnum", - label: "Equals number", - symbol: "is", - db: '=', - uis: ["number"], - ), - "neqnum" => new Operator( - name: "nenum", - label: "Not Equals number", - symbol: "is not", - db: '$ne', - uis: ["number"], - ), - "filter" => new Operator( - name: "filter", - label: "Equals Object", - symbol: "is", - db: 'filter', - uis: [], - ), - "eqtrue" => new Operator( - name: "eqtrue", - label: "Equals true", - symbol: "is", - db: '=', - uis: ["checkbox"], - ), - "eqfalse" => new Operator( - name: "eqfalse", - label: "Equals false", - symbol: "is not", - db: '=', - uis: ["checkbox"], - ), - "netrue" => new Operator( - name: "netrue", - label: "Not equals true", - symbol: "!=", - db: '$ne', - uis: ["checkbox"], - ), - "nefalse" => new Operator( - name: "nefalse", - label: "Not equals false", - symbol: "!=", - db: '$ne', - uis: ["checkbox"], - ), - "in" => new Operator( - name: "in", - label: "In list", - symbol: "in", - db: 'in', - uis: ["id", "text", "textarea", "url", "color", "date", "datetime"], - ), - "innum" => new Operator( - name: "innum", - label: "In list of numbers", - symbol: "in", - db: '$in', - uis: ["number"], - ), - "nin" => new Operator( - name: "nin", - label: "Not in list", - symbol: "not in", - db: 'nin', - uis: ["id", "text", "textarea", "url", "color", "date", "datetime"], - ), - "ninnum" => new Operator( - name: "ninnum", - label: "Not In list of numbers", - symbol: "not in", - db: '$nin', - uis: ["number"], - ), - "lt" => new Operator( - name: "lt", - label: "Less than", - symbol: "<", - db: '<', - uis: ["number", "date", "datetime"], - ), - "lte" => new Operator( - name: "lte", - label: "Less than equals", - symbol: "<=", - db: '<=', - uis: ["number", "date", "datetime"], - ), - "gt" => new Operator( - name: "gt", - label: "Greater than", - symbol: ">", - db: '>', - uis: ["number", "date", "datetime"], - ), - "gte" => new Operator( - name: "gte", - label: "Greater than equals", - symbol: ">=", - db: '>=', - uis: ["number", "date", "datetime"], - ), - "null" => new Operator( - name: "null", - label: "Is null", - symbol: "=", - db: '$eq', - uis: ["*"], - ), - "nnull" => new Operator( - name: "nnull", - label: "Not null", - symbol: "!=", - db: '$ne', - uis: ["*"], - ), - "exists" => new Operator( - name: "exists", - label: "Exists", - symbol: "exists", - db: 'exists', - uis: ["*"], - ), - "nexists" => new Operator( - name: "nexists", - label: "Not exists", - symbol: "not exists", - db: '$exists', - uis: ["*"], - ), - - - ]; - } -} diff --git a/src/Query/Operator/Equals.php b/src/Query/Operator/Equals.php new file mode 100644 index 0000000..357f63b --- /dev/null +++ b/src/Query/Operator/Equals.php @@ -0,0 +1,15 @@ +"; + public array $uis = ["number", "date", "datetime"]; + public bool $hasValue = true; + public string $converter = \Lucent\Query\BuilderConverter\GreaterThan::class; + +} \ No newline at end of file diff --git a/src/Query/Operator/GreaterThanEquals.php b/src/Query/Operator/GreaterThanEquals.php new file mode 100644 index 0000000..6e99612 --- /dev/null +++ b/src/Query/Operator/GreaterThanEquals.php @@ -0,0 +1,15 @@ +"; + public array $uis = ["number", "date", "datetime"]; + public bool $hasValue = true; + public string $converter = \Lucent\Query\BuilderConverter\GreaterThanEquals::class; + +} \ No newline at end of file diff --git a/src/Query/Operator/In.php b/src/Query/Operator/In.php new file mode 100644 index 0000000..be778a2 --- /dev/null +++ b/src/Query/Operator/In.php @@ -0,0 +1,14 @@ +"; + public array $uis = ["number", "date", "datetime"]; + public bool $hasValue = true; + public string $converter = \Lucent\Query\BuilderConverter\LessThan::class; + +} \ No newline at end of file diff --git a/src/Query/Operator/LessThanEquals.php b/src/Query/Operator/LessThanEquals.php new file mode 100644 index 0000000..35c72b0 --- /dev/null +++ b/src/Query/Operator/LessThanEquals.php @@ -0,0 +1,15 @@ +"; + public array $uis = ["number", "date", "datetime"]; + public bool $hasValue = true; + public string $converter = \Lucent\Query\BuilderConverter\LessThanEquals::class; + +} \ No newline at end of file diff --git a/src/Query/Operator/NotEquals.php b/src/Query/Operator/NotEquals.php new file mode 100644 index 0000000..b04e306 --- /dev/null +++ b/src/Query/Operator/NotEquals.php @@ -0,0 +1,14 @@ +detectOperator($filter); + $field = $this->detectField($filter, $operator->name); + return new Argument( + field: str_replace(".", "->", $field), + operator: $operator, + value: $value + ); + } + + private function detectOperator(string $filter): Operator + { + $exploded = explode("_", $filter); + $candidate = end($exploded); + return $this->operatorRegistry->matchByName($candidate); + } + + private function detectField(string $filter, string $operator): string + { + $exploded = explode("_", $filter); + $candidate = array_pop($exploded); + if ($candidate === $operator) { + return implode("_", $exploded); + } + return $filter; + } +} \ No newline at end of file diff --git a/src/Query/Operator/OperatorRegistry.php b/src/Query/Operator/OperatorRegistry.php new file mode 100644 index 0000000..2d4f648 --- /dev/null +++ b/src/Query/Operator/OperatorRegistry.php @@ -0,0 +1,49 @@ + + */ + public function all(): array + { + return [ + new Equals(), + new NotEquals(), + new EqualsNumber(), + new NotEqualsNumber(), + new EqualsTrue(), + new EqualsFalse(), + new NotEqualsFalse(), + new NotEqualsTrue(), + new Regex(), + new In(), + new NotIn(), + new InNum(), + new NotInNum(), + new GreaterThan(), + new GreaterThanEquals(), + new LessThan(), + new LessThanEquals(), + new IsNull(), + new NotNull(), + new Exists(), + new NotExists(), + + ]; + } + + public function matchByName(string $name): Operator + { + $operator = collect($this->all())->where('name', $name)->first(); + if (empty($operator)) { + return new Equals(); + } + return $operator; + } + + +} diff --git a/src/Query/Operator/Regex.php b/src/Query/Operator/Regex.php new file mode 100644 index 0000000..b791b46 --- /dev/null +++ b/src/Query/Operator/Regex.php @@ -0,0 +1,15 @@ +options->notLinked)){ + if (empty($this->options->notLinked)) { return $query; } @@ -169,8 +169,7 @@ final class Query $query ->select("records.*") ->join('edges', 'records.id', '=', 'edges.target', 'left outer') - ->whereNull("edges.target") - ; + ->whereNull("edges.target"); return $query; }