Skip to content

Commit 3702578

Browse files
Gregory Haddowlindyhopchris
authored andcommitted
feat: add WhereAll and WhereAny filters
1 parent 0401362 commit 3702578

File tree

6 files changed

+354
-0
lines changed

6 files changed

+354
-0
lines changed

src/Filters/Concerns/HasColumns.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
/*
3+
* Copyright 2024 Cloud Creativity Limited
4+
*
5+
* Use of this source code is governed by an MIT-style
6+
* license that can be found in the LICENSE file or at
7+
* https://opensource.org/licenses/MIT.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace LaravelJsonApi\Eloquent\Filters\Concerns;
13+
14+
trait HasColumns
15+
{
16+
17+
/**
18+
* @var string|null
19+
*/
20+
private ?string $table = null;
21+
22+
23+
/**
24+
* @var array<string>
25+
*/
26+
private array $columns = [];
27+
28+
/**
29+
* @return array<string>
30+
*/
31+
public function columns(): array
32+
{
33+
return $this->columns;
34+
}
35+
36+
public function withColumn(string $column): self
37+
{
38+
$this->columns[] = $column;
39+
40+
return $this;
41+
}
42+
43+
/**
44+
* Force the table name when qualifying the columns.
45+
*
46+
* This allows the developer to force the table that the columns are qualified with.
47+
*
48+
* @param string $table
49+
* @return $this
50+
*/
51+
public function qualifyAs(string $table): self
52+
{
53+
$this->table = $table;
54+
55+
return $this;
56+
}
57+
58+
/**
59+
* Determine if developer has forced a table to qualify columns as
60+
*
61+
* @return bool
62+
*/
63+
public function isQualified(): bool
64+
{
65+
return $this->table === null;
66+
}
67+
68+
/**
69+
* Get qualified columns.
70+
*
71+
* @return array<string>
72+
*/
73+
protected function qualifiedColumns(): array
74+
{
75+
if ($this->table) {
76+
return array_map(fn($column) => $this->table . '.' . $column, $this->columns);
77+
}
78+
79+
return $this->columns;
80+
}
81+
}

src/Filters/WhereAll.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
/*
3+
* Copyright 2024 Cloud Creativity Limited
4+
*
5+
* Use of this source code is governed by an MIT-style
6+
* license that can be found in the LICENSE file or at
7+
* https://opensource.org/licenses/MIT.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace LaravelJsonApi\Eloquent\Filters;
13+
14+
use Illuminate\Support\Traits\Conditionable;
15+
use LaravelJsonApi\Eloquent\Contracts\Filter;
16+
17+
class WhereAll implements Filter
18+
{
19+
20+
use Concerns\DeserializesValue;
21+
use Concerns\HasColumns;
22+
use Concerns\HasOperator;
23+
use Concerns\IsSingular;
24+
use Conditionable;
25+
26+
/**
27+
* @var string
28+
*/
29+
private string $name;
30+
31+
/**
32+
* Create a new filter.
33+
*
34+
* @param string $name
35+
* @param array<string> $columns
36+
* @return static
37+
*/
38+
public static function make(string $name, array $columns = null): self
39+
{
40+
return new static($name, $columns);
41+
}
42+
43+
/**
44+
* WhereAny constructor.
45+
*
46+
* @param string $name
47+
* @param array<string> $columns
48+
*/
49+
public function __construct(string $name, array $columns = null)
50+
{
51+
$this->name = $name;
52+
$this->columns = $columns ?? [];
53+
$this->operator = '=';
54+
}
55+
56+
/**
57+
* @inheritDoc
58+
*/
59+
public function key(): string
60+
{
61+
return $this->name;
62+
}
63+
64+
/**
65+
* @inheritDoc
66+
*/
67+
public function apply($query, $value)
68+
{
69+
if (!$this->isQualified()){
70+
$this->qualifyAs($query->getModel()->getTable());
71+
}
72+
73+
return $query->whereAll(
74+
$this->qualifiedColumns(),
75+
$this->operator(),
76+
$this->deserialize($value)
77+
);
78+
}
79+
}

src/Filters/WhereAny.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
/*
3+
* Copyright 2024 Cloud Creativity Limited
4+
*
5+
* Use of this source code is governed by an MIT-style
6+
* license that can be found in the LICENSE file or at
7+
* https://opensource.org/licenses/MIT.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace LaravelJsonApi\Eloquent\Filters;
13+
14+
use Illuminate\Support\Traits\Conditionable;
15+
use LaravelJsonApi\Eloquent\Contracts\Filter;
16+
17+
class WhereAny implements Filter
18+
{
19+
20+
use Concerns\DeserializesValue;
21+
use Concerns\HasColumns;
22+
use Concerns\HasOperator;
23+
use Concerns\IsSingular;
24+
use Conditionable;
25+
26+
/**
27+
* @var string
28+
*/
29+
private string $name;
30+
31+
/**
32+
* Create a new filter.
33+
*
34+
* @param string $name
35+
* @param array<string> $columns
36+
* @return static
37+
*/
38+
public static function make(string $name, array $columns = null): self
39+
{
40+
return new static($name, $columns);
41+
}
42+
43+
/**
44+
* WhereAny constructor.
45+
*
46+
* @param string $name
47+
* @param array<string> $columns
48+
*/
49+
public function __construct(string $name, array $columns = null)
50+
{
51+
$this->name = $name;
52+
$this->columns = $columns ?? [];
53+
$this->operator = '=';
54+
}
55+
56+
/**
57+
* @inheritDoc
58+
*/
59+
public function key(): string
60+
{
61+
return $this->name;
62+
}
63+
64+
/**
65+
* @inheritDoc
66+
*/
67+
public function apply($query, $value)
68+
{
69+
if (!$this->isQualified()){
70+
$this->qualifyAs($query->getModel()->getTable());
71+
}
72+
73+
return $query->whereAny(
74+
$this->qualifiedColumns(),
75+
$this->operator(),
76+
$this->deserialize($value)
77+
);
78+
}
79+
}

