Skip to content

Commit

Permalink
feat(graphql): Ability to disable operators.
Browse files Browse the repository at this point in the history
Closes: #113
  • Loading branch information
LastDragon-ru committed Feb 23, 2024
1 parent 084c619 commit 01c7f71
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 82 deletions.
62 changes: 40 additions & 22 deletions packages/graphql/UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,27 @@ Please also see [changelog](https://github.com/LastDragon-ru/lara-asp/releases)
}
```

If you want to use old query syntax, you can add following bindings into application provider:
If you want to use old query syntax, you need:

```php
$this->app->bind(
LastDragon_ru\LaraASP\GraphQL\SearchBy\Types\Condition\Root::class,
LastDragon_ru\LaraASP\GraphQL\SearchBy\Types\Condition\V5::class,
);
$this->app->bind(
LastDragon_ru\LaraASP\GraphQL\SearchBy\Types\Condition\Condition::class,
LastDragon_ru\LaraASP\GraphQL\SearchBy\Types\Condition\V5::class,
);
```
1. Add following bindings into application provider:

```php
$this->app->bind(
LastDragon_ru\LaraASP\GraphQL\SearchBy\Types\Condition\Root::class,
LastDragon_ru\LaraASP\GraphQL\SearchBy\Types\Condition\V5::class,
);
$this->app->bind(
LastDragon_ru\LaraASP\GraphQL\SearchBy\Types\Condition\Condition::class,
LastDragon_ru\LaraASP\GraphQL\SearchBy\Types\Condition\V5::class,
);
```

2. Disable `LastDragon_ru\LaraASP\GraphQL\SearchBy\Definitions\SearchByOperatorFieldDirective` operator to avoid possible conflict with field names (via schema or config)

```graphql
scalar SearchByDisabled
@searchByOperatorField
```

## `@sortBy`

Expand Down Expand Up @@ -122,18 +131,27 @@ Please also see [changelog](https://github.com/LastDragon-ru/lara-asp/releases)
}
```

If you want to use old query syntax, you can add following bindings into application provider:
If you want to use old query syntax, you need:

```php
$this->app->bind(
LastDragon_ru\LaraASP\GraphQL\SortBy\Types\Clause\Root::class,
LastDragon_ru\LaraASP\GraphQL\SortBy\Types\Clause\V5::class,
);
$this->app->bind(
LastDragon_ru\LaraASP\GraphQL\SortBy\Types\Clause\Clause::class,
LastDragon_ru\LaraASP\GraphQL\SortBy\Types\Clause\V5::class,
);
```
1. Add following bindings into application provider:

```php
$this->app->bind(
LastDragon_ru\LaraASP\GraphQL\SortBy\Types\Clause\Root::class,
LastDragon_ru\LaraASP\GraphQL\SortBy\Types\Clause\V5::class,
);
$this->app->bind(
LastDragon_ru\LaraASP\GraphQL\SortBy\Types\Clause\Clause::class,
LastDragon_ru\LaraASP\GraphQL\SortBy\Types\Clause\V5::class,
);
```

2. Disable `LastDragon_ru\LaraASP\GraphQL\SortBy\Definitions\SortByOperatorFieldDirective` operator to avoid possible conflict with field names (via schema or config)

```graphql
scalar SortByDisabled
@sortByOperatorField
```

* [ ] `@sortByOperatorRandom` cannot be added to `FIELD_DEFINITION` anymore.

Expand Down
1 change: 1 addition & 0 deletions packages/graphql/docs/Directives/@searchBy.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ The package also defines a few own types in addition to the standard GraphQL typ
* `SearchByNull` / [`Operators::Null`](../../src/SearchBy/Operators.php) - Additional operators available for nullable fields.
* `SearchByExtra` / [`Operators::Extra`](../../src/SearchBy/Operators.php) - List of additional extra operators for all types.
* `SearchByEnum` / [`Operators::Enum`](../../src/SearchBy/Operators.php) - Default operators for enums.
* `SearchByDisabled` / [`Operators::Disabled`](../../src/SearchBy/Operators.php) - Disabled operators.

### GraphQL

Expand Down
50 changes: 45 additions & 5 deletions packages/graphql/src/Builder/Operators.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
use LastDragon_ru\LaraASP\GraphQL\Builder\Directives\ExtendOperatorsDirective;
use LastDragon_ru\LaraASP\GraphQL\Utils\AstManipulator;

use function array_filter;
use function array_map;
use function array_merge;
use function array_values;
use function is_a;
use function is_object;
use function is_string;

