File Coverage

blib/lib/RDF/Query/Plan/BasicGraphPattern.pm
Criterion Covered Total %
statement 93 101 92.0
branch 19 34 55.8
condition 1 3 33.3
subroutine 15 15 100.0
pod 9 9 100.0
total 137 162 84.5


line stmt bran cond sub pod time code
1             # RDF::Query::Plan::BasicGraphPattern
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Query::Plan::BasicGraphPattern - Executable query plan for BasicGraphPatterns.
7              
8             =head1 VERSION
9              
10             This document describes RDF::Query::Plan::BasicGraphPattern version 2.918.
11              
12             =head1 METHODS
13              
14             Beyond the methods documented below, this class inherits methods from the
15             L<RDF::Query::Plan> class.
16              
17             =over 4
18              
19             =cut
20              
21             package RDF::Query::Plan::BasicGraphPattern;
22              
23 35     35   148 use strict;
  35         53  
  35         882  
24 35     35   137 use warnings;
  35         45  
  35         863  
25 35     35   127 use base qw(RDF::Query::Plan);
  35         42  
  35         2203  
26              
27 35     35   165 use Scalar::Util qw(blessed);
  35         51  
  35         1447  
28 35     35   163 use RDF::Trine::Statement;
  35         50  
  35         1266  
