blob: 9c275e895a9ed8535e9befaed44d3c31ead47f7c [file] [log] [blame]
Akron5cf5fca2017-10-09 19:01:47 +02001package Krawfish::Koral::Compile::Aggregate;
2use Krawfish::Koral::Compile::Node::Aggregate;
Akrona411d312017-08-12 01:15:11 +02003use Krawfish::Log;
Akron78c49502017-07-27 16:00:36 +02004use List::MoreUtils qw/uniq/;
5use strict;
6use warnings;
7
Akron94256e62017-10-10 17:29:18 +02008use constant DEBUG => 0;
Akrona411d312017-08-12 01:15:11 +02009
Akron78c49502017-07-27 16:00:36 +020010# TODO:
11# Check that only valid aggregate objects are passed
12
13our %AGGR_ORDER = (
14 'length' => 1,
15 'freq' => 2,
Akrona3581a92017-08-17 17:45:37 +020016 'fields' => 3,
Akronc1ed58c2017-08-04 17:26:30 +020017 'values' => 4
Akron78c49502017-07-27 16:00:36 +020018);
19
Akrona588d072017-10-13 14:45:34 +020020
21# Constructor
Akron78c49502017-07-27 16:00:36 +020022sub new {
23 my $class = shift;
24 bless [@_], $class;
25};
26
27
Akrona588d072017-10-13 14:45:34 +020028# Aggregation type
Akron78c49502017-07-27 16:00:36 +020029sub type {
30 'aggregate';
31};
32
Akrona411d312017-08-12 01:15:11 +020033
Akron78c49502017-07-27 16:00:36 +020034# Get or set operations
35sub operations {
36 my $self = shift;
37 if (@_) {
38 @$self = @_;
39 return $self;
40 };
41 return @$self;
42};
43
Akronc1ed58c2017-08-04 17:26:30 +020044
Akrona411d312017-08-12 01:15:11 +020045# Wrap aggregates in each other
Akronc1ed58c2017-08-04 17:26:30 +020046sub wrap {
47 my ($self, $query) = @_;
48
Akrona411d312017-08-12 01:15:11 +020049 if (DEBUG) {
50 print_log('kq_aggr', 'Wrap operation ' . join(',', @$self));
51 };
Akronc1ed58c2017-08-04 17:26:30 +020052
Akrona411d312017-08-12 01:15:11 +020053 # Join aggregates
Akron5cf5fca2017-10-09 19:01:47 +020054 return Krawfish::Koral::Compile::Node::Aggregate->new(
Akronc1ed58c2017-08-04 17:26:30 +020055 $query,
56 [$self->operations]
57 );
Akrona411d312017-08-12 01:15:11 +020058
59 return $query;
Akronc1ed58c2017-08-04 17:26:30 +020060};
61
62
Akron78c49502017-07-27 16:00:36 +020063# Normalize aggregations
64sub normalize {
65 my $self = shift;
66
67 # Sort objects in defined order
68 my @ops = sort {
69 $AGGR_ORDER{$a->type} <=> $AGGR_ORDER{$b->type}
70 } @$self;
71
72 # Check for doubles
73 for (my $i = 1; $i < @ops; $i++) {
74
75 # Two consecutive operations are identical
76 if ($ops[$i]->type eq $ops[$i-1]->type) {
77
Akrona3581a92017-08-17 17:45:37 +020078 # Merge fields or values
79 if ($ops[$i]->type eq 'fields' || $ops[$i]->type eq 'values') {
Akron78c49502017-07-27 16:00:36 +020080 $ops[$i-1]->operations(
81 $ops[$i-1]->operations,
82 $ops[$i]->operations
Akroncfa3e012017-08-07 19:46:41 +020083 );
Akron78c49502017-07-27 16:00:36 +020084
Akroncfa3e012017-08-07 19:46:41 +020085 # Remove double operation
86 splice(@ops, $i, 1);
87 $i--;
88 }
89
90 else {
91 # Remove double operation
92 splice(@ops, $i, 1);
93 };
Akron78c49502017-07-27 16:00:36 +020094
Akron4204f172017-10-02 22:32:02 +020095 CORE::next;
Akron78c49502017-07-27 16:00:36 +020096 };
97
98 # Normalize when no longer consecutive operations
99 # can be expected
100 $ops[$i-1] = $ops[$i-1]->normalize;
101 };
102
103 # Normalize last operation
104 $ops[-1] = $ops[-1]->normalize;
105
106 $self->operations(@ops);
107
108 return $self;
109};
110
111
Akrona588d072017-10-13 14:45:34 +0200112# Stringification
Akron78c49502017-07-27 16:00:36 +0200113sub to_string {
Akron10448e12017-10-11 18:04:53 +0200114 my ($self, $id) = @_;
115 return 'aggr=[' . join(',', map { $_->to_string($id) } @$self) . ']';
Akron78c49502017-07-27 16:00:36 +0200116};
117
Akron492674d2017-10-11 16:30:34 +0200118
Akron78c49502017-07-27 16:00:36 +02001191;