File Coverage

blib/lib/RDF/Trine/Store.pm
Criterion Covered Total %
statement 144 197 73.1
branch 28 52 53.8
condition 3 12 25.0
subroutine 27 31 87.1
pod 11 11 100.0
total 213 303 70.3


line stmt bran cond sub pod time code
1             # RDF::Trine::Store
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Trine::Store - RDF triplestore base class
7              
8             =head1 VERSION
9              
10             This document describes RDF::Trine::Store version 1.017
11              
12             =head1 DESCRIPTION
13              
14             RDF::Trine::Store provides a base class and common API for implementations of
15             triple/quadstores for use with the RDF::Trine framework. In general, it should
16             be used only be people implementing new stores. For interacting with stores
17             (e.g. to read, insert, and delete triples) the RDF::Trine::Model interface
18             should be used (using the model as an intermediary between the client/user and
19             the underlying store).
20              
21             To be used by the RDF::Trine framework, store implementations must implement a
22             set of required functionality:
23              
24             =over 4
25              
26             =item * C<< new >>
27              
28             =item * C<< get_statements >>
29              
30             =item * C<< get_contexts >>
31              
32             =item * C<< add_statement >>
33              
34             =item * C<< remove_statement >>
35              
36             =item * C<< count_statements >>
37              
38             =item * C<< supports >>
39              
40             =back
41              
42             Implementations may also provide the following methods if a native
43             implementation would be more efficient than the default provided by
44             RDF::Trine::Store:
45              
46             =over 4
47              
48             =item * C<< get_pattern >>
49              
50             =item * C<< get_sparql >>
51              
52             =item * C<< remove_statements >>
53              
54             =item * C<< size >>
55              
56             =item * C<< nuke >>
57              
58             =item * C<< _begin_bulk_ops >>
59              
60             =item * C<< _end_bulk_ops >>
61              
62             =back
63              
64             =cut
65              
66             package RDF::Trine::Store;
67              
68 68     68   427 use strict;
  68         155  
  68         1750  
69 68     68   332 use warnings;
  68         143  
  68         1703  
70 68     68   330 no warnings 'redefine';
  68         146  
  68         1716  
71              
72 68     68   335 use Data::Dumper;
  68         134  
  68         2608  
73 68     68   385 use Log::Log4perl;
  68         145  
  68         657  
74 68     68   4149 use Carp qw(carp croak confess);
  68         149  
  68         3092  
75 68     68   373 use Scalar::Util qw(blessed reftype);
  68         144  
  68         2855  
76 68     68   408 use Module::Load::Conditional qw[can_load];
  68         158  
  68         2786  
77              
78 68     68   25531 use RDF::Trine::Store::Memory;
  68         214  
  68         2326  
79 68     68   31202 use RDF::Trine::Store::Hexastore;
  68         217  
  68         2307  
80 68     68   27365 use RDF::Trine::Store::SPARQL;
  68         225  
  68         2344  
81 68     68   26606 use RDF::Trine::Store::LanguagePreference;
  68         206  
  68         5170  
