Skip to content

Commit

Permalink
Merge pull request #11 from andrey-mokhov/schema-warmupper
Browse files Browse the repository at this point in the history
Release SchemaWarmupper
  • Loading branch information
andrey-mokhov committed Dec 18, 2023
2 parents bc62038 + 1ba85d9 commit dc6a17d
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 10 deletions.
10 changes: 0 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,3 @@
The library integrates the GraphQL library
[andi-lab/graphql-php](https://packagist.org/packages/andi-lab/graphql-php) with
[SpiralFramework](https://packagist.org/packages/spiral/framework).

## Roadmap

release 0.1
- [x] Enum loader
- [x] Interface loader
- [x] configure package: `.editorconfig`, `.gitattributes`, `.styleci.yml`, `phpunit.xml`, `psalm.xml`

release 1.0
- [ ] Clear memory after GraphQL schema initialization
6 changes: 6 additions & 0 deletions src/Bootloader/GraphQLBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Andi\GraphQL\ObjectFieldResolver\ObjectFieldResolver;
use Andi\GraphQL\ObjectFieldResolver\ObjectFieldResolverInterface;
use Andi\GraphQL\Spiral\Command\ConfigCommand;
use Andi\GraphQL\Spiral\Common\SchemaWarmupper;
use Andi\GraphQL\Spiral\Config\GraphQLConfig;
use Andi\GraphQL\Spiral\Common\ValueResolver;
use Andi\GraphQL\Spiral\Listener\AdditionalFieldListener;
Expand All @@ -33,6 +34,7 @@
use GraphQL\Type\Schema;
use GraphQL\Type\SchemaConfig;
use Psr\Container\ContainerInterface;
use Spiral\Boot\AbstractKernel;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Boot\EnvironmentInterface;
use Spiral\Bootloader\Http\HttpBootloader;
Expand Down Expand Up @@ -70,6 +72,7 @@ public function __construct(
}

public function init(
AbstractKernel $kernel,
EnvironmentInterface $env,
HttpBootloader $http,
ConsoleBootloader $console,
Expand All @@ -81,6 +84,9 @@ public function init(
$http->addMiddleware(GraphQLMiddleware::class);

$console->addCommand(ConfigCommand::class);
$kernel->bootstrapped(static function (Schema $schema): void {
SchemaWarmupper::warmup($schema);
});
}

public function boot(
Expand Down
119 changes: 119 additions & 0 deletions src/Common/SchemaWarmupper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php

declare(strict_types=1);

namespace Andi\GraphQL\Spiral\Common;

use GraphQL\Type\Definition as Webonyx;
use GraphQL\Type\Schema;

final class SchemaWarmupper
{
public static function warmup(Schema $schema): void
{
$allTypes = [];

$types = $schema->getConfig()->getTypes();
if (is_callable($types)) {
$types = $types();
}

foreach ($types as $type) {
self::warmupType(Schema::resolveType($type), $allTypes);
}

foreach ($schema->getDirectives() as $directive) {
foreach ($directive->args as $arg) {
self::warmupType($arg->getType(), $allTypes);
}
}

if ($type = $schema->getQueryType()) {
self::warmupType($type, $allTypes);
}

if ($type = $schema->getMutationType()) {
self::warmupType($type, $allTypes);
}

if ($type = $schema->getSubscriptionType()) {
self::warmupType($type, $allTypes);
}

$schema->getTypeMap();
}

private static function warmupType(Webonyx\Type $type, array &$allTypes): void
{
if ($type instanceof Webonyx\WrappingType) {
self::warmupType($type->getInnermostType(), $allTypes);

return;
}
assert($type instanceof Webonyx\NamedType);
/**
* @psalm-suppress NoInterfaceProperties
* @psalm-suppress UndefinedPropertyFetch
*/
$name = $type->name;
if (isset($allTypes[$name])) {
return;
}

$allTypes[$name] = true;

if ($type instanceof Webonyx\EnumType) {
$enumValues = $type->getValues();
if (is_callable($type->config['values'])) {
$values = [];
foreach ($enumValues as $value) {
$values[$value->name] = [
'value' => $value->value,
'description' => $value->description,
'deprecationReason' => $value->deprecationReason,
];
}
$type->config['values'] = $values;
}
return;
}

if ($type instanceof Webonyx\UnionType) {
$type->config['types'] = $type->getTypes();
foreach ($type->config['types'] as $member) {
self::warmupType($member, $allTypes);
}
return;
}

if ($type instanceof Webonyx\InputObjectType) {
$type->config['fields'] = $type->getFields();
foreach ($type->config['fields'] as $field) {
self::warmupType($field->getType(), $allTypes);
}
return;
}

if ($type instanceof Webonyx\ImplementingType) {
$interfaces = $type->getInterfaces();
foreach ($interfaces as $interface) {
self::warmupType($interface, $allTypes);
}
assert($type instanceof Webonyx\ObjectType || $type instanceof Webonyx\InterfaceType);
$type->config['interfaces'] = $interfaces;
}

if ($type instanceof Webonyx\HasFieldsType) {
$fields = $type->getFields();
foreach ($fields as $field) {
foreach ($field->args as $arg) {
self::warmupType($arg->config['type'] = $arg->getType(), $allTypes);
}
self::warmupType($field->getType(), $allTypes);
}

assert($type instanceof Webonyx\ObjectType || $type instanceof Webonyx\InterfaceType);
$type->config['fields'] = $fields;
}
}
}
2 changes: 2 additions & 0 deletions tests/Feature/Command/ConfigCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Andi\GraphQL\Spiral\Bootloader\GraphQLBootloader;
use Andi\GraphQL\Spiral\Command\ConfigCommand;
use Andi\GraphQL\Spiral\Common\SchemaWarmupper;
use Andi\GraphQL\Spiral\Config\GraphQLConfig;
use Andi\GraphQL\Spiral\Listener\AbstractAdditionalFieldListener;
use Andi\GraphQL\Spiral\Listener\AdditionalFieldListener;
Expand All @@ -30,6 +31,7 @@
#[UsesClass(MutationFieldListener::class)]
#[UsesClass(QueryFieldListener::class)]
#[UsesClass(TypeLoaderListener::class)]
#[UsesClass(SchemaWarmupper::class)]
final class ConfigCommandTest extends TestCase
{
public function rootDirectory(): string
Expand Down
2 changes: 2 additions & 0 deletions tests/Feature/Config/GraphQLConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Andi\Tests\GraphQL\Spiral\Feature\Config;

use Andi\GraphQL\Spiral\Bootloader\GraphQLBootloader;
use Andi\GraphQL\Spiral\Common\SchemaWarmupper;
use Andi\GraphQL\Spiral\Config\GraphQLConfig;
use Andi\GraphQL\Spiral\Listener\AbstractAdditionalFieldListener;
use Andi\GraphQL\Spiral\Listener\AdditionalFieldListener;
Expand Down Expand Up @@ -33,6 +34,7 @@
#[UsesClass(QueryFieldListener::class)]
#[UsesClass(MutationFieldListener::class)]
#[UsesClass(TypeLoaderListener::class)]
#[UsesClass(SchemaWarmupper::class)]
final class GraphQLConfigTest extends TestCase
{
private GraphQLConfig $config;
Expand Down

0 comments on commit dc6a17d

Please sign in to comment.