Skip to content

Commit

Permalink
fix: calculating max depth for nested filters
Browse files Browse the repository at this point in the history
  • Loading branch information
alexzarbn committed Nov 27, 2023
1 parent 6cc031f commit 794c135
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 27 deletions.
27 changes: 18 additions & 9 deletions src/Drivers/Standard/ParamsValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Illuminate\Support\Facades\Validator;
use Orion\Exceptions\MaxNestedDepthExceededException;
use Orion\Helpers\ArrayHelper;
use Orion\Http\Requests\Request;
use Orion\Http\Rules\WhitelistedField;
use Orion\Http\Rules\WhitelistedQueryFields;
Expand Down Expand Up @@ -107,7 +106,7 @@ public function validateSearch(Request $request): void

public function validateAggregators(Request $request): void
{
$depth = $this->nestedFiltersDepth($request->input('aggregates', []), -1);
$depth = $this->nestedFiltersDepth($request->input('aggregates', []));

Validator::make(
$request->all(),
Expand Down Expand Up @@ -192,7 +191,7 @@ public function validateAggregators(Request $request): void

public function validateIncludes(Request $request): void
{
$depth = $this->nestedFiltersDepth($request->input('includes', []), -1);
$depth = $this->nestedFiltersDepth($request->input('includes', []));

Validator::make(
$request->all(),
Expand Down Expand Up @@ -221,15 +220,25 @@ public function validateIncludes(Request $request): void
/**
* @throws MaxNestedDepthExceededException
*/
protected function nestedFiltersDepth($array, $modifier = 0)
protected function nestedFiltersDepth($array): int
{
$depth = ArrayHelper::depth($array);
$configMaxNestedDepth = config('orion.search.max_nested_depth', 1);
$depth = 0;

foreach ($array as $filterDescriptor) {
if (!isset($filterDescriptor['nested'])) {
continue;
}

$currentFilterDescriptorDepth = 1 + $this->nestedFiltersDepth($filterDescriptor['nested']);

// Here we calculate the real nested filters depth
$depth = floor($depth / 2);
if ($depth < $currentFilterDescriptorDepth) {
$depth = $currentFilterDescriptorDepth;
}
}

$configMaxNestedDepth = config('orion.search.max_nested_depth', 1);

if ($depth + $modifier > $configMaxNestedDepth) {
if ($depth > $configMaxNestedDepth) {
throw new MaxNestedDepthExceededException(
422,
__('Max nested depth :depth is exceeded', ['depth' => $configMaxNestedDepth])
Expand Down
71 changes: 53 additions & 18 deletions tests/Feature/StandardIndexNestedFilteringOperationsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

namespace Orion\Tests\Feature;

use Carbon\Carbon;
use Illuminate\Support\Facades\Gate;
use Orion\Tests\Fixtures\App\Models\Company;
use Orion\Tests\Fixtures\App\Models\Post;
use Orion\Tests\Fixtures\App\Models\Team;
use Orion\Tests\Fixtures\App\Models\User;
use Orion\Tests\Fixtures\App\Policies\GreenPolicy;

class StandardIndexNestedFilteringOperationsTest extends TestCase
Expand All @@ -24,11 +20,13 @@ public function getting_a_list_of_resources_nested_filtered_by_model_field_using
'/api/posts/search',
[
'filters' => [
['field' => 'title', 'operator' => 'in' ,'value' => ['match', 'not_match']],
['nested' => [
['field' => 'title', 'value' => 'match'],
['field' => 'title', 'operator' => '!=', 'value' => 'not match']
]],
['field' => 'title', 'operator' => 'in', 'value' => ['match', 'not_match']],
[
'nested' => [
['field' => 'title', 'value' => 'match'],
['field' => 'title', 'operator' => '!=', 'value' => 'not match'],
],
],
],
]
);
Expand All @@ -53,9 +51,12 @@ public function getting_a_list_of_resources_nested_filtered_by_model_field_using
[
'filters' => [
['field' => 'title', 'operator' => '=', 'value' => 'match'],
['type' => 'or', 'nested' => [
['field' => 'position', 'operator' => '=', 'value' => 3],
]],
[
'type' => 'or',
'nested' => [
['field' => 'position', 'operator' => '=', 'value' => 3],
],
],
],
]
);
Expand All @@ -66,6 +67,36 @@ public function getting_a_list_of_resources_nested_filtered_by_model_field_using
);
}

/** @test */
public function getting_a_list_of_resources_nested_filtered_by_model_field_using_in_operator(): void
{
$matchingPost = factory(Post::class)->create(['title' => 'match'])->fresh();
factory(Post::class)->create(['title' => 'not match'])->fresh();

Gate::policy(Post::class, GreenPolicy::class);

$response = $this->post(
'/api/posts/search',
[
'filters' => [

['field' => 'title', 'operator' => '!=', 'value' => 'not match'],
[
'nested' => [
['field' => 'title', 'operator' => 'in', 'value' => ['match']],
['field' => 'title', 'operator' => '!=', 'value' => 'not match'],
],
],
],
]
);

$this->assertResourcesPaginated(
$response,
$this->makePaginator([$matchingPost], 'posts/search')
);
}

/** @test */
public function getting_a_list_of_resources_nested_filtered_by_model_field_using_not_equal_operator(): void
{
Expand All @@ -78,9 +109,11 @@ public function getting_a_list_of_resources_nested_filtered_by_model_field_using
'/api/posts/search',
[
'filters' => [
['nested' => [
['field' => 'position', 'operator' => '!=', 'value' => 5]
]],
[
'nested' => [
['field' => 'position', 'operator' => '!=', 'value' => 5],
],
],
],
]
);
Expand All @@ -103,9 +136,11 @@ public function getting_a_list_of_resources_nested_filtered_by_not_whitelisted_f
'/api/posts/search',
[
'filters' => [
['nested' => [
['field' => 'body', 'operator' => '=', 'value' => 'match']
]],
[
'nested' => [
['field' => 'body', 'operator' => '=', 'value' => 'match'],
],
],
],
]
);
Expand Down

0 comments on commit 794c135

Please sign in to comment.