File Coverage

blib/lib/RDF/AllegroGraph/Repository3.pm
Criterion Covered Total %
statement 33 201 16.4
branch 0 72 0.0
condition 0 24 0.0
subroutine 11 28 39.2
pod 14 15 93.3
total 58 340 17.0


line stmt bran cond sub pod time code
1             package RDF::AllegroGraph::Repository3;
2              
3 15     15   89 use strict;
  15         26  
  15         539  
4 15     15   81 use warnings;
  15         28  
  15         418  
5              
6 15     15   71 use base qw(RDF::AllegroGraph::Repository);
  15         25  
  15         8699  
7              
8 15     15   100 use Data::Dumper;
  15         36  
  15         870  
9 15     15   6201 use feature "switch";
  15         154  
  15         1403  
10              
11 15     15   90 use JSON;
  15         28  
  15         451  
12 15     15   2205 use URI::Escape qw/uri_escape_utf8/;
  15         32  
  15         895  
13              
14 15     15   15440 use HTTP::Request::Common;
  15         34272  
  15         7513  
15              
16             =pod
17              
18             =head1 NAME
19              
20             RDF::AllegroGraph::Repository3 - AllegroGraph repository handle for AGv3
21              
22             =cut
23              
24             sub new {
25 0     0 0   my $class = shift;
26 0           my %options = @_;
27 0           my $self = bless \%options, $class;
28 0           $self->{path} = $self->{CATALOG}->{SERVER}->{ADDRESS} . '/catalogs' . $self->{CATALOG}->{NAME} . '/repositories/' . $self->{id};
29 0           return $self;
30             }
31              
32             sub id {
33 0     0 1   my $self = shift;
34 0           return $self->{CATALOG}->{NAME} . '/' . $self->{id};
35             }
36              
37             sub disband {
38 0     0 1   my $self = shift;
39 0           my $requ = HTTP::Request->new (DELETE => $self->{path});
40 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->request ($requ);
41 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
42             }
43              
44             sub size {
45 0     0 1   my $self = shift;
46 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($self->{path} . '/size');
47 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
48 0           return $resp->content;
49             }
50              
51             sub add {
52 0     0 1   _put_post_stmts ('POST', @_);
53             }
54              
55             sub _put_post_stmts {
56 0     0     my $method = shift;
57 0           my $self = shift;
58              
59 0           my @stmts; # collect triples there
60             my $n3; # collect N3 stuff there
61 0           my @files; # collect file names here
62 15     15   134 use Regexp::Common qw/URI/;
  15         34  
  15         223  
63              
64 0           foreach my $item (@_) { # walk through what we got
65 0 0         if (ref($item) eq 'ARRAY') { # a triple statement
    0          
    0          
    0          
    0          
66 0           push @stmts, $item;
67             } elsif (ref ($item)) {
68 0           die "don't know what to do with it";
69             } elsif ($item =~ /^$RE{URI}{HTTP}/) {
70 0           push @files, $item;
71             } elsif ($item =~ /^$RE{URI}{FTP}/) {
72 0           push @files, $item;
73             } elsif ($item =~ /^$RE{URI}{file}/) {
74 0           push @files, $item;
75             } else { # scalar => N3
76 0           $n3 .= $item;
77             }
78             }
79              
80 0           my $ua = $self->{CATALOG}->{SERVER}->{ua}; # local handle
81              
82 0 0         if (@stmts) { # if we have something to say to the server
83 0           given ($method) {
84 0           when ('POST') {
85 0           my $resp = $ua->post ($self->{path} . '/statements',
86             'Content-Type' => 'application/json', 'Content' => encode_json (\@stmts) );
87 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
88             }
89 0           when ('PUT') {
90 0           my $requ = HTTP::Request->new (PUT => $self->{path} . '/statements',
91             [ 'Content-Type' => 'application/json' ], encode_json (\@stmts));
92 0           my $resp = $ua->request ($requ);
93 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
94             }
95 0           when ('DELETE') { # DELETE
96             # first bulk delete facts, i.e. where there are no wildcards
97 0 0 0       my @facts = grep { defined $_->[0] && defined $_->[1] && defined $_->[2] } @stmts;
  0            
98 0           my $requ = HTTP::Request->new (POST => $self->{path} . '/statements/delete',
99             [ 'Content-Type' => 'application/json' ], encode_json (\@facts));
100 0           my $resp = $ua->request ($requ);
101 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
102              
103             # the delete one by one those with wildcards
104 0   0       my @wildcarded = grep { ! defined $_->[0] || ! defined $_->[1] || ! defined $_->[2] } @stmts;
  0            
105 0           foreach my $w (@wildcarded) {
106 0           my $requ = HTTP::Request->new (DELETE => $self->{path} . '/statements' . '?' . _to_uri ($w) );
107 0           my $resp = $ua->request ($requ);
108 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
109             }
110             }
111 0           default { die $method; }
  0            
112             }
113             }
114 0 0         if ($n3) { # if we have something to say to the server
115 0           my $requ = HTTP::Request->new ($method => $self->{path} . '/statements', [ 'Content-Type' => 'text/plain' ], $n3);
116 0           my $resp = $ua->request ($requ);
117 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
118             }
119 0           for my $file (@files) { # if we have something to say to the server
120 15     15   20274 use LWP::Simple;
  15         31  
  15         138  
121 0 0         my $content = get ($file) or die "Could not open URL '$file'";
122 0           my $mime; # lets guess the mime type
123 0           given ($file) { # magic does not normally cope well with RDF/N3, so do it by extension
124 0           when (/\.n3$/) { $mime = 'text/plain'; } # well, not really, since its text/n3
  0            
125 0           when (/\.nt$/) { $mime = 'text/plain'; }
  0            
126 0           when (/\.xml$/) { $mime = 'application/rdf+xml'; }
  0            
127 0           when (/\.rdf$/) { $mime = 'application/rdf+xml'; }
  0            
128 0           default { die; }
  0            
129             }
130              
131 0           my $requ = HTTP::Request->new ($method => $self->{path} . '/statements', [ 'Content-Type' => $mime ], $content);
132 0           my $resp = $ua->request ($requ);
133 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
134              
135 0           $method = 'POST'; # whatever the first was, the others must add to it!
136             }
137              
138              
139             }
140              
141             sub _to_uri {
142 0     0     my $w = shift;
143 0           my @params;
144 0 0         push @params, 'subj='.$w->[0] if $w->[0];
145 0 0         push @params, 'pred='.$w->[1] if $w->[1];
146 0 0         push @params, 'obj=' .$w->[2] if $w->[2];
147 0           return join ('&', @params); # TODO URI escape?
148             }
149              
150             sub replace {
151 0     0 1   _put_post_stmts ('PUT', @_);
152             }
153              
154             sub delete {
155 0     0 1   _put_post_stmts ('DELETE', @_);
156             }
157              
158             sub match {
159 0     0 1   my $self = shift;
160 0           my @stmts;
161              
162 0           my $ua = $self->{CATALOG}->{SERVER}->{ua};
163 0           foreach my $w (@_) {
164 0           my $resp = $ua->get ($self->{path} . '/statements' . '?' . _to_uri ($w));
165 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
166 0           push @stmts, @{ from_json ($resp->content) };
  0            
167             }
168 0           return @stmts;
169             }
170              
171             sub sparql {
172 0     0 1   my $self = shift;
173 0           my $query = shift;
174 0           my %options = @_;
175 0   0       $options{RETURN} ||= 'TUPLE_LIST'; # a good default
176              
177 0           my @params;
178 0           push @params, 'queryLn=sparql';
179 0           push @params, 'query='.uri_escape_utf8 ($query);
180            
181 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($self->{path} . '?' . join ('&', @params) );
182 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
183              
184 0           my $json = from_json ($resp->content);
185 0           given ($options{RETURN}) {
186 0           when ('TUPLE_LIST') {
187 0           return @{ $json->{values} };
  0            
188             }
189 0           default { die };
  0            
190             }
191             }
192              
193             sub namespaces {
194 0     0 1   my $self = shift;
195 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($self->{path} . '/namespaces');
196 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
197             return
198 0           map { $_->{prefix} => $_->{namespace} }
  0            
199 0           @{ from_json ($resp->content) };
200             }
201              
202             sub namespace {
203 0     0 1   my $self = shift;
204 0           my $prefix = shift;
205              
206 0           my $uri = $self->{path} . '/namespaces/' . $prefix;
207 0 0         if (scalar @_) { # there was a second argument!
208 0 0         if (my $nsuri = shift) {
209 0           my $requ = HTTP::Request->new ('PUT' => $uri, [ 'Content-Type' => 'text/plain' ], $nsuri);
210 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->request ($requ);
211 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
212 0           return $nsuri;
213             } else {
214 0           my $requ = HTTP::Request->new ('DELETE' => $uri);
215 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->request ($requ);
216 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
217             }
218             } else {
219 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($uri);
220 0 0         return undef if $resp->code == 404;
221 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
222 0   0       return $resp->content =~ m/^"?(.*?)"?$/ && $1;
223             }
224             }
225              
226             sub geotypes {
227 0     0 1   my $self = shift;
228 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($self->{path} . '/geo/types');
229 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
230 0           return @{ from_json ($resp->content) };
  0            
231             }
232              
233             sub cartesian {
234 0     0 1   my $self = shift;
235              
236 0           my $url = new URI ($self->{path} . '/geo/types/cartesian');
237              
238 15     15   38410 use Regexp::Common;
  15         35  
  15         107  
239 0 0         if ($_[0] =~ /($RE{num}{real})x($RE{num}{real})(\+($RE{num}{real})\+($RE{num}{real}))?/) {
240 0           shift;
241 0   0       my ($W, $H, $X, $Y) = ($1, $2, $4||0, $5||0);
      0        
242 0           my $stripW = shift;
243 0           $url->query_form (stripWidth => $stripW, xmin => $X, xmax => $X+$W, ymin => $Y, ymax => $Y+$H);
244             } else {
245 0           my ($X1, $Y1, $X2, $Y2, $stripW) = @_;
246 0           $url->query_form (stripWidth => $stripW, xmin => $X1, xmax => $X2, ymin => $Y1, ymax => $Y2);
247             }
248              
249 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (PUT $url);
250 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
251 0   0       return $resp->content =~ m/^"?(.*?)"?$/ && $1;
252             }
253              
254             sub inBox {
255 0     0 1   my $self = shift;
256 0           my $geotype = shift;
257 0           my $pred = shift;
258 0           my ($xmin, $ymin, $xmax, $ymax) = @_;
259 0           my $options = $_[4];
260              
261 0           my $url = new URI ($self->{path} . '/geo/box');
262 0 0 0       $url->query_form (type => $geotype,
263             predicate => $pred,
264             xmin => $xmin,
265             ymin => $ymin,
266             xmax => $xmax,
267             ymax => $ymax,
268             ($options && defined $options->{limit}
269             ? (limit => $options->{limit})
270             : ())
271             );
272 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (GET $url);
273 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
274 0           return @{ from_json ($resp->content) };
  0            
275             }
276              
277             sub inCircle {
278 0     0 1   my $self = shift;
279 0           my $geotype = shift;
280 0           my $pred = shift;
281 0           my ($x, $y, $radius) = @_;
282 0           my $options = $_[3];
283              
284 0           my $url = new URI ($self->{path} . '/geo/circle');
285 0 0 0       $url->query_form (type => $geotype,
286             predicate => $pred,
287             x => $x,
288             y => $y,
289             radius => $radius,
290             ($options && defined $options->{limit}
291             ? (limit => $options->{limit})
292             : ())
293             );
294 0           my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (GET $url);
295 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
296 0           return @{ from_json ($resp->content) };
  0            
297             }
298              
299              
300             our $VERSION = '0.04';
301              
302             1;
303              
304             __END__