File Coverage

blib/lib/Async/Redis/Iterator.pm
Criterion Covered Total %
statement 11 37 29.7
branch 0 16 0.0
condition 0 11 0.0
subroutine 4 9 44.4
pod 0 5 0.0
total 15 78 19.2


line stmt bran cond sub pod time code
1             package Async::Redis::Iterator;
2              
3 73     73   574 use strict;
  73         180  
  73         3453  
4 73     73   451 use warnings;
  73         150  
  73         4652  
5 73     73   1273 use 5.018;
  73         321  
6              
7 73     73   418 use Future::AsyncAwait;
  73         186  
  73         606  
8              
9             sub new {
10 0     0 0   my ($class, %args) = @_;
11              
12             return bless {
13             redis => $args{redis},
14             command => $args{command} // 'SCAN',
15             key => $args{key}, # For HSCAN/SSCAN/ZSCAN
16             match => $args{match},
17             count => $args{count},
18             type => $args{type}, # For SCAN TYPE filter
19 0   0       cursor => 0,
20             done => 0,
21             }, $class;
22             }
23              
24 0     0 0   async sub next {
25 0           my ($self) = @_;
26              
27             # Already exhausted
28 0 0         return undef if $self->{done};
29              
30 0           my @args;
31              
32             # Build command args based on scan type
33 0 0         if ($self->{command} eq 'SCAN') {
34 0           @args = ($self->{cursor});
35             }
36             else {
37             # HSCAN, SSCAN, ZSCAN take key first, then cursor
38 0           @args = ($self->{key}, $self->{cursor});
39             }
40              
41             # Add MATCH pattern if specified
42 0 0         if (defined $self->{match}) {
43 0           push @args, 'MATCH', $self->{match};
44             }
45              
46             # Add COUNT hint if specified
47 0 0         if (defined $self->{count}) {
48 0           push @args, 'COUNT', $self->{count};
49             }
50              
51             # Add TYPE filter for SCAN (Redis 6.0+)
52 0 0 0       if ($self->{command} eq 'SCAN' && defined $self->{type}) {
53 0           push @args, 'TYPE', $self->{type};
54             }
55              
56             # Execute scan command
57 0           my $result = await $self->{redis}->command($self->{command}, @args);
58              
59             # Result is [cursor, [elements...]]
60 0           my ($new_cursor, $elements) = @$result;
61              
62             # Update cursor
63 0           $self->{cursor} = $new_cursor;
64              
65             # Check if iteration complete (cursor returned to 0)
66 0 0 0       if ($new_cursor eq '0' || $new_cursor == 0) {
67 0           $self->{done} = 1;
68             }
69              
70             # Return batch (may be empty)
71             # Return undef only when done AND no elements in final batch
72 0 0 0       return $elements && @$elements ? $elements : ($self->{done} ? undef : []);
    0          
73             }
74              
75             sub reset {
76 0     0 0   my ($self) = @_;
77 0           $self->{cursor} = 0;
78 0           $self->{done} = 0;
79             }
80              
81 0     0 0   sub cursor { shift->{cursor} }
82 0     0 0   sub done { shift->{done} }
83              
84             1;
85              
86             __END__