File Coverage

blib/lib/ODS/Storage/File.pm
Criterion Covered Total %
statement 106 121 87.6
branch 17 32 53.1
condition n/a
subroutine 23 25 92.0
pod 0 16 0.0
total 146 194 75.2


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