From 6785649a96c28291861ae76d4e5f90ededb85c90 Mon Sep 17 00:00:00 2001 From: Aleksei Zarubin Date: Thu, 18 Nov 2021 13:52:33 +0500 Subject: [PATCH] fix: filtering timestamp fields by date only --- src/Drivers/Standard/QueryBuilder.php | 43 +++++++++++++++---- .../StandardIndexFilteringOperationsTest.php | 23 ++++++++++ tests/Fixtures/app/Models/Post.php | 1 + 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/Drivers/Standard/QueryBuilder.php b/src/Drivers/Standard/QueryBuilder.php index 003d600b..68fb816e 100644 --- a/src/Drivers/Standard/QueryBuilder.php +++ b/src/Drivers/Standard/QueryBuilder.php @@ -122,7 +122,12 @@ function ($relationQuery) use ($relationField, $filterDescriptor) { ); } } else { - $this->buildFilterQueryWhereClause($this->getQualifiedFieldName($filterDescriptor['field']), $filterDescriptor, $query, $or); + $this->buildFilterQueryWhereClause( + $this->getQualifiedFieldName($filterDescriptor['field']), + $filterDescriptor, + $query, + $or + ); } } } @@ -138,8 +143,16 @@ function ($relationQuery) use ($relationField, $filterDescriptor) { */ protected function buildFilterQueryWhereClause(string $field, array $filterDescriptor, $query, bool $or = false) { - if (!is_array($filterDescriptor['value'])) { - $query->{$or ? 'orWhere' : 'where'}($field, $filterDescriptor['operator'], $filterDescriptor['value']); + if ($filterDescriptor['value'] !== null && + in_array($filterDescriptor['field'], (new $this->resourceModelClass)->getDates(), true) + ) { + $constraint = 'whereDate'; + } else { + $constraint = 'where'; + } + + if (!is_array($filterDescriptor['value']) || $constraint === 'whereDate') { + $query->{$or ? 'or' . ucfirst($constraint) : $constraint}($field, $filterDescriptor['operator'], $filterDescriptor['value']); } else { $query->{$or ? 'orWhereIn' : 'whereIn'}($field, $filterDescriptor['value'], 'and', $filterDescriptor['operator'] === 'not in'); } @@ -156,8 +169,12 @@ protected function buildFilterQueryWhereClause(string $field, array $filterDescr * @param bool $or * @return Builder|Relation */ - protected function buildPivotFilterQueryWhereClause(string $field, array $filterDescriptor, $query, bool $or = false) - { + protected function buildPivotFilterQueryWhereClause( + string $field, + array $filterDescriptor, + $query, + bool $or = false + ) { if (!is_array($filterDescriptor['value'])) { $query->{$or ? 'orWherePivot' : 'wherePivot'}($field, $filterDescriptor['operator'], $filterDescriptor['value']); } else { @@ -212,11 +229,19 @@ function ($relationQuery) use ($relationField, $requestedSearchString) { /** * @var Builder $relationQuery */ - return $relationQuery->where($relationField, 'like', '%'.$requestedSearchString.'%'); + return $relationQuery->where( + $relationField, + 'like', + '%' . $requestedSearchString . '%' + ); } ); } else { - $whereQuery->orWhere($this->getQualifiedFieldName($searchable), 'like', '%'.$requestedSearchString.'%'); + $whereQuery->orWhere( + $this->getQualifiedFieldName($searchable), + 'like', + '%' . $requestedSearchString . '%' + ); } } } @@ -257,7 +282,9 @@ public function applySortingToQuery($query, Request $request): void } $relationTable = $this->relationsResolver->relationTableFromRelationInstance($relationInstance); - $relationForeignKey = $this->relationsResolver->relationForeignKeyFromRelationInstance($relationInstance); + $relationForeignKey = $this->relationsResolver->relationForeignKeyFromRelationInstance( + $relationInstance + ); $relationLocalKey = $this->relationsResolver->relationLocalKeyFromRelationInstance($relationInstance); $query->leftJoin($relationTable, $relationForeignKey, '=', $relationLocalKey) diff --git a/tests/Feature/StandardIndexFilteringOperationsTest.php b/tests/Feature/StandardIndexFilteringOperationsTest.php index 1ac333ef..7d97a609 100644 --- a/tests/Feature/StandardIndexFilteringOperationsTest.php +++ b/tests/Feature/StandardIndexFilteringOperationsTest.php @@ -418,4 +418,27 @@ public function getting_a_list_of_resources_filtered_by_model_field_using_nullab $this->makePaginator([$matchingPost], 'posts/search') ); } + + /** @test */ + public function getting_a_list_of_resources_filtered_by_model_date_field(): void + { + $matchingPost = factory(Post::class)->create(['publish_at' => Carbon::parse('2019-01-05 13:30:00')])->fresh(); + factory(Post::class)->create(['publish_at' => Carbon::now()])->fresh(); + + Gate::policy(Post::class, GreenPolicy::class); + + $response = $this->post( + '/api/posts/search', + [ + 'filters' => [ + ['field' => 'publish_at', 'operator' => '=', 'value' => '2019-01-05'], + ], + ] + ); + + $this->assertResourcesPaginated( + $response, + $this->makePaginator([$matchingPost], 'posts/search') + ); + } } diff --git a/tests/Fixtures/app/Models/Post.php b/tests/Fixtures/app/Models/Post.php index cae68f5a..0ca6f777 100644 --- a/tests/Fixtures/app/Models/Post.php +++ b/tests/Fixtures/app/Models/Post.php @@ -36,6 +36,7 @@ class Post extends Model * @var array */ protected $dates = [ + 'publish_at', 'deleted_at' //workaround for Laravel 5.7 - SoftDeletes trait adds deleted_at column to dates automatically since Laravel 5.8 ];