File Coverage

blib/lib/CHI/Driver/DBI.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package CHI::Driver::DBI;
2              
3 1     1   37620 use strict;
  1         2  
  1         43  
4 1     1   6 use warnings;
  1         2  
  1         32  
5              
6 1     1   1046 use DBI::Const::GetInfoType;
  1         30487  
  1         192  
7 1     1   718 use Moose;
  0            
  0            
8             use Moose::Util::TypeConstraints;
9             use Carp qw(croak);
10              
11             our $VERSION = '1.24';
12              
13             extends 'CHI::Driver';
14              
15             my $type = "CHI::Driver::DBI";
16              
17             subtype "$type.DBIHandleGenerator" => as 'CodeRef';
18             subtype "$type.DBIXConnector" => as 'DBIx::Connector';
19             subtype "$type.DBIHandle" => as 'DBI::db';
20              
21             coerce "$type.DBIHandleGenerator" => from "$type.DBIXConnector" => via {
22             my $dbixconn = $_;
23             sub { $dbixconn->dbh }
24             };
25             coerce "$type.DBIHandleGenerator" => from "$type.DBIHandle" => via {
26             my $dbh = $_;
27             sub { $dbh }
28             };
29              
30             has 'db_name' => ( is => 'rw', isa => 'Str' );
31             has 'dbh' => ( is => 'ro', isa => "$type.DBIHandleGenerator", coerce => 1 );
32             has 'dbh_ro' => ( is => 'ro', isa => "$type.DBIHandleGenerator", predicate => 'has_dbh_ro', coerce => 1 );
33             has 'sql_strings' => ( is => 'rw', isa => 'HashRef', lazy_build => 1 );
34             has 'table_prefix' => ( is => 'rw', isa => 'Str', default => 'chi_' );
35              
36             __PACKAGE__->meta->make_immutable;
37              
38             sub BUILD {
39             my ( $self, $args ) = @_;
40              
41             my $dbh = $self->dbh->();
42              
43             $self->db_name( $dbh->get_info( $GetInfoType{SQL_DBMS_NAME} ) );
44             $self->sql_strings;
45              
46             if ( $args->{create_table} ) {
47             $dbh->do( $self->sql_strings->{create} )
48             or croak $dbh->errstr;
49             }
50              
51             return;
52             }
53              
54             sub _table {
55             my ( $self, ) = @_;
56              
57             return $self->table_prefix() . $self->namespace();
58             }
59              
60             sub _build_sql_strings {
61             my ( $self, ) = @_;
62              
63             my $dbh = $self->dbh->();
64             my $table = $dbh->quote_identifier( $self->_table );
65             my $value = $dbh->quote_identifier('value');
66             my $key = $dbh->quote_identifier('key');
67              
68             my $strings = {
69             fetch => "SELECT $value FROM $table WHERE $key = ?",
70             store => "INSERT INTO $table ( $key, $value ) VALUES ( ?, ? )",
71             store2 => "UPDATE $table SET $value = ? WHERE $key = ?",
72             remove => "DELETE FROM $table WHERE $key = ?",
73             clear => "DELETE FROM $table",
74             get_keys => "SELECT DISTINCT $key FROM $table",
75             create => "CREATE TABLE IF NOT EXISTS $table ("
76             . " $key VARCHAR( 300 ), $value TEXT,"
77             . " PRIMARY KEY ( $key ) )",
78             };
79              
80             if ( $self->db_name eq 'MySQL' ) {
81             $strings->{store} =
82             "INSERT INTO $table"
83             . " ( $key, $value )"
84             . " VALUES ( ?, ? )"
85             . " ON DUPLICATE KEY UPDATE $value=VALUES($value)";
86             delete $strings->{store2};
87             }
88             elsif ( $self->db_name eq 'SQLite' ) {
89             $strings->{store} =
90             "INSERT OR REPLACE INTO $table"
91             . " ( $key, $value )"
92             . " values ( ?, ? )";
93             delete $strings->{store2};
94             }
95             elsif ( $self->db_name eq 'PostgreSQL' ) {
96             $strings->{create} =
97             "CREATE TABLE IF NOT EXISTS $table ("
98             . " $key BYTEA, $value BYTEA,"
99             . " PRIMARY KEY ( $key ) )";
100             }
101              
102             return $strings;
103             }
104              
105             sub fetch {
106             my ( $self, $key, ) = @_;
107              
108             my $dbh = $self->has_dbh_ro ? $self->dbh_ro->() : $self->dbh->();
109             my $sth = $dbh->prepare_cached( $self->sql_strings->{fetch} )
110             or croak $dbh->errstr;
111             if ( $self->db_name eq 'PostgreSQL' ) {
112             $sth->bind_param( 1, undef, { pg_type => DBD::Pg::PG_BYTEA() } );
113             }
114             $sth->execute($key) or croak $sth->errstr;
115             my $results = $sth->fetchall_arrayref;
116              
117             return $results->[0]->[0];
118             }
119              
120             sub store {
121             my ( $self, $key, $data, ) = @_;
122              
123             my $dbh = $self->dbh->();
124             my $sth = $dbh->prepare_cached( $self->sql_strings->{store} );
125             if ( $self->db_name eq 'PostgreSQL' ) {
126             $sth->bind_param( 1, undef, { pg_type => DBD::Pg::PG_BYTEA() } );
127             $sth->bind_param( 2, undef, { pg_type => DBD::Pg::PG_BYTEA() } );
128             }
129             if ( not $sth->execute( $key, $data ) ) {
130             if ( $self->sql_strings->{store2} ) {
131             my $sth = $dbh->prepare_cached( $self->sql_strings->{store2} )
132             or croak $dbh->errstr;
133             if ( $self->db_name eq 'PostgreSQL' ) {
134             $sth->bind_param( 1, undef,
135             { pg_type => DBD::Pg::PG_BYTEA() } );
136             $sth->bind_param( 2, undef,
137             { pg_type => DBD::Pg::PG_BYTEA() } );
138             }
139             $sth->execute( $data, $key )
140             or croak $sth->errstr;
141             }
142             else {
143             croak $sth->errstr;
144             }
145             }
146             $sth->finish;
147              
148             return;
149             }
150              
151             sub remove {
152             my ( $self, $key, ) = @_;
153              
154             my $dbh = $self->dbh->();
155             my $sth = $dbh->prepare_cached( $self->sql_strings->{remove} )
156             or croak $dbh->errstr;
157             if ( $self->db_name eq 'PostgreSQL' ) {
158             $sth->bind_param( 1, undef, { pg_type => DBD::Pg::PG_BYTEA() } );
159             }
160             $sth->execute($key) or croak $sth->errstr;
161             $sth->finish;
162              
163             return;
164             }
165              
166             sub clear {
167             my ( $self, $key, ) = @_;
168              
169             my $dbh = $self->dbh->();
170             my $sth = $dbh->prepare_cached( $self->sql_strings->{clear} )
171             or croak $dbh->errstr;
172             $sth->execute() or croak $sth->errstr;
173             $sth->finish();
174              
175             return;
176             }
177              
178             sub get_keys {
179             my ( $self, ) = @_;
180              
181             my $dbh = $self->has_dbh_ro ? $self->dbh_ro->() : $self->dbh->();
182             my $sth = $dbh->prepare_cached( $self->sql_strings->{get_keys} )
183             or croak $dbh->errstr;
184             $sth->execute() or croak $sth->errstr;
185             my $results = $sth->fetchall_arrayref( [0] );
186             $_ = $_->[0] for @{$results};
187              
188             return @{$results};
189             }
190              
191             sub get_namespaces { croak 'not supported' }
192              
193             # TODO: For pg see "upsert" - http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE
194              
195             1;
196              
197             __END__