File Coverage

blib/lib/BackPAN/Index/Database.pm
Criterion Covered Total %
statement 34 34 100.0
branch 3 6 50.0
condition n/a
subroutine 10 10 100.0
pod 0 7 0.0
total 47 57 82.4


line stmt bran cond sub pod time code
1             package BackPAN::Index::Database;
2              
3 11     11   5315764 use Mouse;
  11         40146  
  11         130  
4             with 'BackPAN::Index::Role::HasCache';
5              
6 11     11   10107 use BackPAN::Index::Types;
  11         33  
  11         429  
7 11     11   823 use Path::Class;
  11         54531  
  11         9473  
8              
9             has db_file =>
10             is => 'ro',
11             isa => 'Path::Class::File',
12             lazy => 1,
13             coerce => 1,
14             default => sub {
15             my $self = shift;
16             return Path::Class::File->new($self->cache->directory, "backpan.sqlite").'';
17             };
18              
19             has dsn =>
20             is => 'ro',
21             isa => 'Str',
22             lazy => 1,
23             default => sub {
24             my $self = shift;
25             return "dbi:SQLite:dbname=@{[$self->db_file]}";
26             };
27              
28             has dbh =>
29             is => 'ro',
30             isa => 'DBI::db',
31             lazy => 1,
32             default => sub {
33             my $self = shift;
34             require DBI;
35             return DBI->connect($self->dsn, undef, undef, {RaiseError => 1});
36             };
37              
38             has schema =>
39             is => 'ro',
40             isa => 'DBIx::Class::Schema',
41             lazy => 1,
42             default => sub {
43             my $self = shift;
44              
45             require BackPAN::Index::Schema;
46             return BackPAN::Index::Schema->connect(sub { $self->dbh });
47             };
48              
49             # If you change the schema, be sure to run ./Build result_classes
50             # to update the result classes.
51             #
52             # This is denormalized for performance, its read-only anyway
53             has create_tables_sql =>
54             is => 'ro',
55             isa => 'HashRef[Str]',
56             default => sub {
57             return {
58             files => <<'SQL',
59             CREATE TABLE IF NOT EXISTS files (
60             path TEXT NOT NULL PRIMARY KEY,
61             date INTEGER NOT NULL,
62             size INTEGER NOT NULL CHECK ( size >= 0 )
63             )
64             SQL
65             releases => <<'SQL',
66             CREATE TABLE IF NOT EXISTS releases (
67             path TEXT NOT NULL PRIMARY KEY REFERENCES files,
68             dist TEXT NOT NULL REFERENCES dists,
69             date INTEGER NOT NULL,
70             size TEXT NOT NULL,
71             version TEXT NOT NULL,
72             maturity TEXT NOT NULL,
73             distvname TEXT NOT NULL,
74             cpanid TEXT NOT NULL
75             )
76             SQL
77              
78             dists => <<'SQL',
79             CREATE TABLE IF NOT EXISTS dists (
80             name TEXT NOT NULL PRIMARY KEY,
81             first_release TEXT NOT NULL REFERENCES releases,
82             latest_release TEXT NOT NULL REFERENCES releases,
83             first_date INTEGER NOT NULL,
84             latest_date INTEGER NOT NULL,
85             first_author TEXT NOT NULL,
86             latest_author TEXT NOT NULL,
87             num_releases INTEGER NOT NULL
88             )
89             SQL
90             }
91             };
92              
93             has create_indexes_sql =>
94             is => 'ro',
95             isa => 'ArrayRef[Str]',
96             default => sub {
97             return [
98             # Speed up dists_by several orders of magnitude
99             "CREATE INDEX IF NOT EXISTS dists_by ON releases (cpanid, dist)",
100              
101             # Speed up files_by a lot
102             "CREATE INDEX IF NOT EXISTS files_by ON releases (cpanid, path)",
103              
104             # Let us order releases by date quickly
105             "CREATE INDEX IF NOT EXISTS releases_by_date ON releases (date, dist)",
106             ]
107             };
108              
109             sub create_tables {
110 1     1 0 3 my $self = shift;
111              
112 1         8 my $dbh = $self->dbh;
113              
114 1         16209 for my $sql (values %{$self->create_tables_sql}) {
  1         10  
115 3         4543285 $dbh->do($sql);
116             }
117              
118 1         11331 return;
119             }
120              
121             sub create_indexes {
122 1     1 0 5 my $self = shift;
123              
124 1         9 my $dbh = $self->dbh;
125 1         1 for my $sql (@{$self->create_indexes_sql}) {
  1         8  
126 3         4576333 $dbh->do($sql);
127             }
128              
129 1         1290753 return;
130             }
131              
132             sub db_file_exists {
133 9     9 0 33 my $self = shift;
134 9         57 return -e $self->db_file;
135             }
136              
137             sub should_update_db {
138 9     9 0 26 my $self = shift;
139              
140 9 50       43 return 1 if !$self->db_file_exists;
141 9 50       1672 return 1 if $self->cache_is_old;
142 9         112 return 0;
143             }
144              
145             sub cache_is_old {
146 9     9 0 22 my $self = shift;
147              
148 9 50       33 return 1 if $self->db_age > $self->cache->ttl;
149 9         2162 return 0;
150             }
151              
152             sub db_mtime {
153 18     18 0 42 my $self = shift;
154              
155             # XXX Should probably just put a timestamp in the DB
156 18         93 return $self->db_file->stat->mtime;
157             }
158              
159             sub db_age {
160 9     9 0 20 my $self = shift;
161              
162 9         43 return time - $self->db_mtime;
163             }
164              
165             1;