diff --git a/src/Fields/Field.php b/src/Fields/Field.php index 744dcba0..0579d984 100644 --- a/src/Fields/Field.php +++ b/src/Fields/Field.php @@ -46,6 +46,11 @@ class Field */ protected $nullable = false; + /** + * @var bool + */ + protected $nullableItems = false; + /** * @var bool */ @@ -138,6 +143,7 @@ public function getType(): Type $type->nullable($this->isNullable()); $type->list($this->isList()); + $type->nullableItems($this->hasNullableItems()); return $type->setRegistry($this->getRegistry()); } @@ -265,6 +271,29 @@ public function isNullable(): bool return $this->nullable; } + /** + * Set if the field has nullable items. + * + * @param bool $nullable + * @return \Bakery\Fields\Field + */ + public function nullableItems(bool $nullable = true): self + { + $this->nullableItems = $nullable; + + return $this; + } + + /** + * Return if the field has nullable items. + * + * @return bool + */ + public function hasNullableItems(): bool + { + return $this->nullableItems; + } + /** * Set if the field is fillable. * diff --git a/src/Types/CollectionFilterType.php b/src/Types/CollectionFilterType.php index 03621b38..5a02dea9 100644 --- a/src/Types/CollectionFilterType.php +++ b/src/Types/CollectionFilterType.php @@ -34,7 +34,7 @@ public function fields(): array ->put('OR', $this->registry->field($this->registry->type($this->name()))->list()); return $fields->map(function (Field $type) { - return $type->nullable(); + return $type->nullable()->nullableItems(); })->toArray(); } diff --git a/src/Types/Definitions/Type.php b/src/Types/Definitions/Type.php index cc29fd7b..d1dad4f6 100644 --- a/src/Types/Definitions/Type.php +++ b/src/Types/Definitions/Type.php @@ -201,7 +201,7 @@ public function hasNullableItems(): bool * * @param bool $value */ - public function setNullableItems(bool $value = true) + public function nullableItems(bool $value = true) { $this->nullableItems = $value; } diff --git a/tests/Feature/CollectionQueryTest.php b/tests/Feature/CollectionQueryTest.php index 44fe0e24..16fb7cc5 100644 --- a/tests/Feature/CollectionQueryTest.php +++ b/tests/Feature/CollectionQueryTest.php @@ -255,6 +255,54 @@ public function it_can_filter_with_AND_and_OR_filters() $response->assertJsonMissing(['id' => $articleThree->id]); } + /** @test */ + public function it_can_filter_with_null_AND_and_OR_filters() + { + $userOne = factory(Models\User::class)->create(); + $userTwo = factory(Models\User::class)->create(); + $articleOne = factory(Models\Article::class)->create([ + 'title' => 'Hello world', + 'content' => 'Lorem ipsum', + 'user_id' => $userOne->id, + ]); + $articleTwo = factory(Models\Article::class)->create([ + 'title' => 'Hello world', + 'content' => 'Lorem ipsum', + 'user_id' => $userOne->id, + ]); + $articleThree = factory(Models\Article::class)->create([ + 'title' => 'Hello world', + 'content' => 'Lorem ipsum', + 'user_id' => $userTwo->id, + ]); + + $query = ' + query { + articles(filter: { + AND: [ + { user: { id: "'.$userOne->id.'" } }, + null, + { OR: [null] }, + ] + }) { + items { + id + } + pagination { + total + } + } + } + '; + + $response = $this->json('GET', '/graphql', ['query' => $query]); + $response->assertStatus(200); + $response->assertJsonFragment(['total' => 2]); + $response->assertJsonFragment(['id' => $articleOne->id]); + $response->assertJsonFragment(['id' => $articleTwo->id]); + $response->assertJsonMissing(['id' => $articleThree->id]); + } + /** @test */ public function it_can_order_by_field() {