Passed
Push — master ( 43996d...1595cb )
by Kirill
04:07
created

Backend::precompile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
/**
4
 * This file is part of Railt package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Railt\SDL;
13
14
use GraphQL\Contracts\TypeSystem\SchemaInterface;
15
use Phplrt\Visitor\Traverser;
16
use Railt\SDL\Backend\Context;
17
use Railt\SDL\Backend\Linker\LinkerInterface;
18
use Railt\SDL\Backend\Linker\LinkerVisitor;
19
use Railt\SDL\Backend\TypeBuilderVisitor;
20
use Railt\SDL\Frontend\Ast\Node;
21
use Railt\SDL\Spec\Executor;
22
use Railt\SDL\Spec\SpecificationInterface;
23
use Railt\TypeSystem\Exception\TypeUniquenessException;
24
use Railt\TypeSystem\Schema;
25
26
/**
27
 * Class Backend
28
 */
29
class Backend
30
{
31
    /**
32
     * @var Executor
33
     */
34
    private Executor $spec;
35
36
    /**
37
     * @var Context
38
     */
39
    private Context $context;
40
41
    /**
42
     * @var LinkerInterface
43
     */
44
    private LinkerInterface $linker;
45
46
    /**
47
     * Backend constructor.
48
     *
49
     * @param SpecificationInterface $spec
50
     * @param Context $context
51
     * @param LinkerInterface $linker
52
     */
53
    public function __construct(SpecificationInterface $spec, Context $context, LinkerInterface $linker)
54
    {
55
        $this->spec = new Executor($spec);
56
        $this->context = $context;
57
        $this->linker = $linker;
58
    }
59
60
    /**
61
     * @param iterable|Node[] $ast
62
     * @param array $variables
63
     * @return SchemaInterface
64
     * @throws \Throwable
65
     */
66
    public function run(iterable $ast, array $variables = []): SchemaInterface
67
    {
68
        $schema = new Schema();
69
70
        $ast = $this->adoptSpecification($ast);
71
        $ast = $this->buildTypes($ast, $schema);
72
73
        $this->linkTypes($ast);
74
75
        return $this->moveData($this->context, $schema, $variables);
76
    }
77
78
    /**
79
     * @param iterable|Node[] $ast
80
     * @return iterable|Node[]
81
     */
82
    private function adoptSpecification(iterable $ast): iterable
83
    {
84
        return $this->spec->execute($ast);
85
    }
86
87
    /**
88
     * @param iterable $ast
89
     * @param Schema $schema
90
     * @return iterable
91
     */
92
    private function buildTypes(iterable $ast, Schema $schema): iterable
93
    {
94
        $traverser = new Traverser([
95
            new TypeBuilderVisitor($this->context, $schema),
96
        ]);
97
98
        return $traverser->traverse($ast);
99
    }
100
101
    /**
102
     * @param iterable $ast
103
     * @return iterable
104
     */
105
    private function linkTypes(iterable $ast): iterable
106
    {
107
        $traverser = new Traverser([
108
            new LinkerVisitor($this->context, $this->linker),
109
        ]);
110
111
        return $traverser->traverse($ast);
112
    }
113
114
    /**
115
     * @param Context $context
116
     * @param Schema $schema
117
     * @param array $variables
118
     * @return Schema
119
     * @throws TypeUniquenessException
120
     * @throws \InvalidArgumentException
121
     * @throws \Throwable
122
     */
123
    private function moveData(Context $context, Schema $schema, array $variables): Schema
124
    {
125
        foreach ($this->context->getTypes() as $type) {
126
            $schema->addType($type->resolve($variables));
127
        }
128
129
        foreach ($this->context->getDirectives() as $type) {
130
            $schema->addDirective($type->resolve($variables));
131
        }
132
133
        $schema->setQueryType($context->getQuery());
134
        $schema->setMutationType($context->getMutation());
135
        $schema->setSubscriptionType($context->getSubscription());
136
137
        return $schema;
138
    }
139
}
140