File Coverage

blib/lib/DataWarehouse/Fact.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package DataWarehouse::Fact;
2              
3 1     1   24800 use warnings;
  1         4  
  1         34  
4 1     1   7 use strict;
  1         2  
  1         52  
5              
6             our $VERSION = '0.04';
7              
8 1     1   6 use Carp;
  1         6  
  1         91  
9 1     1   1128 use Data::Dumper;
  1         24088  
  1         101  
10 1     1   422 use DBI;
  0            
  0            
11              
12             use DataWarehouse::Dimension;
13             use DataWarehouse::Aggregate;
14              
15             use List::MoreUtils qw/uniq/;
16              
17             sub new {
18             my ( $class, %params ) = @_;
19              
20             croak "Error: One of 'dbh' or 'dsn' parameters is required" if !($params{dbh} xor $params{dsn});
21             croak "Error: missing fact name" if !$params{name};
22              
23             if ( $params{dsn} ) {
24             $params{dbh} = DBI->connect( $params{dsn}, $params{db_user}, $params{db_password} );
25             }
26              
27             bless {%params}, $class;
28             }
29              
30             sub dimension {
31             my ( $self, $dim_table ) = @_;
32              
33             return DataWarehouse::Dimension->new(
34             dbh => $self->{dbh},
35             name => $dim_table,
36             );
37             }
38              
39             sub aggregate {
40             my ( $self, @dimensions ) = @_;
41              
42             return DataWarehouse::Aggregate->new(
43             dbh => $self->{dbh},
44             base_table => $self->{name},
45             dimension => \@dimensions,
46             );
47             }
48              
49             sub base_query {
50             my ( $self, $dim_attr, $where ) = @_;
51              
52             # @dim_attr is a list of "table.columns"
53             my $fact_table = $self->{name};
54             my @dim_attr = @{$dim_attr};
55             my @dim_tables = uniq( map { ( split( /\./, $_ ) )[0] } @dim_attr );
56              
57             my $query = <<"SQL";
58             SELECT
59             @{[ join(", ", @dim_attr) ]},
60             SUM(n) AS n
61             FROM
62             $fact_table
63             JOIN
64             @{[ join(",\n", map { $self->_join_str($_) } @dim_tables) ]}
65             GROUP BY
66             @{[ join(", ", @dim_attr) ]}
67             SQL
68              
69             return $query;
70              
71             my $dbh = $self->{dbh};
72              
73             my $sth = $dbh->prepare($query);
74              
75             my $rv = $sth->execute() or die $dbh->errstr;
76              
77             return $sth->fetchall_arrayref();
78             }
79              
80             sub aggr_query {
81             my ( $self, $dim_attr, $where ) = @_;
82              
83             my $base_query = $self->base_query( $dim_attr, $where );
84              
85             my @dim_attr = @{$dim_attr};
86             my @dim_tables = uniq( map { ( split( /\./, $_ ) )[0] } @dim_attr );
87              
88             # don't aggregate the full granularity
89             return $base_query if scalar @dim_attr == scalar @{ $self->{dimension} };
90              
91             my $aggregate = $self->aggregate(@dim_tables);
92              
93             # only necessary if the aggregate
94             # does not exist
95             $aggregate->create();
96              
97             my $fact_table = $self->{name};
98             my $aggr_table = $aggregate->name();
99              
100             if ($aggr_table) {
101             $base_query =~ s/$fact_table/$aggr_table/gs;
102             }
103              
104             return $base_query;
105             }
106              
107             sub prepare {
108             my $self = shift;
109              
110             $self->{sth} = $self->{dbh}->prepare(@_);
111              
112             return $self->{sth};
113             }
114              
115             sub _join_str {
116             my ( $self, $dim_table ) = @_;
117             my $fact_table = $self->{name};
118             return " $dim_table ON $fact_table.$dim_table = $dim_table.id";
119             }
120              
121             1;
122              
123             __END__