File Coverage

blib/lib/GraphQL/Client.pm
Criterion Covered Total %
statement 96 97 98.9
branch 24 30 80.0
condition 12 18 66.6
subroutine 26 26 100.0
pod 6 6 100.0
total 164 177 92.6


line stmt bran cond sub pod time code
1             package GraphQL::Client;
2             # ABSTRACT: A GraphQL client
3              
4 2     2   93594 use warnings;
  2         15  
  2         89  
5 2     2   12 use strict;
  2         5  
  2         94  
6              
7 2     2   1037 use Module::Load qw(load);
  2         2388  
  2         13  
8 2     2   179 use Scalar::Util qw(reftype);
  2         4  
  2         140  
9 2     2   1002 use namespace::clean;
  2         34742  
  2         16  
10              
11             our $VERSION = '0.603'; # VERSION
12              
13 1     1   6 sub _croak { require Carp; goto &Carp::croak }
  1         34  
14 2     2   24 sub _throw { GraphQL::Client::Error->throw(@_) }
15              
16             sub new {
17 6     6 1 9339 my $class = shift;
18 6         30 bless {@_}, $class;
19             }
20              
21             sub execute {
22 13     13 1 7037 my $self = shift;
23 13         30 my ($query, $variables, $operation_name, $options) = @_;
24              
25 13 100 100     75 if ((reftype($operation_name) || '') eq 'HASH') {
26 1         4 $options = $operation_name;
27 1         3 $operation_name = undef;
28             }
29              
30 13 100 66     58 my $request = {
    100          
31             query => $query,
32             ($variables && %$variables) ? (variables => $variables) : (),
33             $operation_name ? (operationName => $operation_name) : (),
34             };
35              
36 13         30 return $self->_handle_result($self->transport->execute($request, $options));
37             }
38              
39             sub _handle_result {
40 13     13   160 my $self = shift;
41 13         23 my ($result) = @_;
42              
43             my $handle_result = sub {
44 13     13   17 my $result = shift;
45 13         22 my $resp = $result->{response};
46 13 100       29 if (my $exception = $result->{error}) {
47 2         3 unshift @{$resp->{errors}}, {
  2         9  
48             message => "$exception",
49             };
50             }
51 13 100       26 if ($self->unpack) {
52 4 100       9 if ($resp->{errors}) {
53             _throw $resp->{errors}[0]{message}, {
54             type => 'graphql',
55             response => $resp,
56             details => $result->{details},
57 2         8 };
58             }
59 2         10 return $resp->{data};
60             }
61 9         59 return $resp;
62 13         58 };
63              
64 13 100       22 if (eval { $result->isa('Future') }) {
  13         96  
65             return $result->transform(
66             done => sub {
67 2     2   200 my $result = shift;
68 2         3 my $resp = eval { $handle_result->($result) };
  2         5  
69 2 50       6 if (my $err = $@) {
70 0         0 Future::Exception->throw("$err", $err->{type}, $err->{response}, $err->{details});
71             }
72 2         6 return $resp;
73             },
74 2         16 );
75             }
76             else {
77 11         26 return $handle_result->($result);
78             }
79             }
80              
81             sub url {
82 1     1 1 2 my $self = shift;
83 1         3 $self->{url};
84             }
85              
86             sub transport_class {
87 4     4 1 9 my $self = shift;
88 4         13 $self->{transport_class};
89             }
90              
91             sub transport {
92 16     16 1 76 my $self = shift;
93 16   66     69 $self->{transport} //= do {
94 3         8 my $class = $self->_autodetermine_transport_class;
95 3         7 eval { load $class };
  3         10  
96 3 100 66     279 if ((my $err = $@) || !$class->can('execute')) {
97 1   33     7 $err ||= "Loaded $class, but it doesn't look like a proper transport.\n";
98 1 50       5 warn $err if $ENV{GRAPHQL_CLIENT_DEBUG};
99 1         5 _croak "Failed to load transport for \"${class}\"";
100             }
101 2         12 $class->new(%$self);
102             };
103             }
104              
105             sub unpack {
106 13     13 1 21 my $self = shift;
107 13   100     42 $self->{unpack} //= 0;
108             }
109              
110             sub _url_protocol {
111 1     1   2 my $self = shift;
112              
113 1         4 my $url = $self->url;
114 1         7 my ($protocol) = $url =~ /^([^+:]+)/;
115              
116 1         3 return $protocol;
117             }
118              
119             sub _autodetermine_transport_class {
120 3     3   6 my $self = shift;
121              
122 3         7 my $class = $self->transport_class;
123 3 100       30 return _expand_class($class) if $class;
124              
125 1         5 my $protocol = $self->_url_protocol;
126 1 50       3 _croak 'Failed to determine transport from URL' if !$protocol;
127              
128 1         4 $class = lc($protocol);
129 1         3 $class =~ s/[^a-z]/_/g;
130              
131 1         3 return _expand_class($class);
132             }
133              
134             sub _expand_class {
135 3     3   10 my $class = shift;
136 3 50       15 $class = "GraphQL::Client::$class" unless $class =~ s/^\+//;
137 3         9 $class;
138             }
139              
140             {
141             package GraphQL::Client::Error;
142              
143 2     2   2584 use warnings;
  2         6  
  2         77  
144 2     2   18 use strict;
  2         4  
  2         95  
145              
146 2     2   13 use overload '""' => \&error, fallback => 1;
  2         4  
  2         33  
147              
148 2 50 50 2   3 sub new { bless {%{$_[2] || {}}, error => $_[1] || 'Something happened'}, $_[0] }
  2         33  
149              
150 3     3   439 sub error { "$_[0]->{error}" }
151 1     1   7 sub type { "$_[0]->{type}" }
152              
153             sub throw {
154 2     2   5 my $self = shift;
155 2 50       5 die $self if ref $self;
156 2         6 die $self->new(@_);
157             }
158             }
159              
160             1;
161              
162             __END__