Skip to content
This repository has been archived by the owner on Dec 11, 2017. It is now read-only.

Commit

Permalink
added basic blocking GridFS support
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Jul 8, 2013
1 parent 608b95d commit 73b4081
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 1 deletion.
6 changes: 6 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@

0.06 2013-07-09
- Added GridFS support.
- Added modules Mango::GridFS, Mango::GridFS::Reader and
Mango::GridFS::Writer.
- Added gridfs method to Mango::Database.

0.05 2013-07-06
- Changed heuristics for number detection in Mango::BSON to better line up
with user expectations.
Expand Down
2 changes: 1 addition & 1 deletion lib/Mango.pm
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ has protocol => sub { Mango::Protocol->new };
has w => 1;
has wtimeout => 1000;

our $VERSION = '0.05';
our $VERSION = '0.06';

# Operations with reply
for my $name (qw(get_more query)) {
Expand Down
9 changes: 9 additions & 0 deletions lib/Mango/Database.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use Mojo::Base -base;
use Carp 'croak';
use Mango::BSON qw(bson_code bson_doc);
use Mango::Collection;
use Mango::GridFS;

has [qw(mango name)];

Expand Down Expand Up @@ -53,6 +54,8 @@ sub command {
return $doc;
}

sub gridfs { Mango::GridFS->new(db => shift) }

sub stats { shift->command(bson_doc(dbstats => 1), @_) }

1;
Expand Down Expand Up @@ -130,6 +133,12 @@ non-blocking.
});
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
=head2 gridfs
my $gridf = $db->gridfs;
Get L<Mango::GridFS> object.
=head2 stats
my $stats = $db->stats;
Expand Down
85 changes: 85 additions & 0 deletions lib/Mango/GridFS.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package Mango::GridFS;
use Mojo::Base -base;

use Mango::GridFS::Reader;
use Mango::GridFS::Writer;

has 'db';
has prefix => 'fs';

sub chunks { $_[0]->db->collection($_[0]->prefix . '.chunks') }
sub files { $_[0]->db->collection($_[0]->prefix . '.files') }

sub reader { Mango::GridFS::Reader->new(gridfs => shift) }
sub writer { Mango::GridFS::Writer->new(gridfs => shift) }

1;

=encoding utf8
=head1 NAME
Mango::GridFS - GridFS
=head1 SYNOPSIS
use Mango::GridFS;
my $gridfs = Mango::GridFS->new(db => $db);
=head1 DESCRIPTION
L<Mango::GridFS> is an interface for MongoDB GridFS access.
=head1 ATTRIBUTES
L<Mango::GridFS> implements the following attributes.
=head2 db
my $db = $gridfs->db;
$gridfs = $gridfs->db(Mango::Database->new);
L<Mango::Database> object GridFS belongs to.
=head2 prefix
my $db = $gridfs->prefix;
$gridfs = $gridfs->prefix('foo');
Prefix for GridFS collections, defaults to C<fs>.
=head1 METHODS
L<Mango::GridFS> inherits all methods from L<Mojo::Base> and implements the
following new ones.
=head2 chunks
my $chunks = $gridfs->chunks;
Get L<Mango::Collection> object for C<chunks> collection.
=head2 files
my $files = $gridfs->files;
Get L<Mango::Collection> object for C<files> collection.
=head2 reader
my $reader = $gridfs->reader;
Get L<Mango::GridFS::Reader> object.
=head2 writer
my $writer = $gridfs->writer;
Get L<Mango::GridFS::Writer> object.
=head1 SEE ALSO
L<Mango>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
=cut
77 changes: 77 additions & 0 deletions lib/Mango/GridFS/Reader.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package Mango::GridFS::Reader;
use Mojo::Base -base;

has 'gridfs';

sub open {
my ($self, $oid) = @_;
my $file = $self->gridfs->files->find_one($oid);
$self->{id} = $oid;
$self->{chunk_size} = $file->{chunkSize};
$self->{len} = $file->{length};
}

sub read {
my $self = shift;

$self->{pos} //= 0;
return undef if $self->{pos} >= $self->{len};
my $n = $self->{pos} / $self->{chunk_size};
my $chunk
= $self->gridfs->chunks->find_one({files_id => $self->{id}, n => $n});
my $data = $chunk->{data};
$self->{pos} += length $data;
return $data;
}

1;

