File Coverage

blib/lib/GraphQL/Type/Library.pm
Criterion Covered Total %
statement 24 57 42.1
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 32 65 49.2


line stmt bran cond sub pod time code
1             package GraphQL::Type::Library;
2              
3 22     22   577 use 5.014;
  22         80  
4 22     22   214 use strict;
  22         43  
  22         494  
5 22     22   126 use warnings;
  22         48  
  22         1221  
6             use Type::Library
7 22         254 -base,
8             -declare => qw(
9             StrNameValid FieldMapInput ValuesMatchTypes DocumentLocation JSONable
10             ErrorResult FieldsGot
11 22     22   665 );
  22         21313  
12 2586     22   251860 use Type::Utils -all;
  2586         109776  
  22         239  
13 22     22   68171 use Types::TypeTiny -all;
  22         54  
  22         117  
14 22     22   13352 use Types::Standard -all;
  22         42205  
  22         135  
15 22     22   948707 use JSON::MaybeXS;
  22         13186  
  22         24042  
16              
17             our $VERSION = '0.02';
18             my $JSON = JSON::MaybeXS->new->allow_nonref;
19              
20             =head1 NAME
21              
22             GraphQL::Type::Library - GraphQL type library
23              
24             =head1 SYNOPSIS
25              
26             use GraphQL::Type::Library -all;
27             has name => (is => 'ro', isa => StrNameValid, required => 1);
28              
29             =head1 DESCRIPTION
30              
31             Provides L<Type::Tiny> types.
32              
33             =head1 TYPES
34              
35             =head2 StrNameValid
36              
37             If called with a string that is not a valid GraphQL name, will throw
38             an exception. Suitable for passing to an C<isa> constraint in L<Moo>.
39              
40             =cut
41              
42             declare "StrNameValid", as StrMatch[ qr/^[_a-zA-Z][_a-zA-Z0-9]*$/ ];
43              
44             =head2 ValuesMatchTypes
45              
46             Subtype of L<Types::Standard/HashRef>, whose values are hash-refs. Takes
47             two parameters:
48              
49             =over
50              
51             =item value keyname
52              
53             Optional within the second-level hashes.
54              
55             =item type keyname
56              
57             Values will be a L<GraphQL::Type>. Mandatory within the second-level hashes.
58              
59             =back
60              
61             In the second-level hashes, the values (if given) must pass the GraphQL
62             type constraint.
63              
64             =cut
65              
66             declare "ValuesMatchTypes",
67             constraint_generator => sub {
68             my ($value_key, $type_key) = @_;
69             declare as HashRef[Dict[
70             $type_key => ConsumerOf['GraphQL::Role::Input'],
71             slurpy Any,
72             ]], where {
73             !grep {
74             $_->{$value_key} and !$_->{$type_key}->is_valid($_->{$value_key})
75             } values %$_
76             }, inline_as {
77             (undef, <<EOF);
78             !grep {
79             \$_->{$value_key} and !\$_->{$type_key}->is_valid(\$_->{$value_key})
80             } values %{$_[1]}
81             EOF
82             };
83             };
84              
85             =head2 FieldsGot
86              
87             Data item describing the fields found in a particular object in a query.
88             Preserves their order.
89              
90             =cut
91              
92             declare "FieldsGot", as Tuple[ArrayRef[StrNameValid], Map[
93             StrNameValid,
94             ArrayRef[HashRef]
95             ]];
96              
97             =head2 FieldMapInput
98              
99             Hash-ref mapping field names to a hash-ref
100             description. Description keys, all optional except C<type>:
101              
102             =over
103              
104             =item type
105              
106             GraphQL input type for the field.
107              
108             =item default_value
109              
110             Default value for this argument if none supplied. Must be same type as
111             the C<type> (implemented with type L</ValuesMatchTypes>.
112             B<NB> this is a Perl value, not a JSON/GraphQL value.
113              
114             =item description
115              
116             Description.
117              
118             =back
119              
120             =cut
121              
122             declare "FieldMapInput", as Map[
123             StrNameValid,
124             Dict[
125             type => ConsumerOf['GraphQL::Role::Input'],
126             default_value => Optional[Any],
127             directives => Optional[ArrayRef[HashRef]],
128             description => Optional[Str],
129             ]
130             ] & ValuesMatchTypes['default_value', 'type' ];
131              
132             =head2 FieldMapOutput
133              
134             Hash-ref mapping field names to a hash-ref
135             description. Description keys, all optional except C<type>:
136              
137             =head3 type
138              
139             GraphQL output type for the field.
140              
141             =head3 args
142              
143             A L</FieldMapInput>.
144              
145             =head3 subscribe
146              
147             Code-ref to return a subscription to the field from a given
148             source-object. See L<GraphQL::Subscription/subscribe>.
149              
150             =head3 deprecation_reason
151              
152             Reason if deprecated. If given, also sets a boolean key of
153             C<is_deprecated> to true.
154              
155             =head3 description
156              
157             Description.
158              
159             =head3 resolve
160              
161             Code-ref to return a given property from a given source-object.
162             A key concept is to remember that the "object" on which these fields
163             exist, were themselves returned by other fields.
164              
165             There are no restrictions on what you can return, so long as it is a
166             scalar, and if your return type is a L<list|GraphQL::Type::List>, that
167             scalar is an array-ref.
168              
169             Emphasis has been put on there being Perl values here. Conversion
170             between Perl and GraphQL values is taken care of by
171             L<scalar|GraphQL::Type::Scalar> types, and it is only scalar information
172             that will be returned to the client, albeit in the shape dictated by
173             the object types.
174              
175             An example function that takes a name and GraphQL type, and returns a
176             field definition, with a resolver that calls read-only L<Moo> accessors,
177             suitable for placing (several of) inside the hash-ref defining a type's
178             fields:
179              
180             sub _make_moo_field {
181             my ($field_name, $type) = @_;
182             ($field_name => { resolve => sub {
183             my ($root_value, $args, $context, $info) = @_;
184             my @passon = %$args ? ($args) : ();
185             return undef unless $root_value->can($field_name);
186             $root_value->$field_name(@passon);
187             }, type => $type });
188             }
189             # ...
190             fields => {
191             _make_moo_field(name => $String),
192             _make_moo_field(description => $String),
193             },
194             # ...
195              
196             The code-ref will be called with these parameters:
197              
198             =head4 $source
199              
200             The Perl entity (possibly a blessed object) returned by the resolver
201             that conjured up this GraphQL object.
202              
203             =head4 $args
204              
205             Hash-ref of the arguments passed to the field. The values will be
206             Perl values.
207              
208             =head4 $context
209              
210             The "context" value supplied to the call to
211             L<GraphQL::Execution/execute>. Can be used for authenticated user
212             information, or a per-request cache.
213              
214             =head4 $info
215              
216             A hash-ref describing this node of the request; see L</info hash> below.
217              
218             =head3 info hash
219              
220             =head4 field_name
221              
222             The real name of this field.
223              
224             =head4 field_nodes
225              
226             The array of Abstract Syntax Tree (AST) nodes that refer to this field
227             in this "selection set" (set of fields) on this object. There may be
228             more than one such set for a given field, if it is requested more
229             than once with a given name (not with an alias) - the results will
230             be combined into one reply.
231              
232             =head4 return_type
233              
234             The return type.
235              
236             =head4 parent_type
237              
238             The type of which this field is part.
239              
240             =head4 path
241              
242             The hierarchy of fields from the query root to this field-resolution.
243              
244             =head4 schema
245              
246             L<GraphQL::Schema> object.
247              
248             =head4 fragments
249              
250             Any fragments applying to this request.
251              
252             =head4 root_value
253              
254             The "root value" given to C<execute>.
255              
256             =head4 operation
257              
258             A hash-ref describing the operation (C<query>, etc) being executed.
259              
260             =head4 variable_values
261              
262             the operation's arguments, filled out with the variables hash supplied
263             to the request.
264              
265             =head4 promise_code
266              
267             A hash-ref. The relevant value supplied to the C<execute> function.
268              
269             =cut
270              
271             declare "FieldMapOutput", as Map[
272             StrNameValid,
273             Dict[
274             type => ConsumerOf['GraphQL::Role::Output'],
275             args => Optional[FieldMapInput],
276             resolve => Optional[CodeRef],
277             subscribe => Optional[CodeRef],
278             directives => Optional[ArrayRef[HashRef]],
279             deprecation_reason => Optional[Str],
280             description => Optional[Str],
281             ]
282             ];
283              
284             =head2 Int32Signed
285              
286             32-bit signed integer.
287              
288             =cut
289              
290             declare "Int32Signed", as Int, where { $_ >= -2147483648 and $_ <= 2147483647 };
291              
292             =head2 ArrayRefNonEmpty
293              
294             Like L<Types::Standard/ArrayRef> but requires at least one entry.
295              
296             =cut
297              
298             declare "ArrayRefNonEmpty", constraint_generator => sub {
299             intersection [ ArrayRef[@_], Tuple[Any, slurpy Any] ]
300             };
301              
302             =head2 UniqueByProperty
303              
304             An ArrayRef, its members' property (the one in the parameter) can occur
305             only once.
306              
307             use Moo;
308             use GraphQL::Type::Library -all;
309             has types => (
310             is => 'ro',
311             isa => UniqueByProperty['name'] & ArrayRef[InstanceOf['GraphQL::Type::Object']],
312             required => 1,
313             );
314              
315             =cut
316              
317             declare "UniqueByProperty",
318             constraint_generator => sub {
319             die "must give one property name" unless @_ == 1;
320             my ($prop) = @_;
321             declare as ArrayRef[HasMethods[$prop]], where {
322             my %seen;
323             !grep $seen{$_->$prop}++, @$_;
324             }, inline_as {
325             (undef, "my %seen; !grep \$seen{\$_->$prop}++, \@{$_[1]};");
326             };
327             };
328              
329             =head2 ExpectObject
330              
331             A C<Maybe[HashRef]> that produces a GraphQL-like message if it fails,
332             saying "found not an object".
333              
334             =cut
335              
336             declare "ExpectObject",
337             as Maybe[HashRef],
338 0         0 message { "found not an object" };
339              
340             =head2 DocumentLocation
341              
342             Hash-ref that has keys C<line> and C<column> which are C<Int>.
343              
344             =cut
345              
346             declare "DocumentLocation",
347             as Dict[
348             line => Int,
349             column => Int,
350             ];
351              
352             =head2 JSONable
353              
354             A value that will be JSON-able.
355              
356             =cut
357              
358             declare "JSONable",
359             as Any,
360 0         0 where { $JSON->encode($_); 1 };
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         83  
361              
362             =head2 ErrorResult
363              
364             Hash-ref that has keys C<message>, C<location>, C<path>, C<extensions>.
365              
366             =cut
367              
368             declare "ErrorResult",
369             as Dict[
370             message => Str,
371             path => Optional[ArrayRef[Str]],
372             locations => Optional[ArrayRef[DocumentLocation]],
373             extensions => Optional[HashRef[JSONable]],
374             ];
375              
376             =head2 ExecutionResult
377              
378             Hash-ref that has keys C<data> and/or C<errors>.
379              
380             The C<errors>, if present, will be an array-ref of C<ErrorResult>.
381              
382             The C<data> if present will be the return data, being a hash-ref whose
383             values are either further hashes, array-refs, or scalars. It will be
384             JSON-able.
385              
386             =cut
387              
388             declare "ExecutionResult",
389             as Dict[
390             data => Optional[JSONable],
391             errors => Optional[ArrayRef[ErrorResult]],
392             ];
393              
394             =head2 ExecutionPartialResult
395              
396             Hash-ref that has keys C<data> and/or C<errors>. Like L</ExecutionResult>
397             above, but the C<errors>, if present, will be an array-ref of
398             L<GraphQL::Error> objects.
399              
400             =cut
401              
402             declare "ExecutionPartialResult",
403             as Dict[
404             data => Optional[JSONable],
405             errors => Optional[ArrayRef[InstanceOf['GraphQL::Error']]],
406             ];
407              
408             =head2 Promise
409              
410             An object that has a C<then> method.
411              
412             =cut
413              
414             declare "Promise",
415             as HasMethods[qw(then)];
416              
417             =head2 PromiseCode
418              
419             A hash-ref with three keys: C<resolve>, C<all>, C<reject>. The values are
420             all code-refs that take one value (for C<all>, an array-ref), and create
421             the given kind of Promise.
422              
423             An example, enabling interoperation with L<Promises>:
424              
425             use Promises qw(collect resolved rejected);
426             {
427             all => \&collect,
428             resolve => \&resolved,
429             reject => \&rejected,
430             },
431              
432             Must also have a C<new> key for use with L<GraphQL::Subscription>,
433             with code returning a promise that can then have C<resolve> or C<reject>
434             called on it.
435              
436             =cut
437              
438             declare "PromiseCode",
439             as Dict[
440             resolve => CodeLike,
441             all => CodeLike,
442             reject => CodeLike,
443             new => Optional[CodeLike],
444             ];
445              
446             =head2 AsyncIterator
447              
448             An instance of L<GraphQL::AsyncIterator>.
449              
450             =cut
451              
452             declare "AsyncIterator",
453             as InstanceOf['GraphQL::AsyncIterator'];
454              
455             =head1 AUTHOR
456              
457             Ed J, C<< <etj at cpan.org> >>
458              
459             =cut
460              
461             1;