File Coverage

blib/lib/TableDataRole/Source/Iterator.pm
Criterion Covered Total %
statement 73 83 87.9
branch 18 36 50.0
condition 3 10 30.0
subroutine 13 15 86.6
pod 0 8 0.0
total 107 152 70.3


line stmt bran cond sub pod time code
1             package TableDataRole::Source::Iterator;
2              
3 1     1   505 use 5.010001;
  1         4  
4 1     1   7 use strict;
  1         2  
  1         19  
5 1     1   5 use warnings;
  1         2  
  1         22  
6              
7 1     1   5 use Role::Tiny;
  1         2  
  1         10  
8              
9             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
10             our $DATE = '2023-06-14'; # DATE
11             our $DIST = 'TableDataRoles-Standard'; # DIST
12             our $VERSION = '0.016'; # VERSION
13              
14             with 'TableDataRole::Spec::Basic';
15              
16             sub _new {
17 1     1   5 my ($class, %args) = @_;
18              
19 1 50       4 my $gen_iterator = delete $args{gen_iterator} or die "Please specify 'gen_iterator' argument";
20 1   50     6 my $gen_iterator_params = delete $args{gen_iterator_params} // {};
21              
22 1 50       4 die "Unknown argument(s): ". join(", ", sort keys %args)
23             if keys %args;
24              
25 1         9 bless {
26             gen_iterator => $gen_iterator,
27             gen_iterator_params => $gen_iterator_params,
28             iterator => undef,
29             pos => 0,
30             # buffer => undef,
31             # column_names => undef,
32             # column_idxs => undef,
33             }, $class;
34             }
35              
36             sub _get_row {
37             # get a row from iterator or buffer, and empty the buffer
38 8     8   15 my $self = shift;
39 8 50       17 if ($self->{buffer}) {
40 0         0 my $row = delete $self->{buffer};
41 0 0 0     0 if (!ref($row) && $row == -1) {
42 0         0 return undef; ## no critic: Subroutines::ProhibitExplicitReturnUndef
43             } else {
44 0         0 return $row;
45             }
46             } else {
47 8 50       18 $self->reset_iterator unless $self->{iterator};
48 8         18 my $row = $self->{iterator}->();
49 8 100       18 return undef unless $row; ## no critic: Subroutines::ProhibitExplicitReturnUndef
50 7         25 return $row;
51             }
52             }
53              
54             sub _peek_row {
55             # get a row from iterator, put it in buffer. will return the existing buffer
56             # content if it exists.
57 1     1   3 my $self = shift;
58 1 50       5 unless ($self->{buffer}) {
59 1 50       7 $self->reset_iterator unless $self->{iterator};
60 1   50     5 $self->{buffer} = $self->{iterator}->() // -1;
61             }
62 1 50 33     6 if (!ref($self->{buffer}) && $self->{buffer} == -1) {
63 0         0 return undef; ## no critic: Subroutines::ProhibitExplicitReturnUndef
64             } else {
65 1         4 return $self->{buffer};
66             }
67             }
68              
69             sub get_column_count {
70 1     1 0 8 my $self = shift;
71 1         5 $self->get_column_names;
72 1         2 scalar(@{ $self->{column_names} });
  1         8  
73             }
74              
75             sub get_column_names {
76 4     4 0 8 my $self = shift;
77 4 100       17 unless ($self->{column_names}) {
78 1         5 my $row = $self->_peek_row;
79 1 50       3 unless ($row) {
80 0 0       0 return wantarray ? () : [];
81             }
82 1         3 my $i = -1;
83 1         4 $self->{column_names} = [];
84 1         3 $self->{column_idxs} = {};
85 1         6 for (sort keys %$row) {
86 1         2 push @{ $self->{column_names} }, $_;
  1         4  
87 1         3 $self->{column_idxs}{$_} = ++$i;
88             }
89             }
90 4 100       12 wantarray ? @{ $self->{column_names} } : $self->{column_names};
  1         8  
91             }
92              
93             sub has_next_item {
94 0     0 0 0 my $self = shift;
95 0 0       0 $self->_peek_row ? 1:0;
96             }
97              
98             sub get_next_item {
99 2     2 0 10 my $self = shift;
100 2         7 $self->get_column_names;
101 2         6 my $row_hashref = $self->_get_row;
102 2 50       7 die "StopIteration" unless $row_hashref;
103 2         4 my $row_aryref = [];
104 2         8 for (keys %$row_hashref) {
105 2         5 my $idx = $self->{column_idxs}{$_};
106 2 50       5 next unless defined $idx;
107 2         5 $row_aryref->[$idx] = $row_hashref->{$_};
108             }
109 2         4 $self->{pos}++;
110 2         11 $row_aryref;
111             }
112              
113             sub get_next_row_hashref {
114 2     2 0 5 my $self = shift;
115 2         5 my $row_hashref = $self->_get_row;
116 2 50       9 die "StopIteration" unless $row_hashref;
117 2         5 $self->{pos}++;
118 2         8 $row_hashref;
119             }
120              
121             sub get_row_count {
122 1     1 0 3 my $self = shift;
123 1         5 $self->reset_iterator;
124 1 50       5 unless (defined $self->{row_count}) {
125 1         2 my $i = 0;
126 1         4 $i++ while $self->_get_row;
127 1         4 $self->{row_count} = $i;
128             }
129 1         4 $self->{row_count};
130             }
131              
132             sub reset_iterator {
133 4     4 0 10 my $self = shift;
134 4         20 $self->{iterator} = $self->{gen_iterator}->(%{ $self->{gen_iterator_params} });
  4         17  
135 4         9 delete $self->{buffer};
136 4         8 $self->{pos} = 0;
137             }
138              
139             sub get_iterator_pos {
140 0     0 0   my $self = shift;
141 0           $self->{pos};
142             }
143              
144             1;
145             # ABSTRACT: Get table data from an iterator
146              
147             __END__