File Coverage

blib/lib/Data/Generator/FromDDL/RecordSet.pm
Criterion Covered Total %
statement 76 77 98.7
branch 5 6 83.3
condition n/a
subroutine 16 16 100.0
pod 0 4 0.0
total 97 103 94.1


line stmt bran cond sub pod time code
1             package Data::Generator::FromDDL::RecordSet;
2             # Data::Generator::FromDDL::RecordSet is columnar-oriented storage.
3             # To output each generated record, it's needed to convert columns into rows.
4              
5 7     7   39388 use strict;
  7         16  
  7         349  
6 7     7   40 use warnings;
  7         14  
  7         213  
7 7     7   2311 use POSIX qw(ceil);
  7         16545  
  7         55  
8 7     7   3939 use List::Util qw(first);
  7         15  
  7         634  
9 7     7   10833 use Compress::Zlib qw(compress uncompress);
  7         571184  
  7         794  
10 7     7   69 use bytes ();
  7         22  
  7         176  
11             use Class::Accessor::Lite (
12 7         101 rw => [qw(table n columns)],
13 7     7   1153 );
  7         1248  
14              
15 7     7   688 use constant RECORDS_PER_CHUNK => 100_000;
  7         35  
  7         6348  
16              
17             sub new {
18 24     24 0 141282 my ($class, $table, $n) = @_;
19 24         215 return bless {
20             table => $table,
21             n => $n,
22             columns => [],
23             }, $class;
24             }
25              
26             sub set_column_values {
27 25     25 0 459862 my ($self, $field, $values) = @_;
28              
29 25         169 my $n = $self->n;
30 25         204 my $offset = 0;
31 25         56 my $size;
32             my @chunks;
33 25         114 while ($n > 0) {
34 52 100       335 $size = $n >= RECORDS_PER_CHUNK ? RECORDS_PER_CHUNK : $n;
35 52         324560 my @sliced_values = @$values[$offset..($offset + $size - 1)];
36 52         76129 push @chunks, _store_values_into_chunk(\@sliced_values);
37              
38 52         2384243 $n -= $size;
39 52         230918 $offset += $size;
40             }
41              
42 25         64 push @{$self->{columns}}, {
  25         322  
43             field => $field,
44             chunks => \@chunks,
45             };
46             }
47              
48             sub get_column_values {
49 2     2 0 23706 my ($self, $field_name) = @_;
50 2     2   17 my $col = first { $_->{field}->name eq $field_name } @{$self->columns};
  2         78  
  2         15  
51 2 50       114 if ($col) {
52 2         6 return map { _fetch_values_from_chunk($_) } @{$col->{chunks}};
  11         97  
  2         10  
53             } else {
54 0         0 return;
55             }
56             }
57              
58             sub _store_values_into_chunk {
59 52     52   240 my ($values) = @_;
60 52         793841 return compress(join ',', @$values);
61             }
62              
63             sub _fetch_values_from_chunk {
64 43     43   146 my ($chunk) = @_;
65 43         278 my $joined_chunk = uncompress($chunk);
66 43         908723 return split ',', $joined_chunk;
67             }
68              
69             sub iterate_through_chunks(&) {
70 22     22 0 31467 my ($self, $code) = @_;
71 22         115 my $columns = $self->columns;
72 22         209 my $num_of_chunks = ceil($self->n / RECORDS_PER_CHUNK);
73              
74 22         356 my $table = $self->table;
75 22         148 my @fields = map { $_->{field} } @{$self->columns};
  23         189  
  22         74  
76 22         2295 for my $chunk_no (0..($num_of_chunks - 1)) {
77 31         223241 my @rows = $self->_construct_rows_with_chunk_no($chunk_no);
78 31         66302 $code->($table, \@fields, \@rows);
79             }
80             }
81              
82             sub _construct_rows_with_chunk_no {
83 31     31   141 my ($self, $chunk_no) = @_;
84 31         154 my $n = $self->n;
85 31         321 my $columns = $self->columns;
86 31 100       316 my $chunk_size
87             = ($n - ($chunk_no * RECORDS_PER_CHUNK)) >= RECORDS_PER_CHUNK
88             ? RECORDS_PER_CHUNK
89             : $n % RECORDS_PER_CHUNK
90             ;
91             my @all_columns_values
92 32         171 = map {
93 31         99 my @values = _fetch_values_from_chunk($_->{chunks}->[$chunk_no]);
94 32         38302 \@values;
95             } @$columns;
96              
97 31         84 my @rows;
98 31         138 my $last_idx_of_columns = scalar(@$columns) - 1;
99 31         133 for my $row_idx (0..($chunk_size - 1)) {
100 1000034         921942 my @row;
101 1000034         1301696 for my $col_idx (0..$last_idx_of_columns) {
102 1000037         2364221 $row[$col_idx] = $all_columns_values[$col_idx]->[$row_idx];
103             }
104 1000034         1727004 push @rows, \@row;
105             }
106              
107 31         419932 return @rows;
108             }
109              
110             1;