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