File Coverage

blib/lib/RDF/Query/Algebra.pm
Criterion Covered Total %
statement 201 232 86.6
branch 32 42 76.1
condition 21 33 63.6
subroutine 52 56 92.8
pod 12 12 100.0
total 318 375 84.8


line stmt bran cond sub pod time code
1             # RDF::Query::Algebra
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Query::Algebra - Base class for Algebra expressions
7              
8             =head1 VERSION
9              
10             This document describes RDF::Query::Algebra version 2.915_01.
11              
12             =head1 METHODS
13              
14             =over 4
15              
16             =cut
17              
18             package RDF::Query::Algebra;
19              
20             our (@ISA, @EXPORT_OK);
21             BEGIN {
22 36     36   95 our $VERSION = '2.915_01';
23            
24 36         198 require Exporter;
25 36         399 @ISA = qw(Exporter);
26 36         772 @EXPORT_OK = qw(triple bgp ggp);
27             }
28              
29 36     36   187 use strict;
  36         66  
  36         737  
30 36     36   352 use warnings;
  36         65  
  36         891  
31 36     36   171 no warnings 'redefine';
  36         77  
  36         1136  
32              
33 36     36   1680 use Set::Scalar;
  36         23962  
  36         1542  
34 36     36   215 use Scalar::Util qw(blessed);
  36         145  
  36         1749  
35 36     36   186 use Data::Dumper;
  36         68  
  36         1716  
36              
37 36     36   1217 use RDF::Query::Expression;
  36         65  
  36         975  
38 36     36   20853 use RDF::Query::Expression::Alias;
  36         87  
  36         904  
39 36     36   20520 use RDF::Query::Expression::Nary;
  36         90  
  36         944  
40 36     36   21372 use RDF::Query::Expression::Binary;
  36         98  
  36         1103  
41 36     36   21124 use RDF::Query::Expression::Unary;
  36         90  
  36         957  
42 36     36   21616 use RDF::Query::Expression::Function;
  36         100  
  36         1324  
43              
44 36     36   23056 use RDF::Query::Algebra::BasicGraphPattern;
  36         104  
  36         1848  
45 36     36   21899 use RDF::Query::Algebra::Construct;
  36         104  
  36         1690  
46 36     36   21259 use RDF::Query::Algebra::Filter;
  36         97  
  36         1891  
47 36     36   21968 use RDF::Query::Algebra::GroupGraphPattern;
  36         172  
  36         1884  
48 36     36   20952 use RDF::Query::Algebra::Optional;
  36         94  
  36         1834  
49 36     36   21677 use RDF::Query::Algebra::Triple;
  36         98  
  36         1887  
50 36     36   21596 use RDF::Query::Algebra::Quad;
  36         92  
  36         2072  
51 36     36   21029 use RDF::Query::Algebra::Union;
  36         94  
  36         1928  
52 36     36   21741 use RDF::Query::Algebra::NamedGraph;
  36         101  
  36         2134  
53 36     36   21567 use RDF::Query::Algebra::Service;
  36         93  
  36         2330  
54 36     36   21241 use RDF::Query::Algebra::TimeGraph;
  36         95  
  36         2283  
55 36     36   21410 use RDF::Query::Algebra::Aggregate;
  36         106  
  36         2214  
56 36     36   21057 use RDF::Query::Algebra::Sort;
  36         102  
  36         2259  
57 36     36   20986 use RDF::Query::Algebra::Limit;
  36         100  
  36         2339  
58 36     36   20911 use RDF::Query::Algebra::Offset;
  36         99  
  36         2310  
59 36     36   21056 use RDF::Query::Algebra::Distinct;
  36         104  
  36         2357  
60 36     36   21975 use RDF::Query::Algebra::Path;
  36         99  
  36         2531  
61 36     36   22599 use RDF::Query::Algebra::Project;
  36         104  
  36         2722  
62 36     36   21559 use RDF::Query::Algebra::Extend;
  36         105  
  36         2790  
63 36     36   20828 use RDF::Query::Algebra::SubSelect;
  36         97  
  36         2747  
