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   1045 use YAOO;
  2         4  
  2         11  
4 2     2   654 use Cwd qw/getcwd/;
  2         4  
  2         134  
5              
6             extends 'ODS::Storage::Base';
7              
8 2     2   11 use ODS::Utils qw/load move error/;
  2         12  
  2         19  
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 13 my ($self, $data) = @_;
33 4         16 return $self->serialize_class->parse($data);
34             }
35              
36             sub stringify_data_format {
37 12     12 0 27 my ($self, $data) = @_;
38 12         37 return $self->serialize_class->stringify($data);
39             }
40              
41             sub all {
42 4     4 0 61 my ($self) = @_;
43              
44 4         19 my $data = $self->into_rows($self->read_file());
45              
46 4         667 return $data;
47             }
48              
49             sub create {
50 4 50   4 0 67 my ($self, %params) = (shift, @_ > 1 ? @_ : %{ $_[0] });
  4         20  
51              
52 4         25 my $data = $self->into_rows(\%params, 1);
53              
54 4         43 $data->validate();
55              
56 4         12 push @{ $self->table->rows }, $data;
  4         15  
57              
58 4         63 $data = $self->into_storage(1);
59              
60 4         23 $self->write_file( $data );
61              
62 4         901 $self->table;
63             }
64              
65             sub search {
66 2 50   2 0 70 my ($self, %params) = (shift, @_ > 1 ? @_ : %{ $_[0] });
  0         0  
67              
68 2 50       9 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       16 if ( $params{$key} ne $row->{$key} ) {
77 4         7 $select = undef;
78 4         7 last;
79             }
80             }
81 6         30 $select;
82 2         391 });
83              
84 2         14 my $table = $self->table->clone();
85 2         8 $table->rows($select);
86 2         70 ODS::Iterator->new(table => $table);
87             }
88              
89             sub find {
90 6 50   6 0 73 my ($self, %params) = (shift, @_ > 1 ? @_ : %{ $_[0] });
  0         0  
91              
92 6 50       20 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   32 my $row = shift;
98 24         26 my $select = 1;
99 24         43 for my $key ( keys %params ) {
100 26 100       56 if ( $params{$key} ne $row->{$key} ) {
101 20         23 $select = undef;
102 20         26 last;
103             }
104             }
105 24         47 $select;
106 6         1001 });
107              
108 6         43 return $select;
109             }
110              
111             sub update {
112 2     2 0 41 my ($self, $update, %params) = (shift, pop, @_);
113              
114 2         14 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         10 $find->validate($update);
120              
121 2         15 $self->update_row();
122             }
123              
124             sub update_row {
125 4     4 0 22 my ($self) = @_;
126              
127 4         17 my $data = $self->into_storage(1);
128              
129 4         19 $self->write_file( $data );
130              
131 4         10008 $self->table;
132             }
133              
134             sub delete {
135 2 50   2 0 54 my ($self, %params) = (shift, @_ > 1 ? @_ : %{ $_[0] });
  0         0  
136              
137 2 50       7 my $data = $self->table->rows ? ODS::Iterator->new(table => $self->table) : $self->all;
138              
139             my $index = $data->find_index(sub {
140 8     8   11 my $row = shift;
141 8         11 my $select = 1;
142 8         16 for my $key ( keys %params ) {
143 8 100       19 if ( $params{$key} ne $row->{$key} ) {
144 6         10 $select = undef;
145 6         9 last;
146             }
147             }
148 8         17 $select;
149 2         382 });
150              
151 2         17 $data->splice($index, 1);
152              
153 2         83 $data = $self->into_storage(1);
154              
155 2         13 $self->write_file( $data );
156              
157 2         436 $self->table;
158             }
159              
160             sub delete_row {
161 2     2 0 31 my ($self, $r) = @_;
162              
163 2         8 my $data = ODS::Iterator->new(table => $self->table);
164              
165 2         316 my $keyfield = $data->table->keyfield;
166              
167 2         23 my $index;
168 2 50       7 if ($keyfield) {
169             $index = $data->find_index(sub {
170 8     8   21 $_[0]->{$keyfield} eq $r->$keyfield;
171 2         17 });
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         17 $data->splice($index, 1);
187              
188 2         28 $data = $self->into_storage(1);
189              
190 2         13 $self->write_file( $data );
191              
192 2         401 $self->table;
193             }
194              
195              
196             # methods very much specific to files
197              
198             sub open_file {
199 4     4 0 9 my ($self) = @_;
200 2 50   2   134 open my $fh, '<:encoding(UTF-8)', $self->file or die "Cannot open file for reading: $!";
  2         3  
  2         14  
  4         31  
201 4         23779 $self->file_handle($fh);
202 4         107 return $fh;
203             }
204              
205             sub open_write_file {
206 12     12 0 22 my ($self) = @_;
207 12 50       79 open my $fh, '>:encoding(UTF-8)', $self->save_file or die "Cannot open file for writing: $!";
208 12         2696 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 8 my ($self) = @_;
219 4         17 my $fh = $self->open_file;
220 4         12 my $data = do { local $/; <$fh> };
  4         18  
  4         218  
221 4         124 return $data;
222             }
223              
224             sub write_file {
225 12     12 0 33 my ($self, $data) = @_;
226 12         37 my $fh = $self->open_write_file;
227 12         118 print $fh $data;
228 12         83 $self->close_file($fh);
229 12         80 $self->close_file($self->file_handle);
230 12         36 move($self->save_file, $self->file);
231             }
232              
233             sub close_file {
234 24     24 0 921 close $_[1];
235             }
236              
237             1;