Skip to content

Commit

Permalink
refactor(graphql)!: Builder Context (#116)
Browse files Browse the repository at this point in the history
  • Loading branch information
LastDragon-ru authored Jan 10, 2024
2 parents abcae15 + e184bd7 commit 79b3bf0
Show file tree
Hide file tree
Showing 98 changed files with 774 additions and 270 deletions.
28 changes: 25 additions & 3 deletions packages/graphql/UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,30 @@ Please also see [changelog](https://github.com/LastDragon-ru/lara-asp/releases)

* [ ] `enum SortByTypeDirection { asc, desc }` => `enum SortByTypeDirection { Asc, Desc }`. 🤝

* [ ] `LastDragon_ru\LaraASP\GraphQL\SortBy\Builders\*` => `LastDragon_ru\LaraASP\GraphQL\SortBy\Sorters\*`.
* [ ] If you are testing generated queries, you need to update `sort_by_*` alias to `lara_asp_graphql__sort_by__*`.

* [ ] Update `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeDefinition` implementations.
## API

* [ ] If you are testing generated queries, you need to update `sort_by_*` alias to `lara_asp_graphql__sort_by__*`.
This section is actual only if you are extending the package. Please review and update (listed the most significant changes only):

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler`

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator`

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeDefinition`.

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeProvider`

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Manipulator` (removed `BuilderInfo`)

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Directives\HandlerDirective`

* [ ] `LastDragon_ru\LaraASP\GraphQL\Builder\Directives\PropertyDirective`

* [ ] `LastDragon_ru\LaraASP\GraphQL\SortBy\Builders\*` => `LastDragon_ru\LaraASP\GraphQL\SortBy\Sorters\*`

* [ ] 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
```
46 changes: 46 additions & 0 deletions packages/graphql/src/Builder/Context.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\GraphQL\Builder;

use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context as ContextContract;
use Override;

/**
* @internal
*/
class Context implements ContextContract {
/**
* @var array<class-string, object|null>
*/
private array $context = [];

public function __construct() {
// empty
}

#[Override]
public function has(string $key): bool {
return isset($this->context[$key]) && $this->context[$key] instanceof $key;
}

#[Override]
public function get(string $key): mixed {
return isset($this->context[$key]) && $this->context[$key] instanceof $key
? $this->context[$key]
: null;
}

/**
* @inheritDoc
*/
#[Override]
public function override(array $context): static {
$overridden = clone $this;

foreach ($context as $key => $value) {
$overridden->context[$key] = $value;
}

return $overridden;
}
}
13 changes: 13 additions & 0 deletions packages/graphql/src/Builder/Contexts/AstManipulation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\GraphQL\Builder\Contexts;

use LastDragon_ru\LaraASP\GraphQL\Builder\BuilderInfo;

class AstManipulation {
public function __construct(
public readonly BuilderInfo $builderInfo,
) {
// empty
}
}
26 changes: 26 additions & 0 deletions packages/graphql/src/Builder/Contracts/Context.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types = 1);

namespace LastDragon_ru\LaraASP\GraphQL\Builder\Contracts;

interface Context {
/**
* @param class-string $key
*/
public function has(string $key): bool;

/**
* @template T of object
*
* @param class-string<T> $key
*
* @return T|null
*/
public function get(string $key): mixed;

/**
* @template T of object
*
* @param array<class-string<T>, T|null> $context
*/
public function override(array $context): static;
}
2 changes: 1 addition & 1 deletion packages/graphql/src/Builder/Contracts/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ interface Handler {
*
* @return TBuilder
*/
public function handle(object $builder, Property $property, ArgumentSet $conditions): object;
public function handle(object $builder, Property $property, ArgumentSet $conditions, Context $context): object;
}
10 changes: 8 additions & 2 deletions packages/graphql/src/Builder/Contracts/Operator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface Operator extends Directive {
*/
public static function getName(): string;

public function getFieldType(TypeProvider $provider, TypeSource $source): string;
public function getFieldType(TypeProvider $provider, TypeSource $source, Context $context): string;

public function getFieldDescription(): string;

Expand All @@ -31,5 +31,11 @@ public function isBuilderSupported(string $builder): bool;
*
* @return TBuilder
*/
public function call(Handler $handler, object $builder, Property $property, Argument $argument): object;
public function call(
Handler $handler,
object $builder,
Property $property,
Argument $argument,
Context $context,
): object;
}
3 changes: 2 additions & 1 deletion packages/graphql/src/Builder/Contracts/TypeDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface TypeDefinition {
/**
* Returns the type name for given Builder and Source.
*/
public function getTypeName(Manipulator $manipulator, TypeSource $source): string;
public function getTypeName(TypeSource $source, Context $context): string;

/**
* Returns the type definition for given Source if possible. The name must be equal to `$name`.
Expand All @@ -22,6 +22,7 @@ public function getTypeName(Manipulator $manipulator, TypeSource $source): strin
public function getTypeDefinition(
Manipulator $manipulator,
TypeSource $source,
Context $context,
string $name,
): TypeDefinitionNode|Type|null;
}
2 changes: 1 addition & 1 deletion packages/graphql/src/Builder/Contracts/TypeProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface TypeProvider {
/**
* @param class-string<TypeDefinition> $definition
*/
public function getType(string $definition, TypeSource $source): string;
public function getType(string $definition, TypeSource $source, Context $context): string;

/**
* @param (TypeDefinitionNode&Node)|NamedTypeNode|ListTypeNode|NonNullTypeNode|Type $type
Expand Down
43 changes: 33 additions & 10 deletions packages/graphql/src/Builder/Directives/HandlerDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
use Illuminate\Database\Query\Builder as QueryBuilder;
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\Contracts\Context as ContextContract;
use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler;
use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Operator;
use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Scope;
Expand All @@ -41,6 +44,9 @@
use function is_array;
use function reset;

/**
* @see AstManipulation
*/
abstract class HandlerDirective extends BaseDirective implements Handler {
use WithManipulator;
use WithSource;
Expand Down Expand Up @@ -87,7 +93,7 @@ public function handleScoutBuilder(ScoutBuilder $builder, mixed $value): ScoutBu
*
* @return T
*/
protected function handleAnyBuilder(object $builder, mixed $value): object {
protected function handleAnyBuilder(object $builder, mixed $value, ContextContract $context = null): object {
if ($value !== null && $this->definitionNode instanceof InputValueDefinitionNode) {
$argument = !($value instanceof Argument)
? $this->getFactory()->getArgument($this->definitionNode, $value)
Expand All @@ -99,7 +105,7 @@ protected function handleAnyBuilder(object $builder, mixed $value): object {

foreach ($conditions as $condition) {
if ($condition instanceof ArgumentSet) {
$builder = $this->handle($builder, new Property(), $condition);
$builder = $this->handle($builder, new Property(), $condition, $context ?? new Context());
} else {
throw new HandlerInvalidConditions($this);
}
Expand All @@ -117,7 +123,12 @@ protected function handleAnyBuilder(object $builder, mixed $value): object {
* @return T
*/
#[Override]
public function handle(object $builder, Property $property, ArgumentSet $conditions): object {
public function handle(
object $builder,
Property $property,
ArgumentSet $conditions,
ContextContract $context,
): object {
// Empty?
if (count($conditions->arguments) === 0) {
return $builder;
Expand All @@ -131,7 +142,7 @@ public function handle(object $builder, Property $property, ArgumentSet $conditi
}

// Call
return $this->call($builder, $property, $conditions);
return $this->call($builder, $property, $conditions, $context);
}

/**
Expand All @@ -141,7 +152,12 @@ public function handle(object $builder, Property $property, ArgumentSet $conditi
*
* @return T
*/
protected function call(object $builder, Property $property, ArgumentSet $operator): object {
protected function call(
object $builder,
Property $property,
ArgumentSet $operator,
ContextContract $context,
): object {
// Arguments?
if (count($operator->arguments) > 1) {
throw new ConditionTooManyOperators(
Expand Down Expand Up @@ -184,7 +200,7 @@ static function (Operator $operator): string {
}

// Return
return $op->call($this, $builder, $property, $value);
return $op->call($this, $builder, $property, $value, $context);
}
// </editor-fold>

Expand All @@ -199,15 +215,20 @@ public function manipulateArgDefinition(
// Converted?
$detector = Container::getInstance()->make(BuilderInfoDetector::class);
$builder = $detector->getFieldArgumentBuilderInfo($documentAST, $parentType, $parentField, $argDefinition);
$manipulator = $this->getManipulator($documentAST, $builder);
$manipulator = $this->getAstManipulator($documentAST);

if ($this->isTypeName($manipulator->getTypeName($argDefinition))) {
return;
}

// Argument
$source = $this->getFieldArgumentSource($manipulator, $parentType, $parentField, $argDefinition);
$type = $this->getArgDefinitionType($manipulator, $documentAST, $source);
$context = (new Context())->override([
AstManipulation::class => new AstManipulation(
builderInfo: $builder,
),
]);
$source = $this->getFieldArgumentSource($manipulator, $parentType, $parentField, $argDefinition);
$type = $this->getArgDefinitionType($manipulator, $documentAST, $source, $context);

$manipulator->setArgumentType(
$parentType,
Expand All @@ -226,6 +247,7 @@ abstract protected function getArgDefinitionType(
Manipulator $manipulator,
DocumentAST $document,
ObjectFieldArgumentSource|InterfaceFieldArgumentSource $argument,
ContextContract $context,
): ListTypeNode|NamedTypeNode|NonNullTypeNode;

/**
Expand All @@ -236,6 +258,7 @@ protected function getArgumentTypeDefinitionNode(
DocumentAST $document,
ObjectFieldArgumentSource|InterfaceFieldArgumentSource $argument,
string $operator,
ContextContract $context,
): ListTypeNode|NamedTypeNode|NonNullTypeNode|null {
$type = null;
$definition = $manipulator->isPlaceholder($argument->getArgument())
Expand All @@ -245,7 +268,7 @@ protected function getArgumentTypeDefinitionNode(
if ($definition) {
$operator = $manipulator->getOperator(static::getScope(), $operator);
$node = $manipulator->getTypeSource($definition);
$type = $operator->getFieldType($manipulator, $node);
$type = $operator->getFieldType($manipulator, $node, $context);
$type = Parser::typeReference($type);
}

Expand Down
13 changes: 10 additions & 3 deletions packages/graphql/src/Builder/Directives/PropertyDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace LastDragon_ru\LaraASP\GraphQL\Builder\Directives;

use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context;
use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Handler;
use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeProvider;
use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeSource;
Expand All @@ -23,7 +24,7 @@ public static function getName(): string {
}

#[Override]
public function getFieldType(TypeProvider $provider, TypeSource $source): string {
public function getFieldType(TypeProvider $provider, TypeSource $source, Context $context): string {
return $source->getTypeName();
}

Expand All @@ -33,7 +34,13 @@ public function isBuilderSupported(string $builder): bool {
}

#[Override]
public function call(Handler $handler, object $builder, Property $property, Argument $argument): object {
public function call(
Handler $handler,
object $builder,
Property $property,
Argument $argument,
Context $context,
): object {
if (!($argument->value instanceof ArgumentSet)) {
throw new HandlerInvalidConditions($handler);
}
Expand All @@ -51,6 +58,6 @@ public function call(Handler $handler, object $builder, Property $property, Argu
}

// Apply
return $handler->handle($builder, $property, $argument->value);
return $handler->handle($builder, $property, $argument->value, $context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace LastDragon_ru\LaraASP\GraphQL\Builder\Exceptions;

use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\Context;
use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeDefinition;
use Stringable;
use Throwable;
Expand All @@ -14,14 +15,15 @@ class TypeDefinitionImpossibleToCreateType extends BuilderException {
*/
public function __construct(
protected string $definition,
protected Stringable|string|null $source,
protected Stringable|string $source,
protected Context $context,
Throwable $previous = null,
) {
parent::__construct(
sprintf(
'Definition `%s`: Impossible to create type for `%s`.',
$this->definition,
$this->source ?: 'null',
$this->source,
),
$previous,
);
Expand All @@ -31,7 +33,11 @@ public function getDefinition(): string {
return $this->definition;
}

public function getSource(): Stringable|string|null {
public function getSource(): Stringable|string {
return $this->source;
}

public function getContext(): Context {
return $this->context;
}
}
Loading

0 comments on commit 79b3bf0

Please sign in to comment.