File Coverage

blib/lib/RDF/Query/Algebra/Aggregate.pm
Criterion Covered Total %
statement 89 115 77.3
branch 10 20 50.0
condition 6 13 46.1
subroutine 18 21 85.7
pod 12 12 100.0
total 135 181 74.5


line stmt bran cond sub pod time code
1             # RDF::Query::Algebra::Aggregate
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Query::Algebra::Aggregate - Algebra class for aggregate patterns
7              
8             =head1 VERSION
9              
10             This document describes RDF::Query::Algebra::Aggregate version 2.916.
11              
12             =cut
13              
14             package RDF::Query::Algebra::Aggregate;
15              
16 36     36   179 use strict;
  36         70  
  36         900  
17 36     36   183 use warnings;
  36         66  
  36         938  
18 36     36   178 no warnings 'redefine';
  36         66  
  36         1150  
19 36     36   197 use base qw(RDF::Query::Algebra);
  36         69  
  36         2762  
20              
21 36     36   186 use Scalar::Util qw(blessed reftype);
  36         92  
  36         1847  
22 36     36   178 use Data::Dumper;
  36         67  
  36         1674  
23 36     36   168 use Carp qw(carp croak confess);
  36         75  
  36         2174  
24 36     36   198 use RDF::Trine::Iterator qw(smap);
  36         74  
  36         2269  