29              
30             ######################################################################
31              
32             our ($VERSION);
33             BEGIN {
34 35     35   25906 $VERSION = '2.918';
35             }
36              
37             ######################################################################
38              
39             =item C<< new ( @triples ) >>
40              
41             =cut
42              
43             sub new {
44 76     76 1 118 my $class = shift;
45             my @triples = map {
46 76         165 my @nodes = $_->nodes;
  206         1645  
47 206   33     981 $nodes[3] ||= RDF::Trine::Node::Nil->new();
48 206 50       1572 (scalar(@nodes) == 4)
49             ? RDF::Trine::Statement::Quad->new( @nodes )
50             : RDF::Trine::Statement->new( @nodes )
51             } @_;
52 76         846 my @vars = map { $_->name } grep { $_->isa('RDF::Trine::Node::Variable') } map { $_->nodes } @triples;
  330         892  
  824         1608  
  206         564  
53 76         378 my @uvars = keys %{ { map { $_ => 1 } @vars } };
  76         120  
  330         743  
54 76         501 my $self = $class->SUPER::new( \@triples );
55 76         244 $self->[0]{referenced_variables} = \@uvars;
56 76         208 return $self;
57             }
58              
59             =item C<< execute ( $execution_context ) >>
60              
61             =cut
62              
63             sub execute ($) {
64 78     78 1 117 my $self = shift;
65 78         103 my $context = shift;
66 78         202 $self->[0]{delegate} = $context->delegate;
67 78 50       251 if ($self->state == $self->OPEN) {
68 0         0 throw RDF::Query::Error::ExecutionError -text => "BGP plan can't be executed twice";
69             }
70            
71 78         566 my $l = Log::Log4perl->get_logger("rdf.query.plan.basicgraphpattern");
72 78         7118 $l->trace( "executing RDF::Query::Plan::BasicGraphPattern" );
73            
74 78         371 my @bound_triples;
75 78         218 my $bound = $context->bound;
76 78 100       209 if (%$bound) {
77 5         8 $self->[0]{bound} = $bound;
78 5         8 my @triples = @{ $self->[1] };
  5         11  
79 5         13 foreach my $j (0 .. $#triples) {
80 10         25 my @nodes = $triples[$j]->nodes;
81 10         36 foreach my $i (0 .. $#nodes) {
82 40 100       186 next unless ($nodes[$i]->isa('RDF::Trine::Node::Variable'));
83 26 100       45 next unless (blessed($bound->{ $nodes[$i]->name }));
84             # warn "pre-bound variable found: " . $nodes[$i]->name;
85 9         49 $nodes[$i] = $bound->{ $nodes[$i]->name };
86             }
87 10 50       51 my $triple = (scalar(@nodes) == 4)
88             ? RDF::Trine::Statement::Quad->new( @nodes )
89             : RDF::Trine::Statement->new( @nodes );
90 10         110 push(@bound_triples, $triple);
91             }
92             } else {
93 73         100 @bound_triples = @{ $self->[1] };
  73         178  
94             }
95            
96 78 50       151 my @tmp = grep { $_->isa('RDF::Trine::Statement::Quad') and $_->context->isa('RDF::Trine::Node::Variable') } @bound_triples;
  210         1847  
97 78 50       583 my $quad = scalar(@tmp) ? $tmp[0]->context : undef;
98            
99 78         223 my $model = $context->model;
100 78         1182 my $pattern = RDF::Trine::Pattern->new( @bound_triples );
101 78         1437 $l->trace( "BGP: " . $pattern->sse );
102 78         7491 my $iter = $model->get_pattern( $pattern );
103            
104 78 50       221688 if (blessed($iter)) {
105 78         232 $self->[0]{iter} = $iter;
106 78         169 $self->[0]{quad} = $quad;
107 78         351 $self->[0]{nil} = RDF::Trine::Node::Nil->new();
108 78         854 $self->state( $self->OPEN );
109             } else {
110 0         0 warn "no iterator in execute()";
111             }
112 78         325 $self;
113             }
114              
115             =item C<< next >>
116              
117             =cut
118              
119             sub next {
120 255     255 1 297 my $self = shift;
121 255 50       550 unless ($self->state == $self->OPEN) {
122 0         0 throw RDF::Query::Error::ExecutionError -text => "next() cannot be called on an un-open BGP";
123             }
124            
125 255         368 my $q = $self->[0]{quad};
126            
127 255         307 my $iter = $self->[0]{iter};
128 255 50       889 return undef unless ($iter);
129 255         1423 while (ref(my $row = $iter->next)) {
130 193 100       3144 if (ref(my $bound = $self->[0]{bound})) {
131 4         10 @{ $row }{ keys %$bound } = values %$bound;
  4         7  
132             }
133 193 50       530 if (blessed($q)) {
134             # skip results when we were matching over variable named graphs (GRAPH ?g {...})
135             # and where the graph variable is bound to the nil node
136             # (the nil node is used to represent the default graph, which should never match inside a GRAPH block).
137 0         0 my $node = $row->{ $q->name };
138 0 0       0 if (blessed($node)) {
139 0 0       0 next if ($node->isa('RDF::Trine::Node::Nil'));
140             }
141             }
142 193         748 my $result = RDF::Query::VariableBindings->new( $row );
143 193 50       657 if (my $d = $self->delegate) {
144 0         0 $d->log_result( $self, $result );
145             }
146 193         754 return $result;
147             }
148 62         1099 return;
149             }
150              
151             =item C<< close >>
152              
153             =cut
154              
155             sub close {
156 78     78 1 119 my $self = shift;
157 78 50       181 unless ($self->state == $self->OPEN) {
158 0         0 throw RDF::Query::Error::ExecutionError -text => "close() cannot be called on an un-open BGP";
159             }
160            
161 78         480 delete $self->[0]{iter};
162 78         456 $self->SUPER::close();
163             }
164              
165             =item C<< distinct >>
166              
167             Returns true if the pattern is guaranteed to return distinct results.
168              
169             =cut
170              
171             sub distinct {
172 59     59 1 208 return 0;
173             }
174              
175             =item C<< ordered >>
176              
177             Returns true if the pattern is guaranteed to return ordered results.
178              
179             =cut
180              
181             sub ordered {
182 44     44 1 175 return [];
183             }
184              
185             =item C<< plan_node_name >>
186              
187             Returns the string name of this plan node, suitable for use in serialization.
188              
189             =cut
190              
191             sub plan_node_name {
192 25     25 1 61 return 'bgp';
193             }
194              
195             =item C<< plan_prototype >>
196              
197             Returns a list of scalar identifiers for the type of the content (children)
198             nodes of this plan node. See L<RDF::Query::Plan> for a list of the allowable
199             identifiers.
200              
201             =cut
202              
203             sub plan_prototype {
204 25     25 1 35 my $self = shift;
205 25         76 return qw(*T);
206             }
207              
208             =item C<< plan_node_data >>
209              
210             Returns the data for this plan node that corresponds to the values described by
211             the signature returned by C<< plan_prototype >>.
212              
213             =cut
214              
215             sub plan_node_data {
216 26     26 1 34 my $self = shift;
217 26         34 my @triples = @{ $self->[1] };
  26         55  
218 26         61 return @triples;
219             }
220              
221             1;
222              
223             __END__
224              
225             =back
226              
227             =head1 AUTHOR
228              
229             Gregory Todd Williams <gwilliams@cpan.org>
230              
231             =cut