From 83fd80107beb0641b28403344cee414e29e9c587 Mon Sep 17 00:00:00 2001 From: Allan Mariucci Carvalho Date: Wed, 11 Dec 2024 13:30:59 -0300 Subject: [PATCH 1/2] wip --- src/DataAdapter/Filter.php | 46 ++++++++++++++++++++++++++++----- src/DataAdapter/QueryHelper.php | 2 +- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/DataAdapter/Filter.php b/src/DataAdapter/Filter.php index 6129844..6e0565d 100644 --- a/src/DataAdapter/Filter.php +++ b/src/DataAdapter/Filter.php @@ -2,6 +2,7 @@ namespace LaravelToolkit\DataAdapter; +use Illuminate\Contracts\Database\Query\Expression; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Support\Arr; @@ -22,23 +23,27 @@ private function __construct( /** * @return \Illuminate\Support\Collection|null */ - public static function create(?array $filters, string $globalFilterName): ?Collection + public static function create(?array $filters, string $globalFilterName, EloquentBuilder $builder): ?Collection { if (empty($filters)) { return null; } $collection = collect($filters) - ->mapWithKeys(function (array $filter, string $key) use ($globalFilterName) { - return [$key => self::createItem($key, $globalFilterName, $filter)]; - }) + ->mapWithKeys(fn (array $filter, string $key) => [ + $key => self::createItem($key, $globalFilterName, $filter, $builder), + ]) ->filter(fn ($filter) => $filter instanceof Filter); return $collection->count() > 0 ? $collection : null; } - protected static function createItem(string $field, string $globalFilterName, array $data): ?Filter - { + protected static function createItem( + string $field, + string $globalFilterName, + array $data, + EloquentBuilder $builder + ): ?Filter { $operatorValue = trim(Arr::get($data, 'operator', 'and')); $operator = Operator::tryFrom(! empty($operatorValue) ? $operatorValue : 'and'); $constraints = collect(Arr::get($data, 'constraints', [$data])) @@ -46,7 +51,34 @@ protected static function createItem(string $field, string $globalFilterName, ar ->filter(fn ($filter) => $filter instanceof Constraint); $valid = $constraints->isNotEmpty() && $operator !== null; - return $valid ? new Filter($field, $operator, $constraints, $field === $globalFilterName) : null; + return $valid + ? new Filter(self::fieldName($field, $builder), $operator, $constraints, $field === $globalFilterName) + : null; + } + + protected static function fieldName(string $field, EloquentBuilder $builder): string + { + $query = $builder->getQuery(); + if (count($query?->joins ?? []) === 0) { + return $field; + } + + foreach ($query->columns as $column) { + if ($column instanceof Expression) { + $column = $column->getValue($query->grammar); + } + $column = str($column) + ->deduplicate() + ->remove(['(', ')', '`', '\'', '"'], '') + ->replace([' As ', 'AS', 'aS'], ' as '); + if ($column->contains(".$field") || $column->contains(" as $field")) { + $field = $column + ->before(' as ') + ->toString(); + } + } + + return $field; } public function apply(QueryBuilder $builder): void diff --git a/src/DataAdapter/QueryHelper.php b/src/DataAdapter/QueryHelper.php index ce1eabb..8583814 100644 --- a/src/DataAdapter/QueryHelper.php +++ b/src/DataAdapter/QueryHelper.php @@ -32,7 +32,7 @@ public function rows(): int public function filters(EloquentBuilder $builder): void { - if (($filters = Filter::create($this->get('filters'), $this->get('global_filter_name'))) === null) { + if (($filters = Filter::create($this->get('filters'), $this->get('global_filter_name'), $builder)) === null) { return; } if (($filter = $filters->where('global', true)->first()) !== null) { From 903d0e600a3ace004ee34111fdb70c7764d222b9 Mon Sep 17 00:00:00 2001 From: Allan Mariucci Carvalho Date: Wed, 11 Dec 2024 13:45:08 -0300 Subject: [PATCH 2/2] fix tests --- tests/DataAdapterTest.php | 39 +++++++++++++++++++ ...024_09_24_163917_create_products_table.php | 5 +++ tests/Model/Product.php | 2 + 3 files changed, 46 insertions(+) diff --git a/tests/DataAdapterTest.php b/tests/DataAdapterTest.php index c182e11..af5f279 100644 --- a/tests/DataAdapterTest.php +++ b/tests/DataAdapterTest.php @@ -1,5 +1,6 @@ and($response->json('users.total')) ->toEqual(100); }); + +it('test join feature', function () { + $user = User::factory()->create(); + foreach (range(1, 10) as $item) { + Product::create(['user_id' => $user->id, 'name' => 'Product '.$item]); + } + Route::getAndPost('/', function () { + return response()->json([ + 'products' => Product::query() + ->select('products.*', 'users.email_verified_at') + ->selectSub('users.name', 'user_name') + ->join('users', 'users.id', '=', 'products.user_id') + ->primevueData(), + ]); + }); + $response = $this->post('/', [ + 'page' => 1, + 'page-options' => [ + 'global_filter_name' => 'global', + 'rows' => 15, + 'filters' => [ + 'user_name' => [ + 'operator' => 'and', 'constraints' => [['value' => $user->name, 'matchMode' => 'contains']], + ], + 'email_verified_at' => [ + 'operator' => 'and', 'constraints' => [['value' => 'foo', 'matchMode' => 'notContains']], + ], + ], + ], + ]); + $response->assertSuccessful(); + expect($response->content()) + ->toBeJson() + ->and($response->json('products')) + ->toBeArray() + ->and($response->json('products.total')) + ->toEqual(10); +}); diff --git a/tests/Model/2024_09_24_163917_create_products_table.php b/tests/Model/2024_09_24_163917_create_products_table.php index 2a862f0..16d0740 100644 --- a/tests/Model/2024_09_24_163917_create_products_table.php +++ b/tests/Model/2024_09_24_163917_create_products_table.php @@ -13,6 +13,11 @@ public function up(): void { Schema::create('products', function (Blueprint $table) { $table->id(); + $table->foreignId('user_id') + ->nullable() + ->constrained('users') + ->cascadeOnUpdate() + ->cascadeOnDelete(); $table->uuid('image')->nullable(); $table->timestamps(); }); diff --git a/tests/Model/Product.php b/tests/Model/Product.php index 0972ba0..d8f4e2a 100644 --- a/tests/Model/Product.php +++ b/tests/Model/Product.php @@ -7,6 +7,7 @@ /** * @property int $id + * @property int|null $user_id * @property string|\LaravelToolkit\StoredAssets\Assets $image * @property \Illuminate\Support\Carbon $created_at * @property \Illuminate\Support\Carbon $updated_at @@ -22,6 +23,7 @@ class Product extends Model */ protected $fillable = [ 'id', + 'user_id', 'image', 'created_at', 'updated_at',