82              
83             ######################################################################
84              
85             our ($VERSION, $HAVE_REDLAND, %STORE_CLASSES);
86             BEGIN {
87 68     68   242 $VERSION = '1.017';
88 68 50       437 if ($RDF::Redland::VERSION) {
89 0         0 $HAVE_REDLAND = 1;
90             }
91 68         504 can_load( modules => {
92             'RDF::Trine::Store::DBI' => undef,
93             } );
94             }
95              
96             ######################################################################
97              
98             =head1 METHODS
99              
100             =over 4
101              
102             =cut
103              
104             =item C<< new ( $data ) >>
105              
106             Returns a new RDF::Trine::Store object based on the supplied data value.
107             This constructor delegates to one of the following methods depending on the
108             value of C<< $data >>:
109              
110             * C<< new_with_string >> if C<< $data >> is not a reference
111              
112             * C<< new_with_config >> if C<< $data >> is a HASH reference
113              
114             * C<< new_with_object >> if C<< $data >> is a blessed object
115              
116             =cut
117              
118             sub new {
119 1     1 1 3 my $class = shift;
120 1         2 my $data = shift;
121 1 50       6 if (blessed($data)) {
    50          
122 0         0 return $class->new_with_object($data);
123             } elsif (ref($data)) {
124 0         0 return $class->new_with_config($data);
125             } else {
126 1         6 return $class->new_with_string($data);
127             }
128             }
129              
130             =item C<< new_with_string ( $config ) >>
131              
132             Returns a new RDF::Trine::Store object based on the supplied configuration
133             string. The format of the string specifies the Store subclass to be
134             instantiated as well as any required constructor arguments. These are separated
135             by a semicolon. An example configuration string for the DBI store would be:
136              
137             DBI;mymodel;DBI:mysql:database=rdf;user;password
138              
139             The format of the constructor arguments (everything after the first ';') is
140             specific to the Store subclass.
141              
142             =cut
143              
144             sub new_with_string {
145 5     5 1 22 my $proto = shift;
146 5         11 my $string = shift;
147 5 50       16 if (defined($string)) {
148 5         26 my ($subclass, $config) = split(/;/, $string, 2);
149 5         17 my $class = join('::', 'RDF::Trine::Store', $subclass);
150 5 50 33     30 if (can_load(modules => { $class => 0 }) and $class->can('_new_with_string')) {
151 5         48079 return $class->_new_with_string( $config );
152             } else {
153 0         0 throw RDF::Trine::Error::UnimplementedError -text => "The class $class doesn't support the use of new_with_string";
154             }
155             } else {
156 0         0 throw RDF::Trine::Error::MethodInvocationError;
157             }
158             }
159              
160              
161             =item C<< new_with_config ( \%config ) >>
162              
163             Returns a new RDF::Trine::Store object based on the supplied
164             configuration hashref. This requires the the Store subclass to be
165             supplied with a C<storetype> key, while other keys are required by the
166             Store subclasses, please refer to each subclass for specific
167             documentation.
168              
169             An example invocation for the DBI store may be:
170              
171             my $store = RDF::Trine::Store->new_with_config({
172             storetype => 'DBI',
173             name => 'mymodel',
174             dsn => 'DBI:mysql:database=rdf',
175             username => 'dahut',
176             password => 'Str0ngPa55w0RD'
177             });
178              
179             =cut
180              
181              
182             sub new_with_config {
183 6     6 1 3814 my $proto = shift;
184 6         13 my $config = shift;
185 6 100       20 if (defined($config)) {
186 5   33     74 my $class = $config->{storeclass} || join('::', 'RDF::Trine::Store', $config->{storetype});
187 5 100       57 if ($class->can('_new_with_config')) {
188 4         21 return $class->_new_with_config( $config );
189             } else {
190 1         13 throw RDF::Trine::Error::UnimplementedError -text => "The class $class doesn't support the use of new_with_config";
191             }
192             } else {
193 1         12 throw RDF::Trine::Error::MethodInvocationError;
194             }
195             }
196              
197              
198             =item C<< new_with_object ( $object ) >>
199              
200             Returns a new RDF::Trine::Store object based on the supplied opaque C<< $object >>.
201             If the C<< $object >> is recognized by an available backend as being sufficient
202             to construct a store object, the store object will be returned. Otherwise undef
203             will be returned.
204              
205             =cut
206              
207             sub new_with_object {
208 0     0 1 0 my $proto = shift;
209 0         0 my $obj = shift;
210 0         0 foreach my $class (keys %STORE_CLASSES) {
211 0 0       0 if ($class->can('_new_with_object')) {
212 0         0 my $s = $class->_new_with_object( $obj );
213 0 0       0 if ($s) {
214 0         0 return $s;
215             }
216             }
217             }
218 0         0 return;
219             }
220              
221             =item C<< nuke >>
222              
223             Permanently removes the store and its data.
224              
225             =cut
226              
227       0 1   sub nuke {}
228              
229             =item C<< class_by_name ( $name ) >>
230              
231             Returns the class of the storage implementation with the given name.
232             For example, C<< 'Memory' >> would return C<< 'RDF::Trine::Store::Memory' >>.
233              
234             =cut
235              
236             sub class_by_name {
237 0     0 1 0 my $proto = shift;
238 0         0 my $name = shift;
239 0         0 foreach my $class (keys %STORE_CLASSES) {
240 0 0       0 if (lc($class) =~ m/::${name}$/i) {
241 0         0 return $class;
242             }
243             }
244 0         0 return;
245             }
246              
247             =item C<< temporary_store >>
248              
249             Returns a new temporary triplestore (using appropriate default values).
250              
251             =cut
252              
253             sub temporary_store {
254 331     331 1 7133 return RDF::Trine::Store::Memory->new();
255             }
256              
257             # =item C<< get_pattern ( $bgp [, $context] ) >>
258             #
259             # Returns a stream object of all bindings matching the specified graph pattern.
260             #
261             # =cut
262              
263             sub _get_pattern {
264 7     7   17 my $self = shift;
265 7         12 my $bgp = shift;
266 7         16 my $context = shift;
267 7         19 my @args = @_;
268 7         20 my %args = @args;
269            
270 7 50       37 if ($bgp->isa('RDF::Trine::Statement')) {
271 0         0 $bgp = RDF::Trine::Pattern->new($bgp);
272             } else {
273 7         21 $bgp = $bgp->sort_for_join_variables();
274             }
275            
276 7         13 my %iter_args;
277 7         19 my @triples = $bgp->triples;
278            
279 7         15 my ($iter);
280 7 50       21 if (1 == scalar(@triples)) {
281 7         14 my $t = shift(@triples);
282 7         25 my @nodes = $t->nodes;
283 7         17 my $size = scalar(@nodes);
284 7         9 my %vars;
285 7         24 my @names = qw(subject predicate object context);
286 7         23 foreach my $n (0 .. $#nodes) {
287 25 100       99 if ($nodes[$n]->isa('RDF::Trine::Node::Variable')) {
288 9         27 $vars{ $names[ $n ] } = $nodes[$n]->name;
289             }
290             }
291 7         28 my $_iter = $self->get_statements( @nodes );
292 7 100       38 if ($_iter->finished) {
293 1         7 return RDF::Trine::Iterator::Bindings->new( [], [] );
294             }
295 6         23 my @vars = values %vars;
296             my $sub = sub {
297 25     25   71 my $row = $_iter->next;
298 25 100       63 return unless ($row);
299 19         51 my %data = map { $vars{ $_ } => $row->$_() } (keys %vars);
  33         104  
300 19         88 return RDF::Trine::VariableBindings->new( \%data );
301 6         35 };
302 6         52 $iter = RDF::Trine::Iterator::Bindings->new( $sub, \@vars );
303             } else {
304 0         0 my $t = pop(@triples);
305 0         0 my $rhs = $self->get_pattern( RDF::Trine::Pattern->new( $t ), $context, @args );
306 0         0 my $lhs = $self->get_pattern( RDF::Trine::Pattern->new( @triples ), $context, @args );
307 0         0 my @inner;
308 0         0 while (my $row = $rhs->next) {
309 0         0 push(@inner, $row);
310             }
311 0         0 my @results;
312 0         0 while (my $row = $lhs->next) {
313 0         0 RESULT: foreach my $irow (@inner) {
314 0         0 my %keysa;
315 0         0 my @keysa = keys %$irow;
316 0         0 @keysa{ @keysa } = (1) x scalar(@keysa);
317 0         0 my @shared = grep { exists $keysa{ $_ } } (keys %$row);
  0         0  
318 0         0 foreach my $key (@shared) {
319 0         0 my $val_a = $irow->{ $key };
320 0         0 my $val_b = $row->{ $key };
321 0 0 0     0 next unless (defined($val_a) and defined($val_b));
322 0         0 my $equal = $val_a->equal( $val_b );
323 0 0       0 unless ($equal) {
324 0         0 next RESULT;
325             }
326             }
327            
328 0         0 my $jrow = { (map { $_ => $irow->{$_} } grep { defined($irow->{$_}) } keys %$irow), (map { $_ => $row->{$_} } grep { defined($row->{$_}) } keys %$row) };
  0         0  
  0         0  
  0         0  
  0         0  
329 0         0 push(@results, RDF::Trine::VariableBindings->new($jrow));
330             }
331             }
332 0         0 $iter = RDF::Trine::Iterator::Bindings->new( \@results, [ $bgp->referenced_variables ] );
333             }
334            
335 6 100       26 if (my $o = $args{ 'orderby' }) {
336 2 50       10 unless (reftype($o) eq 'ARRAY') {
337 0         0 throw RDF::Trine::Error::MethodInvocationError -text => "The orderby argument to get_pattern must be an ARRAY reference";
338             }
339            
340 2         5 my @order;
341             my %order;
342 2         5 my @o = @$o;
343 2         4 my @sorted_by;
344 2         8 my %vars = map { $_ => 1 } $bgp->referenced_variables;
  4         8  
345 2 50       12 if (scalar(@o) % 2 != 0) {
346 0         0 throw RDF::Trine::Error::MethodInvocationError -text => "The orderby argument ARRAY to get_pattern must contain an even number of elements";
347             }
348 2         7 while (@o) {
349 2         5 my ($k,$dir) = splice(@o, 0, 2, ());
350 2 50       7 next unless ($vars{ $k });
351 2 50       11 unless ($dir =~ m/^ASC|DESC$/i) {
352 0         0 throw RDF::Trine::Error::MethodInvocationError -text => "The sort direction for key $k must be either 'ASC' or 'DESC' in get_pattern call";
353             }
354 2 50       7 my $asc = ($dir eq 'ASC') ? 1 : 0;
355 2         5 push(@order, $k);
356 2         8 $order{ $k } = $asc;
357 2         7 push(@sorted_by, $k, $dir);
358             }
359            
360 2         12 my @results = $iter->get_all;
361 2         8 @results = _sort_bindings( \@results, \@order, \%order );
362 2         6 $iter_args{ sorted_by } = \@sorted_by;
363 2         8 return RDF::Trine::Iterator::Bindings->new( \@results, [ $bgp->referenced_variables ], %iter_args );
364             } else {
365 4         15 return $iter;
366             }
367             }
368              
369             sub _sort_bindings {
370 2     2   4 my $res = shift;
371 2         3 my $o = shift;
372 2         5 my $dir = shift;
373 2         5 my @sorted = map { $_->[0] } sort { _sort_mapped_data($a,$b,$o,$dir) } map { _map_sort_data( $_, $o ) } @$res;
  6         15  
  8         14  
  6         12  
374 2         6 return @sorted;
375             }
376              
377             sub _sort_mapped_data {
378 8     8   14 my $a = shift;
379 8         11 my $b = shift;
380 8         12 my $o = shift;
381 8         11 my $dir = shift;
382 8         11 foreach my $i (1 .. $#{ $a }) {
  8         16  
383 8         13 my $av = $a->[ $i ];
384 8         13 my $bv = $b->[ $i ];
385 8         12 my $key = $o->[ $i-1 ];
386 8 50 33     20 next unless (defined($av) or defined($bv));
387 8         19 my $cmp = RDF::Trine::Node::compare( $av, $bv );
388 8 50       18 unless ($dir->{ $key }) {
389 0         0 $cmp *= -1;
390             }
391 8 100       23 return $cmp if ($cmp);
392             }
393 6         12 return 0;
394             }
395              
396             sub _map_sort_data {
397 6     6   10 my $res = shift;
398 6         10 my $o = shift;
399 6         10 my @data = ($res, map { $res->{ $_ } } @$o);
  6         18  
400 6         16 return \@data;
401             }
402              
403             =item C<< get_statements ($subject, $predicate, $object [, $context] ) >>
404              
405             Returns a stream object of all statements matching the specified subject,
406             predicate and objects. Any of the arguments may be undef to match any value.
407              
408             =cut
409              
410             sub get_statements;
411              
412             =item C<< get_contexts >>
413              
414             Returns an RDF::Trine::Iterator over the RDF::Trine::Node objects comprising
415             the set of contexts of the stored quads.
416              
417             =cut
418              
419             sub get_contexts;
420              
421             =item C<< add_statement ( $statement [, $context] ) >>
422              
423             Adds the specified C<$statement> to the underlying model.
424              
425             =cut
426              
427             sub add_statement;
428              
429             =item C<< remove_statement ( $statement [, $context]) >>
430              
431             Removes the specified C<$statement> from the underlying model.
432              
433             =cut
434              
435             sub remove_statement;
436              
437             =item C<< remove_statements ( $subject, $predicate, $object [, $context]) >>
438              
439             Removes the specified C<$statement> from the underlying model.
440              
441             =cut
442              
443             sub remove_statements { # Fallback implementation
444 3     3 1 7 my $self = shift;
445 3         12 my $iterator = $self->get_statements(@_);
446 3         11 while (my $st = $iterator->next) {
447 4         13 $self->remove_statement($st);
448             }
449             }
450              
451             =item C<< count_statements ($subject, $predicate, $object) >>
452              
453             Returns a count of all the statements matching the specified subject,
454             predicate and objects. Any of the arguments may be undef to match any value.
455              
456             =cut
457              
458             sub count_statements;
459              
460             =item C<< size >>
461              
462             Returns the number of statements in the store.
463              
464             =cut
465              
466             sub size {
467 95     95 1 1454 my $self = shift;
468 95         431 return $self->count_statements( undef, undef, undef, undef );
469             }
470              
471             =item C<< etag >>
472              
473             If the store has the capability and knowledge to support caching, returns a
474             persistent token that will remain consistent as long as the store's data doesn't
475             change. This token is acceptable for use as an HTTP ETag.
476              
477             =cut
478              
479             sub etag {
480 4     4 1 17 return;
481             }
482              
483             =item C<< supports ( [ $feature ] ) >>
484              
485             If C<< $feature >> is specified, returns true if the feature is supported by the
486             store, false otherwise. If C<< $feature >> is not specified, returns a list of
487             supported features.
488              
489             =cut
490              
491             sub supports {
492 0     0 1   return;
493             }
494              
495       776     sub _begin_bulk_ops {}
496       7077     sub _end_bulk_ops {}
497              
498             1;
499              
500             __END__
501              
502             =back
503              
504             =head1 BUGS
505              
506             Please report any bugs or feature requests to through the GitHub web interface
507             at L<https://github.com/kasei/perlrdf/issues>.
508              
509             =head1 AUTHOR
510              
511             Gregory Todd Williams C<< <gwilliams@cpan.org> >>
512              
513             =head1 COPYRIGHT
514              
515             Copyright (c) 2006-2012 Gregory Todd Williams. This
516             program is free software; you can redistribute it and/or modify it under
517             the same terms as Perl itself.
518              
519             =cut
520              
521             get_statements() XXX maybe this should instead follow the quad semantics?
522             get_statements( s, p, o )
523             return (s,p,o,nil) for all distinct (s,p,o)
524             get_statements( s, p, o, g )
525             return all (s,p,o,g)
526              
527             add_statement( TRIPLE )
528             add (s, p, o, nil)
529             add_statement( TRIPLE, CONTEXT )
530             add (s, p, o, context)
531             add_statement( QUAD )
532             add (s, p, o, g )
533             add_statement( QUAD, CONTEXT )
534             throw exception
535              
536             remove_statement( TRIPLE )
537             remove (s, p, o, nil)
538             remove_statement( TRIPLE, CONTEXT )
539             remove (s, p, o, context)
540             remove_statement( QUAD )
541             remove (s, p, o, g)
542             remove_statement( QUAD, CONTEXT )
543             throw exception
544              
545             count_statements() XXX maybe this should instead follow the quad semantics?
546             count_statements( s, p, o )
547             count distinct (s,p,o) for all statements (s,p,o,g)
548             count_statements( s, p, o, g )
549             count (s,p,o,g)