File Coverage

blib/lib/Mango/GridFS/Reader.pm
Criterion Covered Total %
statement 6 54 11.1
branch 0 16 0.0
condition 0 12 0.0
subroutine 2 20 10.0
pod 12 12 100.0
total 20 114 17.5


line stmt bran cond sub pod time code
1             package Mango::GridFS::Reader;
2 9     9   56 use Mojo::Base -base;
  9         19  
  9         57  
3              
4 9     9   1139 use Carp 'croak';
  9         17  
  9         8744  
5              
6             has 'gridfs';
7              
8 0     0 1   sub chunk_size { shift->{meta}{chunkSize} }
9 0     0 1   sub content_type { shift->{meta}{contentType} }
10 0     0 1   sub filename { shift->{meta}{filename} }
11 0     0 1   sub md5 { shift->{meta}{md5} }
12 0     0 1   sub metadata { shift->{meta}{metadata} }
13              
14             sub open {
15 0     0 1   my ($self, $oid, $cb) = @_;
16              
17             # Non-blocking
18             return $self->gridfs->files->find_one(
19             $oid => sub {
20 0     0     my ($collection, $err, $doc) = @_;
21 0 0 0       $err //= "$oid does not exist" unless $self->{meta} = $doc;
22 0           $self->$cb($err);
23             }
24 0 0         ) if $cb;
25              
26             # Blocking
27             croak "$oid does not exist"
28 0 0         unless $self->{meta} = $self->gridfs->files->find_one($oid);
29 0           return $self;
30             }
31              
32             sub read {
33 0     0 1   my ($self, $cb) = @_;
34              
35 0   0       $self->{pos} //= 0;
36              
37             # EOF
38 0 0 0       if ($self->{pos} >= ($self->size // 0)) {
39 0 0         return undef unless $cb;
40 0     0     return Mojo::IOLoop->next_tick(sub { $self->$cb(undef, undef) });
  0            
41             }
42              
43             # Blocking
44 0           my $n = int($self->{pos} / $self->chunk_size);
45 0           my $query = {files_id => $self->{meta}{_id}, n => $n};
46 0           my $fields = {_id => 0, data => 1};
47             return $self->_slice($n,
48             $self->gridfs->chunks->find_one($query, $fields)->{data})
49 0 0         unless $cb;
50              
51             # Non-blocking
52             $self->gridfs->chunks->find_one(
53             ($query, $fields) => sub {
54 0     0     my ($collection, $err, $doc) = @_;
55 0           $self->$cb($err, $self->_slice($n, $doc->{data}));
56             }
57 0           );
58             }
59              
60             sub seek {
61 0     0 1   my ($self, $pos) = @_;
62 0           $self->{pos} = $pos;
63 0           return $self;
64             }
65              
66             sub slurp {
67 0     0 1   my ($self, $cb) = @_;
68              
69             # Blocking
70 0           my $data;
71 0 0         unless ($cb) {
72 0           while (defined(my $chunk = $self->read)) { $data .= $chunk }
  0            
73 0           return $data;
74             }
75              
76             # Non-blocking
77 0           $self->_chunk(\$data, $cb);
78             }
79              
80 0     0 1   sub size { shift->{meta}{length} }
81              
82 0   0 0 1   sub tell { shift->{pos} // 0 }
83              
84 0     0 1   sub upload_date { shift->{meta}{uploadDate} }
85              
86             sub _chunk {
87 0     0     my ($self, $dataref, $cb) = @_;
88              
89             $self->read(
90             sub {
91 0     0     my ($self, $err, $chunk) = @_;
92 0 0 0       return $self->$cb($err, $$dataref) if $err || !defined $chunk;
93 0           $$dataref .= $chunk;
94 0           $self->_chunk($dataref, $cb);
95             }
96 0           );
97             }
98              
99             sub _slice {
100 0     0     my ($self, $n, $chunk) = @_;
101 0           my $offset = $self->{pos} - ($n * $self->chunk_size);
102 0           $self->{pos} += length $chunk;
103 0           return substr $chunk, $offset;
104             }
105              
106             1;
107              
108             =encoding utf8
109              
110             =head1 NAME
111              
112             Mango::GridFS::Reader - GridFS reader
113              
114             =head1 SYNOPSIS
115              
116             use Mango::GridFS::Reader;
117              
118             my $reader = Mango::GridFS::Reader->new(gridfs => $gridfs);
119              
120             =head1 DESCRIPTION
121              
122             L reads files from GridFS.
123              
124             =head1 ATTRIBUTES
125              
126             L implements the following attributes.
127              
128             =head2 gridfs
129              
130             my $gridfs = $reader->gridfs;
131             $reader = $reader->gridfs(Mango::GridFS->new);
132              
133             L object this reader belongs to.
134              
135             =head1 METHODS
136              
137             L inherits all methods from L and
138             implements the following new ones.
139              
140             =head2 chunk_size
141              
142             my $size = $reader->chunk_size;
143              
144             Chunk size in bytes.
145              
146             =head2 content_type
147              
148             my $type = $reader->content_type;
149              
150             Content type of file.
151              
152             =head2 filename
153              
154             my $name = $reader->filename;
155              
156             Name of file.
157              
158             =head2 md5
159              
160             my $checksum = $reader->md5;
161              
162             MD5 checksum for file.
163              
164             =head2 metadata
165              
166             my $data = $reader->metadata;
167              
168             Additional information.
169              
170             =head2 open
171              
172             $reader = $reader->open($oid);
173              
174             Open file. You can also append a callback to perform operation non-blocking.
175              
176             $reader->open($oid => sub {
177             my ($reader, $err) = @_;
178             ...
179             });
180             Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
181              
182             =head2 read
183              
184             my $chunk = $reader->read;
185              
186             Read chunk. You can also append a callback to perform operation non-blocking.
187              
188             $reader->read(sub {
189             my ($reader, $err, $chunk) = @_;
190             ...
191             });
192             Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
193              
194             =head2 seek
195              
196             $reader = $reader->seek(13);
197              
198             Change current position.
199              
200             =head2 size
201              
202             my $size = $reader->size;
203              
204             Size of entire file in bytes.
205              
206             =head2 slurp
207              
208             my $data = $reader->slurp;
209              
210             Slurp all remaining data from file. You can also append a callback to perform
211             operation non-blocking.
212              
213             $reader->slurp(sub {
214             my ($reader, $err, $data) = @_;
215             ...
216             });
217             Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
218              
219             =head2 tell
220              
221             my $pos = $reader->tell;
222              
223             Current position.
224              
225             =head2 upload_date
226              
227             my $time = $reader->upload_date;
228              
229             Date file was uploaded.
230              
231             =head1 SEE ALSO
232              
233             L, L, L.
234              
235             =cut