File Coverage

blib/lib/File/Properties/Cache.pm
Criterion Covered Total %
statement 62 82 75.6
branch 13 24 54.1
condition 3 6 50.0
subroutine 13 16 81.2
pod 8 8 100.0
total 99 136 72.7


line stmt bran cond sub pod time code
1             # ----------------------------------------------------------------------------
2             #
3             # This module supports caching of data in an SQL database. Once the
4             # cache table format has been defined, a simple interface is available
5             # for inserting and retrieving data from the cache.
6             #
7             # Copyright © 2010,2011 Brendt Wohlberg
8             # See distribution LICENSE file for license details.
9             #
10             # Most recent modification: 4 November 2011
11             #
12             # ----------------------------------------------------------------------------
13              
14             package File::Properties::Cache;
15             our $VERSION = 0.01;
16              
17 4     4   111079 use File::Properties::Error;
  4         13  
  4         33  
18 4     4   3643 use File::Properties::Database;
  4         14  
  4         1743  
19 4     4   25 use base qw(File::Properties::Database);
  4         12  
  4         586  
20              
21             require 5.005;
22 4     4   32 use strict;
  4         10  
  4         166  
23 4     4   23 use warnings;
  4         7  
  4         235  
24 4     4   24 use Error qw(:try);
  4         8  
  4         25  
