line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
use 5.014; |
3
|
17
|
|
|
17
|
|
65041
|
use strict; |
|
5877
|
|
|
|
|
48614
|
|
4
|
5877
|
|
|
17
|
|
20585
|
use warnings; |
|
3342
|
|
|
|
|
10596
|
|
|
3347
|
|
|
|
|
18613
|
|
5
|
1130
|
|
|
17
|
|
2211
|
use Moo; |
|
1126
|
|
|
|
|
2950
|
|
|
1168
|
|
|
|
|
3206
|
|
6
|
1173
|
|
|
17
|
|
3848
|
use Types::Standard -all; |
|
94
|
|
|
|
|
3610
|
|
|
620
|
|
|
|
|
12494
|
|
7
|
1520
|
|
|
17
|
|
122611
|
use GraphQL::Type::Library -all; |
|
429
|
|
|
|
|
916
|
|
|
426
|
|
|
|
|
1263
|
|
8
|
1741
|
|
|
17
|
|
688970
|
use GraphQL::MaybeTypeCheck; |
|
739
|
|
|
|
|
34028
|
|
|
779
|
|
|
|
|
22887
|
|
9
|
2605
|
|
|
17
|
|
205762
|
use GraphQL::Debug qw(_debug); |
|
2808
|
|
|
|
|
8797
|
|
|
2563
|
|
|
|
|
17965
|
|
10
|
1125
|
|
|
17
|
|
26706
|
use GraphQL::Directive; |
|
1161
|
|
|
|
|
3627
|
|
|
70
|
|
|
|
|
1140
|
|
11
|
68
|
|
|
17
|
|
7385
|
use GraphQL::Introspection qw($SCHEMA_META_TYPE); |
|
68
|
|
|
|
|
808
|
|
|
163
|
|
|
|
|
1644
|
|
12
|
63
|
|
|
17
|
|
31061
|
use GraphQL::Language::Parser qw(parse); |
|
59
|
|
|
|
|
24526
|
|
|
17
|
|
|
|
|
2349
|
|
13
|
17
|
|
|
17
|
|
8492
|
use GraphQL::Plugin::Type; |
|
17
|
|
|
|
|
61
|
|
|
17
|
|
|
|
|
1112
|
|
14
|
17
|
|
|
17
|
|
113
|
use Module::Runtime qw(require_module); |
|
17
|
|
|
|
|
29
|
|
|
17
|
|
|
|
|
142
|
|
15
|
17
|
|
|
17
|
|
118
|
use Exporter 'import'; |
|
17
|
|
|
|
|
35
|
|
|
17
|
|
|
|
|
127
|
|
16
|
17
|
|
|
17
|
|
1035
|
|
|
17
|
|
|
|
|
39
|
|
|
17
|
|
|
|
|
978
|
|
17
|
|
|
|
|
|
|
our $VERSION = '0.02'; |
18
|
|
|
|
|
|
|
our @EXPORT_OK = qw(lookup_type); |
19
|
|
|
|
|
|
|
use constant DEBUG => $ENV{GRAPHQL_DEBUG}; |
20
|
17
|
|
|
17
|
|
94
|
my @TYPE_ATTRS = qw(query mutation subscription); |
|
17
|
|
|
|
|
39
|
|
|
17
|
|
|
|
|
6642
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 NAME |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
GraphQL::Schema - GraphQL schema object |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 SYNOPSIS |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
use GraphQL::Schema; |
29
|
|
|
|
|
|
|
use GraphQL::Type::Object; |
30
|
|
|
|
|
|
|
my $schema = GraphQL::Schema->new( |
31
|
|
|
|
|
|
|
query => GraphQL::Type::Object->new( |
32
|
|
|
|
|
|
|
name => 'Query', |
33
|
|
|
|
|
|
|
fields => { |
34
|
|
|
|
|
|
|
getObject => { |
35
|
|
|
|
|
|
|
type => $interfaceType, |
36
|
|
|
|
|
|
|
resolve => sub { |
37
|
|
|
|
|
|
|
return {}; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
) |
42
|
|
|
|
|
|
|
); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 DESCRIPTION |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Class implementing GraphQL schema. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head2 query |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=cut |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
has query => (is => 'ro', isa => InstanceOf['GraphQL::Type::Object'], required => 1); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head2 mutation |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=cut |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
has mutation => (is => 'ro', isa => InstanceOf['GraphQL::Type::Object']); |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head2 subscription |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=cut |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
has subscription => (is => 'ro', isa => InstanceOf['GraphQL::Type::Object']); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head2 types |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
Defaults to the types returned by L<GraphQL::Plugin::Type/registered>. |
71
|
|
|
|
|
|
|
Note that this includes the standard scalar types always loaded by |
72
|
|
|
|
|
|
|
L<GraphQL::Type::Scalar>. If you |
73
|
|
|
|
|
|
|
wish to supply an overriding value for this attribute, bear that in mind. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=cut |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
has types => ( |
78
|
|
|
|
|
|
|
is => 'ro', |
79
|
|
|
|
|
|
|
isa => ArrayRef[ConsumerOf['GraphQL::Role::Named']], |
80
|
|
|
|
|
|
|
default => sub { [ GraphQL::Plugin::Type->registered ] }, |
81
|
|
|
|
|
|
|
); |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head2 directives |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=cut |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
has directives => ( |
88
|
|
|
|
|
|
|
is => 'ro', |
89
|
|
|
|
|
|
|
isa => ArrayRef[InstanceOf['GraphQL::Directive']], |
90
|
|
|
|
|
|
|
default => sub { \@GraphQL::Directive::SPECIFIED_DIRECTIVES }, |
91
|
|
|
|
|
|
|
); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head1 METHODS |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head2 name2type |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
In this schema, returns a hash-ref mapping all types' names to their |
98
|
|
|
|
|
|
|
type object. |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=cut |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
has name2type => (is => 'lazy', isa => Map[StrNameValid, ConsumerOf['GraphQL::Role::Named']]); |
103
|
|
|
|
|
|
|
my ($self) = @_; |
104
|
|
|
|
|
|
|
my @types = grep $_, (map $self->$_, @TYPE_ATTRS), $SCHEMA_META_TYPE; |
105
|
|
|
|
75
|
|
|
push @types, @{ $self->types || [] }; |
106
|
|
|
|
|
|
|
my %name2type; |
107
|
|
|
|
|
|
|
map _expand_type(\%name2type, $_), @types; |
108
|
|
|
|
|
|
|
\%name2type; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head2 get_possible_types($abstract_type) |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
In this schema, get all of either the implementation types |
114
|
|
|
|
|
|
|
(if interface) or possible types (if union) of the C<$abstract_type>. |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=cut |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
fun _expand_type( |
119
|
|
|
|
|
|
|
(Map[StrNameValid, ConsumerOf['GraphQL::Role::Named']]) $map, |
120
|
|
|
|
|
|
|
(InstanceOf['GraphQL::Type']) $type, |
121
|
|
|
|
|
|
|
) :ReturnType(ArrayRef[ConsumerOf['GraphQL::Role::Named']]) { |
122
|
|
|
|
|
|
|
@_ = ($map, $type->of), goto &_expand_type if $type->can('of'); # avoid blowing out the stack |
123
|
5848
|
50
|
|
5848
|
|
10586
|
my $name = $type->name if $type->can('name'); |
|
5848
|
50
|
|
|
|
8581
|
|
|
5848
|
100
|
|
|
|
7935
|
|
|
5848
|
100
|
|
|
|
11477
|
|
|
17
|
|
|
|
|
20604
|
|
|
17
|
|
|
|
|
39
|
|
124
|
17
|
100
|
|
|
|
86
|
return [] if $name and $map->{$name} and $map->{$name} == $type; # seen |
125
|
12
|
100
|
|
|
|
48
|
die "Duplicate type $name" if $map->{$name}; |
126
|
12
|
100
|
100
|
|
|
43
|
$map->{$name} = $type; |
|
|
|
100
|
|
|
|
|
127
|
12
|
100
|
|
|
|
24
|
my @types; |
128
|
12
|
|
|
|
|
26
|
push @types, ($type, map @{ _expand_type($map, $_) }, @{ $type->interfaces || [] }) |
129
|
12
|
|
|
|
|
43
|
if $type->isa('GraphQL::Type::Object'); |
130
|
17
|
100
|
|
|
|
20774
|
push @types, ($type, map @{ _expand_type($map, $_) }, @{ $type->get_types }) |
|
17
|
100
|
|
|
|
50
|
|
|
17
|
|
|
|
|
160
|
|
131
|
|
|
|
|
|
|
if $type->isa('GraphQL::Type::Union'); |
132
|
14
|
100
|
|
|
|
443
|
if (grep $type->DOES($_), qw(GraphQL::Role::FieldsInput GraphQL::Role::FieldsOutput)) { |
|
14
|
|
|
|
|
37
|
|
|
14
|
|
|
|
|
22
|
|
133
|
|
|
|
|
|
|
my $fields = $type->fields||{}; |
134
|
14
|
100
|
|
|
|
29
|
push @types, map { |
135
|
14
|
|
50
|
|
|
59
|
map @{ _expand_type($map, $_->{type}) }, $_, values %{ $_->{args}||{} } |
136
|
|
|
|
|
|
|
} values %$fields; |
137
|
14
|
50
|
|
|
|
655
|
} |
|
19
|
|
|
|
|
22551
|
|
|
19
|
|
|
|
|
89
|
|
|
19
|
|
|
|
|
107
|
|
138
|
|
|
|
|
|
|
DEBUG and _debug('_expand_type', \@types); |
139
|
|
|
|
|
|
|
\@types; |
140
|
57
|
|
|
|
|
8619
|
} |
141
|
5905
|
|
|
|
|
1157224
|
|
142
|
17
|
|
|
17
|
|
40582
|
has _interface2types => (is => 'lazy', isa => Map[StrNameValid, ArrayRef[InstanceOf['GraphQL::Type::Object']]]); |
|
17
|
|
|
|
|
35
|
|
|
17
|
|
|
|
|
118
|
|
143
|
|
|
|
|
|
|
my ($self) = @_; |
144
|
|
|
|
|
|
|
my $name2type = $self->name2type||{}; |
145
|
|
|
|
|
|
|
my %interface2types; |
146
|
|
|
|
6
|
|
|
map { |
147
|
|
|
|
|
|
|
my $o = $_; |
148
|
|
|
|
|
|
|
map { |
149
|
|
|
|
|
|
|
push @{$interface2types{$_->name}}, $o; |
150
|
|
|
|
|
|
|
# TODO assert_object_implements_interface |
151
|
|
|
|
|
|
|
} @{ $o->interfaces||[] }; |
152
|
|
|
|
|
|
|
} grep $_->isa('GraphQL::Type::Object'), values %$name2type; |
153
|
|
|
|
|
|
|
\%interface2types; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
method get_possible_types( |
157
|
|
|
|
|
|
|
(ConsumerOf['GraphQL::Role::Abstract']) $abstract_type |
158
|
|
|
|
|
|
|
) :ReturnType(ArrayRef[InstanceOf['GraphQL::Type::Object']]) { |
159
|
|
|
|
|
|
|
return $abstract_type->get_types if $abstract_type->isa('GraphQL::Type::Union'); |
160
|
|
|
|
|
|
|
$self->_interface2types->{$abstract_type->name} || []; |
161
|
18
|
50
|
|
12
|
1
|
8065
|
} |
|
18
|
50
|
|
|
|
69
|
|
|
18
|
50
|
|
|
|
186
|
|
|
56
|
|
|
|
|
263752
|
|
|
56
|
|
|
|
|
213
|
|
|
56
|
|
|
|
|
123
|
|
162
|
56
|
50
|
|
|
|
286
|
|
163
|
56
|
50
|
|
|
|
360
|
=head2 is_possible_type($abstract_type, $possible_type) |
164
|
57
|
|
|
17
|
|
233
|
|
|
56
|
|
|
|
|
216
|
|
|
56
|
|
|
|
|
215
|
|
165
|
|
|
|
|
|
|
In this schema, is the given C<$possible_type> either an implementation |
166
|
|
|
|
|
|
|
(if interface) or a possibility (if union) of the C<$abstract_type>? |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=cut |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
has _possible_type_map => (is => 'rw', isa => Map[StrNameValid, Map[StrNameValid, Bool]]); |
171
|
|
|
|
|
|
|
method is_possible_type( |
172
|
|
|
|
|
|
|
(ConsumerOf['GraphQL::Role::Abstract']) $abstract_type, |
173
|
|
|
|
|
|
|
(InstanceOf['GraphQL::Type::Object']) $possible_type, |
174
|
|
|
|
|
|
|
) :ReturnType(Bool) { |
175
|
|
|
|
|
|
|
my $map = $self->_possible_type_map || {}; |
176
|
|
|
|
|
|
|
return $map->{$abstract_type->name}{$possible_type->name} |
177
|
17
|
50
|
|
14
|
1
|
37011
|
if $map->{$abstract_type->name}; # we know about the abstract_type |
|
17
|
100
|
|
|
|
38
|
|
|
17
|
0
|
|
|
|
115
|
|
|
348
|
0
|
|
|
|
6061
|
|
|
348
|
|
|
|
|
618
|
|
|
348
|
|
|
|
|
556
|
|
|
348
|
|
|
|
|
708
|
|
178
|
348
|
|
|
|
|
2308
|
my @possibles = @{ $self->get_possible_types($abstract_type)||[] }; |
179
|
|
|
|
|
|
|
die <<EOF if !@possibles; |
180
|
75
|
0
|
|
|
|
1440
|
Could not find possible implementing types for @{[$abstract_type->name]} |
181
|
75
|
50
|
|
|
|
723
|
in schema. Check that schema.types is defined and is an array of |
|
75
|
|
|
|
|
163
|
|
182
|
75
|
100
|
|
|
|
415
|
all possible types in the schema. |
183
|
75
|
|
|
|
|
139
|
EOF |
184
|
|
|
|
|
|
|
$map->{$abstract_type->name} = { map { ($_->name => 1) } @possibles }; |
185
|
|
|
|
|
|
|
$self->_possible_type_map($map); |
186
|
|
|
|
|
|
|
$map->{$abstract_type->name}{$possible_type->name}; |
187
|
75
|
|
|
|
|
302
|
} |
|
71
|
|
|
|
|
2146
|
|
188
|
6
|
|
|
|
|
82
|
|
189
|
6
|
|
|
|
|
95
|
=head2 assert_object_implements_interface($type, $iface) |
190
|
56
|
|
|
17
|
|
1006
|
|
|
56
|
|
|
|
|
622
|
|
|
56
|
|
|
|
|
354
|
|
191
|
|
|
|
|
|
|
In this schema, does the given C<$type> implement interface C<$iface>? If |
192
|
|
|
|
|
|
|
not, throw exception. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=cut |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
method assert_object_implements_interface( |
197
|
|
|
|
|
|
|
(ConsumerOf['GraphQL::Role::Abstract']) $abstract_type, |
198
|
|
|
|
|
|
|
(InstanceOf['GraphQL::Type::Object']) $possible_type, |
199
|
|
|
|
|
|
|
) { |
200
|
|
|
|
|
|
|
my @types = @{ $self->types }; |
201
|
|
|
|
|
|
|
return; |
202
|
|
|
|
0
|
1
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head2 from_ast($ast[, \%kind2class]) |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
Class method. Takes AST (array-ref of hash-refs) made by |
207
|
|
|
|
|
|
|
L<GraphQL::Language::Parser/parse> and returns a schema object. Will |
208
|
|
|
|
|
|
|
not be a complete schema since it will have only default resolvers. |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
If C<\%kind2class> is given, it will override the default |
211
|
|
|
|
|
|
|
mapping of SDL keywords to Perl classes. This is probably most |
212
|
|
|
|
|
|
|
useful for L<GraphQL::Type::Object>. The default is available as |
213
|
|
|
|
|
|
|
C<%GraphQL::Schema::KIND2CLASS>. E.g. |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
my $schema = GraphQL::Schema->from_ast( |
216
|
|
|
|
|
|
|
$doc, |
217
|
|
|
|
|
|
|
{ %GraphQL::Schema::KIND2CLASS, type => 'GraphQL::Type::Object::DBIC' } |
218
|
|
|
|
|
|
|
); |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
Makes available the additional types returned by |
221
|
|
|
|
|
|
|
L<GraphQL::Plugin::Type/registered>. |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=cut |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
our %KIND2CLASS = qw( |
226
|
|
|
|
|
|
|
type GraphQL::Type::Object |
227
|
|
|
|
|
|
|
enum GraphQL::Type::Enum |
228
|
|
|
|
|
|
|
interface GraphQL::Type::Interface |
229
|
|
|
|
|
|
|
union GraphQL::Type::Union |
230
|
|
|
|
|
|
|
scalar GraphQL::Type::Scalar |
231
|
|
|
|
|
|
|
input GraphQL::Type::InputObject |
232
|
|
|
|
|
|
|
); |
233
|
|
|
|
|
|
|
my %CLASS2KIND = reverse %KIND2CLASS; |
234
|
|
|
|
|
|
|
method from_ast( |
235
|
|
|
|
|
|
|
ArrayRef[HashRef] $ast, |
236
|
|
|
|
|
|
|
HashRef $kind2class = \%KIND2CLASS, |
237
|
|
|
|
|
|
|
) :ReturnType(InstanceOf[__PACKAGE__]) { |
238
|
|
|
|
|
|
|
DEBUG and _debug('Schema.from_ast', $ast); |
239
|
|
|
|
|
|
|
my @type_nodes = grep $kind2class->{$_->{kind}}, @$ast; |
240
|
49
|
50
|
|
55
|
1
|
55
|
my ($schema_node, $e) = grep $_->{kind} eq 'schema', @$ast; |
|
7
|
50
|
|
|
|
171
|
|
|
7
|
|
|
|
|
33
|
|
|
49
|
|
|
|
|
692
|
|
|
6
|
|
|
|
|
180
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
241
|
0
|
|
|
|
|
0
|
die "Must provide only one schema definition.\n" if $e; |
242
|
0
|
|
|
|
|
0
|
my %name2type = (map { $_->name => $_ } GraphQL::Plugin::Type->registered); |
243
|
0
|
|
|
|
|
0
|
for (@type_nodes) { |
244
|
0
|
|
|
|
|
0
|
die "Type '$_->{name}' was defined more than once.\n" |
245
|
0
|
|
|
|
|
0
|
if $name2type{$_->{name}}; |
|
0
|
|
|
|
|
0
|
|
246
|
0
|
|
|
|
|
0
|
require_module $kind2class->{$_->{kind}}; |
247
|
|
|
|
|
|
|
$name2type{$_->{name}} = $kind2class->{$_->{kind}}->from_ast(\%name2type, $_); |
248
|
0
|
|
|
|
|
0
|
} |
249
|
26
|
|
|
|
|
612
|
if (!$schema_node) { |
250
|
26
|
|
|
|
|
58
|
# infer one |
251
|
|
|
|
|
|
|
$schema_node = +{ |
252
|
26
|
|
|
|
|
379
|
map { $name2type{ucfirst $_} ? ($_ => ucfirst $_) : () } @TYPE_ATTRS |
253
|
|
|
|
|
|
|
}; |
254
|
|
|
|
|
|
|
} |
255
|
19
|
|
|
|
|
114
|
die "Must provide schema definition with query type or a type named Query.\n" |
|
21
|
|
|
|
|
197
|
|
256
|
|
|
|
|
|
|
unless $schema_node->{query}; |
257
|
|
|
|
|
|
|
my @directives = map GraphQL::Directive->from_ast(\%name2type, $_), |
258
|
|
|
|
|
|
|
grep $_->{kind} eq 'directive', @$ast; |
259
|
26
|
|
|
|
|
198
|
my $schema = $self->new( |
260
|
|
|
|
|
|
|
(map { |
261
|
132
|
|
|
|
|
337
|
$schema_node->{$_} |
262
|
|
|
|
|
|
|
? ($_ => $name2type{$schema_node->{$_}} |
263
|
|
|
|
|
|
|
// die "Specified $_ type '$schema_node->{$_}' not found.\n") |
264
|
26
|
|
|
|
|
82
|
: () |
265
|
0
|
|
|
|
|
0
|
} @TYPE_ATTRS), |
266
|
|
|
|
|
|
|
(@directives ? (directives => [ @GraphQL::Directive::SPECIFIED_DIRECTIVES, @directives ]) : ()), |
267
|
|
|
|
|
|
|
types => [ values %name2type ], |
268
|
|
|
|
|
|
|
); |
269
|
|
|
|
|
|
|
$schema->name2type; # walks all types, fields, args - finds undefined types |
270
|
|
|
|
|
|
|
$schema; |
271
|
|
|
|
|
|
|
} |
272
|
26
|
|
|
|
|
304
|
|
273
|
26
|
|
|
|
|
516
|
=head2 from_doc($doc[, \%kind2class]) |
274
|
6
|
|
|
17
|
|
2050
|
|
|
6
|
|
|
|
|
89
|
|
|
49
|
|
|
|
|
969
|
|
275
|
|
|
|
|
|
|
Class method. Takes text that is a Schema Definition Language (SDL) (aka |
276
|
|
|
|
|
|
|
Interface Definition Language) document and returns a schema object. Will |
277
|
|
|
|
|
|
|
not be a complete schema since it will have only default resolvers. |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
As of v0.32, this accepts both old-style "meaningful comments" and |
280
|
|
|
|
|
|
|
new-style string values, as field or type descriptions. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
If C<\%kind2class> is given, it will override the default |
283
|
|
|
|
|
|
|
mapping of SDL keywords to Perl classes. This is probably most |
284
|
|
|
|
|
|
|
useful for L<GraphQL::Type::Object>. The default is available as |
285
|
|
|
|
|
|
|
C<%GraphQL::Schema::KIND2CLASS>. |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=cut |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
method from_doc( |
290
|
|
|
|
|
|
|
Str $doc, |
291
|
|
|
|
|
|
|
HashRef $kind2class = \%KIND2CLASS, |
292
|
|
|
|
|
|
|
) :ReturnType(InstanceOf[__PACKAGE__]) { |
293
|
|
|
|
|
|
|
$self->from_ast(parse($doc), $kind2class); |
294
|
|
|
|
|
|
|
} |
295
|
2
|
|
|
56
|
1
|
4
|
|
|
2
|
|
|
|
|
5
|
|
|
10
|
|
|
|
|
62
|
|
|
2
|
|
|
|
|
11
|
|
296
|
|
|
|
|
|
|
=head2 to_doc($doc) |
297
|
2
|
|
|
17
|
|
87
|
|
|
2
|
|
|
|
|
10
|
|
|
2
|
|
|
|
|
4
|
|
298
|
|
|
|
|
|
|
Returns Schema Definition Language (SDL) document that describes this |
299
|
|
|
|
|
|
|
schema object. |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
As of v0.32, this produces the new-style descriptions that are string |
302
|
|
|
|
|
|
|
values, rather than old-style "meaningful comments". |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
As of v0.33, will not return a description of types supplied with the |
305
|
|
|
|
|
|
|
attribute L</types>. Obviously, by default this includes types returned |
306
|
|
|
|
|
|
|
by L<GraphQL::Plugin::Type/registered>. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=cut |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
has to_doc => (is => 'lazy', isa => Str); |
311
|
|
|
|
|
|
|
my %directive2builtin = map { ($_=>1) } @GraphQL::Directive::SPECIFIED_DIRECTIVES; |
312
|
|
|
|
|
|
|
my ($self) = @_; |
313
|
|
|
|
|
|
|
my $schema_doc; |
314
|
|
|
|
|
|
|
if (grep $self->$_->name ne ucfirst $_, grep $self->$_, @TYPE_ATTRS) { |
315
|
|
|
|
|
|
|
$schema_doc = join('', map "$_\n", "schema {", |
316
|
|
|
|
26
|
|
|
(map " $_: @{[$self->$_->name]}", grep $self->$_, @TYPE_ATTRS), |
317
|
|
|
|
|
|
|
"}"); |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
my %supplied_type = (map {$_->name => 1} GraphQL::Plugin::Type->registered); |
320
|
|
|
|
|
|
|
join "\n", grep defined, |
321
|
|
|
|
|
|
|
$schema_doc, |
322
|
|
|
|
|
|
|
(map $_->to_doc, |
323
|
|
|
|
|
|
|
sort { $a->name cmp $b->name } |
324
|
|
|
|
|
|
|
grep !$directive2builtin{$_}, |
325
|
|
|
|
|
|
|
@{ $self->directives }), |
326
|
|
|
|
|
|
|
(map $self->name2type->{$_}->to_doc, |
327
|
|
|
|
|
|
|
grep !/^__/, |
328
|
|
|
|
|
|
|
grep $CLASS2KIND{ref $self->name2type->{$_}}, |
329
|
|
|
|
|
|
|
grep !$supplied_type{$_}, |
330
|
|
|
|
|
|
|
sort keys %{$self->name2type}), |
331
|
|
|
|
|
|
|
; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=head2 name2directive |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
In this schema, returns a hash-ref mapping all directives' names to their |
337
|
|
|
|
|
|
|
directive object. |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=cut |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
has name2directive => (is => 'lazy', isa => Map[StrNameValid, InstanceOf['GraphQL::Directive']]); |
342
|
|
|
|
|
|
|
method _build_name2directive() { |
343
|
|
|
|
|
|
|
+{ map { ($_->name => $_) } @{ $self->directives } }; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
2
|
|
|
=head1 FUNCTIONS |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=head2 lookup_type($typedef, $name2type) |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Turns given AST fragment into a type. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
If the hash-ref's C<type> member is a string, will return a type of that name. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
If an array-ref, first element must be either C<list> or C<non_null>, |
355
|
|
|
|
|
|
|
second will be a recursive AST fragment, which will be passed into a |
356
|
|
|
|
|
|
|
recursive call. The result will then have the modifier method (C<list> |
357
|
|
|
|
|
|
|
or C<non_null>) called, and that will be returned. |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=cut |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
fun lookup_type( |
362
|
|
|
|
|
|
|
HashRef $typedef, |
363
|
|
|
|
|
|
|
(Map[StrNameValid, InstanceOf['GraphQL::Type']]) $name2type, |
364
|
|
|
|
|
|
|
) :ReturnType(InstanceOf['GraphQL::Type']) { |
365
|
|
|
|
|
|
|
my $type = $typedef->{type}; |
366
|
|
|
|
|
|
|
die "Undefined type given\n" if !defined $type; |
367
|
|
|
|
|
|
|
return $name2type->{$type} // die "Unknown type '$type'.\n" |
368
|
|
|
|
348
|
1
|
|
if is_Str($type); |
369
|
|
|
|
|
|
|
my ($wrapper_type, $wrapped) = @$type; |
370
|
|
|
|
|
|
|
lookup_type($wrapped, $name2type)->$wrapper_type; |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable(); |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
17
|
|
|
1; |