abstract class Operators {
Expand Down Expand Up @@ -73,6 +76,10 @@ public function getOperator(
$operator = Container::getInstance()->make($operator);
}

if (!$this->isEnabled($manipulator, $operator)) {
return null;
}

if (!$operator->isAvailable($manipulator, $source, $context)) {
return null;
}
Expand All @@ -84,16 +91,29 @@ public function getOperator(
* @return list<Operator>
*/
public function getOperators(Manipulator $manipulator, string $type, TypeSource $source, Context $context): array {
return array_values(
array_filter(
array_map(
function (mixed $operator) use ($manipulator, $source, $context): ?Operator {
return $this->getOperator($manipulator, $operator, $source, $context);
},
$this->getTypeOperators($manipulator, $type),
),
),
);
}

/**
* @return list<class-string<Operator>|Operator>
*/
protected function getTypeOperators(AstManipulator $manipulator, string $type): array {
// Operators
$unique = [];
$operators = $this->findOperators($manipulator, $type);

foreach ($operators as $operator) {
$operator = $this->getOperator($manipulator, $operator, $source, $context);

if ($operator && !isset($unique[$operator::class])) {
$unique[$operator::class] = $operator;
}
$class = is_object($operator) ? $operator::class : $operator;
$unique[$class] ??= $operator;
}

// Return
Expand Down Expand Up @@ -210,4 +230,24 @@ private function findConfigOperators(string $type): array {
private function findDefaultOperators(string $type): array {
return $this->default[$type] ?? [];
}

private function isEnabled(AstManipulator $manipulator, Operator $operator): bool {
$enabled = true;

foreach ($this->getDisabledOperators($manipulator) as $disabled) {
if (is_a($operator, is_object($disabled) ? $disabled::class : $disabled, true)) {
$enabled = false;
break;
}
}

return $enabled;
}

/**
* @return list<class-string<Operator>|Operator>
*/
protected function getDisabledOperators(AstManipulator $manipulator): array {
return [];
}
}
42 changes: 42 additions & 0 deletions packages/graphql/src/Builder/OperatorsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use LastDragon_ru\LaraASP\GraphQL\Builder\Directives\ExtendOperatorsDirective;
use LastDragon_ru\LaraASP\GraphQL\Builder\Directives\OperatorsDirective;
use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase;
use LastDragon_ru\LaraASP\GraphQL\Utils\AstManipulator;
use Mockery;
use Nuwave\Lighthouse\Execution\Arguments\Argument;
use Nuwave\Lighthouse\Schema\AST\ASTBuilder;
Expand All @@ -40,6 +41,7 @@ public function testGetOperators(): void {
$directives->setResolved('bOperator', OperatorsTest__OperatorB::class);
$directives->setResolved('cOperator', OperatorsTest__OperatorC::class);
$directives->setResolved('externalOperator', OperatorsTest__OperatorExternal::class);
$directives->setResolved('disabledOperator', OperatorsTest__OperatorDisabled::class);

// Schema
$this->useGraphQLSchema(
Expand All @@ -48,6 +50,7 @@ public function testGetOperators(): void {
@aOperator
@bOperator
@cOperator
@disabledOperator
@externalOperator
scalar SchemaTypeIgnored
Expand All @@ -56,10 +59,12 @@ public function testGetOperators(): void {
scalar SchemaTypeD
@operators(type: "TypeD")
@disabledOperator
@externalOperator
scalar TypeD
@extendOperators
@disabledOperator
@externalOperator
scalar SchemaTypeInfiniteLoop
Expand All @@ -80,12 +85,14 @@ public function testGetOperators(): void {
'TypeA' => [
OperatorsTest__OperatorA::class,
OperatorsTest__OperatorA::class,
OperatorsTest__OperatorDisabled::class,
OperatorsTest__OperatorExternal::class,
OperatorsTest__OperatorNotAvailable::class,
],
'TypeB' => [
OperatorsTest__OperatorNotAvailable::class,
OperatorsTest__OperatorExternal::class,
OperatorsTest__OperatorDisabled::class,
OperatorsTest__OperatorA::class,
'TypeB',
],
Expand All @@ -95,34 +102,42 @@ public function testGetOperators(): void {
'InfiniteLoop' => [
OperatorsTest__OperatorNotAvailable::class,
OperatorsTest__OperatorExternal::class,
OperatorsTest__OperatorDisabled::class,
OperatorsTest__OperatorA::class,
'SchemaTypeInfiniteLoop',
],
'Disabled' => [
OperatorsTest__OperatorDisabled::class,
],
];
$default = [
'TypeA' => [
OperatorsTest__OperatorA::class,
OperatorsTest__OperatorB::class,
OperatorsTest__OperatorC::class,
OperatorsTest__OperatorDisabled::class,
OperatorsTest__OperatorExternal::class,
OperatorsTest__OperatorNotAvailable::class,
],
'TypeB' => [
OperatorsTest__OperatorNotAvailable::class,
OperatorsTest__OperatorExternal::class,
OperatorsTest__OperatorDisabled::class,
OperatorsTest__OperatorB::class,
'TypeB',
],
'TypeC' => [
OperatorsTest__OperatorNotAvailable::class,
OperatorsTest__OperatorExternal::class,
OperatorsTest__OperatorDisabled::class,
OperatorsTest__OperatorC::class,
'TypeB',
'TypeA',
],
'TypeD' => [
OperatorsTest__OperatorNotAvailable::class,
OperatorsTest__OperatorExternal::class,
OperatorsTest__OperatorDisabled::class,
OperatorsTest__OperatorA::class,
],
];
Expand Down Expand Up @@ -217,6 +232,14 @@ protected function toClassNames(array $objects): array {
// @phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
// @phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps

/**
* @internal
* @noinspection PhpMultipleClassesDeclarationsInOneFile
*/
interface OperatorsTest__Disabled {
// empty
}

/**
* @internal
* @noinspection PhpMultipleClassesDeclarationsInOneFile
Expand Down Expand Up @@ -262,6 +285,14 @@ public function __construct(array $operators = [], array $default = []) {
public function getScope(): string {
return OperatorsTest__Scope::class;
}

/**
* @inheritDoc
*/
#[Override]
protected function getDisabledOperators(AstManipulator $manipulator): array {
return $this->getTypeOperators($manipulator, 'Disabled');
}
}

/**
Expand Down Expand Up @@ -341,6 +372,17 @@ public function isAvailable(TypeProvider $provider, TypeSource $source, Context
}
}

/**
* @internal
* @noinspection PhpMultipleClassesDeclarationsInOneFile
*/
class OperatorsTest__OperatorDisabled extends OperatorsTest__Operator implements OperatorsTest__Scope {
#[Override]
public function isAvailable(TypeProvider $provider, TypeSource $source, Context $context): bool {
return true;
}
}

/**
* @internal
* @noinspection PhpMultipleClassesDeclarationsInOneFile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ input Comment {
user: User @belongsTo
date: Date
}

scalar SearchByDisabled
@searchByOperatorField
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ scalar ScalarCustom
@searchByOperatorLessThan
@searchByOperatorLessThanOrEqual

scalar SearchByDisabled
@searchByOperatorField

enum EnumA {
One
Two
Expand Down
24 changes: 19 additions & 5 deletions packages/graphql/src/SearchBy/Operators.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,19 @@
use LastDragon_ru\LaraASP\GraphQL\SearchBy\Definitions\SearchByOperatorRelationshipDirective;
use LastDragon_ru\LaraASP\GraphQL\SearchBy\Definitions\SearchByOperatorStartsWithDirective;
use LastDragon_ru\LaraASP\GraphQL\SearchBy\Directives\Directive;
use LastDragon_ru\LaraASP\GraphQL\Utils\AstManipulator;
use Override;

use function array_merge;
use function config;

class Operators extends BuilderOperators {
public const Null = Directive::Name.'Null';
public const Extra = Directive::Name.'Extra';
public const Number = Directive::Name.'Number';
public const Enum = Directive::Name.'Enum';
public const Object = Directive::Name.'Object';
public const Null = Directive::Name.'Null';
public const Extra = Directive::Name.'Extra';
public const Number = Directive::Name.'Number';
public const Enum = Directive::Name.'Enum';
public const Object = Directive::Name.'Object';
public const Disabled = Directive::Name.'Disabled';

/**
* @inheritDoc
Expand Down Expand Up @@ -150,4 +153,15 @@ public function __construct() {
public function getScope(): string {
return Scope::class;
}

/**
* @inheritDoc
*/
#[Override]
protected function getDisabledOperators(AstManipulator $manipulator): array {
return array_merge(
parent::getDisabledOperators($manipulator),
$this->getTypeOperators($manipulator, self::Disabled),
);
}
}
Loading

0 comments on commit 01c7f71

Please sign in to comment.