Skip to content

Commit

Permalink
Merge branch 'release/4.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
lindyhopchris committed Oct 13, 2024
2 parents 35ccb63 + 8875021 commit 05644f3
Show file tree
Hide file tree
Showing 11 changed files with 399 additions and 5 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. This projec

## Unreleased

## [4.3.0] - 2024-10-13

### Added

- [#38](https://github.com/laravel-json-api/eloquent/pull/38) Added `WhereAll` and `WhereAny` filters.

### Fixed

- [#39](https://github.com/laravel-json-api/eloquent/issues/39) Fixed a bug in the eager loader iterator where include
paths starting with the same word were incorrectly removed. E.g. `car` and `carOwner` would result in just `carOwner`.

## [4.2.0] - 2024-08-26

### Added
Expand Down
103 changes: 103 additions & 0 deletions src/Filters/Concerns/HasColumns.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php
/*
* Copyright 2024 Cloud Creativity Limited
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

declare(strict_types=1);

namespace LaravelJsonApi\Eloquent\Filters\Concerns;

use Illuminate\Database\Eloquent\Model;

trait HasColumns
{
/**
* @var string|null
*/
private ?string $table = null;

/**
* @var array<string>
*/
private array $columns = [];

/**
* @return array<string>
*/
public function columns(): array
{
return $this->columns;
}

/**
* Add a column to the filter.
*
* @param string $column
* @return $this
*/
public function withColumn(string $column): static
{
$this->columns[] = $column;

return $this;
}

/**
* Add columns to the filter.
*
* @param string ...$columns
* @return $this
*/
public function withColumns(string ...$columns): static
{
$this->columns = [
...$this->columns,
...$columns,
];

return $this;
}

/**
* Force the table name when qualifying the columns.
*
* This allows the developer to force the table that the columns are qualified with.
*
* @param string $table
* @return $this
*/
public function qualifyAs(string $table): static
{
$this->table = $table;

return $this;
}

/**
* Get qualified columns.
*
* @return array<string>
*/
protected function qualifiedColumns(?Model $model = null): array
{
if ($this->table) {
return array_map(
fn($column) => $this->table . '.' . $column,
$this->columns,
);
}

if ($model) {
return array_map(
static fn($column) => $model->qualifyColumn($column),
$this->columns,
);
}

return $this->columns;
}
}
74 changes: 74 additions & 0 deletions src/Filters/WhereAll.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php
/*
* Copyright 2024 Cloud Creativity Limited
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

declare(strict_types=1);

namespace LaravelJsonApi\Eloquent\Filters;

use Illuminate\Support\Traits\Conditionable;
use LaravelJsonApi\Eloquent\Contracts\Filter;

class WhereAll implements Filter
{
use Concerns\DeserializesValue;
use Concerns\HasColumns;
use Concerns\HasOperator;
use Concerns\IsSingular;
use Conditionable;

/**
* @var string
*/
private string $name;

/**
* Create a new filter.
*
* @param string $name
* @param array<string>|null $columns
* @return static
*/
public static function make(string $name, array $columns = null): static
{
return new static($name, $columns);
}

/**
* WhereAll constructor.
*
* @param string $name
* @param array<string>|null $columns
*/
public function __construct(string $name, array $columns = null)
{
$this->name = $name;
$this->columns = $columns ?? [];
$this->operator = '=';
}

/**
* @inheritDoc
*/
public function key(): string
{
return $this->name;
}

/**
* @inheritDoc
*/
public function apply($query, $value)
{
return $query->whereAll(
$this->qualifiedColumns($query->getModel()),
$this->operator(),
$this->deserialize($value)
);
}
}
74 changes: 74 additions & 0 deletions src/Filters/WhereAny.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php
/*
* Copyright 2024 Cloud Creativity Limited
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

declare(strict_types=1);

namespace LaravelJsonApi\Eloquent\Filters;

use Illuminate\Support\Traits\Conditionable;
use LaravelJsonApi\Eloquent\Contracts\Filter;

class WhereAny implements Filter
{
use Concerns\DeserializesValue;
use Concerns\HasColumns;
use Concerns\HasOperator;
use Concerns\IsSingular;
use Conditionable;

/**
* @var string
*/
private string $name;

