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.916.
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   256 use strict;
  35         74  
  35         937  
24 35     35   186 use warnings;
  35         81  
  35         1057  
25 35     35   188 use base qw(RDF::Query::Plan);
  35         90  
  35         2659  
26              
27 35     35   211 use Scalar::Util qw(blessed);
  35         75  
  35         1676  
28 35     35   220 use RDF::Trine::Statement;
  35         82  
  35         1701  
29              
30             ######################################################################
31              
32             our ($VERSION);
33             BEGIN {
34 35     35   37838 $VERSION = '2.916';
35             }
36              
37             ######################################################################
38              
39             =item C<< new ( @triples ) >>
40              
41             =cut
42              
43             sub new {
44 76     76 1 153 my $class = shift;
45             my @triples = map {
46 76         185 my @nodes = $_->nodes;
  206         2730  
47 206   33     1544 $nodes[3] ||= RDF::Trine::Node::Nil->new();
48 206 50       2688 (scalar(@nodes) == 4)
49             ? RDF::Trine::Statement::Quad->new( @nodes )
50             : RDF::Trine::Statement->new( @nodes )
51             } @_;
52 76         1470 my @vars = map { $_->name } grep { $_->isa('RDF::Trine::Node::Variable') } map { $_->nodes } @triples;
  330         1546  
  824         2644  
  206         963  
53 76         535 my @uvars = keys %{ { map { $_ => 1 } @vars } };
  76         159  
  330         1010  
54 76         622 my $self = $class->SUPER::new( \@triples );
55 76         346 $self->[0]{referenced_variables} = \@uvars;
56 76         311 return $self;
57             }
58              
59             =item C<< execute ( $execution_context ) >>
60              
61             =cut
62              
63             sub execute ($) {
64 78     78 1 1012 my $self = shift;
65 78         154 my $context = shift;
66 78         281 $self->[0]{delegate} = $context->delegate;
67 78 50       356 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         361 my $l = Log::Log4perl->get_logger("rdf.query.plan.basicgraphpattern");
72 78         11529 $l->trace( "executing RDF::Query::Plan::BasicGraphPattern" );
73            
74 78         701 my @bound_triples;
75 78         288 my $bound = $context->bound;
76 78 100       287 if (%$bound) {
77 5         15 $self->[0]{bound} = $bound;
78 5         10 my @triples = @{ $self->[1] };
  5         16  
79 5         19 foreach my $j (0 .. $#triples) {
80 10         39 my @nodes = $triples[$j]->nodes;
81 10         60 foreach my $i (0 .. $#nodes) {
82 40 100       284 next unless ($nodes[$i]->isa('RDF::Trine::Node::Variable'));
83 26 100       82 next unless (blessed($bound->{ $nodes[$i]->name }));
84             # warn "pre-bound variable found: " . $nodes[$i]->name;
85 9         82 $nodes[$i] = $bound->{ $nodes[$i]->name };
86             }
87 10 50       82 my $triple = (scalar(@nodes) == 4)
88             ? RDF::Trine::Statement::Quad->new( @nodes )
89             : RDF::Trine::Statement->new( @nodes );
90 10         193 push(@bound_triples, $triple);
91             }
92             } else {
93 73         138 @bound_triples = @{ $self->[1] };
  73         244  
94             }
95            
96 78 50       184 my @tmp = grep { $_->isa('RDF::Trine::Statement::Quad') and $_->context->isa('RDF::Trine::Node::Variable') } @bound_triples;
  210         2483  
97 78 50       811 my $quad = scalar(@tmp) ? $tmp[0]->context : undef;
98            
99 78         282 my $model = $context->model;
100 78         1345 my $pattern = RDF::Trine::Pattern->new( @bound_triples );
101 78         1929 $l->trace( "BGP: " . $pattern->sse );
102 78         11308 my $iter = $model->get_pattern( $pattern );
103            
104 78 50       328827 if (blessed($iter)) {
105 78         276 $self->[0]{iter} = $iter;
106 78         220 $self->[0]{quad} = $quad;
107 78         385 $self->[0]{nil} = RDF::Trine::Node::Nil->new();
108 78         971 $self->state( $self->OPEN );
109             } else {
110 0         0 warn "no iterator in execute()";
111             }
112 78         401 $self;
113             }
114              
115             =item C<< next >>
116              
117             =cut
118              
119             sub next {
120 256     256 1 401 my $self = shift;
121 256 50       782 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 256         510 my $q = $self->[0]{quad};
126            
127 256         432 my $iter = $self->[0]{iter};
128 256 50       1057 return undef unless ($iter);
129 256         2011 while (ref(my $row = $iter->next)) {
130 194 100       4338 if (ref(my $bound = $self->[0]{bound})) {
131 4         12 @{ $row }{ keys %$bound } = values %$bound;
  4         12  
132             }
133 194 50       616 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 194         942 my $result = RDF::Query::VariableBindings->new( $row );
143 194 50       797 if (my $d = $self->delegate) {
144 0         0 $d->log_result( $self, $result );
145             }
146 194         808 return $result;
147             }
148 62         1562 return;
149             }
150              
151             =item C<< close >>
152              
153             =cut
154              
155             sub close {
156 78     78 1 160 my $self = shift;
157 78 50       269 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         581 delete $self->[0]{iter};
162 78         568 $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 300 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 213 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 66 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 45 my $self = shift;
205 25         86 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 43 my $self = shift;
217 26         38 my @triples = @{ $self->[1] };
  26         86  
218 26         86 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