=encoding utf8
=head1 NAME
Mango::GridFS::Reader - GridFS reader
=head1 SYNOPSIS
use Mango::GridFS::Reader;
my $reader = Mango::GridFS::Reader->new(gridfs => $gridfs);
=head1 DESCRIPTION
L<Mango::GridFS::Reader> reads files from GridFS.
=head1 ATTRIBUTES
L<Mango::GridFS::Reader> implements the following attributes.
=head2 gridfs
my $gridfs = $reader->gridfs;
$reader = $reader->gridfs(Mango::GridFS->new);
L<Mango::GridFS> object this reader belongs to.
=head1 METHODS
L<Mango::GridFS::Reader> inherits all methods from L<Mojo::Base> and
implements the following new ones.
=head2 open
$reader->open(bson_oid '1a2b3c4e5f60718293a4b5c6');
Open file.
=head2 read
my $chunk = $reader->read;
Read chunk.
=head1 SEE ALSO
L<Mango>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
=cut
118 changes: 118 additions & 0 deletions lib/Mango/GridFS/Writer.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package Mango::GridFS::Writer;
use Mojo::Base -base;

use Mango::BSON qw(bson_bin bson_doc bson_oid bson_time bson_true);

has chunk_size => 262144;
has 'gridfs';
has id => sub {bson_oid};

sub close {
my $self = shift;

$self->_chunk;

my $gridfs = $self->gridfs;
$gridfs->files->ensure_index({filename => 1});
$gridfs->chunks->ensure_index(bson_doc(files_id => 1, n => 1),
{unique => bson_true});

my $command = bson_doc
filemd5 => $self->id,
root => $gridfs->prefix;
my $md5 = $gridfs->db->command($command)->{md5};

$gridfs->files->insert(
{
_id => $self->id,
length => $self->{len},
chunkSize => $self->chunk_size,
uploadDate => bson_time,
md5 => $md5
}
);
}

sub write {
my ($self, $chunk) = @_;
$self->{buffer} .= $chunk;
$self->{len} += length $chunk;
$self->_chunk while length $self->{buffer} > $self->chunk_size;
}

sub _chunk {
my $self = shift;

my $chunk = substr $self->{buffer}, 0, $self->chunk_size, '';
return unless length $chunk;

my $n = $self->{n}++;
my $chunks = $self->gridfs->chunks;
$chunks->insert({files_id => $self->id, n => $n, data => bson_bin($chunk)});
}

1;

=encoding utf8
=head1 NAME
Mango::GridFS::Writer - GridFS writer
=head1 SYNOPSIS
use Mango::GridFS::Writer;
my $writer = Mango::GridFS::Writer->new(gridfs => $gridfs);
=head1 DESCRIPTION
L<Mango::GridFS::Writer> writes files to GridFS.
=head1 ATTRIBUTES
L<Mango::GridFS::Writer> implements the following attributes.
=head2 chunk_size
my $size = $writer->chunk_size;
$writer = $writer->chunk_size(1024);
Chunk size in bytes, defaults to C<262144>.
=head2 gridfs
my $gridfs = $writer->gridfs;
$writer = $writer->gridfs(Mango::GridFS->new);
L<Mango::GridFS> object this writer belongs to.
=head2 id
my $id = $writer->id;
$writer = $writer->id(bson_oid '1a2b3c4e5f60718293a4b5c6');
Object id of file, defaults to a newly generated one.
=head1 METHODS
L<Mango::GridFS::Writer> inherits all methods from L<Mojo::Base> and
implements the following new ones.
=head2 close
$writer->close;
Close file.
=head2 write
$writer->write('hello world!');
Write chunk.
=head1 SEE ALSO
L<Mango>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
=cut
28 changes: 28 additions & 0 deletions t/gridfs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use Mojo::Base -strict;

use Test::More;
use Mango;

plan skip_all => 'set TEST_ONLINE to enable this test'
unless $ENV{TEST_ONLINE};

# Cleanup before start
my $mango = Mango->new($ENV{TEST_ONLINE});
my $gridfs = $mango->db->gridfs;
$gridfs->$_->remove for qw(files chunks);

# Blocking roundtrip
my $writer = $gridfs->writer;
my $oid = $writer->id;
isa_ok $oid, 'Mango::BSON::ObjectID', 'right class';
$writer->write('hello ');
$writer->write('world!');
$writer->close;
my $reader = $gridfs->reader;
$reader->open($oid);
my $data;
while (defined(my $chunk = $reader->read)) { $data .= $chunk }
is $data, 'hello world!', 'right content';
$gridfs->$_->drop for qw(files chunks);

done_testing();

0 comments on commit 73b4081

Please sign in to comment.