File Coverage

blib/lib/RDF/AllegroGraph/Repository.pm
Criterion Covered Total %
statement 18 97 18.5
branch 0 36 0.0
condition 0 6 0.0
subroutine 6 23 26.0
pod 15 15 100.0
total 39 177 22.0


line stmt bran cond sub pod time code
1             package RDF::AllegroGraph::Repository;
2              
3 15     15   108 use strict;
  15         29  
  15         585  
4 15     15   82 use warnings;
  15         32  
  15         546  
5              
6             require Exporter;
7 15     15   75 use base qw(Exporter);
  15         24  
  15         1082  
8              
9 15     15   100 use feature 'switch';
  15         32  
  15         3809  
10              
11             =pod
12              
13             =head1 NAME
14              
15             RDF::AllegroGraph::Repository - AllegroGraph repository handle
16              
17             =head1 DESCRIPTION
18              
19             An AllegroGraph repository corresponds to an RDF model. Into such a model you can park RDF
20             information, either as individual statements or via file bulk loading. Then you can navigate through
21             it on a statement level, or query that model.
22              
23             =head1 INTERFACE
24              
25             =head2 Constructor
26              
27             The constructor expects the following fields:
28              
29             =over
30              
31             =item C (mandatory)
32              
33             This is the handle to the catalog the repository belongs to.
34              
35             =item C (mandatory)
36              
37             This identifier is always of the form C.
38              
39             =back
40              
41             Example:
42              
43             my $repo = new RDF::AllegroGraph::Repository (CATALOG => $cat, id => '/whereever');
44              
45             =head2 Methods
46              
47             =over
48              
49             =item B
50              
51             This read-only accessor method returns the id of the repository.
52              
53             =cut
54              
55             sub id {
56 0     0 1   die;
57             }
58              
59             =pod
60              
61             =item B
62              
63             I<$repo>->disband
64              
65             This method removes the repository from the server. The object cannot be used after that, obviously.
66              
67             =cut
68              
69             sub disband {
70 0     0 1   die;
71             }
72              
73             =pod
74              
75             =item B
76              
77             I<$nr_triples> = I<$repo>->size
78              
79             Returns the size of the repository in terms of the number of triples.
80              
81             B: As of time of writing, AllegroGraph counts duplicate triples!
82              
83             =cut
84              
85             sub size {
86 0     0 1   die;
87             }
88              
89             =pod
90              
91             =item B
92              
93             I<$repo>->add ('file://....', ...)
94              
95             I<$repo>->add ('http://....', ...)
96              
97             I<$repo>->add (' triples in N3 ', ...)
98              
99             I<$repo>->add ([ I<$subj_uri>, I<$pred_uri>, I<$obj_uri> ], ...)
100              
101             This method adds triples to the repository. The information can be provided in any of the following
102             ways (also mixed):
103              
104             =over
105              
106             =item file, HTTP, FTP URL
107              
108             If a string looks like an URL, it will be dereferenced, the contents of the resource consulted and
109             that shipped to the repository on the server. If the resource cannot be read, an exception C
110             not open> will be raised. Any number of these URLs can be provided as parameter.
111              
112             B: Only N3 files are supported, and also only when the URL ends with the extension C or
113             C.
114              
115             =item N3 triple string
116              
117             If the string looks like N3 notated triples, that content is shipped to the server.
118              
119             =item ARRAY reference
120              
121             The reference is interpreted as one triple (statement), containing 3 URIs. These will be shipped
122             as-is to the server.
123              
124             =back
125              
126             If the server chokes on any of the above, an exception C is raised.
127              
128             B: There are no precautions for over-large content. Yet.
129              
130             B: Named graphs (aka I) are not handled. Yet.
131              
132              
133             =cut
134              
135             sub add {
136 0     0 1   die;
137             }
138              
139             sub _put_post_stmts {
140 0     0     my $method = shift;
141 0           my $self = shift;
142              
143 0           my @stmts; # collect triples there
144             my $n3; # collect N3 stuff there
145 0           my @files; # collect file names here
146 15     15   17849 use Regexp::Common qw/URI/;
  15         44985  
  15         82  
147              
148 0           foreach my $item (@_) { # walk through what we got
149 0 0         if (ref($item) eq 'ARRAY') { # a triple statement
    0          
    0          
    0          
    0          
150 0           push @stmts, $item;
151             } elsif (ref ($item)) {
152 0           die "don't know what to do with it";
153             } elsif ($item =~ /^$RE{URI}{HTTP}/) {
154 0           push @files, $item;
155             } elsif ($item =~ /^$RE{URI}{FTP}/) {
156 0           push @files, $item;
157             } elsif ($item =~ /^$RE{URI}{file}/) {
158 0           push @files, $item;
159             } else { # scalar => N3
160 0           $n3 .= $item;
161             }
162             }
163              
164 0           my $ua = $self->{CATALOG}->{SERVER}->{ua}; # local handle
165              
166 0 0         if (@stmts) { # if we have something to say to the server
167 0           given ($method) {
168 0           when ('POST') {
169 0           my $resp = $ua->post ($self->{path} . '/statements',
170             'Content-Type' => 'application/json', 'Content' => encode_json (\@stmts) );
171 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
172             }
173 0           when ('PUT') {
174 0           my $requ = HTTP::Request->new (PUT => $self->{path} . '/statements',
175             [ 'Content-Type' => 'application/json' ], encode_json (\@stmts));
176 0           my $resp = $ua->request ($requ);
177 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
178             }
179 0           when ('DELETE') { # DELETE
180             # first bulk delete facts, i.e. where there are no wildcards
181 0 0 0       my @facts = grep { defined $_->[0] && defined $_->[1] && defined $_->[2] } @stmts;
  0            
182 0           my $requ = HTTP::Request->new (POST => $self->{path} . '/statements/delete',
183             [ 'Content-Type' => 'application/json' ], encode_json (\@facts));
184 0           my $resp = $ua->request ($requ);
185 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
186              
187             # the delete one by one those with wildcards
188 0   0       my @wildcarded = grep { ! defined $_->[0] || ! defined $_->[1] || ! defined $_->[2] } @stmts;
  0            
189 0           foreach my $w (@wildcarded) {
190 0           my $requ = HTTP::Request->new (DELETE => $self->{path} . '/statements' . '?' . _to_uri ($w) );
191 0           my $resp = $ua->request ($requ);
192 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
193             }
194             }
195 0           default { die $method; }
  0            
196             }
197             }
198 0 0         if ($n3) { # if we have something to say to the server
199 0           my $requ = HTTP::Request->new ($method => $self->{path} . '/statements', [ 'Content-Type' => 'text/plain' ], $n3);
200 0           my $resp = $ua->request ($requ);
201 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
202             }
203 0           for my $file (@files) { # if we have something to say to the server
204 15     15   689174 use LWP::Simple;
  15         451406  
  15         153  
205 0 0         my $content = get ($file) or die "Could not open URL '$file'";
206 0           my $mime; # lets guess the mime type
207 0           given ($file) { # magic does not normally cope well with RDF/N3, so do it by extension
208 0           when (/\.n3$/) { $mime = 'text/plain'; } # well, not really, since its text/n3
  0            
209 0           when (/\.nt$/) { $mime = 'text/plain'; }
  0            
210 0           when (/\.xml$/) { $mime = 'application/rdf+xml'; }
  0            
211 0           when (/\.rdf$/) { $mime = 'application/rdf+xml'; }
  0            
212 0           default { die; }
  0            
213             }
214              
215 0           my $requ = HTTP::Request->new ($method => $self->{path} . '/statements', [ 'Content-Type' => $mime ], $content);
216 0           my $resp = $ua->request ($requ);
217 0 0         die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success;
218              
219 0           $method = 'POST'; # whatever the first was, the others must add to it!
220             }
221              
222              
223             }
224              
225             sub _to_uri {
226 0     0     my $w = shift;
227 0           my @params;
228 0 0         push @params, 'subj='.$w->[0] if $w->[0];
229 0 0         push @params, 'pred='.$w->[1] if $w->[1];
230 0 0         push @params, 'obj=' .$w->[2] if $w->[2];
231 0           return join ('&', @params); # TODO URI escape?
232             }
233              
234             =pod
235              
236             =item B
237              
238             This method behaves exactly like C, except that any existing content in the repository is wiped
239             before adding anything.
240              
241             =cut
242              
243             sub replace {
244 0     0 1   die;
245             }
246              
247             =pod
248              
249             =item B
250              
251             I<$repo>->delete ([ I<$subj_uri>, I<$pred_uri>, I<$obj_uri> ], ...)
252              
253             This method removes the passed in triples from the repository. In that process, any combination of
254             the subject URI, the predicate or the object URI can be left C. That is interpreted as
255             wildcard which matches anything.
256              
257             Example: This deletes anything where the Stephansdom is the subject:
258              
259             $air->delete ([ '', undef, undef ])
260              
261             =cut
262              
263             sub delete {
264 0     0 1   die;
265             }
266              
267             =pod
268              
269             =item B
270              
271             I<@stmts> = I<$repo>->match ([ I<$subj_uri>, I<$pred_uri>, I<$obj_uri> ], ...)
272              
273             This method returns a list of all statements which match one of the triples provided
274             as parameter. Any C as URI within such a triple is interpreted as wildcard, matching
275             any other URI.
276              
277             (Since v0.06): The object part can now be a range of values. You simply provide an array reference
278             with the lower and the upper bound as values in the array, such as for example
279              
280             $repo->match ([ undef, undef, [ '"1"^^my:type', '"10"^^my:type' ] ]);
281              
282             B: Subject range queries and predicate range queries are not supported as RDF would not allow
283             literals at these places anyway.
284              
285             (Since v0.06): For AGv4 there is now a way to configure some options when fetching matching triples:
286             Simply provide as first parameter an options hash:
287              
288             $repo->match ({ limit => 10 }, [ undef, .....]);
289              
290             These options will apply to all passed in match patterns SEPARATELY, so that with several patterns
291             you might well get more than your limit.
292              
293             =cut
294              
295             sub match {
296 0     0 1   die;
297             }
298              
299             =pod
300              
301             =item B
302              
303             I<@tuples> = I<$repo>->sparql ('SELECT ...')
304              
305             I<@tuples> = I<$repo>->sparql ('SELECT ...' [, I<$option> => I<$value> ])
306              
307             This method takes a SPARQL query string and returns a list of tuples which the query produced from
308             the repository.
309              
310             B: At the moment only SELECT queries are supported.
311              
312             As additional options are accepted:
313              
314             =over
315              
316             =item C (default: C)
317              
318             The result will be a sequence of (references to) arrays. All naming of the individual columns is
319             currently lost.
320              
321             =back
322              
323             =cut
324              
325             sub sparql {
326 0     0 1   die;
327             }
328              
329             =pod
330              
331             =back
332              
333             =head2 Namespace Support
334              
335             =over
336              
337             =item B
338              
339             I<%ns> = I<$repo>->namespaces
340              
341             This read-only function returns a hash containing the namespaces: keys
342             are the prefixes, values are the namespace URIs.
343              
344             B: No AllegroGraph I is honored at the moment.
345              
346             =cut
347              
348             sub namespaces {
349 0     0 1   die;
350             }
351              
352             =pod
353              
354             =item B
355              
356             $uri = $repo->namespace ($prefix)
357              
358             $uri = $repo->namespace ($prefix => $uri)
359              
360             $repo->namespace ($prefix => undef)
361              
362             This method fetches, sets and deletes prefix/uri namespaces. If only the prefix is given,
363             it will look up the namespace URI. If the URI is provided as second parameter, it will set/overwrite
364             that prefix. If the second parameter is C, it will delete the namespace associated with it.
365              
366             B: No I is honored at the moment.
367              
368             =cut
369              
370             sub namespace {
371 0     0 1   die;
372             }
373              
374             =pod
375              
376             =back
377              
378             =head2 GeoSpatial Support
379              
380             =over
381              
382             =item B
383              
384             I<@geotypes> = I<$repo>->geotypes
385              
386             This method returns a list of existing geotypes (in form of specially
387             crafted URIs). You need these URIs when you want to create locations
388             for them, or when you want to retrieve tuples within a specific area
389             (based on the geotype).
390              
391             =cut
392              
393             sub geotypes {
394 0     0 1   die;
395             }
396              
397             =pod
398              
399             =item B
400              
401             I<$uri> = I<$repo>->cartesian ("100x100", I<$stripWidth>);
402              
403             I<$uri> = I<$repo>->cartesian ("100x100+10+10", I<$stripWidth>);
404              
405             I<$uri> = I<$repo>->cartesian (I<$minx>, I<$miny>, I<$maxx>, I<$maxy>, I<$stripWidth>);
406              
407             This method registers one new coordinate system at the server. The returned URI is later used as
408             reference to that system. The extensions of the system is provided either
409              
410             =over
411              
412             =item in the form C
413              
414             All numbers being floats. The X,Y offset part can be omitted.
415              
416             =item or, alternatively, as minx, miny, maxx, maxy quadruple
417              
418             Again all numbers being floats.
419              
420             =back
421              
422             The last parameter defines the resolution of the stripes, and gives the server optimization hints.
423             (See the general AG description for a deep explanation.)
424              
425             =cut
426              
427             sub cartesian {
428 0     0 1   die;
429             }
430              
431             =pod
432              
433             =item B
434              
435             I<@ss> = I<$repo>->inBox (I<$geotype>, I<$predicate>, 35, 35, 65, 65, { limit => 10 });
436              
437             This method tries to find all triples which lie within a certain bounding box.
438              
439             The geotype is the one you create with C or C. The bounding box is given by the
440             bottom/left and the top/right corner coordinates. The optional C restricts the number of
441             triples you request.
442              
443             For cartesian coordinates you provide the bottom/left corner, and then the top/right one.
444              
445             For spherical coordinates you provide the longitude/latitude of the bottom/left corner, then
446             the longitude/latitude of the top/right one.
447              
448             =cut
449              
450             sub inBox {
451 0     0 1   die;
452             }
453              
454             =pod
455              
456             =item B
457              
458             I<@ss> = I<$repo>->inCircle (I<$geotype>, I<$predicate>, 35, 35, 10, { limit => 10 });
459              
460             This method tries to find all triples which lie within a certain bounding circle.
461              
462             The geotype is the one you create with C or C. The bounding circle is given by
463             the center and the radius. The optional C restricts the number of triples you request.
464              
465             For cartesian coordinates you simply provide the X/Y coordinates of the circle center, and the
466             radius (in the unit as provided with the geotype.
467              
468             For spherical coordinates the center is specified with a longitude/latitude pair. The radius is also
469             interpreted along the provided geotype.
470              
471             B: As it seems, the circle MUST be totally within the range you specified for your
472             geotype. Otherwise AG will return 0 tuples.
473              
474             =cut
475              
476             sub inCircle {
477 0     0 1   die;
478             }
479              
480             =pod
481              
482             =item I (since v0.06, only for AG4)
483              
484             I<@ss> = I<$repo>->inPolygon (I<$coordtype>, I<$preduri>, I<@points>, { I<%options> })
485              
486             This method tries to identify all statements where the object is within a polygon defined by the
487             C array. Each point is simply an array reference with 2 entries (x,y, of course).
488              
489             The predicate URI defines which predicates should be considered. Do not leave it C. The
490             coordinate type is the one you will have generated before with C.
491              
492             The optional options can only contain C to restrict the number of tuples to be returned.
493              
494             For spherical coordinates make sure that you (a) provide longitude/latitude pairs and then that the
495             polygon is built clockwise.
496              
497             B: This is a somewhat expensive operation in terms of communication round-trips.
498              
499             =cut
500              
501             sub inPolygon {
502 0     0 1   die;
503             }
504              
505             =pod
506              
507             =back
508              
509             =head1 AUTHOR
510              
511             Robert Barta, C<< >>
512              
513             =head1 COPYRIGHT & LICENSE
514              
515             Copyright 20(09|1[01]) Robert Barta, all rights reserved.
516              
517             This program is free software; you can redistribute it and/or modify it under the same terms as Perl
518             itself.
519              
520             L
521              
522             =cut
523              
524             our $VERSION = '0.03';
525              
526             1;
527              
528             __END__