File Coverage

blib/lib/DBIx/ThinSQL/SQLite.pm
Criterion Covered Total %
statement 61 61 100.0
branch 17 22 77.2
condition 9 17 52.9
subroutine 19 19 100.0
pod 3 3 100.0
total 109 122 89.3


line stmt bran cond sub pod time code
1             package DBIx::ThinSQL::SQLite;
2 1     1   75310 use 5.010;
  1         3  
3 1     1   3 use strict;
  1         1  
  1         14  
4 1     1   3 use warnings;
  1         5  
  1         21  
5 1     1   3 use Log::Any qw/$log/;
  1         1  
  1         4  
6 1         8 use Exporter::Tidy all =>
7 1     1   150 [qw/create_sqlite_sequence create_functions create_methods/];
  1         1  
8              
9             our $VERSION = '0.0.17';
10              
11             my %sqlite_functions = (
12             debug => sub {
13             my $dbh = shift;
14              
15             $dbh->sqlite_create_function(
16             'debug', -1,
17             sub {
18             if ( @_ && defined $_[0] && $_[0] =~ m/^\s*(select|pragma)/i ) {
19             $dbh->log_debug(@_);
20             }
21             else {
22             $log->debug( join( ' ', map { $_ // 'NULL' } @_ ) );
23             }
24             }
25             );
26             },
27             warn => sub {
28             my $dbh = shift;
29              
30             $dbh->sqlite_create_function(
31             'warn', -1,
32             sub {
33             if ( @_ && defined $_[0] && $_[0] =~ m/^\s*(select|pragma)/i ) {
34             $dbh->log_warn(@_);
35             }
36             else {
37             warn join( ' ', map { $_ // 'NULL' } @_ );
38             }
39             }
40             );
41             },
42             create_sequence => sub {
43             my $dbh = shift;
44             $dbh->sqlite_create_function( 'create_sequence', 1,
45             sub { _create_sequence( $dbh, @_ ) } );
46             },
47             currval => sub {
48             my $dbh = shift;
49             $dbh->sqlite_create_function( 'currval', 1,
50             sub { _currval( $dbh, @_ ) } );
51             },
52             nextval => sub {
53             my $dbh = shift;
54             $dbh->sqlite_create_function( 'nextval', 1,
55             sub { _nextval( $dbh, @_ ) } );
56             },
57             sha1 => sub {
58             require Digest::SHA;
59             my $dbh = shift;
60             $dbh->sqlite_create_function(
61             'sha1', -1,
62             sub {
63             Digest::SHA::sha1(
64             map { utf8::is_utf8($_) ? Encode::encode_utf8($_) : $_ }
65             grep { defined $_ } @_
66             );
67             }
68             );
69             },
70             sha1_hex => sub {
71             require Digest::SHA;
72             my $dbh = shift;
73             $dbh->sqlite_create_function(
74             'sha1_hex',
75             -1,
76             sub {
77             Digest::SHA::sha1_hex(
78             map { utf8::is_utf8($_) ? Encode::encode_utf8($_) : $_ }
79             grep { defined $_ } @_
80             );
81             }
82             );
83             },
84             sha1_base64 => sub {
85             require Digest::SHA;
86             my $dbh = shift;
87             $dbh->sqlite_create_function(
88             'sha1_base64',
89             -1,
90             sub {
91             Digest::SHA::sha1_base64(
92             map { utf8::is_utf8($_) ? Encode::encode_utf8($_) : $_ }
93             grep { defined $_ } @_
94             );
95             }
96             );
97             },
98             agg_sha1 => sub {
99             require Digest::SHA;
100             my $dbh = shift;
101             $dbh->sqlite_create_aggregate( 'agg_sha1', 2,
102             'DBIx::ThinSQL::SQLite::agg_sha1' );
103             },
104             agg_sha1_hex => sub {
105             require Digest::SHA;
106             my $dbh = shift;
107             $dbh->sqlite_create_aggregate( 'agg_sha1_hex', 2,
108             'DBIx::ThinSQL::SQLite::agg_sha1_hex' );
109             },
110             agg_sha1_base64 => sub {
111             require Digest::SHA;
112             my $dbh = shift;
113             $dbh->sqlite_create_aggregate( 'agg_sha1_base64', 2,
114             'DBIx::ThinSQL::SQLite::agg_sha1_base64' );
115             },
116             );
117              
118 6     6   123 sub _croak { require Carp; goto &Carp::croak }
  6         819  
119              
120             # Legacy method
121             sub create_sqlite_sequence {
122 1     1 1 5 return;
123             }
124              
125             sub _create_sequence {
126 3     3   10 my $dbh = shift;
127 3   33     12 my $name = shift || _croak('usage: create_sequence($name)');
128              
129 3 50       27 $dbh->do( 'CREATE TABLE '
130             . $name
131             . '_sequence (seq INTEGER PRIMARY KEY AUTOINCREMENT);' )
132             or _croak( $dbh->errstr );
133              
134 3 50       64677 $dbh->do( 'INSERT INTO ' . $name . '_sequence(seq) VALUES(0)' )
135             or _croak( $dbh->errstr );
136              
137 3 50       49806 $dbh->do( 'DELETE FROM ' . $name . '_sequence' )
138             or _croak( $dbh->errstr );
139             }
140              
141             sub _currval {
142 8     8   7254 my $dbh = shift;
143 8   50     23 my $name = shift || die 'usage: currval($name)';
144              
145 8         76 my $ref = $dbh->selectrow_arrayref(
146             'SELECT seq FROM sqlite_sequence WHERE name = ?',
147             undef, $name . '_sequence' );
148              
149 8 100       1008 _croak("currval: unknown sequence: $name") unless $ref;
150              
151 7         59 $log->debug( "currval('$name') -> " . $ref->[0] );
152 7         214 return $ref->[0];
153             }
154              
155             sub _nextval {
156 5     5   1497 my $dbh = shift;
157 5   50     14 my $name = shift || die 'usage: nextval($name)';
158              
159 5 100       30 $dbh->do( 'INSERT INTO ' . $name . '_sequence(seq) VALUES(NULL)' )
160             or _croak( 'nextval: unknown sequence: ' . $name );
161              
162 3         16644 $dbh->do( 'DELETE FROM ' . $name . '_sequence' );
163 3         67165 return $dbh->selectrow_arrayref('SELECT last_insert_rowid();')->[0];
164             }
165              
166             sub create_functions {
167 8 100   8 1 34094 _croak('usage: create_functions($dbh,@functions)') unless @_ >= 2;
168              
169 7         10 my $dbh = shift;
170             _croak('handle has no sqlite_create_function!')
171 7 100       6 unless eval { $dbh->can('sqlite_create_function') };
  7         49  
172              
173 6         12 foreach my $name (@_) {
174 12         18 my $subref = $sqlite_functions{$name};
175 12 100       22 _croak( 'unknown function: ' . $name ) unless $subref;
176 11         22 $subref->($dbh);
177             }
178             }
179              
180             my %thinsql_methods = (
181             create_sqlite_sequence => \&_create_sqlite_sequence,
182             create_sequence => \&_create_sequence,
183             currval => \&_currval,
184             nextval => \&_nextval,
185             );
186              
187             sub create_methods {
188 2 50   2 1 6557 _croak('usage: create_methods(@methods)') unless @_ >= 1;
189              
190 2         4 foreach my $name (@_) {
191 4         8 my $subref = $thinsql_methods{$name};
192 4 100       10 _croak( 'unknown method: ' . $name ) unless $subref;
193              
194 1     1   895 no strict 'refs';
  1         1  
  1         256  
195 3         4 *{ 'DBIx::ThinSQL::db::' . $name } = $subref;
  3         23  
196             }
197             }
198              
199             package DBIx::ThinSQL::SQLite::agg_sha1;
200              
201             sub new {
202 11     11   56897 my $class = shift;
203 11         61 return bless [], $class;
204             }
205              
206             sub step {
207 29     29   20 my $self = shift;
208 29 50 100     219 push( @$self,
      0        
      0        
      100        
      100        
209             utf8::is_utf8( $_[0] // '' )
210             ? [ Encode::encode_utf8( $_[0] // '' ), $_[1] // '' ]
211             : [ $_[0] // '', $_[1] // '' ] );
212             }
213              
214             sub _sort {
215 11     11   9 return map { $_->[0] } sort { $a->[1] cmp $b->[1] } @{ $_[0] };
  29         212  
  23         39  
  11         32  
216             }
217              
218             sub finalize {
219 7     7   34 return Digest::SHA::sha1( $_[0]->_sort );
220             }
221              
222             package DBIx::ThinSQL::SQLite::agg_sha1_hex;
223             our @ISA = ('DBIx::ThinSQL::SQLite::agg_sha1');
224              
225             sub finalize {
226 2     2   7 return Digest::SHA::sha1_hex( $_[0]->_sort );
227             }
228              
229             package DBIx::ThinSQL::SQLite::agg_sha1_base64;
230             our @ISA = ('DBIx::ThinSQL::SQLite::agg_sha1');
231              
232             sub finalize {
233 2     2   8 return Digest::SHA::sha1_base64( $_[0]->_sort );
234             }
235              
236             1;
237             __END__