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