tests/app/Schemas/PostSchema.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
use LaravelJsonApi\Eloquent\Fields\Str;
2525
use LaravelJsonApi\Eloquent\Filters\OnlyTrashed;
2626
use LaravelJsonApi\Eloquent\Filters\Where;
27+
use LaravelJsonApi\Eloquent\Filters\WhereAll;
28+
use LaravelJsonApi\Eloquent\Filters\WhereAny;
2729
use LaravelJsonApi\Eloquent\Filters\WhereDoesntHave;
2830
use LaravelJsonApi\Eloquent\Filters\WhereHas;
2931
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
@@ -94,6 +96,8 @@ public function filters(): iterable
9496
Where::make('slug')->singular(),
9597
WhereIn::make('slugs')->delimiter(','),
9698
WithTrashed::make('withTrashed'),
99+
WhereAll::make('all', ['title','content'])->withColumn('slug')->using('like'),
100+
WhereAny::make('any', ['title','content'])->withColumn('slug')->using('like'),
97101
];
98102
}
99103

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
/*
3+
* Copyright 2024 Cloud Creativity Limited
4+
*
5+
* Use of this source code is governed by an MIT-style
6+
* license that can be found in the LICENSE file or at
7+
* https://opensource.org/licenses/MIT.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace LaravelJsonApi\Eloquent\Tests\Acceptance\Filters;
13+
14+
use App\Models\Post;
15+
use App\Schemas\PostSchema;
16+
17+
class WhereAllTest extends TestCase
18+
{
19+
/**
20+
* @var PostSchema
21+
*/
22+
private PostSchema $schema;
23+
24+
/**
25+
* @return void
26+
*/
27+
protected function setUp(): void
28+
{
29+
parent::setUp();
30+
31+
$this->schema = $this->schemas()->schemaFor('posts');
32+
}
33+
34+
/**
35+
* @return void
36+
*/
37+
public function testWhereAll(): void
38+
{
39+
Post::factory()->count(5)->create();
40+
41+
$all = Post::factory()->create(['title' => "foobar boofar", 'content' => "boofar foobar", 'slug' => "totally_foobar_1"]);
42+
Post::factory()->create(['title' => "foobar boofar"]);
43+
Post::factory()->create(['content' => "boofar foobar"]);
44+
Post::factory()->create(['slug' => "totally_foobar"]);
45+
46+
$expected = [$all];
47+
48+
$actual = $this->schema
49+
->repository()
50+
->queryAll()
51+
->filter(['all' => '%foobar%'])
52+
->get();
53+
54+
$this->assertFilteredModels($expected, $actual);
55+
}
56+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
/*
3+
* Copyright 2024 Cloud Creativity Limited
4+
*
5+
* Use of this source code is governed by an MIT-style
6+
* license that can be found in the LICENSE file or at
7+
* https://opensource.org/licenses/MIT.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace LaravelJsonApi\Eloquent\Tests\Acceptance\Filters;
13+
14+
use App\Models\Post;
15+
use App\Schemas\PostSchema;
16+
17+
class WhereAnyTest extends TestCase
18+
{
19+
/**
20+
* @var PostSchema
21+
*/
22+
private PostSchema $schema;
23+
24+
/**
25+
* @return void
26+
*/
27+
protected function setUp(): void
28+
{
29+
parent::setUp();
30+
31+
$this->schema = $this->schemas()->schemaFor('posts');
32+
}
33+
34+
/**
35+
* @return void
36+
*/
37+
public function testWhereAny(): void
38+
{
39+
Post::factory()->count(5)->create();
40+
41+
$title = Post::factory()->create(['title' => "foobar boofar"]);
42+
$content = Post::factory()->create(['content' => "boofar foobar"]);
43+
$slug = Post::factory()->create(['slug' => "totally_foobar"]);
44+
45+
$expected = [$title,$content, $slug];
46+
47+
$actual = $this->schema
48+
->repository()
49+
->queryAll()
50+
->filter(['any' => '%foobar%'])
51+
->get();
52+
53+
$this->assertFilteredModels($expected, $actual);
54+
}
55+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy