File Coverage

blib/lib/ArrayDataRole/Source/DBI.pm
Criterion Covered Total %
statement 76 83 91.5
branch 28 42 66.6
condition 5 11 45.4
subroutine 11 12 91.6
pod 1 8 12.5
total 121 156 77.5


line stmt bran cond sub pod time code
1             package ArrayDataRole::Source::DBI;
2              
3 1     1   686 use strict;
  1         3  
  1         33  
4 1     1   28 use 5.010001;
  1         4  
5 1     1   8 use Role::Tiny;
  1         2  
  1         7  
6 1     1   205 use Role::Tiny::With;
  1         3  
  1         1006  
7             with 'ArrayDataRole::Spec::Basic';
8              
9             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
10             our $DATE = '2021-12-01'; # DATE
11             our $DIST = 'ArrayDataRoles-Standard'; # DIST
12             our $VERSION = '0.007'; # VERSION
13              
14             sub new {
15 1     1 1 62615 my ($class, %args) = @_;
16              
17 1         8 my $dsn = delete $args{dsn};
18 1         4 my $user = delete $args{user};
19 1         31 my $password = delete $args{password};
20 1         28 my $dbh = delete $args{dbh};
21 1 50       14 if (defined $dbh) {
    0          
22             } elsif (defined $dsn) {
23 0         0 require DBI;
24 0         0 $dbh = DBI->connect($dsn, $user, $password, {RaiseError=>1});
25             }
26              
27 1         3 my $sth = delete $args{sth};
28 1         2 my $sth_bind_params = delete $args{sth_bind_params};
29 1         4 my $query = delete $args{query};
30 1         3 my $table = delete $args{table}; # XXX quote
31 1         2 my $column = delete $args{column}; # XXX quote
32 1 50       4 if (defined $sth) {
33             } else {
34 1 50       6 die "You specify 'query' or 'table' & 'column', but you don't specify ".
35             "dbh/dsn+user+password, so I cannot create a statement handle"
36             unless $dbh;
37 1 50 33     10 if (defined $query) {
    50          
38             } elsif (defined $table && defined $column) {
39 1         5 $query = "SELECT $column FROM $table";
40             } else {
41 0         0 die "Please specify 'sth', 'query', or 'table' & 'column' arguments";
42             }
43 1         23 $sth = $dbh->prepare($query);
44 1   50     216 $sth->execute(@{ $sth_bind_params // [] }); # to check query syntax
  1         107  
45             }
46              
47 1         6 my $row_count_sth = delete $args{row_count_sth};
48 1         3 my $row_count_sth_bind_params = delete $args{row_count_sth_bind_params};
49 1         3 my $row_count_query = delete $args{row_count_query};
50 1 50       4 if (defined $row_count_sth) {
51             } else {
52 1 50       4 die "You specify 'row_count_query' or 'table', but you don't specify ".
53             "dbh/dsn+user+password, so I cannot create a statement handle"
54             unless $dbh;
55 1 50       6 if (defined $row_count_query) {
    50          
56             } elsif (defined $table) {
57 1         4 $row_count_query = "SELECT COUNT(*) FROM $table";
58             } else {
59 0         0 die "For getting row count, please specify 'row_count_sth', ".
60             "'row_count_query', or 'table' argument";
61             }
62 1         8 $row_count_sth = $dbh->prepare($row_count_query);
63 1   50     71 $sth->execute(@{ $row_count_sth_bind_params // [] }); # to check query syntax
  1         78  
64             }
65              
66 1 50       10 die "Unknown argument(s): ". join(", ", sort keys %args)
67             if keys %args;
68              
69 1         13 bless {
70             #dbh => $dbh,
71             sth => $sth,
72             sth_bind_params => $sth_bind_params,
73             row_count_sth => $row_count_sth,
74             row_count_sth_bind_params => $row_count_sth_bind_params,
75             pos => 0, # iterator pos
76             #buf => '', # exists when there is a buffer
77             }, $class;
78             }
79              
80             sub get_next_item {
81 9     9 0 24 my $self = shift;
82 9 100       32 if (exists $self->{buf}) {
83 6         8 $self->{pos}++;
84 6         17 return delete $self->{buf};
85             } else {
86 3         36 my $row = $self->{sth}->fetchrow_arrayref;
87 3 50       11 die "StopIteration" unless $row;
88 3         7 $self->{pos}++;
89 3         21 $row->[0];
90             }
91             }
92              
93             sub has_next_item {
94 8     8 0 14 my $self = shift;
95 8 50       17 if (exists $self->{buf}) {
96 0         0 return 1;
97             }
98 8         70 my $row = $self->{sth}->fetchrow_arrayref;
99 8 100       46 return 0 unless $row;
100 6         17 $self->{buf} = $row->[0];
101 6         18 1;
102             }
103              
104             sub get_item_count {
105 1     1 0 4 my $self = shift;
106 1   50     3 $self->{row_count_sth}->execute(@{ $self->{row_count_sth_bind_params} // [] });
  1         24  
107 1         15 my ($row_count) = $self->{row_count_sth}->fetchrow_array;
108 1         7 $row_count;
109             }
110              
111             sub reset_iterator {
112 4     4 0 15 my $self = shift;
113 4   50     16 $self->{sth}->execute(@{ $self->{sth_bind_params} // [] });
  4         264  
114 4         25 $self->{pos} = 0;
115             }
116              
117             sub get_iterator_pos {
118 0     0 0 0 my $self = shift;
119 0         0 $self->{pos};
120             }
121              
122             sub get_item_at_pos {
123 3     3 0 53 my ($self, $pos) = @_;
124 3 100       15 $self->reset_iterator if $self->{pos} > $pos;
125 3         7 while (1) {
126 5 100       14 die "Out of range" unless $self->has_next_item;
127 4         10 my $item = $self->get_next_item;
128 4 100       20 return $item if $self->{pos} > $pos;
129             }
130             }
131              
132             sub has_item_at_pos {
133 3     3 0 8 my ($self, $pos) = @_;
134 3 100       18 return 1 if $self->{pos} > $pos;
135 2         5 while (1) {
136 3 100       8 return 0 unless $self->has_next_item;
137 2         7 $self->get_next_item;
138 2 100       10 return 1 if $self->{pos} > $pos;
139             }
140             }
141              
142             1;
143             # ABSTRACT: Role to access elements from DBI
144              
145             __END__