File Coverage

blib/lib/ODS/Storage/File.pm
Criterion Covered Total %
statement 105 120 87.5
branch 17 32 53.1
condition n/a
subroutine 21 23 91.3
pod 0 14 0.0
total 143 189 75.6


line stmt bran cond sub pod time code
1             package ODS::Storage::File;
2              
3 2     2   927 use YAOO;
  2         5  
  2         12  
4 2     2   616 use Cwd qw/getcwd/;
  2         3  
  2         99  
5              
6             extends 'ODS::Storage::Base';
7              
8 2     2   9 use ODS::Utils qw/move error/;
  2         3  
  2         24  
9              
10             auto_build;
11              
12             has file_handle => isa(fh);
13              
14             has file => isa(string), coerce(sub {
15             my ($self, $value) = @_;
16             my $path = getcwd;
17             $value =~ s/^\///;
18             return sprintf("%s/%s.%s", $path, $value, $self->file_suffix);
19             }), trigger(sub {
20             my ($self, $value) = @_;
21             $value .= '.tmp';
22             $self->save_file($value);
23             });
24              
25             has save_file => isa(string);
26              
27             sub all {
28 4     4 0 70 my ($self) = @_;
29            
30 4         14 my $data = $self->into_rows($self->read_file());
31              
32 4         531 return $data;
33             }
34              
35             sub create {
36 4 50   4 0 52 my ($self, %params) = (shift, @_ > 1 ? @_ : %{ $_[0] });
  4         16  
37              
38 4         14 my $data = $self->into_rows(\%params, 1);
39              
40 4         29 $data->validate();
41              
42 4         7 push @{ $self->table->rows }, $data;
  4         11  
43              
44 4         46 $data = $self->into_storage(1);
45              
46 4         17 $self->write_file( $data );
47              
48 4         104 $self->table;
49             }
50              
51             sub search {
52 2 50   2 0 40 my ($self, %params) = (shift, @_ > 1 ? @_ : %{ $_[0] });
  0         0  
53              
54 2 50       41 my $data = $self->table->rows ? ODS::Iterator->new(table => $self->table) : $self->all;
55            
56             # this only works for JSON and YAML, CSS and JSONL we can stream/read rows/lines instead of reading/loading
57             # all into memory.
58             my $select = $data->filter(sub {
59 6     6   13 my $row = shift;
60 6         46 my $select = 1;
61 6         15 for my $key ( keys %params ) {
62 6 100       53 if ( $params{$key} ne $row->{$key} ) {
63 4         8 $select = undef;
64 4         6 last;
65             }
66             }
67 6         30 $select;
68 2         238 });
69              
70 2         23 my $table = $self->table->clone();
71 2         7 $table->rows($select);
72 2         58 my $table = $self->table->clone();
73 2         21 $table->rows($select);
74 2         65 ODS::Iterator->new(table => $table);
75             }
76              
77             sub find {
78 6 50   6 0 58 my ($self, %params) = (shift, @_ > 1 ? @_ : %{ $_[0] });
  0         0  
79              
80 6 50       13 my $data = $self->table->rows ? ODS::Iterator->new(table => $self->table) : $self->all;
81            
82             # this only works for JSON and YAML, CSS and JSONL we can stream/read rows/lines instead of reading/loading
83             # all into memory.
84             my $select = $data->find(sub {
85 24     24   32 my $row = shift;
86 24         30 my $select = 1;
87 24         36 for my $key ( keys %params ) {
88 26 100       51 if ( $params{$key} ne $row->{$key} ) {
89 20         22 $select = undef;
90 20         23 last;
91             }
92             }
93 24         43 $select;
94 6         692 });
95              
96 6         33 return $select;
97             }
98              
99             sub update {
100 2     2 0 29 my ($self, $update, %params) = (shift, pop, @_);
101              
102 2         10 my $find = $self->find(%params);
103              
104 2 50       7 croak sprintf "No row found for search params %s", Dumper \%params
105             unless $find;
106              
107 2         6 $find->validate($update);
108              
109 2         12 $self->update_row();
110             }
111              
112             sub update_row {
113 4     4 0 16 my ($self) = @_;
114              
115 4         11 my $data = $self->into_storage(1);
116              
117 4         13 $self->write_file( $data );
118              
119 4         102 $self->table;
120             }
121              
122             sub delete {
123 2 50   2 0 46 my ($self, %params) = (shift, @_ > 1 ? @_ : %{ $_[0] });
  0         0  
124              
125 2 50       6 my $data = $self->table->rows ? ODS::Iterator->new(table => $self->table) : $self->all;
126            
127             my $index = $data->find_index(sub {
128 8     8   11 my $row = shift;
129 8         9 my $select = 1;
130 8         11 for my $key ( keys %params ) {
131 8 100       21 if ( $params{$key} ne $row->{$key} ) {
132 6         7 $select = undef;
133 6         7 last;
134             }
135             }
136 8         18 $select;
137 2         232 });
138            
139 2         16 $data->splice($index, 1);
140              
141 2         58 $data = $self->into_storage(1);
142              
143 2         10 $self->write_file( $data );
144              
145 2         55 $self->table;
146             }
147              
148             sub delete_row {
149 2     2 0 22 my ($self, $r) = @_;
150              
151 2         6 my $data = ODS::Iterator->new(table => $self->table);
152              
153 2         210 my $keyfield = $data->table->keyfield;
154              
155 2         18 my $index;
156 2 50       8 if ($keyfield) {
157             $index = $data->find_index(sub {
158 8     8   21 $_[0]->{$keyfield} eq $r->$keyfield;
159 2         11 });
160             } else {
161             $index = $data->find_index(sub {
162 0     0   0 my $row = shift;
163 0         0 my $select = 1;
164 0         0 for my $key ( keys %{ $row->columns } ) {
  0         0  
165 0 0       0 if ( $r->$key ne $row->{$key} ) {
166 0         0 $select = undef;
167 0         0 last;
168             }
169             }
170 0         0 $select;
171 0         0 });
172             }
173              
174 2         11 $data->splice($index, 1);
175              
176 2         23 $data = $self->into_storage(1);
177              
178 2         8 $self->write_file( $data );
179              
180 2         53 $self->table;
181             }
182              
183              
184             # methods very much specific to files
185              
186             sub open_file {
187 4     4 0 14 my ($self) = @_;
188 2 50   2   79 open my $fh, '<:encoding(UTF-8)', $self->file or die "Cannot open file for reading: $!";
  2         4  
  2         17  
  4         28  
189 4         19305 $self->file_handle($fh);
190 4         81 return $fh;
191             }
192              
193             sub open_write_file {
194 12     12 0 17 my ($self) = @_;
195 12 50       42 open my $fh, '>:encoding(UTF-8)', $self->save_file or die "Cannot open file for writing: $!";
196 12         1481 return $fh;
197             }
198              
199             sub seek_file {
200 0     0 0 0 my ($self, @args) = @_;
201 0 0       0 @args = (0, 0) if (!scalar @args);
202 0         0 seek $self->file_handle, shift @args, shift @args;
203             }
204              
205             sub read_file {
206 4     4 0 6 my ($self) = @_;
207 4         21 my $fh = $self->open_file;
208 4         6 my $data = do { local $/; <$fh> };
  4         15  
  4         168  
209 4         103 return $data;
210             }
211              
212             sub write_file {
213 12     12 0 20 my ($self, $data) = @_;
214 12         23 my $fh = $self->open_write_file;
215 12         95 print $fh $data;
216 12         40 $self->close_file($fh);
217 12         61 $self->close_file($self->file_handle);
218 12         35 move($self->save_file, $self->file);
219 12         1762 unlink $self->save_file;
220             }
221              
222             sub close_file {
223 24     24 0 623 close $_[1];
224             }
225              
226             1;