File Coverage

blib/lib/RDF/Sesame/Repository.pm
Criterion Covered Total %
statement 9 185 4.8
branch 0 102 0.0
condition 0 3 0.0
subroutine 3 23 13.0
pod 10 11 90.9
total 22 324 6.7


line stmt bran cond sub pod time code
1             # vim modeline vim600: set foldmethod=marker :
2              
3             package RDF::Sesame::Repository;
4              
5 8     8   46 use strict;
  8         83  
  8         257  
6 8     8   42 use warnings;
  8         149  
  8         257  
7              
8 8     8   37 use Carp;
  8         12  
  8         23668  
9              
10             our $VERSION = '0.17';
11              
12             sub construct {
13 0     0 1   my $self = shift;
14              
15             # establish some sensible defaults
16 0           my %defaults = (
17             language => 'SeRQL',
18             );
19 0           my %opts = ( %defaults, @_ );
20              
21             # validate arguments and install options
22 0 0         croak "No serialization format specified" if !$opts{format};
23 0 0         croak "No query specified" if !$opts{query};
24              
25             # set up the output filehandle
26 0           my $output_fh;
27 0           my $output = q{};
28 0 0         if ( !defined( $opts{output} ) ) {
    0          
29 0           open($output_fh, '>', \$output);
30             }
31             elsif( ref($opts{output}) eq 'GLOB' ) {
32 0           $output_fh = $opts{output};
33             }
34             else {
35 0 0         open $output_fh, '>', $opts{output}
36             or croak "construct can't open $opts{output} for writing: $!";
37             }
38              
39             # construct RDF from Sesame
40             my $r = $self->command(
41             'evaluateGraphQuery',
42             {
43             serialization => $opts{format},
44             queryLanguage => $opts{language},
45             query => $opts{query},
46 0     0     ':content_cb' => sub { print $output_fh $_[0] },
47             }
48 0           );
49 0 0         croak $r->errstr() if !$r->success();
50 0           close $output_fh;
51              
52 0 0         return if defined $opts{output};
53 0           return $output;
54             }
55              
56             sub extract {
57 0     0 1   my $self = shift;
58              
59             # establish some sensible defaults
60 0           my %defaults = (
61             compress => 'none',
62             options => [],
63             );
64 0           my %opts = ( %defaults, @_ );
65              
66             # validate arguments and install options
67 0 0         croak "No serialization format specified" if !$opts{format};
68 0           my %boolean_options;
69 0           for my $option ( @{ $opts{options} } ) {
  0            
70 0           $boolean_options{$option} = 'on';
71             }
72              
73             # set up the output filehandle
74 0           my $output_fh;
75 0           my $output = q{};
76 0 0         if ( !defined( $opts{output} ) ) {
    0          
77 0           open($output_fh, '>', \$output);
78             }
79             elsif( ref($opts{output}) eq 'GLOB' ) {
80 0           $output_fh = $opts{output};
81             }
82             else {
83 0 0         open $output_fh, '>', $opts{output}
84             or croak "extract can't open $opts{output} for writing: $!";
85             }
86              
87             # find and initialize the 'compress' handlers
88 0 0         my $handlers = ref $opts{compress}
89             ? $opts{compress}
90             : $self->_get_compress_handlers()->{ $opts{compress} }
91             ;
92 0           my $context = $handlers->{init}->($output_fh);
93              
94             # extract RDF from Sesame
95             my $r = $self->command(
96             'extractRDF',
97             {
98             serialization => $opts{format},
99             %boolean_options,
100             ':content_cb' => sub {
101 0     0     $handlers->{content}->($context, $output_fh, $_[0]);
102             },
103             }
104 0           );
105 0 0         croak $r->errstr() if !$r->success();
106              
107 0           $handlers->{finish}->($context, $output_fh);
108 0           close $output_fh;
109              
110 0 0         return if defined $opts{output};
111 0           return $output;
112             }
113              
114             sub _get_compress_handlers {
115             return {
116             none => {
117 0     0     init => sub { return },
118             content => sub {
119 0     0     my (undef, $fh, $content) = @_;
120 0           print $fh $content;
121             },
122 0     0     finish => sub { return },
123             },
124             gz => {
125             init => sub {
126 0     0     my ($fh) = @_;
127 0           require Compress::Zlib;
128 0           binmode $fh;
129 0 0         my $gz = Compress::Zlib::gzopen( $fh, 'wb' )
130             or die "gz compression cannot open filehandle: $Compress::Zlib::gzerrno";
131 0           return $gz; # our context object
132             },
133             content => sub {
134 0     0     my ( $context, $fh, $content ) = @_;
135 0 0         $context->gzwrite($content)
136             or die "gz compression couldn't write: $Compress::Zlib::gzerrno";
137             },
138             finish => sub {
139 0     0     my ( $context, $fh ) = @_;
140 0           $context->gzclose();
141             },
142             },
143 0     0     };
144             }
145              
146             sub query_language {
147 0     0 1   my $self = shift;
148              
149 0           $self->{errstr} = ''; # assume no errors
150              
151 0 0         return $self->{lang} unless defined $_[0];
152              
153 0 0         unless( $_[0]=~/^RQL|RDQL|SeRQL$/ ) {
154 0           $self->{errstr} = Carp::shortmess("query language must be RQL, RDQL or SeRQL");
155 0           return $self->{lang};
156             }
157              
158 0           my $old = $self->{lang};
159              
160 0           $self->{lang} = $_[0];
161              
162 0           return $old;
163             }
164              
165             sub select {
166 0     0 1   my $self = shift;
167 0           $self->{errstr} = q{}; # assume no error
168              
169             # process the arguments
170 0 0         my %defaults = (
171             query => @_ == 1 ? shift : q{},
172             language => $self->query_language(),
173             strip => $self->{strip},
174             format => 'binary',
175             );
176 0           my %opts = ( %defaults, @_ );
177              
178 0           my $r = $self->command(
179             'evaluateTableQuery',
180             {
181             query => $opts{query},
182             queryLanguage => $opts{language},
183             resultFormat => $opts{format},
184             }
185             );
186              
187 0 0         if( !$r->success() ) {
188 0           $self->{errstr} = Carp::shortmess($r->errstr);
189 0           return q{};
190             }
191              
192 0           return RDF::Sesame::TableResult->new($r, strip => $opts{strip});
193             }
194              
195             sub upload_data {
196 0     0 1   my $self = shift;
197              
198 0           $self->{errstr} = ''; # assume no error
199              
200             # establish some sensible defaults
201 0           my %defaults = (
202             data => '',
203             format => 'ntriples',
204             verify => 1,
205             );
206              
207             # set the defaults for any option we weren't given
208 0           my %opts;
209 0 0         if( @_ == 1 ) {
210 0           $opts{data} = shift;
211             } else {
212 0           %opts = @_;
213             }
214 0           while( my ($k,$v) = each %defaults ) {
215 0 0         $opts{$k} = $v unless exists $opts{$k};
216             }
217              
218             # verify the format parameter
219 0 0         if( $opts{format} !~ /^rdfxml|ntriples|turtle$/ ) {
220 0           $self->{errstr} = Carp::shortmess("Format must be rdfxml, ntriples or turtle");
221 0           return 0;
222             }
223              
224 0 0         my $params = {
225             data => $opts{data},
226             dataFormat => $opts{format},
227             verifyData => $opts{verify} ? 'on' : 'off',
228             resultFormat => 'xml',
229             };
230              
231             # add in the base URI if we got it
232 0 0         $params->{baseURI} = $opts{base} if exists $opts{base};
233              
234 0           my $r = $self->command( 'uploadData', $params );
235              
236 0 0         unless( $r->success ) {
237 0           $self->{errstr} = Carp::shortmess($r->errstr);
238 0           return 0;
239             }
240              
241 0           foreach ( @{$r->parsed_xml->{status}} ) {
  0            
242 0           my $triple_count;
243 0 0         if( $_->{msg} =~ /^Data is correct and contains ([\d,]+) statement/ ) {
244 0           $triple_count = $1;
245             }
246 0 0         if( $_->{msg} =~ /^Processed ([\d,]+) statement/ ) {
247 0           $triple_count = $1;
248             }
249 0 0         if (defined $triple_count) {
250 0           $triple_count =~ s{,}{}xmsg;
251 0           return $triple_count;
252             }
253             }
254              
255 0           $self->{errstr} = Carp::shortmess('Unknown error');
256 0           return 0;
257             }
258              
259             sub upload_uri {
260 0     0 1   my $self = shift;
261              
262 0           $self->{errstr} = ''; # assume no error
263              
264             # set some sensible defaults
265 0           my %defaults = (
266             uri => '',
267             format => 'rdfxml',
268             verify => 1,
269             server_file => 0,
270             );
271              
272             # set the defaults for any option we weren't given
273 0           my %opts;
274 0 0         if( @_ == 1 ) {
275 0           $opts{uri} = shift;
276             } else {
277 0           %opts = @_;
278             }
279 0           while( my ($k,$v) = each %defaults ) {
280 0 0         $opts{$k} = $v unless exists $opts{$k};
281             }
282              
283             # set the default for the base URI
284 0 0         $opts{base} = $opts{uri} unless exists $opts{base};
285              
286             # validate the format option
287 0 0         if( $opts{format} !~ /^rdfxml|ntriples|turtle$/ ) {
288 0           $self->{errstr} = Carp::shortmess("Format must be rdfxml, ntriples or turtle");
289 0           return 0;
290             }
291              
292             # handle the "file:" URI scheme
293 0 0 0       if( $opts{uri} =~ /^file:/ && !$opts{server_file} ) {
294 0           require LWP::Simple;
295 0           my $content = LWP::Simple::get($opts{uri});
296 0 0         unless( defined $content ) {
297 0           $self->{errstr} = Carp::shortmess("No data in $opts{uri}");
298 0           return 0;
299             }
300              
301 0           delete $opts{uri};
302 0           return $self->upload_data(
303             data => $content,
304             %opts
305             );
306             }
307              
308 0 0         my $params = {
309             url => $opts{uri},
310             dataFormat => $opts{format},
311             verifyData => $opts{verify} ? 'on' : 'off',
312             resultFormat => 'xml',
313             baseURI => $opts{base},
314             };
315              
316 0           my $r = $self->command( 'uploadURL', $params );
317              
318 0 0         unless( $r->success ) {
319 0           $self->{errstr} = Carp::shortmess($r->errstr);
320 0           return 0;
321             }
322              
323 0           foreach ( @{$r->parsed_xml->{status}} ) {
  0            
324 0           my $triple_count;
325 0 0         if( $_->{msg} =~ /^Data is correct and contains ([\d,]+) statement/ ) {
    0          
326 0           $triple_count = $1;
327             }
328             elsif( $_->{msg} =~ /^Processed ([\d,]+) statement/ ) {
329 0           $triple_count = $1;
330             }
331 0 0         if (defined $triple_count) {
332 0           $triple_count =~ s{,}{}xmsg;
333 0           return $triple_count;
334             }
335             }
336              
337 0           $self->{errstr} = Carp::shortmess('Unknown error');
338 0           return 0;
339             }
340              
341             sub clear {
342 0     0 1   my $self = shift;
343              
344 0           my $r = $self->command('clearRepository', { resultFormat => 'xml' });
345              
346 0 0         return '' unless $r->success;
347              
348 0           foreach ( @{ $r->parsed_xml->{status} } ) {
  0            
349 0 0         if( $_->{msg} eq 'Repository cleared' ) {
350 0           return 1;
351             }
352             }
353              
354 0           return 0;
355             }
356              
357             sub remove {
358 0     0 1   my $self = shift;
359              
360             # prepare the parameters for the command
361 0           my $params = { resultFormat => 'xml' };
362 0 0         $params->{subject} = $_[0] if defined $_[0];
363 0 0         $params->{predicate} = $_[1] if defined $_[1];
364 0 0         $params->{object} = $_[2] if defined $_[2];
365              
366 0           my $r = $self->command('removeStatements', $params);
367              
368 0 0         unless( $r->success ) {
369 0           return 0;
370             }
371              
372 0           foreach ( @{ $r->parsed_xml->{notification} } ) {
  0            
373 0 0         if( $_->{msg} =~ /^Removed (\d+)/ ) {
374 0           return $1;
375             }
376             }
377              
378 0           return 0;
379             }
380              
381             sub errstr {
382 0     0 1   my $self = shift;
383              
384 0           return $self->{errstr};
385             }
386              
387             sub command {
388 0     0 1   my $self = shift;
389              
390 0           $self->{conn}->command($self->{id}, $_[0], $_[1]);
391             }
392              
393             # This method should really only be called from
394             # RDF::Sesame::Connection::open.
395             # As parameters, it takes an RDF::Sesame::Connection object and
396             # some named parameters
397             sub new {
398 0     0 0   my $class = shift;
399 0           my $conn = shift;
400              
401             # prepare the options we were given
402 0           my %opts;
403 0 0         if( @_ == 1 ) {
404 0           $opts{id} = shift;
405             } else {
406 0           %opts = @_;
407             }
408 0 0         return '' unless defined $opts{id};
409              
410 0           my $self = bless {
411             id => $opts{id}, # our repository ID
412             conn => $conn, # a connection for accessing the server
413             lang => 'SeRQL', # the default query language
414             errstr => '', # the most recent error string
415             strip => 'none', # the default strip option for select()
416             }, $class;
417              
418 0 0         if( exists $opts{query_language} ) {
419 0           $self->query_language($opts{query_language});
420             }
421              
422 0 0         $self->{strip} = $opts{strip} if exists $opts{strip};
423              
424 0           return $self;
425             }
426              
427             1;
428              
429             __END__