25              
26             ######################################################################
27              
28             our ($VERSION);
29             BEGIN {
30 36     36   44992 $VERSION = '2.916';
31             }
32              
33             ######################################################################
34              
35             =head1 METHODS
36              
37             Beyond the methods documented below, this class inherits methods from the
38             L<RDF::Query::Algebra> class.
39              
40             =over 4
41              
42             =cut
43              
44             =item C<new ( $pattern, \@groupby, $alias => [$op => $col] )>
45              
46             =item C<new ( $pattern, \@groupby, expressions => [ $alias => [$op, \%options, @cols] ] )>
47              
48             Returns a new Aggregate structure. Groups by the named bindings in C<< @groupby >>,
49             and returns new bindings for the named C<< $alias >> for the operation C<< $op >>
50             on column C<< $col >>.
51              
52             C<< $op >> may be one of: COUNT, MIN, MAX, SUM.
53              
54             =cut
55              
56             sub new {
57 17     17 1 37 my $class = shift;
58 17         30 my $pattern = shift;
59 17         26 my $groupby = shift;
60 17         26 my @ops;
61 17 50 33     199 if (scalar(@_) and ref($_[0]) and reftype($_[0]) eq 'HASH') {
      33        
62 17         35 my $hash = shift;
63 17 50       32 @ops = @{ $hash->{ 'expressions' } || [] };
  17         85  
64             } else {
65 0         0 while (@_) {
66 0         0 my ($alias, $data) = splice(@_,0,2,());
67 0         0 my $op = shift(@$data);
68 0         0 my @data = ($op, {}, @$data);
69 0         0 push(@ops, $alias, \@data);
70             }
71 0         0 @ops = @_;
72             }
73            
74 17         70 return bless( [ $pattern, $groupby, \@ops ] );
75             }
76              
77             =item C<< construct_args >>
78              
79             Returns a list of arguments that, passed to this class' constructor,
80             will produce a clone of this algebra pattern.
81              
82             =cut
83              
84             sub construct_args {
85 84     84 1 126 my $self = shift;
86 84         94 my @ops = @{ $self->[2] };
  84         234  
87 84         195 return ($self->pattern, [ $self->groupby ], { expressions => \@ops });
88             }
89              
90             =item C<< pattern >>
91              
92             Returns the aggregates pattern.
93              
94             =cut
95              
96             sub pattern {
97 156     156 1 193 my $self = shift;
98 156         569 return $self->[0];
99             }
100              
101             =item C<< groupby >>
102              
103             Returns the aggregate's GROUP BY binding names.
104              
105             =cut
106              
107             sub groupby {
108 202     202 1 257 my $self = shift;
109 202         212 return @{ $self->[1] };
  202         752  
110             }
111              
112             =item C<< ops >>
113              
114             Returns a list of tuples as ARRAY refs containing C<< $alias, $op, @cols >>.
115              
116             =cut
117              
118             sub ops {
119 80     80 1 131 my $self = shift;
120 80         97 my @ops = @{ $self->[2] };
  80         186  
121 80         101 my @tuples;
122 80         220 while (@ops) {
123 90         130 my $alias = shift(@ops);
124 90         129 my $data = shift(@ops);
125 90         188 my ($op, $opts, @col) = @$data;
126 90         436 push(@tuples, [$alias, $op, $opts, @col]);
127             }
128 80         242 return @tuples;
129             }
130              
131             =item C<< sse >>
132              
133             Returns the SSE string for this algebra expression.
134              
135             =cut
136              
137             sub sse {
138 53     53 1 84 my $self = shift;
139 53         74 my $context = shift;
140 53   100     144 my $prefix = shift || '';
141 53   50     156 my $indent = ($context->{indent} ||= ' ');
142            
143 53         58 my @ops_sse;
144 53         112 my @ops = $self->ops;
145 53         94 foreach my $data (@ops) {
146 59         170 my ($alias, $op, $opts, @cols) = @$data;
147 59 50 33     114 my @col_strings = map { (not(blessed($_)) and $_ eq '*') ? '*' : $_->sse( $context, "${prefix}${indent}" ) } @cols;
  59         401  
148 59         580 my $col_string = join(' ', @col_strings);
149 59 50       146 if (@col_strings > 1) {
150 0         0 $col_string = '(' . $col_string . ')';
151             }
152 59 50       95 my %op_opts = %{ $opts || {} };
  59         193  
153 59         111 my @opts_keys = keys %op_opts;
154 59 50       110 if (@opts_keys) {
155 0         0 my $opt_string = '(' . join(' ', map { $_, qq["$op_opts{$_}"] } @opts_keys) . ')';
  0         0  
156 0         0 push(@ops_sse, sprintf('(alias "%s" (%s %s %s))', $alias, $op, $col_string, $opt_string));
157             } else {
158 59         287 push(@ops_sse, sprintf('(alias "%s" (%s %s))', $alias, $op, $col_string));
159             }
160             }
161            
162 53         118 my @group = $self->groupby;
163 53 100       131 my $group = (@group) ? '(' . join(', ', map {$_->sse($context, $prefix)} @group) . ')' : '';
  26         73  
164 53         378 return sprintf(
165             "(aggregate\n${prefix}${indent}%s\n${prefix}${indent}(%s)\n${prefix}${indent}%s)",
166             $self->pattern->sse( $context, "${prefix}${indent}" ),
167             join(', ', @ops_sse),
168             $group,
169             );
170             }
171              
172             =item C<< as_sparql >>
173              
174             Returns the SPARQL string for this algebra expression.
175              
176             =cut
177              
178             sub as_sparql {
179 1     1 1 2 my $self = shift;
180 1         3 my $context = shift;
181 1         2 my $indent = shift;
182 1         3 return $self->pattern->as_sparql($context, $indent);
183             }
184              
185             =item C<< as_hash >>
186              
187             Returns the query as a nested set of plain data structures (no objects).
188              
189             =cut
190              
191             sub as_hash {
192 0     0 1 0 my $self = shift;
193 0         0 my $context = shift;
194            
195 0         0 my @ops = $self->ops;
196 0         0 my @expressions;
197 0         0 foreach my $o (@ops) {
198 0         0 my ($alias, $op, $agg_options, @cols) = @$o;
199 0         0 push(@expressions, { alias => $alias, op => $op, scalarvals => $agg_options, columns => [ map { $_->as_hash } @cols ] });
  0         0  
200             }
201            
202             return {
203             type => lc($self->type),
204             pattern => $self->pattern->as_hash,
205 0         0 groupby => [ map { $_->as_hash } $self->groupby ],
  0         0  
206             expressions => \@expressions,
207             };
208             }
209              
210             =item C<< type >>
211              
212             Returns the type of this algebra expression.
213              
214             =cut
215              
216             sub type {
217 0     0 1 0 return 'AGGREGATE';
218             }
219              
220             =item C<< referenced_variables >>
221              
222             Returns a list of the variable names used in this algebra expression.
223              
224             =cut
225              
226             sub referenced_variables {
227 2     2 1 4 my $self = shift;
228 2         6 my @aliases = map { $_->[0] } $self->ops;
  2         6  
229 2         7 return RDF::Query::_uniq( @aliases, $self->pattern->referenced_variables );
230             }
231              
232             =item C<< potentially_bound >>
233              
234             Returns a list of the variable names used in this algebra expression that will
235             bind values during execution.
236              
237             =cut
238              
239             sub potentially_bound {
240 16     16 1 25 my $self = shift;
241 16         24 my @vars;
242             # push(@vars, map { $_->[0] } $self->ops);
243 16         63 foreach my $g ($self->groupby) {
244 7 50       49 if (blessed($g)) {
245 7 50       35 if ($g->isa('RDF::Query::Node::Variable')) {
    0          
246 7         25 push(@vars, $g->name);
247             } elsif ($g->isa('RDF::Query::Expression::Alias')) {
248 0         0 push(@vars, $g->name);
249             }
250             }
251             }
252 16         116 return RDF::Query::_uniq(@vars);
253             # return RDF::Query::_uniq( @aliases, $self->pattern->referenced_variables );
254             }
255              
256             =item C<< definite_variables >>
257              
258             Returns a list of the variable names that will be bound after evaluating this algebra expression.
259              
260             =cut
261              
262             sub definite_variables {
263 0     0 1   my $self = shift;
264 0           my @aliases = map { $_->[0] } $self->ops;
  0            
265 0           return @aliases;
266             }
267              
268             1;
269              
270             __END__
271              
272             =back
273              
274             =head1 AUTHOR
275              
276             Gregory Todd Williams <gwilliams@cpan.org>
277              
278             =cut