File Coverage

blib/lib/RDF/Trine/Model/Dataset.pm
Criterion Covered Total %
statement 131 177 74.0
branch 39 66 59.0
condition 10 24 41.6
subroutine 17 27 62.9
pod 16 16 100.0
total 213 310 68.7


line stmt bran cond sub pod time code
1             # RDF::Trine::Model::Dataset
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Trine::Model::Dataset - Model for SPARQL datasets
7              
8             =head1 VERSION
9              
10             This document describes RDF::Trine::Model::Dataset version 1.018
11              
12             =head1 STATUS
13              
14             This module's API and functionality should be considered unstable.
15             In the future, this module may change in backwards-incompatible ways,
16             or be removed entirely. If you need functionality that this module provides,
17             please L<get in touch|http://www.perlrdf.org/>.
18              
19             =head1 METHODS
20              
21             Beyond the methods documented below, this class inherits methods from the
22             L<RDF::Trine::Model> class.
23              
24             =over 4
25              
26             =cut
27              
28             package RDF::Trine::Model::Dataset;
29              
30 68     68   428 use strict;
  68         160  
  68         1748  
31 68     68   336 use warnings;
  68         142  
  68         1682  
32 68     68   316 no warnings 'redefine';
  68         146  
  68         1877  
33 68     68   358 use base qw(RDF::Trine::Model);
  68         153  
  68         4960  
34 68     68   407 use Scalar::Util qw(blessed);
  68         194  
  68         2813  
35              
36 68     68   435 use RDF::Trine::Model;
  68         162  
  68         2646  
