File Coverage

blib/lib/Cache/Historical.pm
Criterion Covered Total %
statement 105 111 94.5
branch 15 22 68.1
condition n/a
subroutine 20 21 95.2
pod 7 13 53.8
total 147 167 88.0


line stmt bran cond sub pod time code
1             ###########################################
2             package Cache::Historical;
3             ###########################################
4 2     2   2140 use strict;
  2         4  
  2         71  
5 2     2   10 use warnings;
  2         3  
  2         57  
6 2     2   2342 use Rose::DB::Object::Loader;
  2         1965050  
  2         64  
7 2     2   24 use File::Basename;
  2         5  
  2         227  
8 2     2   13 use File::Path;
  2         3  
  2         97  
9 2     2   2618 use Log::Log4perl qw(:easy);
  2         114376  
  2         16  
10 2     2   1135 use DBI;
  2         5  
  2         92  
11 2     2   2848 use DateTime::Format::Strptime;
  2         16566  
  2         2306  
12              
13             our $VERSION = "0.05";
14              
15             ###########################################
16             sub new {
17             ###########################################
18 2     2 1 1549 my($class, %options) = @_;
19              
20 2         89 my($home) = glob "~";
21 2         8 my $default_cache_dir = "$home/.cache-historical";
22              
23 2         13 my $self = {
24             sqlite_file => "$default_cache_dir/cache-historical.dat",
25             %options,
26             };
27              
28 2         109 my $cache_dir = dirname( $self->{sqlite_file} );
29              
30 2 50       61 if(! -d $cache_dir ) {
31 0 0       0 mkpath [ $cache_dir ] or
32             die "Cannot mktree $cache_dir ($!)";
33             }
34              
35 2         6 bless $self, $class;
36              
37 2         19 $self->{dsn} = "dbi:SQLite:dbname=$self->{sqlite_file}";
38              
39 2 50       54 if(! -f $self->{sqlite_file}) {
40 2         10 $self->db_init();
41             }
42              
43 2         96 my $loader =
44             Rose::DB::Object::Loader->new(
45             db_dsn => $self->{dsn},
46             db_options => { AutoCommit => 1, RaiseError => 1 },
47             class_prefix => 'Cache::Historical',
48             with_managers => 1,
49             );
50              
51 2         433 $loader->make_classes();
52              
53 2         146993 $self->{loader} = $loader;
54              
55 2         20 return $self;
56             }
57              
58             ###########################################
59             sub make_modules {
60             ###########################################
61 0     0 0 0 my($self, @options) = @_;
62              
63 0         0 DEBUG "Making modules in @options";
64 0         0 $self->{loader}->make_modules( @options );
65             }
66              
67             ###########################################
68             sub dbh {
69             ###########################################
70 3     3 0 5 my($self) = @_;
71              
72 3 100       14 if(! $self->{dbh} ) {
73 2         22 $self->{dbh} = DBI->connect($self->{dsn}, "", "");
74             }
75              
76 3         21457 return $self->{dbh};
77             }
78              
79             ###########################################
80             sub db_init {
81             ###########################################
82 2     2 0 5 my($self) = @_;
83              
84 2         9 my $dbh = $self->dbh();
85              
86 2         23 DEBUG "Creating new SQLite db $self->{sqlite_file}";
87              
88 2         50 $dbh->do(<<'EOT');
89             CREATE TABLE vals (
90             id INTEGER PRIMARY KEY,
91             date DATETIME,
92             upd_time DATETIME,
93             key TEXT,
94             value TEXT,
95             UNIQUE(date, key)
96             );
97             EOT
98              
99 2         282358 $dbh->do(<<'EOT');
100             CREATE INDEX vals_date_idx ON vals(date);
101             EOT
102              
103 2         26750 $dbh->do(<<'EOT');
104             CREATE INDEX vals_key_idx ON vals(key);
105             EOT
106              
107 2         20022 return 1;
108             }
109              
110             ###########################################
111             sub set {
112             ###########################################
113 6     6 0 1121600 my($self, $dt, $key, $value) = @_;
114              
115 6         46 DEBUG "Setting $dt $key => $value";
116              
117 6         436 my $r = Cache::Historical::Val->new();
118 6         325 $r->key( $key );
119 6         122 $r->date( $dt );
120 6         3752 $r->upd_time( DateTime->now() );
121 6         11919 $r->load( speculative => 1 );
122 6         18076 $r->value( $value );
123 6         91 $r->save();
124             }
125              
126             ###########################################
127             sub get {
128             ###########################################
129 10     10 0 39310 my($self, $dt, $key, $interpolate) = @_;
130              
131 10         34 my @date_query = (date => $dt);
132 10 100       242 @date_query = (date => {le => $dt}) if $interpolate;
133              
134 10         99 my $values = Cache::Historical::Val::Manager->get_vals(
135             query => [
136             @date_query,
137             key => $key,
138             ],
139             sort_by => "date DESC",
140             limit => 1,
141             );
142              
143 10 100       50215 if(@$values) {
144 4         123 my $value = $values->[0]->value();
145 4         43 DEBUG "Getting $dt $key => $value";
146 4         334 return $value;
147             }
148              
149 6         75 return undef;
150             }
151              
152             ###########################################
153             sub keys {
154             ###########################################
155 1     1 1 938 my($self) = @_;
156              
157 1         2 my @keys;
158 1         10 my $keys = Cache::Historical::Val::Manager->get_vals(
159             distinct => 1,
160             select => [ 'key' ],
161             );
162              
163 1         4026 for(@$keys) {
164 2         74 push @keys, $_->key();
165             }
166              
167 1         17 return @keys;
168             }
169              
170             ###########################################
171             sub values {
172             ###########################################
173 1     1 1 55717 my($self, $key) = @_;
174              
175 1         5 my @values = ();
176 1         2 my @key = ();
177 1 50       10 @key = (key => $key) if defined $key;
178              
179 1         22 my $values = Cache::Historical::Val::Manager->get_vals(
180             query => [ @key ],
181             sort_by => ['date'],
182             );
183              
184 1         5071 for(@$values) {
185 4         1985 push @values, [$_->date(), $_->value()];
186             }
187              
188 1         581 return @values;
189             }
190              
191             ###########################################
192             sub last_update {
193             ###########################################
194 4     4 1 16314 my($self, $key) = @_;
195              
196 4         10 my @key = ();
197 4 100       19 @key = (key => $key) if defined $key;
198              
199 4         27 my $values = Cache::Historical::Val::Manager->get_vals(
200             query => [ @key ],
201             sort_by => ['upd_time DESC'],
202             limit => 1,
203             );
204              
205 4 50       12790 if(@$values) {
206 4         18 my $date = $values->[0]->upd_time();
207 4         2249 return $date;
208             }
209              
210 0         0 return undef;
211             }
212              
213             ###########################################
214             sub since_last_update {
215             ###########################################
216 2     2 1 1685 my($self, $key) = @_;
217              
218 2         8 my $date = $self->last_update($key);
219              
220 2 50       334 if(defined $date) {
221 2         10 return DateTime->now() - $date;
222             }
223              
224 0         0 return undef;
225             }
226              
227             ###########################################
228             sub get_interpolated {
229             ###########################################
230 8     8 0 42924 my($self, $dtp, $key) = @_;
231              
232 8         38 return $self->get($dtp, $key, 1);
233             }
234              
235             my $date_fmt = DateTime::Format::Strptime->new(
236             pattern => "%Y-%m-%d %H:%M:%S");
237              
238             ###########################################
239             sub time_range {
240             ###########################################
241 1     1 1 3 my($self, $key) = @_;
242              
243 1         5 my $dbh = $self->dbh();
244              
245 1         18 my($from, $to) = $dbh->selectrow_array(
246             "SELECT MIN(date), MAX(date) FROM vals WHERE key = " .
247             $dbh->quote( $key ));
248              
249 1         216 $from = $date_fmt->parse_datetime( $from );
250 1         784 $to = $date_fmt->parse_datetime( $to );
251              
252 1         593 return($from, $to);
253             }
254              
255             ###########################################
256             sub clear {
257             ###########################################
258 2     2 1 2288 my($self, $key) = @_;
259              
260 2         8 my @params = (all => 1);
261              
262 2 100       10 if(defined $key) {
263 1         6 @params = ("where" => [ key => $key ]);
264             }
265              
266 2         18 my $values = Cache::Historical::Val::Manager->delete_vals( @params );
267             }
268              
269             1;
270              
271             __END__