From e36f975c738e91a26a80b142969a636f8c3eff91 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 11 Jan 2024 13:10:32 +0400 Subject: [PATCH 1/8] refactor(graphql): `AstManipulation` => `AstManipulationBuilderInfo`. --- packages/graphql/UPGRADE.md | 2 +- ...AstManipulation.php => AstManipulationBuilderInfo.php} | 4 ++-- .../graphql/src/Builder/Directives/HandlerDirective.php | 8 +++----- packages/graphql/src/Builder/Manipulator.php | 4 ++-- packages/graphql/src/Builder/ManipulatorTest.php | 6 +++--- packages/graphql/src/Builder/Types/InputObject.php | 6 +++--- .../src/SearchBy/Operators/Complex/RelationType.php | 4 ++-- packages/graphql/src/SearchBy/Types/Condition.php | 4 ++-- packages/graphql/src/SearchBy/Types/Enumeration.php | 4 ++-- packages/graphql/src/SearchBy/Types/Scalar.php | 4 ++-- packages/graphql/src/SortBy/Types/Clause.php | 4 ++-- 11 files changed, 24 insertions(+), 26 deletions(-) rename packages/graphql/src/Builder/Contexts/{AstManipulation.php => AstManipulationBuilderInfo.php} (73%) diff --git a/packages/graphql/UPGRADE.md b/packages/graphql/UPGRADE.md index 038dc403d..ab01a3bce 100644 --- a/packages/graphql/UPGRADE.md +++ b/packages/graphql/UPGRADE.md @@ -89,5 +89,5 @@ This section is actual only if you are extending the package. Please review and * [ ] To get `BuilderInfo` instance within Operator the `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context` should be used instead of `LastDragon_ru\LaraASP\GraphQL\Builder\Manipulator`: ```php - $context->get(\LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation\AstManipulation::class)?->builderInfo + $context->get(\LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo::class)?->builderInfo ``` diff --git a/packages/graphql/src/Builder/Contexts/AstManipulation.php b/packages/graphql/src/Builder/Contexts/AstManipulationBuilderInfo.php similarity index 73% rename from packages/graphql/src/Builder/Contexts/AstManipulation.php rename to packages/graphql/src/Builder/Contexts/AstManipulationBuilderInfo.php index e0f3a5e38..9c460a2f2 100644 --- a/packages/graphql/src/Builder/Contexts/AstManipulation.php +++ b/packages/graphql/src/Builder/Contexts/AstManipulationBuilderInfo.php @@ -4,9 +4,9 @@ use LastDragon_ru\LaraASP\GraphQL\Builder\BuilderInfo; -class AstManipulation { +class AstManipulationBuilderInfo { public function __construct( - public readonly BuilderInfo $builderInfo, + public readonly BuilderInfo $value, ) { // empty } diff --git a/packages/graphql/src/Builder/Directives/HandlerDirective.php b/packages/graphql/src/Builder/Directives/HandlerDirective.php index e3ff22ad5..ded9bb7a4 100644 --- a/packages/graphql/src/Builder/Directives/HandlerDirective.php +++ b/packages/graphql/src/Builder/Directives/HandlerDirective.php @@ -17,7 +17,7 @@ use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\BuilderInfoDetector; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context as ContextContract; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator; @@ -45,7 +45,7 @@ use function reset; /** - * @see AstManipulation + * @see AstManipulationBuilderInfo */ abstract class HandlerDirective extends BaseDirective implements Handler { use WithManipulator; @@ -223,9 +223,7 @@ public function manipulateArgDefinition( // Argument $context = (new Context())->override([ - AstManipulation::class => new AstManipulation( - builderInfo: $builder, - ), + AstManipulationBuilderInfo::class => new AstManipulationBuilderInfo($builder), ]); $source = $this->getFieldArgumentSource($manipulator, $parentType, $parentField, $argDefinition); $type = $this->getArgDefinitionType($manipulator, $documentAST, $source, $context); diff --git a/packages/graphql/src/Builder/Manipulator.php b/packages/graphql/src/Builder/Manipulator.php index bb0fbf114..c772bab02 100644 --- a/packages/graphql/src/Builder/Manipulator.php +++ b/packages/graphql/src/Builder/Manipulator.php @@ -22,7 +22,7 @@ use GraphQL\Type\Definition\Type; use Illuminate\Container\Container; use Illuminate\Support\Str; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scope; @@ -147,7 +147,7 @@ public function getTypeOperators(string $scope, string $type, Context $context, } // Builder? - $builder = $context->get(AstManipulation::class)?->builderInfo->getBuilder(); + $builder = $context->get(AstManipulationBuilderInfo::class)?->value->getBuilder(); if (!$builder) { return []; diff --git a/packages/graphql/src/Builder/ManipulatorTest.php b/packages/graphql/src/Builder/ManipulatorTest.php index 3503261c2..1d6874e66 100644 --- a/packages/graphql/src/Builder/ManipulatorTest.php +++ b/packages/graphql/src/Builder/ManipulatorTest.php @@ -5,7 +5,7 @@ use GraphQL\Type\Definition\CustomScalarType; use GraphQL\Type\Definition\ObjectType; use Illuminate\Container\Container; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context as ContextContract; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator; @@ -193,8 +193,8 @@ public function getScope(): string { // Manipulator $context = (new Context())->override([ - AstManipulation::class => new AstManipulation( - builderInfo: new BuilderInfo($builder::class, $builder::class), + AstManipulationBuilderInfo::class => new AstManipulationBuilderInfo( + new BuilderInfo($builder::class, $builder::class), ), ]); $document = Container::getInstance()->make(ASTBuilder::class)->documentAST(); diff --git a/packages/graphql/src/Builder/Types/InputObject.php b/packages/graphql/src/Builder/Types/InputObject.php index 777575e94..8cda5d9e7 100644 --- a/packages/graphql/src/Builder/Types/InputObject.php +++ b/packages/graphql/src/Builder/Types/InputObject.php @@ -9,7 +9,7 @@ use GraphQL\Language\BlockString; use GraphQL\Language\Parser; use GraphQL\Type\Definition\Type; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scope; @@ -166,7 +166,7 @@ protected function getFieldDefinition( Context $context, ): ?InputValueDefinitionNode { // Builder? - $builder = $context->get(AstManipulation::class)?->builderInfo->getBuilder(); + $builder = $context->get(AstManipulationBuilderInfo::class)?->value->getBuilder(); if (!$builder) { return null; @@ -222,7 +222,7 @@ protected function getFieldDirectiveOperator( Context $context, ): ?Operator { // Builder? - $builder = $context->get(AstManipulation::class)?->builderInfo->getBuilder(); + $builder = $context->get(AstManipulationBuilderInfo::class)?->value->getBuilder(); if (!$builder) { return null; diff --git a/packages/graphql/src/SearchBy/Operators/Complex/RelationType.php b/packages/graphql/src/SearchBy/Operators/Complex/RelationType.php index 924d8d458..afa41b76a 100644 --- a/packages/graphql/src/SearchBy/Operators/Complex/RelationType.php +++ b/packages/graphql/src/SearchBy/Operators/Complex/RelationType.php @@ -6,7 +6,7 @@ use GraphQL\Language\Parser; use GraphQL\Type\Definition\Type; use Illuminate\Support\Str; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeDefinition; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeSource; @@ -24,7 +24,7 @@ public function __construct() { #[Override] public function getTypeName(TypeSource $source, Context $context): string { $typeName = $source->getTypeName(); - $builderName = $context->get(AstManipulation::class)?->builderInfo->getName() ?? 'Unknown'; + $builderName = $context->get(AstManipulationBuilderInfo::class)?->value->getName() ?? 'Unknown'; $operatorName = Str::studly(Relation::getName()); $directiveName = Directive::Name; diff --git a/packages/graphql/src/SearchBy/Types/Condition.php b/packages/graphql/src/SearchBy/Types/Condition.php index 45f2b4c4f..2993aa1ff 100644 --- a/packages/graphql/src/SearchBy/Types/Condition.php +++ b/packages/graphql/src/SearchBy/Types/Condition.php @@ -13,7 +13,7 @@ use GraphQL\Type\Definition\InterfaceType; use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\ScalarType; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator as OperatorContract; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeSource; @@ -45,7 +45,7 @@ class Condition extends InputObject { #[Override] public function getTypeName(TypeSource $source, Context $context): string { $typeName = $source->getTypeName(); - $builderName = $context->get(AstManipulation::class)?->builderInfo->getName() ?? 'Unknown'; + $builderName = $context->get(AstManipulationBuilderInfo::class)?->value->getName() ?? 'Unknown'; $directiveName = Directive::Name; return "{$directiveName}{$builderName}Condition{$typeName}"; diff --git a/packages/graphql/src/SearchBy/Types/Enumeration.php b/packages/graphql/src/SearchBy/Types/Enumeration.php index 3181176a1..de6e5b61c 100644 --- a/packages/graphql/src/SearchBy/Types/Enumeration.php +++ b/packages/graphql/src/SearchBy/Types/Enumeration.php @@ -5,7 +5,7 @@ use GraphQL\Language\AST\TypeDefinitionNode; use GraphQL\Language\Parser; use GraphQL\Type\Definition\Type; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeDefinition; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeSource; @@ -22,7 +22,7 @@ public function __construct() { #[Override] public function getTypeName(TypeSource $source, Context $context): string { $directiveName = Directive::Name; - $builderName = $context->get(AstManipulation::class)?->builderInfo->getName() ?? 'Unknown'; + $builderName = $context->get(AstManipulationBuilderInfo::class)?->value->getName() ?? 'Unknown'; $typeName = $source->getTypeName(); $nullable = $source->isNullable() ? 'OrNull' : ''; diff --git a/packages/graphql/src/SearchBy/Types/Scalar.php b/packages/graphql/src/SearchBy/Types/Scalar.php index 98eb5c5f9..1a8195bb8 100644 --- a/packages/graphql/src/SearchBy/Types/Scalar.php +++ b/packages/graphql/src/SearchBy/Types/Scalar.php @@ -5,7 +5,7 @@ use GraphQL\Language\AST\TypeDefinitionNode; use GraphQL\Language\Parser; use GraphQL\Type\Definition\Type; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeDefinition; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeSource; @@ -22,7 +22,7 @@ public function __construct() { #[Override] public function getTypeName(TypeSource $source, Context $context): string { $directiveName = Directive::Name; - $builderName = $context->get(AstManipulation::class)?->builderInfo->getName() ?? 'Unknown'; + $builderName = $context->get(AstManipulationBuilderInfo::class)?->value->getName() ?? 'Unknown'; $typeName = $source->getTypeName(); $nullable = $source->isNullable() ? 'OrNull' : ''; diff --git a/packages/graphql/src/SortBy/Types/Clause.php b/packages/graphql/src/SortBy/Types/Clause.php index 5a51cb3e4..934950443 100644 --- a/packages/graphql/src/SortBy/Types/Clause.php +++ b/packages/graphql/src/SortBy/Types/Clause.php @@ -9,7 +9,7 @@ use GraphQL\Type\Definition\InputObjectType; use GraphQL\Type\Definition\InterfaceType; use GraphQL\Type\Definition\ObjectType; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contexts\AstManipulationBuilderInfo; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator as OperatorContract; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeSource; @@ -39,7 +39,7 @@ class Clause extends InputObject { #[Override] public function getTypeName(TypeSource $source, Context $context): string { $directiveName = Directive::Name; - $builderName = $context->get(AstManipulation::class)?->builderInfo->getName() ?? 'Unknown'; + $builderName = $context->get(AstManipulationBuilderInfo::class)?->value->getName() ?? 'Unknown'; $typeName = $source->getTypeName(); return "{$directiveName}{$builderName}Clause{$typeName}"; From 0cd21de53e237b90b0d6f1de6d2bf66103283315 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 11 Jan 2024 13:34:27 +0400 Subject: [PATCH 2/8] `Property::getChild()` will not split `$name`. --- packages/graphql/src/Builder/Property.php | 3 +-- .../src/SearchBy/Directives/DirectiveTest.php | 12 ++++++------ .../src/SortBy/Directives/DirectiveTest.php | 16 ++++++++-------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/packages/graphql/src/Builder/Property.php b/packages/graphql/src/Builder/Property.php index aa2652565..582a90023 100644 --- a/packages/graphql/src/Builder/Property.php +++ b/packages/graphql/src/Builder/Property.php @@ -8,7 +8,6 @@ use function array_slice; use function array_values; use function end; -use function explode; use function implode; class Property implements Stringable { @@ -37,7 +36,7 @@ public function getPath(): array { } public function getChild(string $name): static { - return new static(...$this->path, ...explode(static::Separator, $name)); + return new static(...$this->path, ...[$name]); } public function getParent(): static { diff --git a/packages/graphql/src/SearchBy/Directives/DirectiveTest.php b/packages/graphql/src/SearchBy/Directives/DirectiveTest.php index 59f01d906..3cd28a92a 100644 --- a/packages/graphql/src/SearchBy/Directives/DirectiveTest.php +++ b/packages/graphql/src/SearchBy/Directives/DirectiveTest.php @@ -250,7 +250,7 @@ public function testHandleBuilder( input Test { id: Int! - value: String @rename(attribute: "renamed") + value: String @rename(attribute: "renamed.field") } GRAPHQL, ); @@ -311,7 +311,7 @@ public function testHandleScoutBuilder( input Test { a: Int! - b: String @rename(attribute: "renamed") + b: String @rename(attribute: "renamed.field") c: Test } GRAPHQL, @@ -560,7 +560,7 @@ public static function dataProviderHandleBuilder(): array { and ( ( ("id" = ?) - or ("renamed" != ?) + or ("renamed"."field" != ?) ) ) ) @@ -616,7 +616,7 @@ public static function dataProviderHandleBuilder(): array { and ( ( ("test_objects"."id" = ?) - or ("test_objects"."renamed" != ?) + or ("test_objects"."renamed"."field" != ?) ) ) ) @@ -718,7 +718,7 @@ public static function dataProviderHandleScoutBuilder(): array { 'c.a' => 2, ], 'whereIns' => [ - 'renamed' => ['a', 'b', 'c'], + 'renamed.field' => ['a', 'b', 'c'], ], ], [ @@ -751,7 +751,7 @@ public static function dataProviderHandleScoutBuilder(): array { 'properties/c/a' => 2, ], 'whereIns' => [ - 'properties/renamed' => ['a', 'b', 'c'], + 'properties/renamed.field' => ['a', 'b', 'c'], ], ], [ diff --git a/packages/graphql/src/SortBy/Directives/DirectiveTest.php b/packages/graphql/src/SortBy/Directives/DirectiveTest.php index d87980878..f3a8f47d3 100644 --- a/packages/graphql/src/SortBy/Directives/DirectiveTest.php +++ b/packages/graphql/src/SortBy/Directives/DirectiveTest.php @@ -289,7 +289,7 @@ public function testHandleBuilder( input Test { id: Int! - value: String @rename(attribute: "renamed") + value: String @rename(attribute: "renamed.field") } GRAPHQL, ); @@ -350,7 +350,7 @@ public function testHandleScoutBuilder( input Test { a: Int! - b: String @rename(attribute: "renamed") + b: String @rename(attribute: "renamed.field") c: Test } GRAPHQL, @@ -491,7 +491,7 @@ public static function dataProviderHandleBuilder(): array { "test_objects" order by "id" asc, - "renamed" desc, + "renamed"."field" desc, RANDOM() SQL , @@ -529,7 +529,7 @@ static function (TestCase $test): void { "test_objects" order by "id" ASC NULLS LAST, - "renamed" DESC NULLS FIRST + "renamed"."field" DESC NULLS FIRST SQL , 'bindings' => [], @@ -562,7 +562,7 @@ static function (): void { "test_objects" order by "id" DESC NULLS FIRST, - "renamed" asc + "renamed"."field" asc SQL , 'bindings' => [], @@ -588,7 +588,7 @@ static function (): void { "test_objects" order by "id" ASC NULLS LAST, - "renamed" desc + "renamed"."field" desc SQL , 'bindings' => [], @@ -665,7 +665,7 @@ public static function dataProviderHandleScoutBuilder(): array { 'direction' => 'desc', ], [ - 'column' => 'renamed', + 'column' => 'renamed.field', 'direction' => 'desc', ], ], @@ -697,7 +697,7 @@ public static function dataProviderHandleScoutBuilder(): array { 'direction' => 'desc', ], [ - 'column' => 'properties/renamed', + 'column' => 'properties/renamed.field', 'direction' => 'desc', ], ], From 3ca02085273f160cf3da2ff49b9b700ddb5f1125 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:07:29 +0400 Subject: [PATCH 3/8] New `BuilderPropertyResolver` contract to convert `Property` into builder property/column/etc. --- .../Contracts/BuilderPropertyResolver.php | 12 ++++++++++ .../Defaults/BuilderPropertyResolver.php | 23 +++++++++++++++++++ .../Builder/Directives/OperatorDirective.php | 5 +++- packages/graphql/src/Provider.php | 3 +++ .../src/SearchBy/Directives/DirectiveTest.php | 4 +++- .../SearchBy/Operators/Complex/Relation.php | 4 +++- .../Operators/Traits/ScoutSupport.php | 4 +++- .../src/SortBy/Operators/Extra/NullsFirst.php | 4 +++- .../src/SortBy/Operators/Extra/NullsLast.php | 4 +++- .../graphql/src/SortBy/Operators/Field.php | 4 +++- 10 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 packages/graphql/src/Builder/Contracts/BuilderPropertyResolver.php create mode 100644 packages/graphql/src/Builder/Defaults/BuilderPropertyResolver.php diff --git a/packages/graphql/src/Builder/Contracts/BuilderPropertyResolver.php b/packages/graphql/src/Builder/Contracts/BuilderPropertyResolver.php new file mode 100644 index 000000000..0b713e46a --- /dev/null +++ b/packages/graphql/src/Builder/Contracts/BuilderPropertyResolver.php @@ -0,0 +1,12 @@ +getPath()); + } +} diff --git a/packages/graphql/src/Builder/Directives/OperatorDirective.php b/packages/graphql/src/Builder/Directives/OperatorDirective.php index 002fb4d17..62cfff346 100644 --- a/packages/graphql/src/Builder/Directives/OperatorDirective.php +++ b/packages/graphql/src/Builder/Directives/OperatorDirective.php @@ -3,6 +3,7 @@ namespace LastDragon_ru\LaraASP\GraphQL\Builder\Directives; use GraphQL\Language\DirectiveLocation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scope; use Nuwave\Lighthouse\Schema\DirectiveLocator; @@ -13,7 +14,9 @@ use function is_a; abstract class OperatorDirective extends BaseDirective implements Operator { - public function __construct() { + public function __construct( + protected readonly BuilderPropertyResolver $resolver, + ) { // empty } diff --git a/packages/graphql/src/Provider.php b/packages/graphql/src/Provider.php index 0a3e7fb6a..f945d0f9c 100644 --- a/packages/graphql/src/Provider.php +++ b/packages/graphql/src/Provider.php @@ -6,7 +6,9 @@ use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Support\ServiceProvider; use LastDragon_ru\LaraASP\Core\Provider\WithConfig; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver as BuilderPropertyResolverContract; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver as ScoutFieldResolverContract; +use LastDragon_ru\LaraASP\GraphQL\Builder\Defaults\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Manipulator; use LastDragon_ru\LaraASP\GraphQL\Builder\Scout\DefaultFieldResolver as ScoutFieldResolver; use LastDragon_ru\LaraASP\GraphQL\Printer\DirectiveResolver; @@ -68,6 +70,7 @@ protected function registerBindings(): void { $this->app->scopedIf(SorterFactoryContract::class, SorterFactory::class); $this->app->scopedIf(StreamFactoryContract::class, StreamFactory::class); $this->app->scopedIf(ScoutFieldResolverContract::class, ScoutFieldResolver::class); + $this->app->scopedIf(BuilderPropertyResolverContract::class, BuilderPropertyResolver::class); } protected function registerOperators(): void { diff --git a/packages/graphql/src/SearchBy/Directives/DirectiveTest.php b/packages/graphql/src/SearchBy/Directives/DirectiveTest.php index 3cd28a92a..b8d5af83a 100644 --- a/packages/graphql/src/SearchBy/Directives/DirectiveTest.php +++ b/packages/graphql/src/SearchBy/Directives/DirectiveTest.php @@ -18,6 +18,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Support\Str; use Laravel\Scout\Builder as ScoutBuilder; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; @@ -404,7 +405,8 @@ static function (self $test): GraphQLExpected { '~custom-complex-operators.graphql', static function (): void { $locator = Container::getInstance()->make(DirectiveLocator::class); - $directive = new class() extends BaseOperator implements TypeDefinition { + $resolver = Container::getInstance()->make(BuilderPropertyResolver::class); + $directive = new class($resolver) extends BaseOperator implements TypeDefinition { #[Override] public static function getName(): string { return 'custom'; diff --git a/packages/graphql/src/SearchBy/Operators/Complex/Relation.php b/packages/graphql/src/SearchBy/Operators/Complex/Relation.php index 871d58c17..3656d0b53 100644 --- a/packages/graphql/src/SearchBy/Operators/Complex/Relation.php +++ b/packages/graphql/src/SearchBy/Operators/Complex/Relation.php @@ -6,6 +6,7 @@ use GraphQL\Language\DirectiveLocation; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use LastDragon_ru\LaraASP\Eloquent\ModelHelper; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeProvider; @@ -26,8 +27,9 @@ class Relation extends BaseOperator { public function __construct( protected SearchByOperatorPropertyDirective $property, + BuilderPropertyResolver $resolver, ) { - parent::__construct(); + parent::__construct($resolver); } // diff --git a/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php b/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php index 5256489b6..0077a1470 100644 --- a/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php +++ b/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php @@ -5,6 +5,7 @@ use Composer\InstalledVersions; use Composer\Semver\VersionParser; use Laravel\Scout\Builder as ScoutBuilder; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; use LastDragon_ru\LaraASP\GraphQL\SearchBy\Definitions\SearchByOperatorPropertyDirective; use Override; @@ -17,8 +18,9 @@ trait ScoutSupport { public function __construct( private FieldResolver $fieldResolver, + BuilderPropertyResolver $resolver, ) { - parent::__construct(); + parent::__construct($resolver); } protected function getFieldResolver(): FieldResolver { diff --git a/packages/graphql/src/SortBy/Operators/Extra/NullsFirst.php b/packages/graphql/src/SortBy/Operators/Extra/NullsFirst.php index 38746d9b5..86f03cdfa 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/NullsFirst.php +++ b/packages/graphql/src/SortBy/Operators/Extra/NullsFirst.php @@ -2,6 +2,7 @@ namespace LastDragon_ru\LaraASP\GraphQL\SortBy\Operators\Extra; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeProvider; @@ -24,8 +25,9 @@ class NullsFirst extends BaseOperator { */ public function __construct( protected readonly SorterFactory $factory, + BuilderPropertyResolver $resolver, ) { - parent::__construct(); + parent::__construct($resolver); } #[Override] diff --git a/packages/graphql/src/SortBy/Operators/Extra/NullsLast.php b/packages/graphql/src/SortBy/Operators/Extra/NullsLast.php index aa1e8e22e..ba197e1e0 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/NullsLast.php +++ b/packages/graphql/src/SortBy/Operators/Extra/NullsLast.php @@ -2,6 +2,7 @@ namespace LastDragon_ru\LaraASP\GraphQL\SortBy\Operators\Extra; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeProvider; @@ -24,8 +25,9 @@ class NullsLast extends BaseOperator { */ public function __construct( protected readonly SorterFactory $factory, + BuilderPropertyResolver $resolver, ) { - parent::__construct(); + parent::__construct($resolver); } #[Override] diff --git a/packages/graphql/src/SortBy/Operators/Field.php b/packages/graphql/src/SortBy/Operators/Field.php index 96a06cc09..137655ccf 100644 --- a/packages/graphql/src/SortBy/Operators/Field.php +++ b/packages/graphql/src/SortBy/Operators/Field.php @@ -2,6 +2,7 @@ namespace LastDragon_ru\LaraASP\GraphQL\SortBy\Operators; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeProvider; @@ -26,8 +27,9 @@ class Field extends BaseOperator { */ public function __construct( protected readonly SorterFactory $factory, + BuilderPropertyResolver $resolver, ) { - parent::__construct(); + parent::__construct($resolver); } #[Override] From 0a2b8a68ffae14fdb6566da060f18c4662b92a50 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Fri, 12 Jan 2024 11:49:20 +0400 Subject: [PATCH 4/8] Added `OperatorTests` trait to reduce copy-pasting in operators tests. --- .../Operators/Comparison/BetweenTest.php | 27 ++--- .../Operators/Comparison/BitwiseAndTest.php | 27 ++--- .../Comparison/BitwiseLeftShiftTest.php | 27 ++--- .../Operators/Comparison/BitwiseOrTest.php | 27 ++--- .../Comparison/BitwiseRightShiftTest.php | 27 ++--- .../Operators/Comparison/BitwiseXorTest.php | 27 ++--- .../Operators/Comparison/ContainsTest.php | 49 ++++---- .../Operators/Comparison/EndsWithTest.php | 27 ++--- .../Operators/Comparison/EqualTest.php | 45 +++---- .../Comparison/GreaterThanOrEqualTest.php | 27 ++--- .../Operators/Comparison/GreaterThanTest.php | 27 ++--- .../SearchBy/Operators/Comparison/InTest.php | 45 +++---- .../Operators/Comparison/IsNotNullTest.php | 27 ++--- .../Operators/Comparison/IsNullTest.php | 27 ++--- .../Comparison/LessThanOrEqualTest.php | 27 ++--- .../Operators/Comparison/LessThanTest.php | 27 ++--- .../Operators/Comparison/LikeTest.php | 27 ++--- .../Operators/Comparison/NotBetweenTest.php | 27 ++--- .../Operators/Comparison/NotContainsTest.php | 49 ++++---- .../Operators/Comparison/NotEndsWithTest.php | 27 ++--- .../Operators/Comparison/NotEqualTest.php | 27 ++--- .../Operators/Comparison/NotInTest.php | 55 ++++----- .../Operators/Comparison/NotLikeTest.php | 27 ++--- .../Comparison/NotStartsWithTest.php | 27 ++--- .../Operators/Comparison/StartsWithTest.php | 27 ++--- .../Operators/Complex/RelationTest.php | 35 +++--- .../SearchBy/Operators/Logical/AllOfTest.php | 48 ++++---- .../SearchBy/Operators/Logical/AnyOfTest.php | 30 ++--- .../SearchBy/Operators/Logical/NotTest.php | 30 ++--- .../SortBy/Operators/Extra/NullsFirstTest.php | 19 ++- .../SortBy/Operators/Extra/NullsLastTest.php | 19 ++- .../src/SortBy/Operators/Extra/RandomTest.php | 27 ++--- .../src/SortBy/Operators/FieldTest.php | 20 ++-- .../src/Testing/Package/OperatorTests.php | 113 ++++++++++++++++++ 34 files changed, 575 insertions(+), 549 deletions(-) create mode 100644 packages/graphql/src/Testing/Package/OperatorTests.php diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BetweenTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BetweenTest.php index a20ecb6b9..20584f212 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BetweenTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BetweenTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(Between::class)] -class BetweenTest extends TestCase { +final class BetweenTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class BetweenTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(Between::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" between ? and ?', 'bindings' => [1, 2], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" between ? and ?', 'bindings' => [1, 2], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAndTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAndTest.php index 3cab7b3ba..88fd2bce4 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAndTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAndTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(BitwiseAnd::class)] -class BitwiseAndTest extends TestCase { +final class BitwiseAndTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class BitwiseAndTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(BitwiseAnd::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" & ?', 'bindings' => ['abc'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" & ?', 'bindings' => [123], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShiftTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShiftTest.php index a8a681a90..360365895 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShiftTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShiftTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(BitwiseLeftShift::class)] -class BitwiseLeftShiftTest extends TestCase { +final class BitwiseLeftShiftTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class BitwiseLeftShiftTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(BitwiseLeftShift::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" << ?', 'bindings' => ['abc'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" << ?', 'bindings' => [123], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOrTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOrTest.php index 6659b886c..350c82aea 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOrTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOrTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(BitwiseOr::class)] -class BitwiseOrTest extends TestCase { +final class BitwiseOrTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class BitwiseOrTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(BitwiseOr::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" | ?', 'bindings' => ['abc'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" | ?', 'bindings' => [123], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShiftTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShiftTest.php index 0f7f416d4..12fb6abe1 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShiftTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShiftTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(BitwiseRightShift::class)] -class BitwiseRightShiftTest extends TestCase { +final class BitwiseRightShiftTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class BitwiseRightShiftTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(BitwiseRightShift::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" >> ?', 'bindings' => ['abc'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" >> ?', 'bindings' => [123], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXorTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXorTest.php index 4f6826c2a..c4dd6ab67 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXorTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXorTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(BitwiseXor::class)] -class BitwiseXorTest extends TestCase { +final class BitwiseXorTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class BitwiseXorTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(BitwiseXor::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" ^ ?', 'bindings' => ['abc'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" ^ ?', 'bindings' => [123], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/ContainsTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/ContainsTest.php index 8e3ab434f..219a02040 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/ContainsTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/ContainsTest.php @@ -3,7 +3,6 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Query\Grammars\Grammar; use Illuminate\Database\Query\Grammars\MySqlGrammar; @@ -11,13 +10,13 @@ use Illuminate\Database\Query\Grammars\SQLiteGrammar; use Illuminate\Database\Query\Grammars\SqlServerGrammar; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -27,7 +26,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(Contains::class)] -class ContainsTest extends TestCase { +final class ContainsTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -37,6 +38,7 @@ class ContainsTest extends TestCase { * @param BuilderFactory $builderFactory * @param class-string $grammar * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, @@ -44,24 +46,23 @@ public function testCall( string $grammar, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $builder = $builderFactory($this); - $grammar = new $grammar(); + $self = $this; + $builderFactory = static function () use ($self, $builderFactory, $grammar): mixed { + $builder = $builderFactory($self); + $grammar = new $grammar(); - if ($builder instanceof EloquentBuilder) { - $builder->getQuery()->grammar = $grammar; - } else { - $builder->grammar = $grammar; - } + if ($builder instanceof EloquentBuilder) { + $builder->getQuery()->grammar = $grammar; + } else { + $builder->grammar = $grammar; + } - $operator = Container::getInstance()->make(Contains::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $operator->call($search, $builder, $property, $argument, $context); + return $builder; + }; - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -80,10 +81,11 @@ public static function dataProviderCall(): array { 'bindings' => ['%!%a[!_]c!!!%%'], ], MySqlGrammar::class, - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], SQLiteGrammar::class => [ [ @@ -91,10 +93,11 @@ static function (self $test): Argument { 'bindings' => ['%!%a[!_]c!!!%%'], ], SQLiteGrammar::class, - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], PostgresGrammar::class => [ [ @@ -102,10 +105,11 @@ static function (self $test): Argument { 'bindings' => ['%!%a[!_]c!!!%%'], ], PostgresGrammar::class, - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], SqlServerGrammar::class => [ [ @@ -113,10 +117,11 @@ static function (self $test): Argument { 'bindings' => ['%!%a![!_!]c!!!%%'], ], SqlServerGrammar::class, - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/EndsWithTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/EndsWithTest.php index c15d57d31..d4e163612 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/EndsWithTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/EndsWithTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(EndsWith::class)] -class EndsWithTest extends TestCase { +final class EndsWithTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class EndsWithTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(EndsWith::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" LIKE ? ESCAPE \'!\'', 'bindings' => ['%!%a[!_]c!!!%'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" LIKE ? ESCAPE \'!\'', 'bindings' => ['%abc'], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php index 96c88607b..b9a0b6cb6 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php @@ -3,19 +3,18 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\ScoutBuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use Override; use PHPUnit\Framework\Attributes\CoversClass; @@ -28,7 +27,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(Equal::class)] -class EqualTest extends TestCase { +final class EqualTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -37,22 +38,16 @@ class EqualTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(Equal::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } /** @@ -62,27 +57,21 @@ public function testCall( * @param Closure(static): ScoutBuilder $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure():FieldResolver|null $resolver + * @param Closure(static): Context|null $contextFactory */ public function testCallScout( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, Closure $resolver = null, ): void { if ($resolver) { $this->override(FieldResolver::class, $resolver); } - $operator = Container::getInstance()->make(Equal::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertScoutQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -100,20 +89,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" = ?', 'bindings' => ['abc'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" = ?', 'bindings' => [123], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], ]), ))->getData(); @@ -132,11 +123,12 @@ public static function dataProviderCallScout(): array { 'path.to.property' => 'abc', ], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property with resolver' => [ [ @@ -144,10 +136,11 @@ static function (self $test): Argument { 'properties/path/to/property' => 'abc', ], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, static function (): FieldResolver { return new class() implements FieldResolver { /** diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqualTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqualTest.php index 7668d4f6a..9813d29d3 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqualTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqualTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(GreaterThanOrEqual::class)] -class GreaterThanOrEqualTest extends TestCase { +final class GreaterThanOrEqualTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class GreaterThanOrEqualTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(GreaterThanOrEqual::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" >= ?', 'bindings' => [123], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" >= ?', 'bindings' => [321], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 321); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanTest.php index 819a54947..7cdae1363 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(GreaterThan::class)] -class GreaterThanTest extends TestCase { +final class GreaterThanTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class GreaterThanTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(GreaterThan::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" > ?', 'bindings' => [123], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" > ?', 'bindings' => [321], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 321); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php index f8cec74a9..4f4e4309b 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php @@ -3,19 +3,18 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\ScoutBuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use Override; use PHPUnit\Framework\Attributes\CoversClass; @@ -28,7 +27,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(In::class)] -class InTest extends TestCase { +final class InTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -37,22 +38,16 @@ class InTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(In::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } /** @@ -61,6 +56,7 @@ public function testCall( * @param array $expected * @param Closure(static): ScoutBuilder $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory * @param Closure():FieldResolver|null $resolver */ public function testCallScout( @@ -68,21 +64,14 @@ public function testCallScout( Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, Closure $resolver = null, ): void { if ($resolver) { $this->override(FieldResolver::class, $resolver); } - $operator = Container::getInstance()->make(In::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertScoutQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -100,20 +89,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" in (?, ?, ?)', 'bindings' => [1, 2, 3], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" in (?, ?, ?)', 'bindings' => ['a', 'b', 'c'], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[String!]!', ['a', 'b', 'c']); }, + null, ], ]), ))->getData(); @@ -132,11 +123,12 @@ public static function dataProviderCallScout(): array { 'path.to.property' => [1, 2, 3], ], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, ], 'property with resolver' => [ [ @@ -144,10 +136,11 @@ static function (self $test): Argument { 'properties/path/to/property' => [1, 2, 3], ], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, + null, static function (): FieldResolver { return new class() implements FieldResolver { /** diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNullTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNullTest.php index a4e42a229..8d8b4ef89 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNullTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNullTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(IsNotNull::class)] -class IsNotNullTest extends TestCase { +final class IsNotNullTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class IsNotNullTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(IsNotNull::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" is not null', 'bindings' => [], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Boolean', null); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" is not null', 'bindings' => [], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Boolean', null); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/IsNullTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/IsNullTest.php index 91e34fd6b..eeaa6ac5a 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/IsNullTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/IsNullTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(IsNull::class)] -class IsNullTest extends TestCase { +final class IsNullTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class IsNullTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(IsNull::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" is null', 'bindings' => [], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Boolean', null); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" is null', 'bindings' => [], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Boolean', null); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqualTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqualTest.php index 20cc15c3a..41e87e690 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqualTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqualTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(LessThanOrEqual::class)] -class LessThanOrEqualTest extends TestCase { +final class LessThanOrEqualTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class LessThanOrEqualTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(LessThanOrEqual::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" <= ?', 'bindings' => [123], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" <= ?', 'bindings' => [321], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 321); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanTest.php index 87453e6de..a564573e3 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(LessThan::class)] -class LessThanTest extends TestCase { +final class LessThanTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class LessThanTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(LessThan::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" < ?', 'bindings' => [123], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" < ?', 'bindings' => [321], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 321); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/LikeTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/LikeTest.php index 06a4fc191..f0b2d70b2 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/LikeTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/LikeTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(Like::class)] -class LikeTest extends TestCase { +final class LikeTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class LikeTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(Like::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" like ?', 'bindings' => ['abc'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" like ?', 'bindings' => ['abc'], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotBetweenTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotBetweenTest.php index 4ba2a1fec..9c8720a2a 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotBetweenTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotBetweenTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(NotBetween::class)] -class NotBetweenTest extends TestCase { +final class NotBetweenTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class NotBetweenTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(NotBetween::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" not between ? and ?', 'bindings' => [1, 2], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" not between ? and ?', 'bindings' => [1, 2], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotContainsTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotContainsTest.php index 6d8ee1ae3..ea934a3bb 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotContainsTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotContainsTest.php @@ -3,7 +3,6 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Query\Grammars\Grammar; use Illuminate\Database\Query\Grammars\MySqlGrammar; @@ -11,13 +10,13 @@ use Illuminate\Database\Query\Grammars\SQLiteGrammar; use Illuminate\Database\Query\Grammars\SqlServerGrammar; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -27,7 +26,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(NotContains::class)] -class NotContainsTest extends TestCase { +final class NotContainsTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -37,6 +38,7 @@ class NotContainsTest extends TestCase { * @param BuilderFactory $builderFactory * @param class-string $grammar * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, @@ -44,24 +46,23 @@ public function testCall( string $grammar, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $builder = $builderFactory($this); - $grammar = new $grammar(); + $self = $this; + $builderFactory = static function () use ($self, $builderFactory, $grammar): mixed { + $builder = $builderFactory($self); + $grammar = new $grammar(); - if ($builder instanceof EloquentBuilder) { - $builder->getQuery()->grammar = $grammar; - } else { - $builder->grammar = $grammar; - } + if ($builder instanceof EloquentBuilder) { + $builder->getQuery()->grammar = $grammar; + } else { + $builder->grammar = $grammar; + } - $operator = Container::getInstance()->make(NotContains::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $operator->call($search, $builder, $property, $argument, $context); + return $builder; + }; - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -80,10 +81,11 @@ public static function dataProviderCall(): array { 'bindings' => ['%!%a[!_]c!!!%%'], ], MySqlGrammar::class, - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], SQLiteGrammar::class => [ [ @@ -91,10 +93,11 @@ static function (self $test): Argument { 'bindings' => ['%!%a[!_]c!!!%%'], ], SQLiteGrammar::class, - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], PostgresGrammar::class => [ [ @@ -102,10 +105,11 @@ static function (self $test): Argument { 'bindings' => ['%!%a[!_]c!!!%%'], ], PostgresGrammar::class, - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], SqlServerGrammar::class => [ [ @@ -113,10 +117,11 @@ static function (self $test): Argument { 'bindings' => ['%!%a![!_!]c!!!%%'], ], SqlServerGrammar::class, - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotEndsWithTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotEndsWithTest.php index 706481610..71653c8f2 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotEndsWithTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotEndsWithTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(NotEndsWith::class)] -class NotEndsWithTest extends TestCase { +final class NotEndsWithTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class NotEndsWithTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(NotEndsWith::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,10 +58,11 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" NOT LIKE ? ESCAPE \'!\'', 'bindings' => ['%!%a[!_]c!!!%'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], 'property.path' => [ [ @@ -76,10 +72,11 @@ static function (self $test): Argument { , 'bindings' => ['%abc'], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotEqualTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotEqualTest.php index a7446b5c6..461b18375 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotEqualTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotEqualTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(NotEqual::class)] -class NotEqualTest extends TestCase { +final class NotEqualTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class NotEqualTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(NotEqual::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" != ?', 'bindings' => ['abc'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" != ?', 'bindings' => [123], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php index 43cdb61ca..5c6538f81 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php @@ -8,15 +8,15 @@ use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\ScoutBuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use Override; use PHPUnit\Framework\Attributes\CoversClass; @@ -30,7 +30,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(NotIn::class)] -class NotInTest extends TestCase { +final class NotInTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -39,22 +41,16 @@ class NotInTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(NotIn::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } /** @@ -63,6 +59,7 @@ public function testCall( * @param array $expected * @param Closure(static): ScoutBuilder $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory * @param Closure():FieldResolver|null $resolver */ public function testCallScout( @@ -70,6 +67,7 @@ public function testCallScout( Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, Closure $resolver = null, ): void { // Prepare @@ -81,22 +79,17 @@ public function testCallScout( $operator = Container::getInstance()->make(NotInTest_Operator::class); if (!$operator->isScoutSupported()) { - self::markTestSkipped(sprintf( - 'Minimum version of `laravel/scout` should be `%s`, `%s` installed.', - $operator->getScoutVersion(), - InstalledVersions::getPrettyVersion('laravel/scout'), - )); + self::markTestSkipped( + sprintf( + 'Minimum version of `laravel/scout` should be `%s`, `%s` installed.', + $operator->getScoutVersion(), + InstalledVersions::getPrettyVersion('laravel/scout'), + ), + ); } // Test - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertScoutQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -114,20 +107,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" not in (?, ?, ?)', 'bindings' => [1, 2, 3], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" not in (?, ?, ?)', 'bindings' => ['a', 'b', 'c'], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[String!]!', ['a', 'b', 'c']); }, + null, ], ]), ))->getData(); @@ -146,11 +141,12 @@ public static function dataProviderCallScout(): array { 'path.to.property' => [1, 2, 3], ], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, ], 'property with resolver' => [ [ @@ -158,10 +154,11 @@ static function (self $test): Argument { 'properties/path/to/property' => [1, 2, 3], ], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, + null, static function (): FieldResolver { return new class() implements FieldResolver { /** diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotLikeTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotLikeTest.php index b47e5189c..9275a7a9c 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotLikeTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotLikeTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(NotLike::class)] -class NotLikeTest extends TestCase { +final class NotLikeTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class NotLikeTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(NotLike::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" not like ?', 'bindings' => ['abc'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" not like ?', 'bindings' => ['abc'], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotStartsWithTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotStartsWithTest.php index 640dd1b13..21f1b68cc 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotStartsWithTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotStartsWithTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(NotStartsWith::class)] -class NotStartsWithTest extends TestCase { +final class NotStartsWithTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class NotStartsWithTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(NotStartsWith::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,10 +58,11 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" NOT LIKE ? ESCAPE \'!\'', 'bindings' => ['!%a[!_]c!!!%%'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], 'property.path' => [ [ @@ -76,10 +72,11 @@ static function (self $test): Argument { , 'bindings' => ['abc%'], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/StartsWithTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/StartsWithTest.php index 362fe32e6..98ec0b6ce 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/StartsWithTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/StartsWithTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Comparison; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(StartsWith::class)] -class StartsWithTest extends TestCase { +final class StartsWithTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class StartsWithTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(StartsWith::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" where "property" LIKE ? ESCAPE \'!\'', 'bindings' => ['!%a[!_]c!!!%%'], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" where "path"."to"."property" LIKE ? ESCAPE \'!\'', 'bindings' => ['abc%'], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php b/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php index f6ed6c632..163c725a2 100644 --- a/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php +++ b/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php @@ -4,7 +4,6 @@ use Closure; use Exception; -use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use LastDragon_ru\LaraASP\Eloquent\Exceptions\PropertyIsNotRelation; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; @@ -13,19 +12,20 @@ use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\Models\User; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; -use function is_array; - /** * @internal * * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(Relation::class)] -class RelationTest extends TestCase { +final class RelationTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -34,29 +34,16 @@ class RelationTest extends TestCase { * @param array{query: string, bindings: array}|Exception $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array|Exception $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - if ($expected instanceof Exception) { - self::expectExceptionObject($expected); - } - - $operator = Container::getInstance()->make(Relation::class); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Container::getInstance()->make(Directive::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - if (is_array($expected)) { - self::assertDatabaseQueryEquals($expected, $builder); - } else { - self::fail('Something wrong...'); - } + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -117,6 +104,7 @@ static function (self $test) use ($graphql): Argument { $graphql, ); }, + null, ], '{exists: true}' => [ [ @@ -139,6 +127,7 @@ static function (self $test) use ($graphql): Argument { $graphql, ); }, + null, ], '{notExists: true}' => [ [ @@ -161,6 +150,7 @@ static function (self $test) use ($graphql): Argument { $graphql, ); }, + null, ], '{relation: {property: {equal: 1}}}' => [ [ @@ -192,6 +182,7 @@ static function (self $test) use ($graphql): Argument { $graphql, ); }, + null, ], '{count: {equal: 1}}' => [ [ @@ -221,6 +212,7 @@ static function (self $test) use ($graphql): Argument { $graphql, ); }, + null, ], '{count: { multiple operators }}' => [ new ConditionTooManyOperators(['lessThan', 'equal']), @@ -240,6 +232,7 @@ static function (self $test) use ($graphql): Argument { $graphql, ); }, + null, ], '{where: {{property: {equal: 1}}}} (own)' => [ [ @@ -271,6 +264,7 @@ static function (self $test) use ($graphql): Argument { $graphql, ); }, + null, ], '{relation: {relation: {property: {equal: 1}}}}' => [ [ @@ -324,6 +318,7 @@ static function (self $test) use ($graphql): Argument { $graphql, ); }, + null, ], ]; } diff --git a/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php b/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php index 66c40326d..83a00ea99 100644 --- a/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php +++ b/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php @@ -3,7 +3,6 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Logical; use Closure; -use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; @@ -14,6 +13,7 @@ use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\EloquentBuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\QueryBuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\ScoutBuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; @@ -30,7 +30,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(AllOf::class)] -class AllOfTest extends TestCase { +final class AllOfTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -39,22 +41,16 @@ class AllOfTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(AllOf::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Container::getInstance()->make(Directive::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } /** @@ -63,6 +59,7 @@ public function testCall( * @param array $expected * @param Closure(static): ScoutBuilder $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory * @param Closure():FieldResolver|null $resolver */ public function testCallScout( @@ -70,21 +67,14 @@ public function testCallScout( Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, Closure $resolver = null, ): void { if ($resolver) { $this->override(FieldResolver::class, $resolver); } - $operator = Container::getInstance()->make(AllOf::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Container::getInstance()->make(Directive::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertScoutQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -137,8 +127,9 @@ public static function dataProviderCall(): array { 22, ], ], - new Property(), + new Property('operator name should be ignored'), $factory, + null, ], 'with alias' => [ [ @@ -151,8 +142,9 @@ public static function dataProviderCall(): array { 22, ], ], - new Property('alias'), + new Property('alias', 'operator name should be ignored'), $factory, + null, ], ]), ), @@ -172,8 +164,9 @@ public static function dataProviderCall(): array { 22, ], ], - new Property(), + new Property('operator name should be ignored'), $factory, + null, ], 'with alias' => [ [ @@ -186,8 +179,9 @@ public static function dataProviderCall(): array { 22, ], ], - new Property('alias'), + new Property('alias', 'operator name should be ignored'), $factory, + null, ], ]), ), @@ -243,9 +237,10 @@ public static function dataProviderCallScout(): array { 'path.to.property.b' => [1, 2, 3], ], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), $factory, null, + null, ], 'property with resolver' => [ [ @@ -257,8 +252,9 @@ public static function dataProviderCallScout(): array { 'properties/path/to/property/b' => [1, 2, 3], ], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), $factory, + null, static function (): FieldResolver { return new class() implements FieldResolver { /** diff --git a/packages/graphql/src/SearchBy/Operators/Logical/AnyOfTest.php b/packages/graphql/src/SearchBy/Operators/Logical/AnyOfTest.php index f9305c07e..1ea6f9151 100644 --- a/packages/graphql/src/SearchBy/Operators/Logical/AnyOfTest.php +++ b/packages/graphql/src/SearchBy/Operators/Logical/AnyOfTest.php @@ -3,13 +3,13 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Logical; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\EloquentBuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\QueryBuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; @@ -23,7 +23,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(AnyOf::class)] -class AnyOfTest extends TestCase { +final class AnyOfTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -32,22 +34,16 @@ class AnyOfTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(AnyOf::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Container::getInstance()->make(Directive::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -100,8 +96,9 @@ public static function dataProviderCall(): array { 22, ], ], - new Property(), + new Property('operator name should be ignored'), $factory, + null, ], 'with alias' => [ [ @@ -114,8 +111,9 @@ public static function dataProviderCall(): array { 22, ], ], - new Property('alias'), + new Property('alias', 'operator name should be ignored'), $factory, + null, ], ]), ), @@ -135,8 +133,9 @@ public static function dataProviderCall(): array { 22, ], ], - new Property(), + new Property('operator name should be ignored'), $factory, + null, ], 'with alias' => [ [ @@ -149,8 +148,9 @@ public static function dataProviderCall(): array { 22, ], ], - new Property('alias'), + new Property('alias', 'operator name should be ignored'), $factory, + null, ], ]), ), diff --git a/packages/graphql/src/SearchBy/Operators/Logical/NotTest.php b/packages/graphql/src/SearchBy/Operators/Logical/NotTest.php index 43dedfaae..56aeabc0c 100644 --- a/packages/graphql/src/SearchBy/Operators/Logical/NotTest.php +++ b/packages/graphql/src/SearchBy/Operators/Logical/NotTest.php @@ -3,13 +3,13 @@ namespace LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators\Logical; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\EloquentBuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\QueryBuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; @@ -23,7 +23,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(Not::class)] -class NotTest extends TestCase { +final class NotTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -32,22 +34,16 @@ class NotTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(Not::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Container::getInstance()->make(Directive::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -100,8 +96,9 @@ public static function dataProviderCall(): array { 2, ], ], - new Property(), + new Property('operator name should be ignored'), $factory, + null, ], 'with alias' => [ [ @@ -110,8 +107,9 @@ public static function dataProviderCall(): array { 2, ], ], - new Property('alias'), + new Property('alias', 'operator name should be ignored'), $factory, + null, ], ]), ), @@ -125,8 +123,9 @@ public static function dataProviderCall(): array { 2, ], ], - new Property(), + new Property('operator name should be ignored'), $factory, + null, ], 'with alias' => [ [ @@ -135,8 +134,9 @@ public static function dataProviderCall(): array { 2, ], ], - new Property('alias'), + new Property('alias', 'operator name should be ignored'), $factory, + null, ], ]), ), diff --git a/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php b/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php index f9f556f93..0f76abb8c 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php +++ b/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php @@ -3,12 +3,12 @@ namespace LastDragon_ru\LaraASP\GraphQL\SortBy\Operators\Extra; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\SortBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\SortBy\Enums\Direction; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; @@ -21,7 +21,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(NullsFirst::class)] -class NullsFirstTest extends TestCase { +final class NullsFirstTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +32,16 @@ class NullsFirstTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(NullsFirst::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $handler = Container::getInstance()->make(Directive::class); - $builder = $builderFactory($this); - $builder = $operator->call($handler, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -86,6 +82,7 @@ static function (self $test): Argument { ], ); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php b/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php index bdd0dd7d2..58b8dcc50 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php +++ b/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php @@ -3,12 +3,12 @@ namespace LastDragon_ru\LaraASP\GraphQL\SortBy\Operators\Extra; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\SortBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\SortBy\Enums\Direction; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; @@ -21,7 +21,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(NullsLast::class)] -class NullsLastTest extends TestCase { +final class NullsLastTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +32,16 @@ class NullsLastTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(NullsLast::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $handler = Container::getInstance()->make(Directive::class); - $builder = $builderFactory($this); - $builder = $operator->call($handler, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -86,6 +82,7 @@ static function (self $test): Argument { ], ); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SortBy/Operators/Extra/RandomTest.php b/packages/graphql/src/SortBy/Operators/Extra/RandomTest.php index 920cd39a3..3efd0771f 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/RandomTest.php +++ b/packages/graphql/src/SortBy/Operators/Extra/RandomTest.php @@ -3,15 +3,14 @@ namespace LastDragon_ru\LaraASP\GraphQL\SortBy\Operators\Extra; use Closure; -use Illuminate\Container\Container; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; +use LastDragon_ru\LaraASP\GraphQL\SortBy\Directives\Directive; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; -use Mockery; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,7 +20,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(Random::class)] -class RandomTest extends TestCase { +final class RandomTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -30,22 +31,16 @@ class RandomTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(Random::class); - $property = $property->getChild('operator name should be ignored'); - $argument = $argumentFactory($this); - $context = new Context(); - $search = Mockery::mock(Handler::class); - $builder = $builderFactory($this); - $builder = $operator->call($search, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } // @@ -63,20 +58,22 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" order by RANDOM()', 'bindings' => [], ], - new Property('property'), + new Property('property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('SortByTypeFlag', 'yes'); }, + null, ], 'property.path' => [ [ 'query' => 'select * from "test_objects" order by RANDOM()', 'bindings' => [], ], - new Property('path', 'to', 'property'), + new Property('path', 'to', 'property', 'operator name should be ignored'), static function (self $test): Argument { return $test->getGraphQLArgument('SortByTypeFlag', 'yes'); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SortBy/Operators/FieldTest.php b/packages/graphql/src/SortBy/Operators/FieldTest.php index a980bd4c3..b0eb984ce 100644 --- a/packages/graphql/src/SortBy/Operators/FieldTest.php +++ b/packages/graphql/src/SortBy/Operators/FieldTest.php @@ -19,6 +19,7 @@ use LastDragon_ru\LaraASP\GraphQL\SortBy\Sorters\QuerySorter; use LastDragon_ru\LaraASP\GraphQL\SortBy\Sorters\ScoutSorter; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\OperatorTests; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; @@ -36,7 +37,9 @@ * @phpstan-import-type BuilderFactory from BuilderDataProvider */ #[CoversClass(Field::class)] -class FieldTest extends TestCase { +final class FieldTest extends TestCase { + use OperatorTests; + // // ========================================================================= /** @@ -45,23 +48,16 @@ class FieldTest extends TestCase { * @param array{query: string, bindings: array} $expected * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory - * @param Closure(static): Context $contextFactory + * @param Closure(static): Context|null $contextFactory */ public function testCall( array $expected, Closure $builderFactory, Property $property, Closure $argumentFactory, - Closure $contextFactory, + ?Closure $contextFactory, ): void { - $operator = Container::getInstance()->make(Field::class); - $argument = $argumentFactory($this); - $directive = Container::getInstance()->make(Directive::class); - $context = $contextFactory($this); - $builder = $builderFactory($this); - $builder = $operator->call($directive, $builder, $property, $argument, $context); - - self::assertDatabaseQueryEquals($expected, $builder); + $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); } public function testCallEloquentBuilder(): void { @@ -212,6 +208,7 @@ public static function dataProviderCall(): array { static function (): Context { return new Context(); }, + null, ], 'nulls from Context' => [ [ @@ -225,6 +222,7 @@ static function (): Context { FieldContextNulls::class => new FieldContextNulls(Nulls::First), ]); }, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/Testing/Package/OperatorTests.php b/packages/graphql/src/Testing/Package/OperatorTests.php new file mode 100644 index 000000000..8c5cc93a1 --- /dev/null +++ b/packages/graphql/src/Testing/Package/OperatorTests.php @@ -0,0 +1,113 @@ + $directive + * @param array|Exception $expected + * @param Closure(static): object $builderFactory + * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory + */ + private function testOperator( + string $directive, + array|Exception $expected, + Closure $builderFactory, + Property $property, + Closure $argumentFactory, + ?Closure $contextFactory, + ): void { + if ($expected instanceof Exception) { + self::expectExceptionObject($expected); + } + + $operator = Container::getInstance()->make($this->getOperator()); + $argument = $argumentFactory($this); + $context = $contextFactory ? $contextFactory($this) : new Context(); + $handler = Container::getInstance()->make($directive); + $builder = $builderFactory($this); + $actual = $operator->call($handler, $builder, $property, $argument, $context); + + if (is_array($expected)) { + if ($builder instanceof EloquentBuilder) { + self::assertArrayHasKey('query', $expected); + self::assertArrayHasKey('bindings', $expected); + self::assertInstanceOf(EloquentBuilder::class, $actual); + self::assertDatabaseQueryEquals($expected, $actual); + } elseif ($builder instanceof QueryBuilder) { + self::assertArrayHasKey('query', $expected); + self::assertArrayHasKey('bindings', $expected); + self::assertInstanceOf(QueryBuilder::class, $actual); + self::assertDatabaseQueryEquals($expected, $actual); + } elseif ($builder instanceof ScoutBuilder) { + self::assertInstanceOf(ScoutBuilder::class, $actual); + self::assertScoutQueryEquals($expected, $actual); + } else { + self::fail( + sprintf( + 'Builder `%s` is not supported.', + $builder::class, + ), + ); + } + } else { + self::fail('Something wrong...'); + } + } + + /** + * @return class-string + */ + private function getOperator(): string { + $class = new ReflectionClass($this); + $attrs = $class->getAttributes(CoversClass::class, ReflectionAttribute::IS_INSTANCEOF); + $attr = reset($attrs); + $class = $attr ? $attr->newInstance()->className() : null; + + if (!$class || !is_a($class, Operator::class, true)) { + throw new LogicException( + sprintf( + 'The `%s` attribute is missed or is not an `%s` instance.', + CoversClass::class, + Operator::class, + ), + ); + } + + return $class; + } +} From 0cf15b06341fb468f215c2adafcc5462f33811e9 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Fri, 12 Jan 2024 14:56:05 +0400 Subject: [PATCH 5/8] Operators tests will also check `BuilderPropertyResolver`. --- .../SearchBy/Operators/Comparison/Between.php | 2 +- .../Operators/Comparison/BetweenTest.php | 30 ++++++- .../Operators/Comparison/BitwiseAnd.php | 2 +- .../Operators/Comparison/BitwiseAndTest.php | 30 ++++++- .../Operators/Comparison/BitwiseLeftShift.php | 2 +- .../Comparison/BitwiseLeftShiftTest.php | 30 ++++++- .../Operators/Comparison/BitwiseOr.php | 2 +- .../Operators/Comparison/BitwiseOrTest.php | 30 ++++++- .../Comparison/BitwiseRightShift.php | 2 +- .../Comparison/BitwiseRightShiftTest.php | 30 ++++++- .../Operators/Comparison/BitwiseXor.php | 2 +- .../Operators/Comparison/BitwiseXorTest.php | 30 ++++++- .../Operators/Comparison/Contains.php | 3 +- .../Operators/Comparison/ContainsTest.php | 46 ++++++++++- .../Operators/Comparison/EndsWithTest.php | 30 ++++++- .../SearchBy/Operators/Comparison/Equal.php | 2 +- .../Operators/Comparison/EqualTest.php | 61 +++++++++++--- .../Operators/Comparison/GreaterThan.php | 2 +- .../Comparison/GreaterThanOrEqual.php | 2 +- .../Comparison/GreaterThanOrEqualTest.php | 30 ++++++- .../Operators/Comparison/GreaterThanTest.php | 30 ++++++- .../src/SearchBy/Operators/Comparison/In.php | 2 +- .../SearchBy/Operators/Comparison/InTest.php | 58 ++++++++++--- .../Operators/Comparison/IsNotNull.php | 2 +- .../Operators/Comparison/IsNotNullTest.php | 30 ++++++- .../SearchBy/Operators/Comparison/IsNull.php | 2 +- .../Operators/Comparison/IsNullTest.php | 30 ++++++- .../Operators/Comparison/LessThan.php | 2 +- .../Operators/Comparison/LessThanOrEqual.php | 2 +- .../Comparison/LessThanOrEqualTest.php | 30 ++++++- .../Operators/Comparison/LessThanTest.php | 30 ++++++- .../SearchBy/Operators/Comparison/Like.php | 2 +- .../Operators/Comparison/LikeTest.php | 30 ++++++- .../Operators/Comparison/NotBetween.php | 2 +- .../Operators/Comparison/NotBetweenTest.php | 30 ++++++- .../Operators/Comparison/NotContainsTest.php | 49 ++++++++++- .../Operators/Comparison/NotEndsWithTest.php | 33 +++++++- .../Operators/Comparison/NotEqual.php | 2 +- .../Operators/Comparison/NotEqualTest.php | 30 ++++++- .../SearchBy/Operators/Comparison/NotIn.php | 2 +- .../Operators/Comparison/NotInTest.php | 58 ++++++++++--- .../SearchBy/Operators/Comparison/NotLike.php | 2 +- .../Operators/Comparison/NotLikeTest.php | 30 ++++++- .../Comparison/NotStartsWithTest.php | 33 +++++++- .../Operators/Comparison/StartsWithTest.php | 30 ++++++- .../Operators/Complex/RelationTest.php | 20 ++++- .../SearchBy/Operators/Logical/AllOfTest.php | 82 ++++++++++++++++--- .../SearchBy/Operators/Logical/AnyOfTest.php | 54 +++++++++++- .../SearchBy/Operators/Logical/NotTest.php | 46 ++++++++++- .../SortBy/Operators/Extra/NullsFirstTest.php | 13 ++- .../SortBy/Operators/Extra/NullsLastTest.php | 13 ++- .../src/SortBy/Operators/Extra/RandomTest.php | 14 +++- .../src/SortBy/Operators/FieldTest.php | 14 +++- .../src/Testing/Package/OperatorTests.php | 27 ++++-- 54 files changed, 1105 insertions(+), 97 deletions(-) diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/Between.php b/packages/graphql/src/SearchBy/Operators/Comparison/Between.php index bd9d5ad36..a053dd224 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/Between.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/Between.php @@ -44,7 +44,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = Cast::toIterable($argument->toPlain()); $builder->whereBetween($property, $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BetweenTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BetweenTest.php index 20584f212..f08729d84 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BetweenTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BetweenTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class BetweenTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" between ? and ?', + 'bindings' => [1, 2], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAnd.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAnd.php index b34791617..1b1882b14 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAnd.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAnd.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder = $builder->where($property, '&', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAndTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAndTest.php index 88fd2bce4..2ee9ff066 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAndTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseAndTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class BitwiseAndTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" & ?', + 'bindings' => [123], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 123); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShift.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShift.php index 70ddb2aef..75b32a798 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShift.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShift.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder = $builder->where($property, '<<', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShiftTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShiftTest.php index 360365895..2c1a9031a 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShiftTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseLeftShiftTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class BitwiseLeftShiftTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" << ?', + 'bindings' => [123], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 123); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOr.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOr.php index 1f7a0f403..f4e1f69f6 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOr.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOr.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder = $builder->where($property, '|', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOrTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOrTest.php index 350c82aea..0ca5b99b1 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOrTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseOrTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class BitwiseOrTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" | ?', + 'bindings' => [123], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 123); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShift.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShift.php index 6bacfca33..8fba88636 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShift.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShift.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder = $builder->where($property, '>>', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShiftTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShiftTest.php index 12fb6abe1..b554293b2 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShiftTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseRightShiftTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class BitwiseRightShiftTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" >> ?', + 'bindings' => [123], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 123); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXor.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXor.php index ba7e1f92c..0e1e3f0b7 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXor.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXor.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder = $builder->where($property, '^', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXorTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXorTest.php index c4dd6ab67..d3e9bcc73 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXorTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/BitwiseXorTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class BitwiseXorTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" ^ ?', + 'bindings' => [123], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 123); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/Contains.php b/packages/graphql/src/SearchBy/Operators/Comparison/Contains.php index ed7dabf4e..1a75a0c3e 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/Contains.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/Contains.php @@ -41,7 +41,8 @@ public function call( } $character = $this->getEscapeCharacter(); - $property = $builder->getGrammar()->wrap((string) $property->getParent()); + $property = $this->resolver->getProperty($builder, $property->getParent()); + $property = $builder->getGrammar()->wrap($property); $value = (string) Cast::toStringable($argument->toPlain()); $not = $this->isNegated() ? ' NOT' : ''; diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/ContainsTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/ContainsTest.php index 219a02040..bb40cebe5 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/ContainsTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/ContainsTest.php @@ -20,6 +20,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -39,6 +41,7 @@ final class ContainsTest extends TestCase { * @param class-string $grammar * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -47,6 +50,7 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { $self = $this; $builderFactory = static function () use ($self, $builderFactory, $grammar): mixed { @@ -62,7 +66,15 @@ public function testCall( return $builder; }; - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -86,6 +98,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], SQLiteGrammar::class => [ [ @@ -98,6 +111,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], PostgresGrammar::class => [ [ @@ -110,6 +124,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], SqlServerGrammar::class => [ [ @@ -122,6 +137,35 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, + ], + 'property.path' => [ + [ + 'query' => 'select * from "test_objects" where "path"."to"."property" LIKE ? ESCAPE \'!\'', + 'bindings' => ['%!%a[!_]c!!!%%'], + ], + SQLiteGrammar::class, + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', '%a[_]c!%'); + }, + null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" LIKE ? ESCAPE \'!\'', + 'bindings' => ['%!%a[!_]c!!!%%'], + ], + SQLiteGrammar::class, + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', '%a[_]c!%'); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/EndsWithTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/EndsWithTest.php index d4e163612..7f03977ef 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/EndsWithTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/EndsWithTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class EndsWithTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" LIKE ? ESCAPE \'!\'', + 'bindings' => ['%abc'], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', 'abc'); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/Equal.php b/packages/graphql/src/SearchBy/Operators/Comparison/Equal.php index 4c71b0d24..2b2404d7a 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/Equal.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/Equal.php @@ -39,7 +39,7 @@ public function call( $value = $argument->toPlain(); if ($builder instanceof EloquentBuilder || $builder instanceof QueryBuilder) { - $builder->where((string) $property, '=', $value); + $builder->where($this->resolver->getProperty($builder, $property), '=', $value); } elseif ($builder instanceof ScoutBuilder) { $property = $this->getFieldResolver()->getField($builder->model, $property); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php index b9a0b6cb6..c82a02486 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php @@ -39,6 +39,7 @@ final class EqualTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -46,18 +47,28 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } /** * @dataProvider dataProviderCallScout * - * @param array $expected - * @param Closure(static): ScoutBuilder $builderFactory - * @param Closure(static): Argument $argumentFactory - * @param Closure():FieldResolver|null $resolver - * @param Closure(static): Context|null $contextFactory + * @param array $expected + * @param Closure(static): ScoutBuilder $builderFactory + * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver + * @param Closure():FieldResolver|null $fieldResolver */ public function testCallScout( array $expected, @@ -65,13 +76,22 @@ public function testCallScout( Property $property, Closure $argumentFactory, ?Closure $contextFactory, - Closure $resolver = null, + ?Closure $resolver, + ?Closure $fieldResolver, ): void { - if ($resolver) { - $this->override(FieldResolver::class, $resolver); + if ($fieldResolver) { + $this->override(FieldResolver::class, $fieldResolver); } - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -94,6 +114,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property.path' => [ [ @@ -105,6 +126,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" = ?', + 'bindings' => [123], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 123); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); @@ -129,6 +165,7 @@ static function (self $test): Argument { }, null, null, + null, ], 'property with resolver' => [ [ @@ -141,11 +178,9 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, static function (): FieldResolver { return new class() implements FieldResolver { - /** - * @inheritDoc - */ #[Override] public function getField(Model $model, Property $property): string { return 'properties/'.implode('/', $property->getPath()); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThan.php b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThan.php index de0f785ee..f8d87e29b 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThan.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThan.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder->where($property, '>', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqual.php b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqual.php index c9e1a0aa4..b56bbe2bf 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqual.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqual.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder->where($property, '>=', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqualTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqualTest.php index 9813d29d3..6a9e8e0aa 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqualTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanOrEqualTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class GreaterThanOrEqualTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 321); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" >= ?', + 'bindings' => [321], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 321); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanTest.php index 7cdae1363..cf3c63480 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/GreaterThanTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class GreaterThanTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 321); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" > ?', + 'bindings' => [321], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 321); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/In.php b/packages/graphql/src/SearchBy/Operators/Comparison/In.php index 38976533a..7ffcd565d 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/In.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/In.php @@ -46,7 +46,7 @@ public function call( $value = (array) $argument->toPlain(); if ($builder instanceof EloquentBuilder || $builder instanceof QueryBuilder) { - $builder->whereIn((string) $property, $value); + $builder->whereIn($this->resolver->getProperty($builder, $property), $value); } elseif ($builder instanceof ScoutBuilder) { $property = $this->getFieldResolver()->getField($builder->model, $property); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php index 4f4e4309b..afa301a7a 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php @@ -39,6 +39,7 @@ final class InTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -46,18 +47,28 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } /** * @dataProvider dataProviderCallScout * - * @param array $expected - * @param Closure(static): ScoutBuilder $builderFactory - * @param Closure(static): Argument $argumentFactory - * @param Closure(static): Context|null $contextFactory - * @param Closure():FieldResolver|null $resolver + * @param array $expected + * @param Closure(static): ScoutBuilder $builderFactory + * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver + * @param Closure():FieldResolver|null $fieldResolver */ public function testCallScout( array $expected, @@ -65,13 +76,22 @@ public function testCallScout( Property $property, Closure $argumentFactory, ?Closure $contextFactory, - Closure $resolver = null, + ?Closure $resolver, + Closure $fieldResolver = null, ): void { - if ($resolver) { - $this->override(FieldResolver::class, $resolver); + if ($fieldResolver) { + $this->override(FieldResolver::class, $fieldResolver); } - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -94,6 +114,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, ], 'property.path' => [ [ @@ -105,6 +126,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[String!]!', ['a', 'b', 'c']); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" in (?, ?, ?)', + 'bindings' => ['a', 'b', 'c'], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('[String!]!', ['a', 'b', 'c']); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); @@ -129,6 +165,7 @@ static function (self $test): Argument { }, null, null, + null, ], 'property with resolver' => [ [ @@ -141,6 +178,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, static function (): FieldResolver { return new class() implements FieldResolver { /** diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNull.php b/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNull.php index c74bb417e..287ed531e 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNull.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNull.php @@ -46,7 +46,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $builder->whereNotNull($property); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNullTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNullTest.php index 8d8b4ef89..a4a2ad6fe 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNullTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/IsNotNullTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class IsNotNullTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Boolean', null); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Boolean', null); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" is not null', + 'bindings' => [], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Boolean', null); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/IsNull.php b/packages/graphql/src/SearchBy/Operators/Comparison/IsNull.php index ebc95d475..4a8d8205a 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/IsNull.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/IsNull.php @@ -46,7 +46,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $builder->whereNull($property); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/IsNullTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/IsNullTest.php index eeaa6ac5a..b3bd0d2c9 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/IsNullTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/IsNullTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class IsNullTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Boolean', null); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Boolean', null); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" is null', + 'bindings' => [], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Boolean', null); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/LessThan.php b/packages/graphql/src/SearchBy/Operators/Comparison/LessThan.php index a85a8e42a..329ae7a4e 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/LessThan.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/LessThan.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder->where($property, '<', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqual.php b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqual.php index 4b0da4e8b..ed32b1556 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqual.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqual.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder->where($property, '<=', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqualTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqualTest.php index 41e87e690..d1508ed6c 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqualTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanOrEqualTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class LessThanOrEqualTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 321); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" <= ?', + 'bindings' => [321], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 321); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanTest.php index a564573e3..8db0dfeda 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/LessThanTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/LessThanTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class LessThanTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 321); }, null, + null, + ], + 'resolve' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" < ?', + 'bindings' => [321], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 321); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/Like.php b/packages/graphql/src/SearchBy/Operators/Comparison/Like.php index 0d9fe4fab..a9b22dae5 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/Like.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/Like.php @@ -36,7 +36,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = (string) Cast::toStringable($argument->toPlain()); $builder->where($property, 'like', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/LikeTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/LikeTest.php index f0b2d70b2..b8796ea7e 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/LikeTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/LikeTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class LikeTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" like ?', + 'bindings' => ['abc'], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', 'abc'); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotBetween.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotBetween.php index d5a2feb45..7b444ce29 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotBetween.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotBetween.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = Cast::toIterable($argument->toPlain()); $builder->whereNotBetween($property, $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotBetweenTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotBetweenTest.php index 9c8720a2a..4121f1375 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotBetweenTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotBetweenTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class NotBetweenTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" not between ? and ?', + 'bindings' => [1, 2], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotContainsTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotContainsTest.php index ea934a3bb..2c1367d1c 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotContainsTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotContainsTest.php @@ -20,6 +20,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -39,6 +41,7 @@ final class NotContainsTest extends TestCase { * @param class-string $grammar * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -47,6 +50,7 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { $self = $this; $builderFactory = static function () use ($self, $builderFactory, $grammar): mixed { @@ -62,7 +66,15 @@ public function testCall( return $builder; }; - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -86,6 +98,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], SQLiteGrammar::class => [ [ @@ -98,6 +111,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], PostgresGrammar::class => [ [ @@ -110,6 +124,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], SqlServerGrammar::class => [ [ @@ -122,6 +137,38 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, + ], + 'property.path' => [ + [ + 'query' => <<<'SQL' + select * from "test_objects" where "path"."to"."property" NOT LIKE ? ESCAPE '!' + SQL + , + 'bindings' => ['%!%a[!_]c!!!%%'], + ], + SQLiteGrammar::class, + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', '%a[_]c!%'); + }, + null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" NOT LIKE ? ESCAPE \'!\'', + 'bindings' => ['%!%a[!_]c!!!%%'], + ], + SQLiteGrammar::class, + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', '%a[_]c!%'); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotEndsWithTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotEndsWithTest.php index 71653c8f2..734459f3c 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotEndsWithTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotEndsWithTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class NotEndsWithTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], 'property.path' => [ [ @@ -77,6 +90,24 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => <<<'SQL' + select * from "test_objects" where "path__to__property" NOT LIKE ? ESCAPE '!' + SQL + , + 'bindings' => ['%abc'], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', 'abc'); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotEqual.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotEqual.php index e29707c10..d6d7c432f 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotEqual.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotEqual.php @@ -35,7 +35,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); $builder->where($property, '!=', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotEqualTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotEqualTest.php index 461b18375..dd6f7b239 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotEqualTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotEqualTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class NotEqualTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('Int!', 123); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" != ?', + 'bindings' => [123], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('Int!', 123); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php index 6ea64c2f4..a8545125d 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php @@ -50,7 +50,7 @@ public function call( $value = (array) $argument->toPlain(); if ($builder instanceof EloquentBuilder || $builder instanceof QueryBuilder) { - $builder->whereNotIn((string) $property, $value); + $builder->whereNotIn($this->resolver->getProperty($builder, $property), $value); } elseif ($builder instanceof ScoutBuilder) { $property = $this->getFieldResolver()->getField($builder->model, $property); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php index 5c6538f81..13b21f6a3 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php @@ -42,6 +42,7 @@ final class NotInTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -49,18 +50,28 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } /** * @dataProvider dataProviderCallScout * - * @param array $expected - * @param Closure(static): ScoutBuilder $builderFactory - * @param Closure(static): Argument $argumentFactory - * @param Closure(static): Context|null $contextFactory - * @param Closure():FieldResolver|null $resolver + * @param array $expected + * @param Closure(static): ScoutBuilder $builderFactory + * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver + * @param Closure():FieldResolver|null $fieldResolver */ public function testCallScout( array $expected, @@ -68,11 +79,12 @@ public function testCallScout( Property $property, Closure $argumentFactory, ?Closure $contextFactory, - Closure $resolver = null, + ?Closure $resolver, + ?Closure $fieldResolver, ): void { // Prepare - if ($resolver) { - $this->override(FieldResolver::class, $resolver); + if ($fieldResolver) { + $this->override(FieldResolver::class, $fieldResolver); } // Supported? @@ -89,7 +101,15 @@ public function testCallScout( } // Test - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -112,6 +132,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, ], 'property.path' => [ [ @@ -123,6 +144,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[String!]!', ['a', 'b', 'c']); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" not in (?, ?, ?)', + 'bindings' => ['a', 'b', 'c'], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('[String!]!', ['a', 'b', 'c']); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); @@ -147,6 +183,7 @@ static function (self $test): Argument { }, null, null, + null, ], 'property with resolver' => [ [ @@ -159,6 +196,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); }, null, + null, static function (): FieldResolver { return new class() implements FieldResolver { /** diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotLike.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotLike.php index 5af279c48..96924b362 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotLike.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotLike.php @@ -36,7 +36,7 @@ public function call( throw new OperatorUnsupportedBuilder($this, $builder); } - $property = (string) $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = (string) Cast::toStringable($argument->toPlain()); $builder->where($property, 'not like', $value); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotLikeTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotLikeTest.php index 9275a7a9c..e436495f3 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotLikeTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotLikeTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class NotLikeTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" not like ?', + 'bindings' => ['abc'], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', 'abc'); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotStartsWithTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotStartsWithTest.php index 21f1b68cc..1fc8ebbe4 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotStartsWithTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotStartsWithTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class NotStartsWithTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], 'property.path' => [ [ @@ -77,6 +90,24 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => <<<'SQL' + select * from "test_objects" where "path__to__property" NOT LIKE ? ESCAPE '!' + SQL + , + 'bindings' => ['abc%'], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', 'abc'); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/StartsWithTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/StartsWithTest.php index 98ec0b6ce..8a90fd232 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/StartsWithTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/StartsWithTest.php @@ -14,6 +14,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -32,6 +34,7 @@ final class StartsWithTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +42,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +75,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', '%a[_]c!%'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +87,21 @@ static function (self $test): Argument { return $test->getGraphQLArgument('String!', 'abc'); }, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where "path__to__property" LIKE ? ESCAPE \'!\'', + 'bindings' => ['abc%'], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', 'abc'); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); diff --git a/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php b/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php index 163c725a2..3d20d4bfb 100644 --- a/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php +++ b/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php @@ -35,6 +35,7 @@ final class RelationTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array|Exception $expected, @@ -42,8 +43,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -105,6 +115,7 @@ static function (self $test) use ($graphql): Argument { ); }, null, + null, ], '{exists: true}' => [ [ @@ -128,6 +139,7 @@ static function (self $test) use ($graphql): Argument { ); }, null, + null, ], '{notExists: true}' => [ [ @@ -151,6 +163,7 @@ static function (self $test) use ($graphql): Argument { ); }, null, + null, ], '{relation: {property: {equal: 1}}}' => [ [ @@ -183,6 +196,7 @@ static function (self $test) use ($graphql): Argument { ); }, null, + null, ], '{count: {equal: 1}}' => [ [ @@ -213,6 +227,7 @@ static function (self $test) use ($graphql): Argument { ); }, null, + null, ], '{count: { multiple operators }}' => [ new ConditionTooManyOperators(['lessThan', 'equal']), @@ -233,6 +248,7 @@ static function (self $test) use ($graphql): Argument { ); }, null, + null, ], '{where: {{property: {equal: 1}}}} (own)' => [ [ @@ -265,6 +281,7 @@ static function (self $test) use ($graphql): Argument { ); }, null, + null, ], '{relation: {relation: {property: {equal: 1}}}}' => [ [ @@ -319,6 +336,7 @@ static function (self $test) use ($graphql): Argument { ); }, null, + null, ], ]; } diff --git a/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php b/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php index 83a00ea99..cf78b328f 100644 --- a/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php +++ b/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php @@ -42,6 +42,7 @@ final class AllOfTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -49,18 +50,28 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } /** * @dataProvider dataProviderCallScout * - * @param array $expected - * @param Closure(static): ScoutBuilder $builderFactory - * @param Closure(static): Argument $argumentFactory - * @param Closure(static): Context|null $contextFactory - * @param Closure():FieldResolver|null $resolver + * @param array $expected + * @param Closure(static): ScoutBuilder $builderFactory + * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver + * @param Closure():FieldResolver|null $fieldResolver */ public function testCallScout( array $expected, @@ -68,13 +79,22 @@ public function testCallScout( Property $property, Closure $argumentFactory, ?Closure $contextFactory, - Closure $resolver = null, + ?Closure $resolver, + ?Closure $fieldResolver, ): void { - if ($resolver) { - $this->override(FieldResolver::class, $resolver); + if ($fieldResolver) { + $this->override(FieldResolver::class, $fieldResolver); } - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -130,6 +150,7 @@ public static function dataProviderCall(): array { new Property('operator name should be ignored'), $factory, null, + null, ], 'with alias' => [ [ @@ -145,6 +166,25 @@ public static function dataProviderCall(): array { new Property('alias', 'operator name should be ignored'), $factory, null, + null, + ], + 'resolver' => [ + [ + 'query' => <<<'SQL' + select * from "test_objects" where (("alias__a" = ?) and ("alias__b" != ?)) + SQL + , + 'bindings' => [ + 2, + 22, + ], + ], + new Property('alias', 'operator name should be ignored'), + $factory, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ), @@ -167,6 +207,7 @@ public static function dataProviderCall(): array { new Property('operator name should be ignored'), $factory, null, + null, ], 'with alias' => [ [ @@ -182,6 +223,25 @@ public static function dataProviderCall(): array { new Property('alias', 'operator name should be ignored'), $factory, null, + null, + ], + 'resolver' => [ + [ + 'query' => <<<'SQL' + select * from "test_objects" where (("alias__a" = ?) and ("alias__b" != ?)) + SQL + , + 'bindings' => [ + 2, + 22, + ], + ], + new Property('alias', 'operator name should be ignored'), + $factory, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ), @@ -241,6 +301,7 @@ public static function dataProviderCallScout(): array { $factory, null, null, + null, ], 'property with resolver' => [ [ @@ -255,6 +316,7 @@ public static function dataProviderCallScout(): array { new Property('path', 'to', 'property', 'operator name should be ignored'), $factory, null, + null, static function (): FieldResolver { return new class() implements FieldResolver { /** diff --git a/packages/graphql/src/SearchBy/Operators/Logical/AnyOfTest.php b/packages/graphql/src/SearchBy/Operators/Logical/AnyOfTest.php index 1ea6f9151..9278d7198 100644 --- a/packages/graphql/src/SearchBy/Operators/Logical/AnyOfTest.php +++ b/packages/graphql/src/SearchBy/Operators/Logical/AnyOfTest.php @@ -17,6 +17,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -35,6 +37,7 @@ final class AnyOfTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -42,8 +45,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -99,6 +111,7 @@ public static function dataProviderCall(): array { new Property('operator name should be ignored'), $factory, null, + null, ], 'with alias' => [ [ @@ -114,6 +127,25 @@ public static function dataProviderCall(): array { new Property('alias', 'operator name should be ignored'), $factory, null, + null, + ], + 'resolver' => [ + [ + 'query' => <<<'SQL' + select * from "test_objects" where (("alias__a" = ?) or ("alias__b" != ?)) + SQL + , + 'bindings' => [ + 2, + 22, + ], + ], + new Property('alias', 'operator name should be ignored'), + $factory, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ), @@ -136,6 +168,7 @@ public static function dataProviderCall(): array { new Property('operator name should be ignored'), $factory, null, + null, ], 'with alias' => [ [ @@ -151,6 +184,25 @@ public static function dataProviderCall(): array { new Property('alias', 'operator name should be ignored'), $factory, null, + null, + ], + 'resolver' => [ + [ + 'query' => <<<'SQL' + select * from "test_objects" where (("alias__a" = ?) or ("alias__b" != ?)) + SQL + , + 'bindings' => [ + 2, + 22, + ], + ], + new Property('alias', 'operator name should be ignored'), + $factory, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ), diff --git a/packages/graphql/src/SearchBy/Operators/Logical/NotTest.php b/packages/graphql/src/SearchBy/Operators/Logical/NotTest.php index 56aeabc0c..1be1b109b 100644 --- a/packages/graphql/src/SearchBy/Operators/Logical/NotTest.php +++ b/packages/graphql/src/SearchBy/Operators/Logical/NotTest.php @@ -17,6 +17,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -35,6 +37,7 @@ final class NotTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -42,8 +45,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -99,6 +111,7 @@ public static function dataProviderCall(): array { new Property('operator name should be ignored'), $factory, null, + null, ], 'with alias' => [ [ @@ -110,6 +123,21 @@ public static function dataProviderCall(): array { new Property('alias', 'operator name should be ignored'), $factory, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where (not ("alias__a" = ?))', + 'bindings' => [ + 2, + ], + ], + new Property('alias', 'operator name should be ignored'), + $factory, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ), @@ -126,6 +154,7 @@ public static function dataProviderCall(): array { new Property('operator name should be ignored'), $factory, null, + null, ], 'with alias' => [ [ @@ -137,6 +166,21 @@ public static function dataProviderCall(): array { new Property('alias', 'operator name should be ignored'), $factory, null, + null, + ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" where (not ("alias__a" = ?))', + 'bindings' => [ + 2, + ], + ], + new Property('alias', 'operator name should be ignored'), + $factory, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ), diff --git a/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php b/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php index 0f76abb8c..011f8383f 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php +++ b/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php @@ -33,6 +33,7 @@ final class NullsFirstTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -40,8 +41,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -83,6 +93,7 @@ static function (self $test): Argument { ); }, null, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php b/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php index 58b8dcc50..44fa16f92 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php +++ b/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php @@ -33,6 +33,7 @@ final class NullsLastTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -40,8 +41,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -83,6 +93,7 @@ static function (self $test): Argument { ); }, null, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SortBy/Operators/Extra/RandomTest.php b/packages/graphql/src/SortBy/Operators/Extra/RandomTest.php index 3efd0771f..38a4a69dc 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/RandomTest.php +++ b/packages/graphql/src/SortBy/Operators/Extra/RandomTest.php @@ -32,6 +32,7 @@ final class RandomTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -39,8 +40,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } // @@ -63,6 +73,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('SortByTypeFlag', 'yes'); }, null, + null, ], 'property.path' => [ [ @@ -74,6 +85,7 @@ static function (self $test): Argument { return $test->getGraphQLArgument('SortByTypeFlag', 'yes'); }, null, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/SortBy/Operators/FieldTest.php b/packages/graphql/src/SortBy/Operators/FieldTest.php index b0eb984ce..398a23b12 100644 --- a/packages/graphql/src/SortBy/Operators/FieldTest.php +++ b/packages/graphql/src/SortBy/Operators/FieldTest.php @@ -49,6 +49,7 @@ final class FieldTest extends TestCase { * @param BuilderFactory $builderFactory * @param Closure(static): Argument $argumentFactory * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ public function testCall( array $expected, @@ -56,8 +57,17 @@ public function testCall( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { - $this->testOperator(Directive::class, $expected, $builderFactory, $property, $argumentFactory, $contextFactory); + $this->testOperator( + Directive::class, + $expected, + $builderFactory, + $property, + $argumentFactory, + $contextFactory, + $resolver, + ); } public function testCallEloquentBuilder(): void { @@ -209,6 +219,7 @@ static function (): Context { return new Context(); }, null, + null, ], 'nulls from Context' => [ [ @@ -223,6 +234,7 @@ static function (): Context { ]); }, null, + null, ], ]), ))->getData(); diff --git a/packages/graphql/src/Testing/Package/OperatorTests.php b/packages/graphql/src/Testing/Package/OperatorTests.php index 8c5cc93a1..ac4e44a77 100644 --- a/packages/graphql/src/Testing/Package/OperatorTests.php +++ b/packages/graphql/src/Testing/Package/OperatorTests.php @@ -9,11 +9,13 @@ use Illuminate\Database\Query\Builder as QueryBuilder; use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\BuilderDataProvider; use LogicException; +use Mockery\MockInterface; use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; use ReflectionAttribute; @@ -37,11 +39,12 @@ trait OperatorTests { * PHPStorm or PHPUnit issue). Anyway, this approach requires less * copy-pasting. * - * @param class-string $directive - * @param array|Exception $expected - * @param Closure(static): object $builderFactory - * @param Closure(static): Argument $argumentFactory - * @param Closure(static): Context|null $contextFactory + * @param class-string $directive + * @param array|Exception $expected + * @param Closure(static): object $builderFactory + * @param Closure(static): Argument $argumentFactory + * @param Closure(static): Context|null $contextFactory + * @param Closure(object, Property): string|null $resolver */ private function testOperator( string $directive, @@ -50,11 +53,25 @@ private function testOperator( Property $property, Closure $argumentFactory, ?Closure $contextFactory, + ?Closure $resolver, ): void { if ($expected instanceof Exception) { self::expectExceptionObject($expected); } + if ($resolver) { + $this->override( + BuilderPropertyResolver::class, + static function (MockInterface $mock) use ($resolver): void { + $mock + ->shouldReceive('getProperty') + ->atLeast() + ->once() + ->andReturnUsing($resolver); + }, + ); + } + $operator = Container::getInstance()->make($this->getOperator()); $argument = $argumentFactory($this); $context = $contextFactory ? $contextFactory($this) : new Context(); From 774ae7b60ce837b6eb67a85f8833a2c2f5a6f77a Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 13 Jan 2024 10:08:25 +0400 Subject: [PATCH 6/8] `BuilderPropertyResolver` support for `Sorters` (`@sortBy`). --- .../SortBy/Operators/Extra/NullsFirstTest.php | 62 ++++--- .../SortBy/Operators/Extra/NullsLastTest.php | 62 ++++--- .../src/SortBy/Operators/FieldTest.php | 15 ++ .../src/SortBy/Sorters/DatabaseSorter.php | 5 +- .../src/SortBy/Sorters/DatabaseSorterTest.php | 17 +- .../src/SortBy/Sorters/EloquentSorter.php | 10 +- .../src/SortBy/Sorters/EloquentSorterTest.php | 159 +++++++++++++++++- .../src/SortBy/Sorters/QuerySorter.php | 5 +- .../src/SortBy/Sorters/QuerySorterTest.php | 38 ++++- 9 files changed, 306 insertions(+), 67 deletions(-) diff --git a/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php b/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php index 011f8383f..38ed470ca 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php +++ b/packages/graphql/src/SortBy/Operators/Extra/NullsFirstTest.php @@ -15,6 +15,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -61,6 +63,29 @@ public function testCall( * @return array */ public static function dataProviderCall(): array { + $argument = static function (self $test): Argument { + $test->useGraphQLSchema( + <<<'GRAPHQL' + type Query { + test(input: Test @sortBy): String! @all + } + + input Test { + a: String + } + GRAPHQL, + ); + + return $test->getGraphQLArgument( + 'SortByClauseTest!', + [ + 'nullsFirst' => [ + 'a' => Direction::Desc, + ], + ], + ); + }; + return (new CompositeDataProvider( new BuilderDataProvider(), new ArrayDataProvider([ @@ -69,32 +94,23 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" order by "a" DESC NULLS FIRST', 'bindings' => [], ], - new Property(), - static function (self $test): Argument { - $test->useGraphQLSchema( - <<<'GRAPHQL' - type Query { - test(input: Test @sortBy): String! @all - } - - input Test { - a: String - } - GRAPHQL, - ); - - return $test->getGraphQLArgument( - 'SortByClauseTest!', - [ - 'nullsFirst' => [ - 'a' => Direction::Desc, - ], - ], - ); - }, + new Property('operator name should be ignored'), + $argument, null, null, ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" order by "resolved__a" DESC NULLS FIRST', + 'bindings' => [], + ], + new Property('operator name should be ignored'), + $argument, + null, + static function (object $builder, Property $property): string { + return 'resolved__'.implode('__', $property->getPath()); + }, + ], ]), ))->getData(); } diff --git a/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php b/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php index 44fa16f92..3a818053d 100644 --- a/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php +++ b/packages/graphql/src/SortBy/Operators/Extra/NullsLastTest.php @@ -15,6 +15,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -61,6 +63,29 @@ public function testCall( * @return array */ public static function dataProviderCall(): array { + $argument = static function (self $test): Argument { + $test->useGraphQLSchema( + <<<'GRAPHQL' + type Query { + test(input: Test @sortBy): String! @all + } + + input Test { + a: String + } + GRAPHQL, + ); + + return $test->getGraphQLArgument( + 'SortByClauseTest!', + [ + 'nullsLast' => [ + 'a' => Direction::Asc, + ], + ], + ); + }; + return (new CompositeDataProvider( new BuilderDataProvider(), new ArrayDataProvider([ @@ -69,32 +94,23 @@ public static function dataProviderCall(): array { 'query' => 'select * from "test_objects" order by "a" ASC NULLS LAST', 'bindings' => [], ], - new Property(), - static function (self $test): Argument { - $test->useGraphQLSchema( - <<<'GRAPHQL' - type Query { - test(input: Test @sortBy): String! @all - } - - input Test { - a: String - } - GRAPHQL, - ); - - return $test->getGraphQLArgument( - 'SortByClauseTest!', - [ - 'nullsLast' => [ - 'a' => Direction::Asc, - ], - ], - ); - }, + new Property('operator name should be ignored'), + $argument, null, null, ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" order by "resolved__a" ASC NULLS LAST', + 'bindings' => [], + ], + new Property('operator name should be ignored'), + $argument, + null, + static function (object $builder, Property $property): string { + return 'resolved__'.implode('__', $property->getPath()); + }, + ], ]), ))->getData(); } diff --git a/packages/graphql/src/SortBy/Operators/FieldTest.php b/packages/graphql/src/SortBy/Operators/FieldTest.php index 398a23b12..251ea6272 100644 --- a/packages/graphql/src/SortBy/Operators/FieldTest.php +++ b/packages/graphql/src/SortBy/Operators/FieldTest.php @@ -30,6 +30,7 @@ use PHPUnit\Framework\Attributes\CoversClass; use function config; +use function implode; /** * @internal @@ -236,6 +237,20 @@ static function (): Context { null, null, ], + 'resolver' => [ + [ + 'query' => 'select * from "test_objects" order by "resolved__a" desc', + 'bindings' => [], + ], + new Property('a'), + $factory, + static function (): Context { + return new Context(); + }, + static function (object $builder, Property $property): string { + return 'resolved__'.implode('__', $property->getPath()); + }, + ], ]), ))->getData(); } diff --git a/packages/graphql/src/SortBy/Sorters/DatabaseSorter.php b/packages/graphql/src/SortBy/Sorters/DatabaseSorter.php index 5b7de4807..77013217e 100644 --- a/packages/graphql/src/SortBy/Sorters/DatabaseSorter.php +++ b/packages/graphql/src/SortBy/Sorters/DatabaseSorter.php @@ -10,6 +10,7 @@ use Illuminate\Database\Query\Grammars\SQLiteGrammar; use Illuminate\Database\Query\Grammars\SqlServerGrammar; use Illuminate\Support\Str; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Exceptions\NotImplemented; use LastDragon_ru\LaraASP\GraphQL\Package; use LastDragon_ru\LaraASP\GraphQL\SortBy\Contracts\Sorter; @@ -28,7 +29,9 @@ * @implements Sorter */ abstract class DatabaseSorter implements Sorter { - public function __construct() { + public function __construct( + protected readonly BuilderPropertyResolver $resolver, + ) { // empty } diff --git a/packages/graphql/src/SortBy/Sorters/DatabaseSorterTest.php b/packages/graphql/src/SortBy/Sorters/DatabaseSorterTest.php index f0c64ae23..c0f685ea1 100644 --- a/packages/graphql/src/SortBy/Sorters/DatabaseSorterTest.php +++ b/packages/graphql/src/SortBy/Sorters/DatabaseSorterTest.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Model as EloquentModel; use Illuminate\Database\Query\Builder as QueryBuilder; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\SortBy\Enums\Direction; use LastDragon_ru\LaraASP\GraphQL\SortBy\Enums\Nulls; @@ -16,6 +17,7 @@ use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\UnknownValue; +use Mockery; use Override; use PHPUnit\Framework\Attributes\CoversClass; @@ -44,14 +46,16 @@ public function testSortByColumn( Direction $direction, ?Nulls $nulls, ): void { - $builder = $builderFactory($this); - $column = is_string($columnFactory) ? $columnFactory : $columnFactory($this); - $sorter = new class($nullsDefault, $nullsOrderable) extends DatabaseSorter { + $resolver = Mockery::mock(BuilderPropertyResolver::class); + $builder = $builderFactory($this); + $column = is_string($columnFactory) ? $columnFactory : $columnFactory($this); + $sorter = new class($nullsDefault, $nullsOrderable, $resolver) extends DatabaseSorter { public function __construct( private readonly Nulls $nullsDefault, private readonly bool $nullsOrderable, + BuilderPropertyResolver $resolver, ) { - parent::__construct(); + parent::__construct($resolver); } #[Override] @@ -89,8 +93,9 @@ public function sortByColumn( } public function testGetAlias(): void { - $builder = User::query()->where('name', '=', 'name'); - $sorter = new class() extends DatabaseSorter { + $resolver = Mockery::mock(BuilderPropertyResolver::class); + $builder = User::query()->where('name', '=', 'name'); + $sorter = new class($resolver) extends DatabaseSorter { #[Override] public function sort( object $builder, diff --git a/packages/graphql/src/SortBy/Sorters/EloquentSorter.php b/packages/graphql/src/SortBy/Sorters/EloquentSorter.php index d086dc60a..b7072af61 100644 --- a/packages/graphql/src/SortBy/Sorters/EloquentSorter.php +++ b/packages/graphql/src/SortBy/Sorters/EloquentSorter.php @@ -25,7 +25,6 @@ use Override; use function array_shift; -use function array_slice; use function implode; use function is_a; @@ -53,12 +52,13 @@ class EloquentSorter extends DatabaseSorter { #[Override] public function sort(object $builder, Property $property, Direction $direction, Nulls $nulls = null): object { // Column - $path = $property->getPath(); - $column = $property->getName(); - $relation = array_slice($path, 0, -1); + $relation = $property->getParent()->getPath(); if ($relation) { + $column = $property->getName(); $column = $this->getRelationColumn($builder, $relation, $column, $direction); + } else { + $column = $this->resolver->getProperty($builder, $property); } // Order @@ -104,7 +104,7 @@ protected function getRelationColumn( } // We need only one row - $qualified = "{$alias}.{$column}"; + $qualified = $this->resolver->getProperty($relation->getQuery(), new Property($alias, $column)); $query = $query->select($qualified)->reorder()->limit(1); $query = $this->sortByColumn($query, $qualified, $direction); diff --git a/packages/graphql/src/SortBy/Sorters/EloquentSorterTest.php b/packages/graphql/src/SortBy/Sorters/EloquentSorterTest.php index 981608ed3..2fcc616b7 100644 --- a/packages/graphql/src/SortBy/Sorters/EloquentSorterTest.php +++ b/packages/graphql/src/SortBy/Sorters/EloquentSorterTest.php @@ -17,20 +17,25 @@ use Illuminate\Database\Eloquent\Relations\MorphOne; use Illuminate\Database\Eloquent\Relations\MorphToMany; use LastDragon_ru\LaraASP\Eloquent\Exceptions\PropertyIsNotRelation; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\SortBy\Enums\Direction; +use LastDragon_ru\LaraASP\GraphQL\SortBy\Enums\Nulls; use LastDragon_ru\LaraASP\GraphQL\SortBy\Exceptions\RelationUnsupported; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\EloquentBuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\Models\Car; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\Models\CarEngine; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\Models\Relations\Unsupported; +use LastDragon_ru\LaraASP\GraphQL\Testing\Package\Models\Role; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\Models\User; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\MergeDataProvider; +use Mockery\MockInterface; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; use function is_array; /** @@ -45,20 +50,35 @@ class EloquentSorterTest extends TestCase { * * @param array{query: string, bindings: array}|Exception $expected * @param Closure(static): EloquentBuilder $builder + * @param Closure(object, Property): string|null $resolver */ public function testSort( array|Exception $expected, Closure $builder, Property $property, Direction $direction, + ?Nulls $nulls, + ?Closure $resolver, ): void { if ($expected instanceof Exception) { self::expectExceptionObject($expected); } + if ($resolver) { + $this->override( + BuilderPropertyResolver::class, + static function (MockInterface $mock) use ($resolver): void { + $mock + ->shouldReceive('getProperty') + ->once() + ->andReturnUsing($resolver); + }, + ); + } + $sorter = Container::getInstance()->make(EloquentSorter::class); $builder = $builder($this); - $builder = $sorter->sort($builder, $property, $direction, null); + $builder = $sorter->sort($builder, $property, $direction, $nulls); if (is_array($expected)) { self::assertDatabaseQueryEquals($expected, $builder); @@ -85,6 +105,8 @@ public static function dataProviderSort(): array { ], new Property('name'), Direction::Desc, + null, + null, ], ]), )), @@ -96,6 +118,8 @@ static function (): EloquentBuilder { }, new Property('unknown', 'name'), Direction::Asc, + null, + null, ], 'unsupported' => [ new RelationUnsupported( @@ -118,6 +142,8 @@ static function (): EloquentBuilder { }, new Property('unsupported', 'id'), Direction::Asc, + null, + null, ], BelongsTo::class => [ [ @@ -159,6 +185,8 @@ static function (): EloquentBuilder { }, new Property('user', 'organization', 'name'), Direction::Desc, + null, + null, ], HasOne::class => [ [ @@ -203,6 +231,8 @@ static function (): EloquentBuilder { }, new Property('car', 'engine', 'id'), Direction::Asc, + null, + null, ], HasMany::class => [ [ @@ -236,6 +266,8 @@ static function (): EloquentBuilder { }, new Property('cars', 'name'), Direction::Asc, + null, + null, ], MorphOne::class => [ [ @@ -270,6 +302,8 @@ static function (): EloquentBuilder { }, new Property('avatar', 'id'), Direction::Asc, + null, + null, ], HasOneThrough::class => [ [ @@ -315,6 +349,8 @@ static function (): EloquentBuilder { }, new Property('role', 'user', 'name'), Direction::Desc, + null, + null, ], BelongsToMany::class => [ [ @@ -361,6 +397,8 @@ static function (): EloquentBuilder { }, new Property('roles', 'users', 'name'), Direction::Desc, + null, + null, ], MorphToMany::class => [ [ @@ -405,6 +443,8 @@ static function (): EloquentBuilder { }, new Property('tags', 'users', 'name'), Direction::Asc, + null, + null, ], HasManyThrough::class => [ [ @@ -439,6 +479,8 @@ static function (): EloquentBuilder { }, new Property('users', 'name'), Direction::Asc, + null, + null, ], MorphMany::class => [ [ @@ -473,6 +515,121 @@ static function (): EloquentBuilder { }, new Property('images', 'id'), Direction::Asc, + null, + null, + ], + 'nulls' => [ + [ + 'query' => <<<'SQL' + select + * + from + "users" + order by + "name" DESC NULLS FIRST + SQL + , + 'bindings' => [ + // empty + ], + ], + static function (): EloquentBuilder { + return User::query(); + }, + new Property('name'), + Direction::Desc, + Nulls::First, + null, + ], + 'resolver' => [ + [ + 'query' => <<<'SQL' + select + * + from + "users" + order by + "resolved__name" asc + SQL + , + 'bindings' => [ + // empty + ], + ], + static function (): EloquentBuilder { + return User::query(); + }, + new Property('name'), + Direction::Asc, + null, + static function (object $builder, Property $property): string { + self::assertInstanceOf(EloquentBuilder::class, $builder); + self::assertInstanceOf(User::class, $builder->getModel()); + + return 'resolved__'.implode('__', $property->getPath()); + }, + ], + 'resolver (relation)' => [ + [ + 'query' => <<<'SQL' + select + * + from + "users" + order by + ( + select + "lara_asp_graphql__sort_by__0__relation_1"."resolved__name" + from + "cars" + inner join ( + select + * + from + "users" + where + "deleted_at" is null + ) as "lara_asp_graphql__sort_by__0__relation_0" + on "lara_asp_graphql__sort_by__0__relation_0"."ownerKey" + = "cars"."foreignKey" + inner join ( + select + * + from + "roles" + inner join "user_roles" + on "roles"."relatedKey" = "user_roles"."relatedPivotKey" + where + "deleted_at" is null + ) as "lara_asp_graphql__sort_by__0__relation_1" + on "lara_asp_graphql__sort_by__0__relation_1"."parentKey" + = "lara_asp_graphql__sort_by__0__relation_0"."relatedKey" + where + "users"."localKey" = "cars"."foreignKey" + and "deleted_at" is null + order by + "lara_asp_graphql__sort_by__0__relation_1"."resolved__name" asc + limit + 1 + ) asc + SQL + , + 'bindings' => [ + // empty + ], + ], + static function (): EloquentBuilder { + return User::query(); + }, + new Property('cars', 'user', 'roles', 'name'), + Direction::Asc, + null, + static function (object $builder, Property $property): string { + self::assertInstanceOf(EloquentBuilder::class, $builder); + self::assertInstanceOf(Role::class, $builder->getModel()); + + return implode('.', $property->getParent()->getPath()).'.resolved__'.$property->getName(); + }, ], ])), ]))->getData(); diff --git a/packages/graphql/src/SortBy/Sorters/QuerySorter.php b/packages/graphql/src/SortBy/Sorters/QuerySorter.php index c06b538ba..2027c088b 100644 --- a/packages/graphql/src/SortBy/Sorters/QuerySorter.php +++ b/packages/graphql/src/SortBy/Sorters/QuerySorter.php @@ -8,16 +8,13 @@ use LastDragon_ru\LaraASP\GraphQL\SortBy\Enums\Nulls; use Override; -use function implode; - /** * @extends DatabaseSorter */ class QuerySorter extends DatabaseSorter { #[Override] public function sort(object $builder, Property $property, Direction $direction, Nulls $nulls = null): object { - $path = $property->getPath(); - $column = implode('.', $path); + $column = $this->resolver->getProperty($builder, $property); $builder = $this->sortByColumn($builder, $column, $direction, $nulls); return $builder; diff --git a/packages/graphql/src/SortBy/Sorters/QuerySorterTest.php b/packages/graphql/src/SortBy/Sorters/QuerySorterTest.php index 0f455f0fa..18c633d07 100644 --- a/packages/graphql/src/SortBy/Sorters/QuerySorterTest.php +++ b/packages/graphql/src/SortBy/Sorters/QuerySorterTest.php @@ -6,14 +6,17 @@ use Exception; use Illuminate\Container\Container; use Illuminate\Database\Query\Builder as QueryBuilder; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\SortBy\Enums\Direction; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\DataProviders\QueryBuilderDataProvider; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; +use Mockery\MockInterface; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; use function is_array; /** @@ -28,17 +31,31 @@ class QuerySorterTest extends TestCase { * * @param array{query: string, bindings: array}|Exception $expected * @param Closure(static): QueryBuilder $builder + * @param Closure(object, Property): string|null $resolver */ public function testSort( array|Exception $expected, Closure $builder, Property $property, Direction $direction, + ?Closure $resolver, ): void { if ($expected instanceof Exception) { self::expectExceptionObject($expected); } + if ($resolver) { + $this->override( + BuilderPropertyResolver::class, + static function (MockInterface $mock) use ($resolver): void { + $mock + ->shouldReceive('getProperty') + ->once() + ->andReturnUsing($resolver); + }, + ); + } + $sorter = Container::getInstance()->make(QuerySorter::class); $builder = $builder($this); $builder = $sorter->sort($builder, $property, $direction, null); @@ -60,21 +77,34 @@ public static function dataProviderSort(): array { return (new CompositeDataProvider( new QueryBuilderDataProvider(), new ArrayDataProvider([ - 'simple condition' => [ + 'simple condition' => [ [ 'query' => 'select * from "test_objects" order by "a" asc', 'bindings' => [], ], new Property('a'), Direction::Asc, + null, + ], + 'property.path' => [ + [ + 'query' => 'select * from "test_objects" order by "path"."to"."property" asc', + 'bindings' => [], + ], + new Property('path', 'to', 'property'), + Direction::Asc, + null, ], - 'nested not supported' => [ + 'resolver' => [ [ - 'query' => 'select * from "test_objects" order by "test"."name" asc', + 'query' => 'select * from "test_objects" order by "path__to__property" asc', 'bindings' => [], ], - new Property('test', 'name'), + new Property('path', 'to', 'property'), Direction::Asc, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, ], ]), ))->getData(); From 25475231695d6d175b109a3fff190cd65ab841a5 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 13 Jan 2024 10:40:49 +0400 Subject: [PATCH 7/8] Resolver tests for `Relation` operator (`@searchBy`). --- .../Operators/Complex/RelationTest.php | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php b/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php index 3d20d4bfb..f49f511ad 100644 --- a/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php +++ b/packages/graphql/src/SearchBy/Operators/Complex/RelationTest.php @@ -17,6 +17,8 @@ use Nuwave\Lighthouse\Execution\Arguments\Argument; use PHPUnit\Framework\Attributes\CoversClass; +use function implode; + /** * @internal * @@ -338,6 +340,41 @@ static function (self $test) use ($graphql): Argument { null, null, ], + 'resolver' => [ + [ + 'query' => <<<'SQL' + select * from "users" where exists ( + select * + from "users" as "laravel_reserved_0" + where "users"."localKey" = "laravel_reserved_0"."foreignKey" + and "laravel_reserved_0"."resolved__property" = ? + ) + SQL + , + 'bindings' => [123], + ], + static function (): EloquentBuilder { + return User::query(); + }, + new Property('parent'), + static function (self $test) use ($graphql): Argument { + return $test->getGraphQLArgument( + 'TestRelation', + [ + 'where' => [ + 'property' => [ + 'equal' => 123, + ], + ], + ], + $graphql, + ); + }, + null, + static function (object $builder, Property $property): string { + return implode('.', $property->getParent()->getPath()).'.resolved__'.$property->getName(); + }, + ], ]; } // From 122f29b644d9ae0508d368fa66b3a78c2329180c Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:56:25 +0400 Subject: [PATCH 8/8] deprecate(graphql)!: `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver`, use `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver` instead. --- packages/graphql/README.md | 10 ++- packages/graphql/UPGRADE.md | 2 + .../Builder/Contracts/Scout/FieldResolver.php | 5 ++ .../Defaults/BuilderPropertyResolver.php | 10 ++- .../Builder/Scout/DefaultFieldResolver.php | 24 ------- packages/graphql/src/Provider.php | 3 - .../src/SearchBy/Directives/DirectiveTest.php | 69 +++++++++++++++++-- .../SearchBy/Operators/Comparison/Equal.php | 6 +- .../Operators/Comparison/EqualTest.php | 20 +++++- .../src/SearchBy/Operators/Comparison/In.php | 6 +- .../SearchBy/Operators/Comparison/InTest.php | 20 +++++- .../SearchBy/Operators/Comparison/NotIn.php | 6 +- .../Operators/Comparison/NotInTest.php | 20 +++++- .../SearchBy/Operators/Logical/AllOfTest.php | 22 +++++- .../Operators/Traits/ScoutSupport.php | 13 ---- .../src/SortBy/Directives/DirectiveTest.php | 68 ++++++++++++++++-- .../src/SortBy/Sorters/ScoutSorter.php | 6 +- .../src/SortBy/Sorters/ScoutSorterTest.php | 48 +++++++++++-- 18 files changed, 274 insertions(+), 84 deletions(-) delete mode 100644 packages/graphql/src/Builder/Scout/DefaultFieldResolver.php diff --git a/packages/graphql/README.md b/packages/graphql/README.md index 8016ce2d0..d269be5dc 100644 --- a/packages/graphql/README.md +++ b/packages/graphql/README.md @@ -102,14 +102,18 @@ Represents [JSON](https://json.org) string. # Scout -[Scout](https://laravel.com/docs/scout) is also supported 🤩. By default `@searchBy`/`@sortBy` will convert nested/related properties into dot string: eg `{user: {name: asc}}` will be converted into `user.name`. You can redefine this behavior by [`FieldResolver`](./src/Builder/Contracts/Scout/FieldResolver.php): +[Scout](https://laravel.com/docs/scout) is also supported 🤩. You just need to add [`@search`](https://lighthouse-php.com/master/api-reference/directives.html#search) directive to an argument. + +# Builder property name + +By default `@searchBy`/`@sortBy` will convert nested/related properties into dot string: eg `{user: {name: asc}}` will be converted into `user.name`. You can redefine this behavior by [`BuilderPropertyResolver`](./src/Builder/Contracts/BuilderPropertyResolver.php): ```php // AppProvider $this->app->bind( - LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver::class, - MyScoutColumnResolver::class, + LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver::class, + MyBuilderPropertyResolver::class, ); ``` diff --git a/packages/graphql/UPGRADE.md b/packages/graphql/UPGRADE.md index ab01a3bce..daba3334d 100644 --- a/packages/graphql/UPGRADE.md +++ b/packages/graphql/UPGRADE.md @@ -66,6 +66,8 @@ Please also see [changelog](https://github.com/LastDragon-ru/lara-asp/releases) ]; ``` +* [ ] If you are using `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver`, use `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver` instead. 🤝 + ## API This section is actual only if you are extending the package. Please review and update (listed the most significant changes only): diff --git a/packages/graphql/src/Builder/Contracts/Scout/FieldResolver.php b/packages/graphql/src/Builder/Contracts/Scout/FieldResolver.php index a9ac15ed4..cc5b326e0 100644 --- a/packages/graphql/src/Builder/Contracts/Scout/FieldResolver.php +++ b/packages/graphql/src/Builder/Contracts/Scout/FieldResolver.php @@ -3,10 +3,15 @@ namespace LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout; use Illuminate\Database\Eloquent\Model; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; /** * Convert nested property into Scout field. + * + * @deprecated 5.4.0 Please use {@see BuilderPropertyResolver} instead. + * + * @see BuilderPropertyResolver */ interface FieldResolver { public function getField(Model $model, Property $property): string; diff --git a/packages/graphql/src/Builder/Defaults/BuilderPropertyResolver.php b/packages/graphql/src/Builder/Defaults/BuilderPropertyResolver.php index acc96d0bb..54be94f31 100644 --- a/packages/graphql/src/Builder/Defaults/BuilderPropertyResolver.php +++ b/packages/graphql/src/Builder/Defaults/BuilderPropertyResolver.php @@ -2,7 +2,9 @@ namespace LastDragon_ru\LaraASP\GraphQL\Builder\Defaults; +use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver as BuilderPropertyResolverContract; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver as ScoutFieldResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use Override; @@ -12,12 +14,16 @@ * @internal */ final class BuilderPropertyResolver implements BuilderPropertyResolverContract { - public function __construct() { + public function __construct( + private readonly ?ScoutFieldResolver $resolver = null, + ) { // empty } #[Override] public function getProperty(object $builder, Property $property): string { - return implode('.', $property->getPath()); + return $builder instanceof ScoutBuilder && $this->resolver + ? $this->resolver->getField($builder->model, $property) + : implode('.', $property->getPath()); } } diff --git a/packages/graphql/src/Builder/Scout/DefaultFieldResolver.php b/packages/graphql/src/Builder/Scout/DefaultFieldResolver.php deleted file mode 100644 index 350eba03d..000000000 --- a/packages/graphql/src/Builder/Scout/DefaultFieldResolver.php +++ /dev/null @@ -1,24 +0,0 @@ -getPath()); - } -} diff --git a/packages/graphql/src/Provider.php b/packages/graphql/src/Provider.php index f945d0f9c..ed53a39a9 100644 --- a/packages/graphql/src/Provider.php +++ b/packages/graphql/src/Provider.php @@ -7,10 +7,8 @@ use Illuminate\Support\ServiceProvider; use LastDragon_ru\LaraASP\Core\Provider\WithConfig; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver as BuilderPropertyResolverContract; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver as ScoutFieldResolverContract; use LastDragon_ru\LaraASP\GraphQL\Builder\Defaults\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Manipulator; -use LastDragon_ru\LaraASP\GraphQL\Builder\Scout\DefaultFieldResolver as ScoutFieldResolver; use LastDragon_ru\LaraASP\GraphQL\Printer\DirectiveResolver; use LastDragon_ru\LaraASP\GraphQL\SearchBy\Definitions\SearchByDirective; use LastDragon_ru\LaraASP\GraphQL\SearchBy\Operators as SearchByOperators; @@ -69,7 +67,6 @@ static function (): array { protected function registerBindings(): void { $this->app->scopedIf(SorterFactoryContract::class, SorterFactory::class); $this->app->scopedIf(StreamFactoryContract::class, StreamFactory::class); - $this->app->scopedIf(ScoutFieldResolverContract::class, ScoutFieldResolver::class); $this->app->scopedIf(BuilderPropertyResolverContract::class, BuilderPropertyResolver::class); } diff --git a/packages/graphql/src/SearchBy/Directives/DirectiveTest.php b/packages/graphql/src/SearchBy/Directives/DirectiveTest.php index b8d5af83a..4fdb40648 100644 --- a/packages/graphql/src/SearchBy/Directives/DirectiveTest.php +++ b/packages/graphql/src/SearchBy/Directives/DirectiveTest.php @@ -51,6 +51,7 @@ use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\MergeDataProvider; +use Mockery\MockInterface; use Nuwave\Lighthouse\Execution\Arguments\Argument; use Nuwave\Lighthouse\Schema\DirectiveLocator; use Nuwave\Lighthouse\Schema\TypeRegistry; @@ -284,15 +285,17 @@ public function testHandleBuilder( /** * @dataProvider dataProviderHandleScoutBuilder * - * @param array|Exception $expected - * @param Closure(static): ScoutBuilder $builderFactory - * @param Closure():FieldResolver|null $fieldResolver + * @param array|Exception $expected + * @param Closure(static): ScoutBuilder $builderFactory + * @param Closure(object, Property): string|null $resolver + * @param Closure():FieldResolver|null $fieldResolver */ public function testHandleScoutBuilder( array|Exception $expected, Closure $builderFactory, mixed $value, - Closure $fieldResolver = null, + ?Closure $resolver, + ?Closure $fieldResolver, ): void { $builder = $builderFactory($this); $directive = $this->getExposeBuilderDirective($builder); @@ -300,6 +303,19 @@ public function testHandleScoutBuilder( Container::getInstance()->make(DirectiveLocator::class) ->setResolved('search', SearchDirective::class); + if ($resolver) { + $this->override( + BuilderPropertyResolver::class, + static function (MockInterface $mock) use ($resolver): void { + $mock + ->shouldReceive('getProperty') + ->atLeast() + ->once() + ->andReturnUsing($resolver); + }, + ); + } + if ($fieldResolver) { $this->override(FieldResolver::class, $fieldResolver); } @@ -674,6 +690,7 @@ public static function dataProviderHandleScoutBuilder(): array { // empty ], null, + null, ], 'empty operators' => [ new ConditionEmpty(), @@ -683,6 +700,7 @@ public static function dataProviderHandleScoutBuilder(): array { ], ], null, + null, ], 'too many properties' => [ new ConditionTooManyProperties(['a', 'b']), @@ -695,6 +713,7 @@ public static function dataProviderHandleScoutBuilder(): array { ], ], null, + null, ], 'too many operators' => [ new ConditionTooManyOperators(['equal', 'in']), @@ -705,6 +724,7 @@ public static function dataProviderHandleScoutBuilder(): array { ], ], null, + null, ], 'null' => [ [ @@ -712,6 +732,7 @@ public static function dataProviderHandleScoutBuilder(): array { ], null, null, + null, ], 'default field resolver' => [ [ @@ -745,8 +766,9 @@ public static function dataProviderHandleScoutBuilder(): array { ], ], null, + null, ], - 'custom field resolver' => [ + 'resolver (deprecated)' => [ [ 'wheres' => [ 'properties/a' => 1, @@ -777,6 +799,7 @@ public static function dataProviderHandleScoutBuilder(): array { ], ], ], + null, static function (): FieldResolver { return new class() implements FieldResolver { /** @@ -792,6 +815,42 @@ public function getField( }; }, ], + 'resolver' => [ + [ + 'wheres' => [ + 'a' => 1, + 'c__a' => 2, + ], + 'whereIns' => [ + 'renamed.field' => ['a', 'b', 'c'], + ], + ], + [ + 'allOf' => [ + [ + 'a' => [ + 'equal' => 1, + ], + ], + [ + 'b' => [ + 'in' => ['a', 'b', 'c'], + ], + ], + [ + 'c' => [ + 'a' => [ + 'equal' => 2, + ], + ], + ], + ], + ], + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, + null, + ], ]), ))->getData(); } diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/Equal.php b/packages/graphql/src/SearchBy/Operators/Comparison/Equal.php index 2b2404d7a..cb3498595 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/Equal.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/Equal.php @@ -35,14 +35,12 @@ public function call( Argument $argument, Context $context, ): object { - $property = $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = $argument->toPlain(); if ($builder instanceof EloquentBuilder || $builder instanceof QueryBuilder) { - $builder->where($this->resolver->getProperty($builder, $property), '=', $value); + $builder->where($property, '=', $value); } elseif ($builder instanceof ScoutBuilder) { - $property = $this->getFieldResolver()->getField($builder->model, $property); - $builder->where($property, $value); } else { throw new OperatorUnsupportedBuilder($this, $builder); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php index c82a02486..a9d89cc3a 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/EqualTest.php @@ -153,7 +153,7 @@ public static function dataProviderCallScout(): array { return (new CompositeDataProvider( new ScoutBuilderDataProvider(), new ArrayDataProvider([ - 'property' => [ + 'property' => [ [ 'wheres' => [ 'path.to.property' => 'abc', @@ -167,7 +167,7 @@ static function (self $test): Argument { null, null, ], - 'property with resolver' => [ + 'resolver (deprecated)' => [ [ 'wheres' => [ 'properties/path/to/property' => 'abc', @@ -188,6 +188,22 @@ public function getField(Model $model, Property $property): string { }; }, ], + 'resolver' => [ + [ + 'wheres' => [ + 'path__to__property' => 'abc', + ], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('String!', 'abc'); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, + null, + ], ]), ))->getData(); } diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/In.php b/packages/graphql/src/SearchBy/Operators/Comparison/In.php index 7ffcd565d..822bb6dc3 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/In.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/In.php @@ -42,14 +42,12 @@ public function call( Argument $argument, Context $context, ): object { - $property = $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = (array) $argument->toPlain(); if ($builder instanceof EloquentBuilder || $builder instanceof QueryBuilder) { - $builder->whereIn($this->resolver->getProperty($builder, $property), $value); + $builder->whereIn($property, $value); } elseif ($builder instanceof ScoutBuilder) { - $property = $this->getFieldResolver()->getField($builder->model, $property); - $builder->whereIn($property, $value); } else { throw new OperatorUnsupportedBuilder($this, $builder); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php index afa301a7a..3cbbf0225 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/InTest.php @@ -153,7 +153,7 @@ public static function dataProviderCallScout(): array { return (new CompositeDataProvider( new ScoutBuilderDataProvider(), new ArrayDataProvider([ - 'property' => [ + 'property' => [ [ 'whereIns' => [ 'path.to.property' => [1, 2, 3], @@ -167,7 +167,7 @@ static function (self $test): Argument { null, null, ], - 'property with resolver' => [ + 'resolver (deprecated)' => [ [ 'whereIns' => [ 'properties/path/to/property' => [1, 2, 3], @@ -191,6 +191,22 @@ public function getField(Model $model, Property $property): string { }; }, ], + 'resolver' => [ + [ + 'whereIns' => [ + 'path__to__property' => [1, 2, 3], + ], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, + null, + ], ]), ))->getData(); } diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php index a8545125d..d910efe29 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotIn.php @@ -46,14 +46,12 @@ public function call( Argument $argument, Context $context, ): object { - $property = $property->getParent(); + $property = $this->resolver->getProperty($builder, $property->getParent()); $value = (array) $argument->toPlain(); if ($builder instanceof EloquentBuilder || $builder instanceof QueryBuilder) { - $builder->whereNotIn($this->resolver->getProperty($builder, $property), $value); + $builder->whereNotIn($property, $value); } elseif ($builder instanceof ScoutBuilder) { - $property = $this->getFieldResolver()->getField($builder->model, $property); - $builder->whereNotIn($property, $value); } else { throw new OperatorUnsupportedBuilder($this, $builder); diff --git a/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php b/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php index 13b21f6a3..ec59d9a29 100644 --- a/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php +++ b/packages/graphql/src/SearchBy/Operators/Comparison/NotInTest.php @@ -171,7 +171,7 @@ public static function dataProviderCallScout(): array { return (new CompositeDataProvider( new ScoutBuilderDataProvider(), new ArrayDataProvider([ - 'property' => [ + 'property' => [ [ 'whereNotIns' => [ 'path.to.property' => [1, 2, 3], @@ -185,7 +185,7 @@ static function (self $test): Argument { null, null, ], - 'property with resolver' => [ + 'resolver (deprecated)' => [ [ 'whereNotIns' => [ 'properties/path/to/property' => [1, 2, 3], @@ -209,6 +209,22 @@ public function getField(Model $model, Property $property): string { }; }, ], + 'resolver' => [ + [ + 'whereNotIns' => [ + 'path__to__property' => [1, 2, 3], + ], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + static function (self $test): Argument { + return $test->getGraphQLArgument('[Int!]!', [1, 2, 3]); + }, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, + null, + ], ]), ))->getData(); } diff --git a/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php b/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php index cf78b328f..99a665088 100644 --- a/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php +++ b/packages/graphql/src/SearchBy/Operators/Logical/AllOfTest.php @@ -287,7 +287,7 @@ public static function dataProviderCallScout(): array { return (new CompositeDataProvider( new ScoutBuilderDataProvider(), new ArrayDataProvider([ - 'property' => [ + 'property' => [ [ 'wheres' => [ 'path.to.property.a' => 'aaa', @@ -303,7 +303,7 @@ public static function dataProviderCallScout(): array { null, null, ], - 'property with resolver' => [ + 'resolver (deprecated)' => [ [ 'wheres' => [ 'properties/path/to/property/a' => 'aaa', @@ -329,6 +329,24 @@ public function getField(Model $model, Property $property): string { }; }, ], + 'resolver' => [ + [ + 'wheres' => [ + 'path__to__property__a' => 'aaa', + 'path__to__property__b' => 'bbb', + ], + 'whereIns' => [ + 'path__to__property__b' => [1, 2, 3], + ], + ], + new Property('path', 'to', 'property', 'operator name should be ignored'), + $factory, + null, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, + null, + ], ]), ))->getData(); } diff --git a/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php b/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php index 0077a1470..45f73495b 100644 --- a/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php +++ b/packages/graphql/src/SearchBy/Operators/Traits/ScoutSupport.php @@ -5,8 +5,6 @@ use Composer\InstalledVersions; use Composer\Semver\VersionParser; use Laravel\Scout\Builder as ScoutBuilder; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; use LastDragon_ru\LaraASP\GraphQL\SearchBy\Definitions\SearchByOperatorPropertyDirective; use Override; @@ -16,17 +14,6 @@ * @mixin SearchByOperatorPropertyDirective */ trait ScoutSupport { - public function __construct( - private FieldResolver $fieldResolver, - BuilderPropertyResolver $resolver, - ) { - parent::__construct($resolver); - } - - protected function getFieldResolver(): FieldResolver { - return $this->fieldResolver; - } - #[Override] public function isBuilderSupported(string $builder): bool { return parent::isBuilderSupported($builder) diff --git a/packages/graphql/src/SortBy/Directives/DirectiveTest.php b/packages/graphql/src/SortBy/Directives/DirectiveTest.php index f3a8f47d3..b81772bef 100644 --- a/packages/graphql/src/SortBy/Directives/DirectiveTest.php +++ b/packages/graphql/src/SortBy/Directives/DirectiveTest.php @@ -13,6 +13,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder; use Laravel\Scout\Builder as ScoutBuilder; use LastDragon_ru\LaraASP\GraphQL\Builder\Context; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Exceptions\Client\ConditionTooManyProperties; use LastDragon_ru\LaraASP\GraphQL\Builder\Exceptions\TypeDefinitionImpossibleToCreateType; @@ -36,6 +37,7 @@ use LastDragon_ru\LaraASP\Testing\Constraints\Response\StatusCodes\Ok; use LastDragon_ru\LaraASP\Testing\Providers\ArrayDataProvider; use LastDragon_ru\LaraASP\Testing\Providers\CompositeDataProvider; +use Mockery\MockInterface; use Nuwave\Lighthouse\Schema\DirectiveLocator; use Nuwave\Lighthouse\Schema\TypeRegistry; use Nuwave\Lighthouse\Scout\SearchDirective; @@ -322,15 +324,17 @@ public function testHandleBuilder( /** * @dataProvider dataProviderHandleScoutBuilder * - * @param array|Exception $expected - * @param Closure(static): ScoutBuilder $builderFactory - * @param Closure():FieldResolver|null $fieldResolver + * @param array|Exception $expected + * @param Closure(static): ScoutBuilder $builderFactory + * @param Closure(object, Property): string|null $resolver + * @param Closure():FieldResolver|null $fieldResolver */ public function testHandleScoutBuilder( array|Exception $expected, Closure $builderFactory, mixed $value, - Closure $fieldResolver = null, + ?Closure $resolver, + ?Closure $fieldResolver, ): void { $builder = $builderFactory($this); $directive = $this->getExposeBuilderDirective($builder); @@ -338,6 +342,19 @@ public function testHandleScoutBuilder( Container::getInstance()->make(DirectiveLocator::class) ->setResolved('search', SearchDirective::class); + if ($resolver) { + $this->override( + BuilderPropertyResolver::class, + static function (MockInterface $mock) use ($resolver): void { + $mock + ->shouldReceive('getProperty') + ->atLeast() + ->once() + ->andReturnUsing($resolver); + }, + ); + } + if ($fieldResolver) { $this->override(FieldResolver::class, $fieldResolver); } @@ -624,6 +641,7 @@ public static function dataProviderHandleScoutBuilder(): array { // empty ], null, + null, ], 'empty operators' => [ [ @@ -635,6 +653,7 @@ public static function dataProviderHandleScoutBuilder(): array { ], ], null, + null, ], 'too many properties' => [ new ConditionTooManyProperties(['a', 'b']), @@ -645,6 +664,7 @@ public static function dataProviderHandleScoutBuilder(): array { ], ], null, + null, ], 'null' => [ [ @@ -652,6 +672,7 @@ public static function dataProviderHandleScoutBuilder(): array { ], null, null, + null, ], 'default field resolver' => [ [ @@ -684,8 +705,9 @@ public static function dataProviderHandleScoutBuilder(): array { ], ], null, + null, ], - 'custom field resolver' => [ + 'resolver (deprecated)' => [ [ 'orders' => [ [ @@ -715,6 +737,7 @@ public static function dataProviderHandleScoutBuilder(): array { 'b' => 'desc', ], ], + null, static function (): FieldResolver { return new class() implements FieldResolver { /** @@ -730,6 +753,41 @@ public function getField( }; }, ], + 'resolver' => [ + [ + 'orders' => [ + [ + 'column' => 'a', + 'direction' => 'asc', + ], + [ + 'column' => 'c__a', + 'direction' => 'desc', + ], + [ + 'column' => 'renamed.field', + 'direction' => 'desc', + ], + ], + ], + [ + [ + 'a' => 'asc', + ], + [ + 'c' => [ + 'a' => 'desc', + ], + ], + [ + 'b' => 'desc', + ], + ], + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, + null, + ], ]), ))->getData(); } diff --git a/packages/graphql/src/SortBy/Sorters/ScoutSorter.php b/packages/graphql/src/SortBy/Sorters/ScoutSorter.php index 26c995261..10a1ae1d2 100644 --- a/packages/graphql/src/SortBy/Sorters/ScoutSorter.php +++ b/packages/graphql/src/SortBy/Sorters/ScoutSorter.php @@ -3,7 +3,7 @@ namespace LastDragon_ru\LaraASP\GraphQL\SortBy\Sorters; use Laravel\Scout\Builder as ScoutBuilder; -use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\Exceptions\NotImplemented; use LastDragon_ru\LaraASP\GraphQL\SortBy\Contracts\Sorter; @@ -16,7 +16,7 @@ */ class ScoutSorter implements Sorter { public function __construct( - protected FieldResolver $fieldResolver, + protected readonly BuilderPropertyResolver $resolver, ) { // empty } @@ -32,7 +32,7 @@ public function sort(object $builder, Property $property, Direction $direction, throw new NotImplemented('NULLs ordering'); } - $field = $this->fieldResolver->getField($builder->model, $property); + $field = $this->resolver->getProperty($builder, $property); $builder = match ($direction) { Direction::Asc, Direction::asc => $builder->orderBy($field, 'asc'), Direction::Desc, Direction::desc => $builder->orderBy($field, 'desc'), diff --git a/packages/graphql/src/SortBy/Sorters/ScoutSorterTest.php b/packages/graphql/src/SortBy/Sorters/ScoutSorterTest.php index 3cb8a3aab..b60b2ff09 100644 --- a/packages/graphql/src/SortBy/Sorters/ScoutSorterTest.php +++ b/packages/graphql/src/SortBy/Sorters/ScoutSorterTest.php @@ -7,10 +7,12 @@ use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Builder as ScoutBuilder; +use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\BuilderPropertyResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scout\FieldResolver; use LastDragon_ru\LaraASP\GraphQL\Builder\Property; use LastDragon_ru\LaraASP\GraphQL\SortBy\Enums\Direction; use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; +use Mockery\MockInterface; use Override; use PHPUnit\Framework\Attributes\CoversClass; @@ -27,21 +29,36 @@ class ScoutSorterTest extends TestCase { /** * @dataProvider dataProviderSort * - * @param array|Exception $expected - * @param Closure():FieldResolver|null $resolver + * @param array|Exception $expected + * @param Closure(object, Property): string|null $resolver + * @param Closure():FieldResolver|null $fieldResolver */ public function testSort( array|Exception $expected, Property $property, Direction $direction, - Closure $resolver = null, + ?Closure $resolver, + ?Closure $fieldResolver, ): void { if ($expected instanceof Exception) { self::expectExceptionObject($expected); } if ($resolver) { - $this->override(FieldResolver::class, $resolver); + $this->override( + BuilderPropertyResolver::class, + static function (MockInterface $mock) use ($resolver): void { + $mock + ->shouldReceive('getProperty') + ->atLeast() + ->once() + ->andReturnUsing($resolver); + }, + ); + } + + if ($fieldResolver) { + $this->override(FieldResolver::class, $fieldResolver); } $sorter = Container::getInstance()->make(ScoutSorter::class); @@ -66,7 +83,7 @@ public function testSort( */ public static function dataProviderSort(): array { return [ - 'clause' => [ + 'clause' => [ [ 'orders' => [ [ @@ -77,8 +94,10 @@ public static function dataProviderSort(): array { ], new Property('c', 'd', 'e'), Direction::Desc, + null, + null, ], - 'clause with resolver' => [ + 'resolver (deprecated)' => [ [ 'orders' => [ [ @@ -89,6 +108,7 @@ public static function dataProviderSort(): array { ], new Property('a', 'b'), Direction::Asc, + null, static function (): FieldResolver { return new class() implements FieldResolver { /** @@ -101,6 +121,22 @@ public function getField(Model $model, Property $property): string { }; }, ], + 'resolver' => [ + [ + 'orders' => [ + [ + 'column' => 'a__b', + 'direction' => 'asc', + ], + ], + ], + new Property('a', 'b'), + Direction::Asc, + static function (object $builder, Property $property): string { + return implode('__', $property->getPath()); + }, + null, + ], ]; } //