25              
26              
27             # ----------------------------------------------------------------------------
28             # Initialiser
29             # ----------------------------------------------------------------------------
30             sub _init {
31 2     2   6 my $self = shift;
32 2         5 my $dbfp = shift; # Database file path
33 2         6 my $opts = shift; # Options hash
34              
35             # Initialisation for base
36 2         18 $self->SUPER::_init($dbfp, $opts);
37             # Initialise hash recording cache table information
38 2         6 $self->{'ctbl'} = {};
39             ## Initialise cache persistent metadata table
40 2 50       18 if (not $self->tableexists('FilePropertiesCacheMetaData')) {
41 2         24 $self->definetable('FilePropertiesCacheMetaData',
42             ['Attribute TEXT', 'Value TEXT']);
43 2         15 $self->cmetadata('File::Properties::Cache::Version', $VERSION);
44             }
45             }
46              
47              
48             # ----------------------------------------------------------------------------
49             # Define cache table
50             # ----------------------------------------------------------------------------
51             sub define {
52 3     3 1 8 my $self = shift;
53 3         8 my $tbnm = shift; # Table name
54 3         6 my $cols = shift; # Array of column specifications of form: Name Type
55 3         7 my $opts = shift; # Define options
56              
57             # Set flag indicating whether insertion date column and an
58             # associated trigger should be added to the table
59 3 100 66     37 my $dtrg = (defined $opts and defined $opts->{'IncludeInsertDate'})?
60             $opts->{'IncludeInsertDate'}:0;
61             # Make record of insertion date flag, and initialise properties hash
62             # for new table
63 3         24 $self->{'ctbl'}->{$tbnm} = {'dtrg' => $dtrg, 'props' => {}};
64             ## If table does not exist, initialise it
65 3 50       19 if (!$self->tableexists($tbnm)) {
66             # Add insertion date column to table definition if flag set
67 3 100       14 push @$cols, 'InsertDate DATE' if ($dtrg);
68             # Define the database table
69 3         18 $self->definetable($tbnm, $cols);
70             # Create the insertion date trigger if flag set
71 3 100       27 $self->createinsertdatetrigger($tbnm, 'InsertDate') if ($dtrg);
72             # Create a table version entry in the persistent metadata if
73             # details provided
74 3 50 33     38027 $self->cmetadata($opts->{'TableVersion'}->[0],$opts->{'TableVersion'}->[1])
75             if defined $opts and defined $opts->{'TableVersion'};
76             }
77             }
78              
79              
80             # ----------------------------------------------------------------------------
81             # Create insertion date trigger
82             # ----------------------------------------------------------------------------
83             sub createinsertdatetrigger {
84 2     2 1 8 my $self = shift;
85 2         5 my $tbnm = shift; # Table name
86 2         6 my $tcol = shift; # Name of column for date insertion
87              
88 2         8 my $trgn = $tbnm . "InsertDate";
89 2         11 my $sqlc = <
90             CREATE TRIGGER IF NOT EXISTS $trgn AFTER INSERT ON $tbnm
91             BEGIN
92             UPDATE $tbnm SET $tcol = STRFTIME('%Y-%m-%d','NOW')
93             WHERE rowid = new.rowid;
94             END
95             EOF
96 2         13 return $self->sql($sqlc);
97             }
98              
99              
100             # ----------------------------------------------------------------------------
101             # Insert a cache entry
102             # ----------------------------------------------------------------------------
103             sub cinsert {
104 4     4 1 7 my $self = shift;
105 4         10 my $tbnm = shift; # Table name
106 4         9 my $tbrw = shift; # Hash of column values to insert
107              
108 4         41 return $self->insert($tbnm, {'Data'=> $tbrw});
109             }
110              
111              
112             # ----------------------------------------------------------------------------
113             # Retrieve a cache entry
114             # ----------------------------------------------------------------------------
115             sub cretrieve {
116 8     8 1 16 my $self = shift;
117 8         16 my $tbnm = shift; # Table name
118 8         12 my $tkey = shift; # Hash of key columns and corresponding key values
119              
120 8         74 return $self->retrieve($tbnm, {'Where' => $tkey,
121             'FirstRow' => 1,
122             'ReturnType' => 'Hash'});
123             }
124              
125              
126             # ----------------------------------------------------------------------------
127             # Get (or set) cache properties (non-persistent metadata)
128             # ----------------------------------------------------------------------------
129             sub cproperties {
130 8     8 1 18 my $self = shift;
131 8         21 my $tbnm = shift; # Table name
132 8         17 my $pnam = shift; # Property name
133              
134 8 100       43 $self->{'ctbl'}->{$tbnm}->{'props'}->{$pnam} = shift if (@_);
135 8         65 return $self->{'ctbl'}->{$tbnm}->{'props'}->{$pnam};
136             }
137              
138              
139             # ----------------------------------------------------------------------------
140             # List of cache entries older than a specified number of days
141             # ----------------------------------------------------------------------------
142             sub expirelist {
143 0     0 1 0 my $self = shift;
144 0         0 my $tbnm = shift; # Table name
145 0         0 my $nday = shift; # Expiry age in number of days
146              
147             ## Date based expiry is only possible if the table has an insertion
148             ## date field with insertion trigger
149 0 0       0 if ($self->{'ctbl'}->{$tbnm}->{'dtrg'}) {
150 0         0 return $self->retrieve($tbnm,
151             {'Where' =>
152             "julianday('NOW')-julianday(InsertDate)>$nday",
153             'ReturnType' => 'Array'});
154             } else {
155 0         0 return [];
156             }
157             }
158              
159              
160             # ----------------------------------------------------------------------------
161             # Expire cache entries older than a specified number of days
162             # ----------------------------------------------------------------------------
163             sub expire {
164 0     0 1 0 my $self = shift;
165 0         0 my $tbnm = shift; # Table name
166 0         0 my $nday = shift; # Expiry age in number of days
167              
168             ## Date based expiry is only possible if the table has an insertion
169             ## date field with insertion trigger
170 0 0       0 if ($self->{'ctbl'}->{$tbnm}->{'dtrg'}) {
171 0         0 $self->remove($tbnm,{'Where' =>
172             "julianday('NOW') - julianday(InsertDate) > $nday"});
173             }
174             }
175              
176              
177             # ----------------------------------------------------------------------------
178             # Get (or set) cache persistent metadata
179             # ----------------------------------------------------------------------------
180             sub cmetadata {
181 5     5 1 29 my $self = shift;
182 5         14 my $atrb = shift; # Attribute name
183              
184             # Attempt to retrieve the cache persistent metadata table entry
185             # corresponding to the specified attribute name
186 5         80 my $row = $self->retrieve('FilePropertiesCacheMetaData',
187             {'Where' => {'Attribute' => $atrb},
188             'FirstRow' => 1, 'ReturnType' => 'Array'});
189             ## If a second argument is provided to the method, it is used as a
190             ## new attribute value for the specified attribute name
191 5 50       29 if (@_) {
192             ## The second argument for the method is used as a new attribute
193             ## value for the specified attribute name. If the table row for the
194             ## attribute name exists, update the row, otherwise insert a new
195             ## row.
196 5 50       16 if (defined $row) {
197 0         0 $self->update('FilePropertiesCacheMetaData',
198             {'Data' => {'Attribute' => $atrb, 'Value' => shift}});
199             } else {
200 5         66 $self->insert('FilePropertiesCacheMetaData',
201             {'Data' => {'Attribute' => $atrb, 'Value' => shift}});
202             }
203             } else {
204             # If a new attribute value is not specified, return the current
205             # value of the specified attribute, or undef if the attribute
206             # entry does not exist
207 0 0         return (defined $row)?$row->[1]:undef;
208             }
209             }
210              
211              
212             # ----------------------------------------------------------------------------
213             # Determine whether array includes the specified value
214             # ----------------------------------------------------------------------------
215             sub _inarray {
216 0     0     my $aref = shift;
217 0           my $eval = shift;
218              
219 0           my $hash = {};
220 0           my $a;
221 0           foreach $a (@$aref) {
222 0           $hash->{$a} = 1;
223             }
224 0           return $hash->{$eval};
225             }
226              
227              
228             # ----------------------------------------------------------------------------
229             # End of method definitions
230             # ----------------------------------------------------------------------------
231              
232              
233             1;
234             __END__