File Coverage

blib/lib/Data/Validate/CSV/Table.pm
Criterion Covered Total %
statement 26 67 38.8
branch 0 14 0.0
condition 0 3 0.0
subroutine 9 17 52.9
pod 0 2 0.0
total 35 103 33.9


line stmt bran cond sub pod time code
1 1     1   14 use v5.12;
  1         4  
2 1     1   6 use strict;
  1         3  
  1         23  
3 1     1   5 use warnings;
  1         1  
  1         60  
4              
5             package Data::Validate::CSV::Table;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.002';
9              
10 1     1   6 use Moo;
  1         2  
  1         5  
11 1     1   337 use PerlX::Maybe;
  1         2  
  1         8  
12 1     1   43 use Data::Validate::CSV::Types -types;
  1         10  
  1         21  
13 1     1   5412 use Types::Common::Numeric qw(PositiveOrZeroInt);
  1         2  
  1         8  
14 1     1   453 use Types::Path::Tiny qw(Path);
  1         2  
  1         9  
15 1     1   334 use namespace::autoclean;
  1         3  
  1         7  
16              
17             has columns => (
18             is => 'rwp',
19             isa => ArrayRef[Column],
20             init_arg => undef,
21             );
22              
23             has has_header => (
24             is => 'lazy',
25             isa => Bool,
26             coerce => 1,
27 0     0     builder => sub { 0 },
28             );
29              
30             has skip_rows => (
31             is => 'ro',
32             isa => PositiveOrZeroInt,
33 0     0     builder => sub { 0 },
34             );
35              
36             has skip_rows_after_header => (
37             is => 'ro',
38             isa => PositiveOrZeroInt,
39 0     0     builder => sub { 0 },
40             );
41              
42             has input => (
43             is => 'ro',
44             isa => FileHandle->plus_coercions(
45             Path, q{ $_->openr_utf8 },
46             ScalarRef, q{ do { require IO::String; IO::String->new($$_) } },
47             ),
48             coerce => 1,
49             required => 1,
50             );
51              
52             has schema => (
53             is => 'ro',
54             isa => Schema,
55             coerce => 1,
56             );
57              
58             has reader => (
59             is => 'lazy',
60             isa => CodeRef,
61             );
62              
63             sub _build_reader {
64 0     0     my $self = shift;
65 0           require Text::CSV_XS;
66 0           my $csv = Text::CSV_XS->new({
67             allow_whitespace => 1,
68             sep_char => q{,},
69            
70             });
71 0     0     sub { $csv->getline($_[0]) };
  0            
72             }
73              
74             has _done_init => (
75             is => 'rw',
76             isa => Bool,
77             init_arg => undef,
78             default => !!0,
79             );
80              
81             has row_count => (
82             is => 'rwp',
83             isa => PositiveOrZeroInt,
84             default => 0,
85             );
86              
87             has column_class => (
88             is => 'ro',
89             isa => ClassName,
90             default => Column->class,
91             );
92              
93             has row_class => (
94             is => 'ro',
95             isa => ClassName,
96             default => Row->class,
97             );
98              
99             has _pkey_seen => (
100             is => 'ro',
101             isa => HashRef,
102             default => sub { +{} },
103             );
104              
105             sub get_row {
106 0     0 0   my $self = shift;
107 0 0         $self->_init unless $self->_done_init;
108            
109 0           my $raw = $self->reader->($self->input);
110 0 0         return unless $raw;
111            
112 0           my $n = $self->row_count;
113 0           $self->_set_row_count(++$n);
114            
115 0           my $row = $self->row_class->new(
116             columns => $self->columns,
117             column_class => $self->column_class,
118             raw_values => $raw,
119             row_number => $n,
120             maybe primary_key_columns => $self->schema->primary_key,
121             );
122            
123 0 0         if ($row->primary_key_columns) {
124 0           my $str = $row->key_string;
125 0 0         if (my $seen = $self->_pkey_seen->{$str}) {
126 0           $row->report_error("Already seen primary key on row $seen");
127             }
128             else {
129 0           $self->_pkey_seen->{$str} = $n;
130             }
131             }
132            
133 0           return $row;
134             }
135              
136             sub _init {
137 0     0     my $self = shift;
138 0 0         return if $self->_done_init;
139 0           for (my $i = 0; $i < $self->skip_rows; ++$i) {
140 0           $self->reader->();
141             }
142 0 0         if ($self->has_header) {
143 0           my $columns = $self->schema->clone_columns;
144 0           my $header = $self->reader->($self->input);
145 0 0         if ($header) {
146 0           for my $i (0 .. $#$header) {
147 0   0       ($columns->[$i] ||= $self->column_class->new)->maybe_set_name($header->[$i]);
148             }
149 0           for (my $i = 0; $i < $self->skip_rows_after_header; ++$i) {
150 0           $self->reader->($self->input);
151             }
152             }
153 0           $self->_set_columns($columns);
154             }
155             else {
156 0           $self->_set_columns($self->schema->clone_columns);
157             }
158 0           $self->_done_init(1);
159             }
160              
161             sub all_rows {
162 0     0 0   my $self = shift;
163 0           my @rows;
164 0           while (my $row = $self->get_row) {
165 0           push @rows, $row;
166             }
167 0           return @rows;
168             }
169              
170             1;