/**
* Create a new filter.
*
* @param string $name
* @param array<string>|null $columns
* @return static
*/
public static function make(string $name, array $columns = null): static
{
return new static($name, $columns);
}

/**
* WhereAny constructor.
*
* @param string $name
* @param array<string>|null $columns
*/
public function __construct(string $name, array $columns = null)
{
$this->name = $name;
$this->columns = $columns ?? [];
$this->operator = '=';
}

/**
* @inheritDoc
*/
public function key(): string
{
return $this->name;
}

/**
* @inheritDoc
*/
public function apply($query, $value)
{
return $query->whereAny(
$this->qualifiedColumns($query->getModel()),
$this->operator(),
$this->deserialize($value)
);
}
}
11 changes: 6 additions & 5 deletions src/QueryBuilder/EagerLoading/EagerLoadIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
*/
class EagerLoadIterator implements IteratorAggregate
{

/**
* @var Schema
*/
Expand Down Expand Up @@ -70,11 +69,13 @@ public function __construct(Schema $schema, IncludePaths $paths)
*/
public function collect(): Collection
{
$values = collect($this);
$values = Collection::make($this);

return $values->reject(
fn($path) => $values->contains(fn($check) => $path !== $check && Str::startsWith($check, $path))
)->sort()->values();
return $values
->reject(static fn(string $path) => $values
->contains(fn(string $check) => $path !== $check && Str::startsWith($check, $path . '.')))
->sort()
->values();
}

/**
Expand Down
9 changes: 9 additions & 0 deletions tests/app/Models/Mechanic.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\HasOneThrough;

class Mechanic extends Model
Expand All @@ -25,6 +26,14 @@ class Mechanic extends Model
*/
protected $fillable = ['name'];

/**
* @return HasOne
*/
public function car(): HasOne
{
return $this->hasOne(Car::class);
}

/**
* @return HasOneThrough
*/
Expand Down
2 changes: 2 additions & 0 deletions tests/app/Schemas/MechanicSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use LaravelJsonApi\Eloquent\Contracts\Paginator;
use LaravelJsonApi\Eloquent\Fields\DateTime;
use LaravelJsonApi\Eloquent\Fields\ID;
use LaravelJsonApi\Eloquent\Fields\Relations\HasOne;
use LaravelJsonApi\Eloquent\Fields\Relations\HasOneThrough;
use LaravelJsonApi\Eloquent\Fields\Str;
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
Expand All @@ -39,6 +40,7 @@ public function fields(): array
ID::make(),
DateTime::make('createdAt')->readOnly(),
Str::make('name'),
HasOne::make('car'),
HasOneThrough::make('carOwner'),
DateTime::make('updatedAt')->readOnly(),
];
Expand Down
4 changes: 4 additions & 0 deletions tests/app/Schemas/PostSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
use LaravelJsonApi\Eloquent\Fields\Str;
use LaravelJsonApi\Eloquent\Filters\OnlyTrashed;
use LaravelJsonApi\Eloquent\Filters\Where;
use LaravelJsonApi\Eloquent\Filters\WhereAll;
use LaravelJsonApi\Eloquent\Filters\WhereAny;
use LaravelJsonApi\Eloquent\Filters\WhereDoesntHave;
use LaravelJsonApi\Eloquent\Filters\WhereHas;
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
Expand Down Expand Up @@ -94,6 +96,8 @@ public function filters(): iterable
Where::make('slug')->singular(),
WhereIn::make('slugs')->delimiter(','),
WithTrashed::make('withTrashed'),
WhereAll::make('all', ['title','content'])->withColumn('slug')->using('like'),
WhereAny::make('any', ['title','content'])->withColumn('slug')->using('like'),
];
}

Expand Down
5 changes: 5 additions & 0 deletions tests/lib/Acceptance/EagerLoading/EagerLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ public static function includePathsProvider(): array
'profile', // auto included for users
],
],
'mechanic' => [
'mechanics',
'car,carOwner,carOwner.car,carOwner.car.mechanic,car.mechanic',
['car.mechanic', 'carOwner.car.mechanic'],
],
];
}

Expand Down
Loading

0 comments on commit 05644f3

Please sign in to comment.