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.915_01.
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   250 use strict;
  35         81  
  35         933  
24 35     35   194 use warnings;
  35         81  
  35         1005  
25 35     35   177 use base qw(RDF::Query::Plan);
  35         71  
  35         2647  
26              
27 35     35   198 use Scalar::Util qw(blessed);
  35         77  
  35         1698  
28 35     35   211 use RDF::Trine::Statement;
  35         100  
  35         1635  
29              
30             ######################################################################
31              
32             our ($VERSION);
33             BEGIN {
34 35     35   37205 $VERSION = '2.915_01';
35             }
36              
37             ######################################################################
38              
39             =item C<< new ( @triples ) >>
40              
41             =cut
42              
43             sub new {
44 76     76 1 152 my $class = shift;
45             my @triples = map {
46 76         182 my @nodes = $_->nodes;
  206         2765  
47 206   33     1468 $nodes[3] ||= RDF::Trine::Node::Nil->new();
48 206 50       2594 (scalar(@nodes) == 4)
49             ? RDF::Trine::Statement::Quad->new( @nodes )
50             : RDF::Trine::Statement->new( @nodes )
51             } @_;
52 76         1412 my @vars = map { $_->name } grep { $_->isa('RDF::Trine::Node::Variable') } map { $_->nodes } @triples;
  330         1498  
  824         2556  
  206         931  
53 76         484 my @uvars = keys %{ { map { $_ => 1 } @vars } };
  76         150  
  330         986  
54 76         604 my $self = $class->SUPER::new( \@triples );
55 76         358 $self->[0]{referenced_variables} = \@uvars;
56 76         360 return $self;
57             }
58              
59             =item C<< execute ( $execution_context ) >>
60              
61             =cut
62              
63             sub execute ($) {
64 78     78 1 979 my $self = shift;
65 78         129 my $context = shift;
66 78         277 $self->[0]{delegate} = $context->delegate;
67 78 50       381 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         329 my $l = Log::Log4perl->get_logger("rdf.query.plan.basicgraphpattern");
72 78         10766 $l->trace( "executing RDF::Query::Plan::BasicGraphPattern" );
73            
74 78         550 my @bound_triples;
75 78         287 my $bound = $context->bound;
76 78 100       261 if (%$bound) {
77 5         17 $self->[0]{bound} = $bound;
78 5         10 my @triples = @{ $self->[1] };
  5         18  
79 5         15 foreach my $j (0 .. $#triples) {
80 10         36 my @nodes = $triples[$j]->nodes;
81 10         61 foreach my $i (0 .. $#nodes) {
82 40 100       278 next unless ($nodes[$i]->isa('RDF::Trine::Node::Variable'));
83 26 100       77 next unless (blessed($bound->{ $nodes[$i]->name }));
84             # warn "pre-bound variable found: " . $nodes[$i]->name;
85 9         79 $nodes[$i] = $bound->{ $nodes[$i]->name };
86             }
87 10 50       79 my $triple = (scalar(@nodes) == 4)
88             ? RDF::Trine::Statement::Quad->new( @nodes )
89             : RDF::Trine::Statement->new( @nodes );
90 10         191 push(@bound_triples, $triple);
91             }
92             } else {
93 73         116 @bound_triples = @{ $self->[1] };
  73         242  
94             }
95            
96 78 50       173 my @tmp = grep { $_->isa('RDF::Trine::Statement::Quad') and $_->context->isa('RDF::Trine::Node::Variable') } @bound_triples;
  210         2372  
97 78 50       847 my $quad = scalar(@tmp) ? $tmp[0]->context : undef;
98            
99 78         293 my $model = $context->model;
100 78         1480 my $pattern = RDF::Trine::Pattern->new( @bound_triples );
101 78         1771 $l->trace( "BGP: " . $pattern->sse );
102 78         10802 my $iter = $model->get_pattern( $pattern );
103            
104 78 50       322041 if (blessed($iter)) {
105 78         267 $self->[0]{iter} = $iter;
106 78         212 $self->[0]{quad} = $quad;
107 78         383 $self->[0]{nil} = RDF::Trine::Node::Nil->new();
108 78         927 $self->state( $self->OPEN );
109             } else {
110 0         0 warn "no iterator in execute()";
111             }
112 78         382 $self;
113             }
114              
115             =item C<< next >>
116              
117             =cut
118              
119             sub next {
120 254     254 1 409 my $self = shift;
121 254 50       751 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 254         518 my $q = $self->[0]{quad};
126            
127 254         414 my $iter = $self->[0]{iter};
128 254 50       1045 return undef unless ($iter);
129 254         1970 while (ref(my $row = $iter->next)) {
130 192 100       4135 if (ref(my $bound = $self->[0]{bound})) {
131 4         13 @{ $row }{ keys %$bound } = values %$bound;
  4         13  
132             }
133 192 50       629 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 192         878 my $result = RDF::Query::VariableBindings->new( $row );
143 192 50       799 if (my $d = $self->delegate) {
144 0         0 $d->log_result( $self, $result );
145             }
146 192         822 return $result;
147             }
148 62         1548 return;
149             }
150              
151             =item C<< close >>
152              
153             =cut
154              
155             sub close {
156 78     78 1 159 my $self = shift;
157 78 50       259 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         544 delete $self->[0]{iter};
162 78         528 $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 262 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 224 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 64 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 41 my $self = shift;
205 25         88 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 41 my $self = shift;
217 26         44 my @triples = @{ $self->[1] };
  26         77  
218 26         91 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