37              
38             our ($VERSION);
39             BEGIN {
40 68     68   99443 $VERSION = '1.018';
41             }
42              
43             ################################################################################
44              
45             =item C<< new ( $model ) >>
46              
47             Returns a new dataset-model over the supplied model.
48              
49             =cut
50              
51             sub new {
52 2     2 1 29 my $class = shift;
53 2         5 my $model = shift;
54 2         11 my $self = bless({ model => $model, stack => [] }, $class);
55             }
56              
57             =item C<< push_dataset ( default => \@graphs, named => \@graphs ) >>
58              
59             Creates a new dataset view over the underlying model.
60              
61             =cut
62              
63             sub push_dataset {
64 6     6 1 18 my $self = shift;
65 6         18 my %dataset = @_;
66            
67 6 100       9 my @dgraphs = @{ $dataset{ default } || [] };
  6         27  
68 6         13 unshift(@{ $self->{ stack } }, { default => {}, named => {} });
  6         23  
69 6         15 foreach my $graph (@dgraphs) {
70 8 50       39 my $name = blessed($graph) ? $graph->uri_value : $graph;
71 8 50       24 $graph = blessed($graph) ? $graph : RDF::Trine::Node::Resource->new( $graph );
72 8         24 $self->{stack}[0]{default}{$name} = $graph;
73             }
74            
75 6 100       11 my @ngraphs = @{ $dataset{ named } || [] };
  6         29  
76 6         12 foreach my $graph (@ngraphs) {
77 1 50       6 my $name = blessed($graph) ? $graph->uri_value : $graph;
78 1 50       6 $graph = blessed($graph) ? $graph : RDF::Trine::Node::Resource->new( $graph );
79 1         4 $self->{stack}[0]{named}{$name} = $graph;
80             }
81            
82 6         16 return 1;
83             }
84              
85             =item C<< pop_dataset >>
86              
87             Removes the last pushed dataset view.
88              
89             =cut
90              
91             sub pop_dataset {
92 1     1 1 3 my $self = shift;
93 1         2 shift(@{ $self->{ stack } });
  1         3  
94 1         6 return 1;
95             }
96              
97             =item C<< temporary_model >>
98            
99             Returns a new temporary (non-persistent) model.
100            
101             =cut
102            
103             sub temporary_model {
104 0     0 1 0 my $class = shift;
105 0         0 my $model = RDF::Trine::Model->temporary_model;
106 0         0 return $class->new( $model );
107             }
108              
109             =item C<< add_hashref ( $hashref [, $context] ) >>
110              
111             Add triples represented in an RDF/JSON-like manner to the model.
112              
113             =cut
114              
115             sub add_hashref {
116 0     0 1 0 my $self = shift;
117 0         0 return $self->model->add_hashref( @_ );
118             }
119              
120             =item C<< size >>
121              
122             Returns the number of statements in the model.
123              
124             =cut
125              
126             sub size {
127 0     0 1 0 my $self = shift;
128 0         0 return $self->count_statements( undef, undef, undef, undef );
129             }
130              
131             =item C<< supports ( [ $feature ] ) >>
132              
133             If C<< $feature >> is specified, returns true if the feature is supported by the
134             underlying store, false otherwise. If C<< $feature >> is not specified, returns
135             a list of supported features.
136              
137             =cut
138              
139             sub supports {
140 0     0 1 0 my $self = shift;
141 0         0 my $store = $self->_store;
142 0 0       0 if ($store) {
143 0         0 return $store->supports( @_ );
144             }
145 0         0 return;
146             }
147              
148             =item C<< count_statements ( $subject, $predicate, $object ) >>
149              
150             Returns a count of all the statements matching the specified subject,
151             predicate and objects. Any of the arguments may be undef to match any value.
152              
153             =cut
154              
155             sub count_statements {
156 22     22 1 1081 my $self = shift;
157 22 100       37 return $self->model->count_statements( @_ ) unless (scalar(@{ $self->{stack} }));
  22         76  
158 17         37 my $use_quad = (scalar(@_) >= 4);
159 17 100       39 if ($use_quad) {
160             # warn "counting quads with dataset";
161 15         21 my $quad = $_[3];
162 15 100 66     109 if (blessed($quad) and $quad->isa('RDF::Trine::Node::Nil')) {
    50 0        
      33        
163             # warn "- default graph query";
164             # warn "- " . join(', ', keys %{ $self->{stack}[0] });
165 14         27 my $count = 0;
166 14         21 foreach my $g (values %{ $self->{stack}[0]{default} }) {
  14         43  
167 16         156 $count += $self->model->count_statements( @_[0..2], $g );
168             # warn "$count statments in graph " . $g->uri_value;
169             }
170 14         416 return $count;
171             } elsif (not(defined($quad)) or (blessed($quad) and $quad->isa('RDF::Trine::Node::Variable'))) {
172 1         6 my $iter = $self->get_contexts;
173 1         3 my $count = 0;
174 1         4 while (my $g = $iter->next) {
175 0         0 $count += $self->model->count_statements( @_[0..2], $g );
176             }
177 1         10 return $count;
178             } else {
179 0 0       0 my $name = blessed($quad) ? $quad->uri_value : $quad;
180 0 0       0 if ($self->{stack}[0]{named}{ $name }) {
181 0         0 return $self->model->count_statements( @_[0..2], $quad );
182             } else {
183 0         0 return 0;
184             }
185             }
186             } else {
187 2         4 my %seen;
188 2         4 my $count = 0;
189 2         9 my $iter = $self->get_statements( @_[0..2], undef );
190 2         6 while (my $st = $iter->next) {
191 0         0 warn 'counting triples in dataset: ' . $st->as_string;
192 0 0       0 $count++ unless ($seen{ join(' ', map { $_->as_string } (map { $st->$_() } qw(subject predicate object)) ) }++);
  0         0  
  0         0  
193             }
194 2         16 return $count;
195             }
196             }
197              
198             =item C<< add_statement ( $statement [, $context] ) >>
199            
200             Adds the specified C<< $statement >> to the rdf store.
201            
202             =cut
203            
204             sub add_statement {
205 0     0 1 0 my $self = shift;
206 0         0 return $self->model->add_statement( @_ );
207             }
208              
209             =item C<< remove_statement ( $statement [, $context]) >>
210              
211             Removes the specified C<< $statement >> from the rdf store.
212              
213             =cut
214              
215             sub remove_statement {
216 0     0 1 0 my $self = shift;
217 0         0 return $self->model->remove_statement( @_ );
218             }
219              
220             =item C<< remove_statements ( $subject, $predicate, $object [, $context] ) >>
221              
222             Removes all statements matching the supplied C<< $statement >> pattern from the rdf store.
223              
224             =cut
225              
226             sub remove_statements {
227 0     0 1 0 my $self = shift;
228 0         0 return $self->model->remove_statements( @_ );
229             }
230              
231             =item C<< get_statements ($subject, $predicate, $object [, $context] ) >>
232              
233             Returns an iterator of all statements matching the specified subject,
234             predicate and objects from the rdf store. Any of the arguments may be undef to
235             match any value.
236              
237             If three or fewer arguments are given, the statements returned will be matched
238             based on triple semantics (the graph union of triples from all the named
239             graphs). If four arguments are given (even if C<< $context >> is undef),
240             statements will be matched based on quad semantics (the union of all quads in
241             the underlying store).
242              
243             =cut
244              
245             sub get_statements {
246 16     16 1 3844 my $self = shift;
247 16 100       27 return $self->model->get_statements( @_ ) unless (scalar(@{ $self->{stack} }));
  16         50  
248 14         20 my $bound = 0;
249 14         27 my $use_quad = (scalar(@_) >= 4);
250 14         53 my $nil = RDF::Trine::Node::Nil->new();
251 14 100       30 if ($use_quad) {
252 11         15 my $quad = $_[3];
253 11 100 66     91 if (blessed($quad) and not($quad->isa('RDF::Trine::Node::Variable')) and not($quad->isa('RDF::Trine::Node::Nil'))) {
      100        
254 1 50       5 if (exists($self->{stack}[0]{named}{$quad->uri_value})) {
255 1         4 return $self->model->get_statements( @_ );
256             } else {
257 0         0 return RDF::Trine::Iterator::Graph->new([]);
258             }
259             } else {
260 10         15 my @iters;
261 10         18 foreach my $g (values %{ $self->{stack}[0]{default} }) {
  10         35  
262 13         29 my $iter = $self->model->get_statements( @_[0..2], $g );
263             my $code = sub {
264 31     31   64 my $st = $iter->next;
265 31 100       79 return unless $st;
266 18         50 my @nodes = $st->nodes;
267 18         36 $nodes[3] = $nil;
268 18         55 my $quad = RDF::Trine::Statement::Quad->new( @nodes );
269 18         42 return $quad;
270 13         46 };
271 13         43 push(@iters, RDF::Trine::Iterator::Graph->new( $code ));
272             }
273 10 100 66     52 if (not(defined($quad)) or $quad->isa('RDF::Trine::Node::Variable')) {
274 5         14 my $graphs = $self->get_contexts;
275 5         19 while (my $g = $graphs->next) {
276 1 50       18 next if ($g->isa('RDF::Trine::Node::Nil'));
277 1         5 push(@iters, $self->model->get_statements( @_[0..2], $g ));
278             }
279             }
280 10         18 my %seen;
281             my $code = sub {
282 29     29   45 while (1) {
283 43 100       104 return unless scalar(@iters);
284 33         85 my $st = $iters[0]->next;
285 33 100       85 if ($st) {
286 19 50       57 if ($seen{ $st->as_string }++) {
287 0         0 next;
288             }
289 19         52 return $st;
290             } else {
291 14         94 shift(@iters);
292             }
293             }
294 10         37 };
295 10         31 my $iter = RDF::Trine::Iterator::Graph->new( $code );
296 10         31 return $iter;
297             }
298             } else {
299 3         5 my %seen;
300             my @iters;
301 3         24 my $iter = $self->get_statements( @_[0..2], $nil );
302 3         8 push(@iters, $iter);
303 3         9 my $giter = $self->get_contexts;
304 3         12 while (my $g = $giter->next) {
305 1         5 my $iter = $self->get_statements( @_[0..2], $g );
306 1         4 push(@iters, $iter);
307             }
308            
309             my $code = sub {
310 11     11   22 while (1) {
311 15 100       37 return unless scalar(@iters);
312 12         30 my $st = $iters[0]->next;
313 12 100       24 if ($st) {
314 8         15 my @nodes = (map { $st->$_() } qw(subject predicate object));
  24         59  
315 8 50       18 next if ($seen{ join(' ', map { $_->as_string } @nodes ) }++);
  24         60  
316 8         33 return RDF::Trine::Statement->new( @nodes );
317             } else {
318 4         17 shift(@iters);
319             }
320             }
321 3         12 };
322 3         11 return RDF::Trine::Iterator::Graph->new( $code );
323             }
324             }
325              
326             =item C<< get_pattern ( $bgp [, $context] [, %args ] ) >>
327              
328             Returns a stream object of all bindings matching the specified graph pattern.
329              
330             =cut
331              
332             sub get_pattern {
333 0     0 1 0 my $self = shift;
334 0 0       0 return $self->model->get_pattern( @_ ) unless (scalar(@{ $self->{stack} }));
  0         0  
335 0         0 my $use_quad = (scalar(@_) >= 4);
336 0 0       0 if ($use_quad) {
337 0         0 my $quad = $_[3];
338 0 0 0     0 if (blessed($quad) and not($quad->isa('RDF::Trine::Node::Variable')) and not($quad->isa('RDF::Trine::Node::Nil'))) {
      0        
339 0         0 return $self->model->get_pattern( @_ );
340             } else {
341 0         0 return $self->SUPER::get_pattern( @_ );
342             }
343             } else {
344 0         0 return $self->model->get_pattern( @_ );
345             }
346             }
347              
348             =item C<< get_sparql ( $sparql ) >>
349              
350             Returns a stream object of all bindings matching the specified graph pattern.
351              
352             =cut
353              
354             sub get_sparql {
355 0     0 1 0 my $self = shift;
356 0 0       0 return $self->model->get_sparql( @_ ) unless (scalar(@{ $self->{stack} }));
  0         0  
357 0         0 throw RDF::Trine::Error::UnimplementedError -text => "Cannot execute SPARQL queries against a complex dataset model";
358             }
359              
360             =item C<< get_graphs >>
361              
362             =item C<< get_contexts >>
363              
364             Returns an iterator containing the nodes representing the named graphs in the
365             model.
366              
367             =cut
368              
369             sub get_contexts {
370 9     9 1 15 my $self = shift;
371 9 50       12 return $self->model->get_contexts unless (scalar(@{ $self->{stack} }));
  9         26  
372 9         14 my @nodes = values %{ $self->{stack}[0]{named} };
  9         29  
373 9 50       23 if (wantarray) {
374 0         0 return @nodes;
375             } else {
376 9         30 return RDF::Trine::Iterator->new( \@nodes );
377             }
378             }
379             *get_graphs = \&get_contexts;
380              
381             =item C<< model >>
382              
383             Returns the underlying model object.
384              
385             =cut
386              
387             sub model {
388 38     38 1 62 my $self = shift;
389 38         159 return $self->{model};
390             }
391              
392             sub _store {
393 0     0     my $self = shift;
394 0           return $self->model->_store;
395             }
396              
397             1;
398              
399             __END__
400              
401             =back
402              
403             =head1 BUGS
404              
405             Please report any bugs or feature requests to through the GitHub web interface
406             at L<https://github.com/kasei/perlrdf/issues>.
407              
408             =head1 AUTHOR
409              
410             Gregory Todd Williams C<< <gwilliams@cpan.org> >>
411              
412             =head1 COPYRIGHT
413              
414             Copyright (c) 2006-2012 Gregory Todd Williams. This
415             program is free software; you can redistribute it and/or modify it under
416             the same terms as Perl itself.
417              
418             =cut