File Coverage

blib/lib/Attean/SPARQLClient.pm
Criterion Covered Total %
statement 50 54 92.5
branch 3 8 37.5
condition 1 3 33.3
subroutine 11 11 100.0
pod 2 2 100.0
total 67 78 85.9


line stmt bran cond sub pod time code
1 50     50   617 use v5.14;
  50         165  
2 50     50   252 use warnings;
  50         112  
  50         2138  
3              
4             =head1 NAME
5              
6             Attean::SPARQLClient - RDF blank nodes
7              
8             =head1 VERSION
9              
10             This document describes Attean::SPARQLClient version 0.032
11              
12             =head1 SYNOPSIS
13              
14             use v5.14;
15             use Attean;
16             my $client = Attean::SPARQLClient->new(endpoint => 'http://example.org/sparql');
17             my $results = $client->query('SELECT * WHERE { ?s ?p ?o }');
18             while (my $r = $results->next) {
19             say $r->as_string;
20             }
21              
22             =head1 DESCRIPTION
23              
24             The Attean::SPARQLClient class provides an API to execute SPARQL queries
25             against a remote SPARQL Protocol endpoint.
26              
27             =head1 ATTRIBUTES
28              
29             The following attributes exist:
30              
31             =over 4
32              
33             =item C<< endpoint >>
34              
35             A URL of the remote service implementing the SPARQL 1.1 Protocol. This value
36             is a L<Attean::API::IRI>, but can be coerced from a string.
37              
38             =item C<< silent >>
39              
40             =item << user_agent >>
41              
42             =item C<< request_signer >>
43              
44             =back
45              
46             =head1 METHODS
47              
48             =over 4
49              
50             =cut
51              
52             use Moo;
53 50     50   279 use Types::Standard qw(ConsumerOf Bool Str InstanceOf);
  50         128  
  50         289  
54 50     50   15321 use Encode qw(encode);
  50         125  
  50         321  
55 50     50   35412 use Scalar::Util qw(blessed);
  50         108  
  50         2027  
56 50     50   367 use URI::Escape;
  50         164  
  50         2162  
57 50     50   364 use Attean::RDF qw(iri);
  50         125  
  50         2726  
58 50     50   407 use namespace::clean;
  50         121  
  50         403  
59 50     50   11695  
  50         130  
  50         340  
60             has 'endpoint' => (is => 'ro', isa => ConsumerOf['Attean::API::IRI'], coerce => sub { iri(shift) }, required => 1);
61             has 'silent' => (is => 'ro', isa => Bool, default => 0);
62             has 'user_agent' => (is => 'rw', isa => InstanceOf['LWP::UserAgent'], default => sub { my $ua = LWP::UserAgent->new(); $ua->agent("Attean/$Attean::VERSION " . $ua->_agent); $ua });
63             has 'request_signer' => (is => 'rw');
64              
65             =item C<< query_request( $sparql ) >>
66              
67             Returns an HTTP::Request object for the given SPARQL query string.
68              
69             =cut
70              
71             my $self = shift;
72             my $sparql = shift;
73 1     1 1 2 my $endpoint = $self->endpoint->value;
74 1         1 my $uri = URI->new($endpoint);
75 1         5 my %params = $uri->query_form;
76 1         11 $params{'query'} = $sparql;
77 1         2983 $uri->query_form(%params);
78 1         74 my $url = $uri->as_string;
79 1         5 my $req = HTTP::Request->new('GET', $url);
80 1         206 if (my $signer = $self->request_signer) {
81 1         17 $signer->sign($req);
82 1 50       132 }
83 0         0 return $req;
84             }
85 1         8  
86             =item C<< query( $sparql ) >>
87              
88             Executes the given SPARQL query string at the remote endpoint. If execution is
89             successful, returns an Attean::API::Iterator object with the results. If
90             execution fails but the client C<< silent >> flag is true, returns an empty
91             iterator. Otherwise raises an error via C<< die >>.
92              
93             =cut
94              
95             my $self = shift;
96             my $sparql = shift;
97             my $req = $self->query_request($sparql);
98 1     1 1 2 my $silent = $self->silent;
99 1         2 my $ua = $self->user_agent;
100 1         3
101 1         5 my $response = $ua->request($req);
102 1         22 if (blessed($response) and $response->is_success) {
103             my $type = $response->header('Content-Type');
104 1         16 my $pclass = Attean->get_parser(media_type => $type) or die "No parser for media type: $type";
105 1 50 33     1420 my $parser = $pclass->new();
    0          
106 1         55 my $xml = $response->decoded_content;
107 1 50       50 my $bytes = encode('UTF-8', $xml, Encode::FB_CROAK);
108 1         8 return $parser->parse_iter_from_bytes($bytes);
109 1         53 } elsif ($silent) {
110 1         2002 my $b = Attean::Result->new( bindings => {} );
111 1         34 return Attean::ListIterator->new(variables => [], values => [$b], item_type => 'Attean::API::Result');
112             } else {
113 0           die "SPARQL Protocol error: " . $response->status_line;
114 0           }
115             }
116 0           }
117              
118             1;
119              
120              
121             =back
122              
123             =head1 BUGS
124              
125             Please report any bugs or feature requests to through the GitHub web interface
126             at L<https://github.com/kasei/attean/issues>.
127              
128             =head1 SEE ALSO
129              
130             L<SPARQL 1.1 Protocol|https://www.w3.org/TR/sparql11-protocol/>
131              
132             =head1 AUTHOR
133              
134             Gregory Todd Williams C<< <gwilliams@cpan.org> >>
135              
136             =head1 COPYRIGHT
137              
138             Copyright (c) 2014--2022 Gregory Todd Williams.
139             This program is free software; you can redistribute it and/or modify it under
140             the same terms as Perl itself.
141              
142             =cut