64 36     36   20816 use RDF::Query::Algebra::Load;
  36         96  
  36         2668  
65 36     36   21264 use RDF::Query::Algebra::Clear;
  36         93  
  36         2745  
66 36     36   21750 use RDF::Query::Algebra::Update;
  36         104  
  36         2911  
67 36     36   20999 use RDF::Query::Algebra::Minus;
  36         97  
  36         2851  
68 36     36   21217 use RDF::Query::Algebra::Sequence;
  36         155  
  36         3089  
69 36     36   21008 use RDF::Query::Algebra::Create;
  36         95  
  36         3079  
70 36     36   20721 use RDF::Query::Algebra::Copy;
  36         103  
  36         2932  
71 36     36   21373 use RDF::Query::Algebra::Move;
  36         102  
  36         2933  
72 36     36   21293 use RDF::Query::Algebra::Table;
  36         100  
  36         4821  
73              
74 36         61169 use constant SSE_TAGS => {
75             'BGP' => 'RDF::Query::Algebra::BasicGraphPattern',
76             'constant' => 'RDF::Query::Algebra::Constant',
77             'construct' => 'RDF::Query::Algebra::Construct',
78             'distinct' => 'RDF::Query::Algebra::Distinct',
79             'filter' => 'RDF::Query::Algebra::Filter',
80             'limit' => 'RDF::Query::Algebra::Limit',
81             'namedgraph' => 'RDF::Query::Algebra::NamedGraph',
82             'offset' => 'RDF::Query::Algebra::Offset',
83             'project' => 'RDF::Query::Algebra::Project',
84             'quad' => 'RDF::Query::Algebra::Quad',
85             'service' => 'RDF::Query::Algebra::Service',
86             'sort' => 'RDF::Query::Algebra::Sort',
87             'triple' => 'RDF::Query::Algebra::Triple',
88             'union' => 'RDF::Query::Algebra::Union',
89             'join' => 'RDF::Query::Algebra::GroupGraphPattern',
90             'leftjoin' => 'RDF::Query::Algebra::Optional',
91 36     36   233 };
  36         66  
