diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 01c4385..617222c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,5 +37,6 @@ jobs: - name: Install dependencies run: | composer update --prefer-stable --prefer-dist --no-interaction --no-suggest + - name: Execute tests - run: vendor/bin/phpunit + run: composer test diff --git a/NEXT.md b/NEXT.md index 22b75d3..be9fbe2 100644 --- a/NEXT.md +++ b/NEXT.md @@ -3,12 +3,14 @@ - [x] Add commands for make **authorizers** and **resolvers.** - [ ] Add mutation **clausule** for update resources. - [ ] Add mutation **clausule** for delete resources. +- [ ] Allow to add multiple where clausules and document it. - [ ] Create **orWhere** clausule. - [ ] Create **whereBetween** clausule. - [x] Create **whereIn** clausule. - [x] Create **whereNotIn** clausule. -- [ ] Add **pagination** support. -- [ ] Add **pagination** documentation. +- [ ] Create **orWhere** clausule. +- [ ] Allow to select attributes from resolvers. +- [ ] Add **pagination** support and documentation. - [x] Move all testing for SQLite. - [x] Update the wiki and write documentation about the **RestQL.** -- [x] Implement `orchestra/testbench` testing for "real world" situations. \ No newline at end of file +- [x] Implement `orchestra/testbench` testing for "real world" situations. diff --git a/composer.json b/composer.json index f0af1e8..dc8cd72 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "gregorip02/restql", "description": "A data resolution package for Laravel", "type": "library", - "keywords": ["restql", "eloquent", "laravel", "graphql", "drp"], + "keywords": ["restql", "eloquent", "laravel", "graphql"], "url": "https://github.com/gregorip02/restql", "license": "LGPL-3.0", "authors": [ diff --git a/config/restql.php b/config/restql.php index 3dad6b0..03139d1 100644 --- a/config/restql.php +++ b/config/restql.php @@ -41,7 +41,7 @@ // Uncoment this and get the currently authenticated user. // 'whoami' => [ // 'class' => 'Restql\Resolvers\WhoamiResolver', - // 'authorizer' => 'Restql\Authorizers\WhoamiAuthorizer', + // 'authorizer' => 'Restql\Authorizers\PermissiveAuthorizer', // 'middlewares' => ['auth'] // ] ], diff --git a/src/Arguments/WhereArgument.php b/src/Arguments/WhereArgument.php index f182165..11a8c93 100644 --- a/src/Arguments/WhereArgument.php +++ b/src/Arguments/WhereArgument.php @@ -2,8 +2,8 @@ namespace Restql\Arguments; -use Restql\Contracts\ArgumentContract; use Restql\ModelArgument; +use Restql\Contracts\ArgumentContract; class WhereArgument extends ModelArgument implements ArgumentContract { @@ -22,11 +22,11 @@ class WhereArgument extends ModelArgument implements ArgumentContract public function values(): array { if ($this->isImplicitValue()) { - $value = $this->first(); - /// When an implicit type value is received, it will be assumed that /// it corresponds to the value of the primary column of the model. - return compact('value'); + return [ + 'value' => $this->first() + ]; } return parent::values(); @@ -42,7 +42,8 @@ public function getDefaultArgumentValues(): array return [ 'column' => $this->getKeyName(), 'operator' => '=', - 'value' => null + 'value' => null, + 'boolean' => 'and' ]; } } diff --git a/src/Arguments/WhereInOrNotInArgument.php b/src/Arguments/WhereInOrNotInArgument.php index dc6295f..4c7f2f8 100644 --- a/src/Arguments/WhereInOrNotInArgument.php +++ b/src/Arguments/WhereInOrNotInArgument.php @@ -2,10 +2,36 @@ namespace Restql\Arguments; -use Restql\Arguments\WhereArgument; +use Restql\ModelArgument; +use Restql\Contracts\ArgumentContract; -class WhereInOrNotInArgument extends WhereArgument +class WhereInOrNotInArgument extends ModelArgument implements ArgumentContract { + /** + * Determines if the argument accepts implicit values. + * + * @var boolean + */ + protected $hasImplicitValues = true; + + /** + * Get the argument values as array. + * + * @return array + */ + public function values(): array + { + if ($this->isImplicitValue()) { + /// When an implicit type value is received, it will be assumed that + /// it corresponds to the value of the primary column of the model. + return [ + 'value' => (array) $this->first() + ]; + } + + return parent::values(); + } + /** * Get default argument values. * diff --git a/src/Arguments/WithArgument.php b/src/Arguments/WithArgument.php index 413b92a..cdd56c6 100644 --- a/src/Arguments/WithArgument.php +++ b/src/Arguments/WithArgument.php @@ -2,13 +2,13 @@ namespace Restql\Arguments; -use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\Relations\Relation; -use Illuminate\Support\Collection; -use Restql\ClausuleExecutor; -use Restql\Contracts\ArgumentContract; use Restql\ModelArgument; +use Restql\ClausuleExecutor; use Restql\Support\ReflectionSupport; +use Restql\Contracts\ArgumentContract; +use Illuminate\Support\Collection; +use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Database\Eloquent\Relations\Relation; class WithArgument extends ModelArgument implements ArgumentContract { diff --git a/src/Authorizers/PermissiveAuthorizer.php b/src/Authorizers/PermissiveAuthorizer.php new file mode 100644 index 0000000..ca426e7 --- /dev/null +++ b/src/Authorizers/PermissiveAuthorizer.php @@ -0,0 +1,19 @@ +arguments->data()); - $builder->whereIn($args[0], (array) $args[1]); + $builder->whereIn(...$args); } /** diff --git a/src/Clausules/WhereNotInClausule.php b/src/Clausules/WhereNotInClausule.php index 63dab35..c862b38 100644 --- a/src/Clausules/WhereNotInClausule.php +++ b/src/Clausules/WhereNotInClausule.php @@ -18,6 +18,17 @@ public function build(QueryBuilder $builder): void { $args = array_values($this->arguments->data()); - $builder->whereNotIn($args[0], (array) $args[1]); + $builder->whereNotIn(...$args); + } + + /** + * Throw a exception if can't build this clausule. + * + * @return void + */ + protected function canBuild(): void + { + parent::throwIfMethodIsNotAllowed('whereNotIn'); + $this->throwIfArgumentIsMissing('whereNotIn'); } } diff --git a/src/Clausules/WithClausule.php b/src/Clausules/WithClausule.php index 72183ec..ed59f3b 100644 --- a/src/Clausules/WithClausule.php +++ b/src/Clausules/WithClausule.php @@ -2,15 +2,10 @@ namespace Restql\Clausules; -use Illuminate\Database\Eloquent\Builder as QueryBuilder; -use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Relations\HasMany; -use Illuminate\Database\Eloquent\Relations\Relation; -use Illuminate\Support\Collection; +use Restql\Clausule; use Restql\Argument; use Restql\Arguments\WithArgument; -use Restql\Clausule; -use Restql\Support\ReflectionSupport; +use Illuminate\Database\Eloquent\Builder as QueryBuilder; class WithClausule extends Clausule { diff --git a/src/MutationClausule.php b/src/MutationClausule.php index bf39394..17ee534 100644 --- a/src/MutationClausule.php +++ b/src/MutationClausule.php @@ -9,7 +9,6 @@ use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Builder as QueryBuilder; abstract class MutationClausule extends Clausule { diff --git a/src/RequestParser.php b/src/RequestParser.php index 6bdc43f..421c798 100644 --- a/src/RequestParser.php +++ b/src/RequestParser.php @@ -4,8 +4,6 @@ use Illuminate\Http\Request; use Illuminate\Support\Collection; -use Restql\Exceptions\InvalidEncodingValue; -use Restql\Services\ConfigService; use Restql\Traits\HasConfigService; final class RequestParser diff --git a/src/Resolvers/QueryBuilderResolver.php b/src/Resolvers/QueryBuilderResolver.php index 70b6c85..3d12b67 100644 --- a/src/Resolvers/QueryBuilderResolver.php +++ b/src/Resolvers/QueryBuilderResolver.php @@ -8,7 +8,6 @@ use Restql\Resolver; use Restql\SchemaDefinition; use Restql\Traits\ModelResolver; -use Illuminate\Database\Eloquent\Builder as QueryBuilder; final class QueryBuilderResolver extends Resolver implements SchemaHandlerContract { diff --git a/src/Resolvers/WhoamiResolver.php b/src/Resolvers/WhoamiResolver.php index 641d132..d45362e 100644 --- a/src/Resolvers/WhoamiResolver.php +++ b/src/Resolvers/WhoamiResolver.php @@ -20,9 +20,6 @@ public function handle(SchemaDefinition $schema): Collection { $user = Auth::user(); - /// Uncoment this for testing... - /// $user = factory('App\Author', 1)->make(); - return Collection::make($user); } } diff --git a/src/Restql.php b/src/Restql.php index d7d9c97..7da8895 100644 --- a/src/Restql.php +++ b/src/Restql.php @@ -9,7 +9,6 @@ use Illuminate\Http\Response; use Illuminate\Support\Collection; use Illuminate\Contracts\Support\Responsable; -use Illuminate\Database\Eloquent\Builder as QueryBuilder; final class Restql implements Responsable { diff --git a/tests/App/app/Restql/Resolvers/.gitkeep b/tests/App/app/Restql/Resolvers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/App/config/restql.php b/tests/App/config/restql.php index cb5abe7..672df47 100644 --- a/tests/App/config/restql.php +++ b/tests/App/config/restql.php @@ -52,7 +52,7 @@ 'resolvers' => [ 'whoami' => [ 'class' => 'Restql\Resolvers\WhoamiResolver', - 'authorizer' => 'Restql\Authorizers\WhoamiAuthorizer', + 'authorizer' => 'Restql\Authorizers\PermissiveAuthorizer', 'middlewares' => ['auth'] ] ], diff --git a/tests/Feature/Clausules/WhereInClausuleTest.php b/tests/Feature/Clausules/WhereInClausuleTest.php new file mode 100644 index 0000000..13d7944 --- /dev/null +++ b/tests/Feature/Clausules/WhereInClausuleTest.php @@ -0,0 +1,42 @@ +json('get', 'restql', [ + 'articles' => [ + 'whereIn' => [$this->articles], + 'select' => 'id' + ] + ]); + + $response->assertJsonCount(count($this->articles), 'data.articles'); + + $response->assertExactJson([ + 'data' => [ + 'articles' => array_map(function (int $id) { + return ['id' => $id]; + }, $this->articles) + ] + ]); + + $articles = $response->decodeResponseJson('data.articles.*.id'); + + $this->assertEquals($this->articles, $articles); + } +} diff --git a/tests/Feature/Clausules/WhereNotInClausuleTest.php b/tests/Feature/Clausules/WhereNotInClausuleTest.php new file mode 100644 index 0000000..758aebf --- /dev/null +++ b/tests/Feature/Clausules/WhereNotInClausuleTest.php @@ -0,0 +1,42 @@ +json('get', 'restql', [ + 'articles' => [ + 'select' => 'id', + 'whereNotIn' => [$this->articles] + ] + ]); + + /// We get 15 by default because we are excluding [$this->articles] + /// and this is rejected with others articles. + $response->assertJsonCount(15, 'data.articles'); + + $articles = $response->decodeResponseJson('data.articles.*.id'); + + /// Don't see any article id defined in $this->articles in + /// $articles responsed by RestQL. + foreach ($this->articles as $article) { + $this->assertFalse( + in_array($article, $articles) + ); + } + } +} \ No newline at end of file