92              
93             =item C<< potentially_bound >>
94              
95             Returns a list of the variable names used in this algebra expression that will
96             bind values during execution.
97              
98             =cut
99              
100             sub potentially_bound {
101 51     51 1 84 my $self = shift;
102 51         213 return $self->referenced_variables;
103             }
104              
105             =item C<< referenced_blanks >>
106              
107             Returns a list of the blank node names used in this algebra expression.
108              
109             =cut
110              
111             sub referenced_blanks {
112 21     21 1 30 my $self = shift;
113 21         26 my @list;
114 21         62 foreach my $arg ($self->construct_args) {
115 33 100 66     216 if (blessed($arg) and $arg->isa('RDF::Query::Algebra')) {
116 30         86 my @blanks = $arg->referenced_blanks;
117 30         84 push(@list, @blanks);
118             }
119             }
120 21         49 return RDF::Query::_uniq(@list);
121             }
122              
123             =item C<< referenced_functions >>
124              
125             Returns a list of the Function URIs used in this algebra expression.
126              
127             =cut
128              
129             sub referenced_functions {
130 993     993 1 1300 my $self = shift;
131 993         1180 my @list;
132 993         3107 foreach my $arg ($self->construct_args) {
133 2153 100       8250 if (blessed($arg)) {
134 1905 100       12834 if ($arg->isa('RDF::Query::Expression::Function')) {
    100          
135 33         119 push(@list, $arg->uri);
136             } elsif ($arg->isa('RDF::Query::Algebra')) {
137 836         2427 my @funcs = $arg->referenced_functions;
138 836         2493 push(@list, @funcs);
139             }
140             }
141             }
142 993         2641 return RDF::Query::_uniq(@list);
143             }
144              
145             =item C<< check_duplicate_blanks >>
146              
147             Returns true if blank nodes respect the SPARQL rule of no blank-label re-use
148             across BGPs, otherwise throws a RDF::Query::Error::QueryPatternError exception.
149              
150             =cut
151              
152             sub check_duplicate_blanks {
153 121     121 1 200 my $self = shift;
154 121         140 my @data;
155 121         463 foreach my $arg ($self->construct_args) {
156 295 100 100     2223 if (blessed($arg) and $arg->isa('RDF::Query::Algebra')) {
157 122         436 $arg->check_duplicate_blanks();
158             }
159             }
160            
161 121         350 return 1;
162             }
163              
164             sub _referenced_blanks {
165 108     108   167 my $self = shift;
166 108         152 my @data;
167 108         364 foreach my $arg ($self->construct_args) {
168 165 100 100     1350 if (blessed($arg) and $arg->isa('RDF::Query::Algebra')) {
169 127         444 push( @data, $arg->_referenced_blanks );
170             }
171             }
172 108         353 return @data;
173             }
174              
175             =item C<< qualify_uris ( \%namespaces, $base_uri ) >>
176              
177             Returns a new algebra pattern where all referenced Resource nodes representing
178             QNames (ns:local) are qualified using the supplied %namespaces.
179              
180             =cut
181              
182             sub qualify_uris {
183 42     42 1 72 my $self = shift;
184 42         84 my $class = ref($self);
185 42         64 my $ns = shift;
186 42         61 my $base_uri = shift;
187 42         52 my @args;
188 42         242 foreach my $arg ($self->construct_args) {
189 100 100 66     1577 if (blessed($arg) and $arg->isa('RDF::Query::Algebra')) {
    100 66        
190 25         108 push(@args, $arg->qualify_uris( $ns, $base_uri ));
191             } elsif (blessed($arg) and $arg->isa('RDF::Query::Node::Resource')) {
192 34         185 my $uri = $arg->uri_value;
193 34 50       490 if (ref($uri)) {
194 0         0 $uri = join('', $ns->{ $uri->[0] }, $uri->[1]);
195 0         0 $arg = RDF::Query::Node::Resource->new( $uri );
196             }
197 34         89 push(@args, $arg);
198             } else {
199 41         112 push(@args, $arg);
200             }
201             }
202 42         501 return $class->new( @args );
203             }
204              
205             =item C<< bind_variables ( \%bound ) >>
206              
207             Returns a new algebra pattern with variables named in %bound replaced by their corresponding bound values.
208              
209             =cut
210              
211             sub bind_variables {
212 0     0 1 0 my $self = shift;
213 0         0 my $class = ref($self);
214 0         0 my $bound = shift;
215 0         0 my @args;
216 0         0 foreach my $arg ($self->construct_args) {
217 0 0 0     0 if (blessed($arg) and $arg->isa('RDF::Query::Algebra')) {
    0 0        
      0        
218 0         0 push(@args, $arg->bind_variables( $bound ));
219             } elsif (blessed($arg) and $arg->isa('RDF::Trine::Node::Variable') and exists($bound->{ $arg->name })) {
220 0         0 push(@args, $bound->{ $arg->name });
221             } else {
222 0         0 push(@args, $arg);
223             }
224             }
225 0         0 return $class->new( @args );
226             }
227              
228             =item C<< is_solution_modifier >>
229              
230             Returns true if this node is a solution modifier.
231              
232             =cut
233              
234             sub is_solution_modifier {
235 545     545 1 2463 return 0;
236             }
237              
238             =item C<< subpatterns_of_type ( $type [, $block] ) >>
239              
240             Returns a list of Algebra patterns matching C<< $type >> (tested with C<< isa >>).
241             If C<< $block >> is given, then matching stops descending a subtree if the current
242             node is of type C<< $block >>, continuing matching on other subtrees.
243             This list includes the current algebra object if it matches C<< $type >>, and is
244             generated in infix order.
245              
246             =cut
247              
248             sub subpatterns_of_type {
249 2677     2677 1 4070 my $self = shift;
250 2677         3430 my $type = shift;
251 2677         3267 my $block = shift;
252            
253 2677 100 100     8937 return if ($block and $self->isa($block));
254            
255 2676         2898 my @patterns;
256 2676 100       11339 push(@patterns, $self) if ($self->isa($type));
257 2676         7413 foreach my $arg ($self->construct_args) {
258 5849 100 100     59118 if (blessed($arg) and $arg->isa('RDF::Query::Algebra')) {
    100 100        
259 2250         5094 push(@patterns, $arg->subpatterns_of_type($type, $block));
260             } elsif (blessed($arg) and $arg->isa('RDF::Query')) {
261 5         15 my $pattern = $arg->pattern;
262 5         16 push(@patterns, $pattern->subpatterns_of_type($type, $block));
263             }
264             }
265 2676         6864 return @patterns;
266             }
267              
268             =item C<< from_sse ( $sse, \%context ) >>
269              
270             Given an SSE serialization, returns the corresponding algebra expression.
271              
272             =cut
273              
274             sub from_sse {
275 4     4 1 1691 my $class = shift;
276 4         9 my $context = $_[1];
277 4 100       12 if (substr($_[0], 0, 1) eq '(') {
278 3         8 for ($_[0]) {
279 3 50       18 if (my ($tag) = m/^[(](\w+)/) {
280 3 50       9 if ($tag eq 'prefix') {
281 0         0 s/^[(]prefix\s*[(]\s*//;
282 0 0       0 my $c = { %{ $context || {} } };
  0         0  
283 0         0 while (my ($ns, $iri) = m/^[(](\S+):\s*<([^>]+)>[)]/) {
284 0         0 s/^[(](\S+):\s*<([^>]+)>[)]\s*//;
285 0         0 $c->{namespaces}{ $ns } = $iri;
286 0         0 $context = $c;
287             }
288 0         0 s/^[)]\s*//;
289 0         0 my $alg = $class->from_sse( $_, $c );
290 0         0 s/^[)]\s*//;
291 0         0 return $alg;
292             }
293            
294 3 50       12 if (my $class = SSE_TAGS->{ $tag }) {
295 3 100       35 if ($class->can('_from_sse')) {
296 2         11 return $class->_from_sse( $_, $context );
297             } else {
298 1         6 s/^[(](\w+)\s*//;
299 1         3 my @nodes;
300 1         12 while (my $alg = $class->from_sse( $_, $context )) {
301 1         354 push(@nodes, $alg);
302             }
303 1         7 return $class->new( @nodes );
304             }
305             } else {
306 0         0 throw RDF::Query::Error -text => "Unknown SSE tag '$tag' in SSE string: >>$_<<";
307             }
308             } else {
309 0         0 throw RDF::Trine::Error -text => "Cannot parse pattern from SSE string: >>$_<<";
310             }
311             }
312             } else {
313 1         5 return;
314             }
315             }
316              
317             =back
318              
319             =head1 FUNCTIONS
320              
321             =over 4
322              
323             =item C<< triple ( $subj, $pred, $obj ) >>
324              
325             Returns a RDF::Query::Algebra::Triple object with the supplied node objects.
326              
327             =cut
328              
329             sub triple {
330 0     0 1   my @nodes = @_[0..2];
331 0           return RDF::Query::Algebra::Triple->new( @nodes );
332             }
333              
334             =item C<< bgp ( @triples ) >>
335              
336             Returns a RDF::Query::Algebra::BasicGraphPattern object with the supplied triples.
337              
338             =cut
339              
340             sub bgp {
341 0     0 1   my @triples = @_;
342 0           return RDF::Query::Algebra::BasicGraphPattern->new( @triples );
343             }
344              
345             =item C<< ggp ( @patterns ) >>
346              
347             Returns a RDF::Query::Algebra::GroupGraphPattern object with the supplied algebra patterns.
348              
349             =cut
350              
351             sub ggp {
352 0     0 1   my @patterns = @_;
353 0           return RDF::Query::Algebra::GroupGraphPattern->new( @patterns );
354             }
355              
356              
357              
358             1;
359              
360             __END__
361              
362             =back
363              
364             =head1 AUTHOR
365              
366             Gregory Todd Williams <gwilliams@cpan.org>
367              
368             =cut