AnyEvent-CouchDB
view release on metacpan or search on metacpan
lib/AnyEvent/CouchDB/Database.pm view on Meta::CPAN
? '?' . join('&', @buf)
: '';
};
our $code_to_string = sub {
ref($_[0])
? sprintf 'do { my $CODE1; %s; $CODE1 }',
Data::Dump::Streamer->new->Data($_[0])->Out
: $_[0];
# ^- taken from CouchDB::View::Document ------^
};
sub new {
my ($class, $name, $uri, $json_encoder) = @_;
$json_encoder ||= $default_json;
my $self = bless { name => $name, uri => $uri, json_encoder => $json_encoder } => $class;
if (my $userinfo = $self->uri->userinfo) {
my $auth = encode_base64($userinfo, '');
$self->{http_auth} = "Basic $auth";
}
return $self;
}
sub name {
$_[0]->{name};
}
sub uri {
$_[0]->{uri};
}
sub json_encoder {
my ($self, $encoder) = @_;
if ($encoder) {
$self->{json_encoder} = $encoder;
} else {
$self->{json_encoder};
}
}
sub json {
my ( $self, $target ) = @_;
ref($target) ? $self->json_encoder->encode($target) : $target;
}
sub compact {
my ( $self, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, 202, $self->json_encoder );
http_request(
POST => ( $self->uri . "_compact" ),
headers => $self->_build_headers($options),
$cb
);
$cv;
}
sub create {
my ( $self, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, 201, $self->json_encoder );
http_request(
PUT => $self->uri,
headers => $self->_build_headers($options),
$cb
);
$cv;
}
sub drop {
my ( $self, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
http_request(
DELETE => $self->uri,
headers => $self->_build_headers($options),
$cb
);
$cv;
}
sub info {
my ( $self, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
http_request(
GET => $self->uri,
headers => $self->_build_headers($options),
$cb
);
$cv;
}
sub all_docs {
my ( $self, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
http_request(
GET => $self->uri . '_all_docs' . $query->($options),
headers => $self->_build_headers($options),
$cb
);
$cv;
}
sub all_docs_by_seq {
my ( $self, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
http_request(
GET => $self->uri . '_all_docs_by_seq' . $query->($options),
headers => $self->_build_headers($options),
$cb
);
$cv;
}
sub open_doc {
my ( $self, $doc_id, $options ) = @_;
if ( not defined $doc_id ) {
AnyEvent::CouchDB::Exception::UndefinedDocument->throw(
"An undefined id was passed to open_doc()."
);
}
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
my $id = uri_escape_utf8($doc_id);
if ( $id =~ qr{^_design%2F} ) {
lib/AnyEvent/CouchDB/Database.pm view on Meta::CPAN
sub open_docs {
my ( $self, $doc_ids, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
$options ||= {};
$options->{'include_docs'} = 'true';
http_request(
POST => $self->uri . '_all_docs' . $query->($options),
headers => $self->_build_headers($options),
body => $self->json( { "keys" => $doc_ids } ),
$cb
);
$cv;
}
sub save_doc {
my ( $self, $doc, $options ) = @_;
# create attachment stubs for new inlined attachments
my $_attachments = sub {
my ( $doc ) = @_;
my $_a = $doc->{_attachments};
return unless defined $_a;
my $revpos = $doc->{_rev};
$revpos =~ s/-.*$//;
for my $key (keys %$_a) {
if ( exists($_a->{$key}{data}) ) {
my $file = $_a->{$key};
$file->{length} = length(decode_base64($file->{data}));
$file->{revpos} = $revpos;
$file->{stub} = JSON::true();
delete $file->{data};
}
}
};
if ( $options->{success} ) {
my $orig = $options->{success};
$options->{success} = sub {
my ($resp) = @_;
$orig->($resp);
$doc->{_id} = $resp->{id};
$doc->{_rev} = $resp->{rev};
$_attachments->($doc);
};
}
else {
$options->{success} = sub {
my ($resp) = @_;
$doc->{_id} = $resp->{id};
$doc->{_rev} = $resp->{rev};
$_attachments->($doc);
};
}
my ( $cv, $cb ) = cvcb( $options, 201, $self->json_encoder );
my ( $method, $uri );
if ( not defined $doc->{_id} ) {
$method = 'POST';
$uri = $self->uri;
}
else {
$method = 'PUT';
$uri = $self->uri . uri_escape_utf8( $doc->{_id} );
}
http_request(
$method => $uri . $query->($options),
headers => $self->_build_headers($options),
body => $self->json($doc),
$cb
);
$cv;
}
sub remove_doc {
my ( $self, $doc, $options ) = @_;
die("Document is missing _id!") unless ( defined $doc->{_id} );
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
http_request(
DELETE => $self->uri
. uri_escape_utf8( $doc->{_id} )
. $query->( { rev => $doc->{_rev} } ),
headers => $self->_build_headers($options),
$cb
);
$cv;
}
sub attach {
my ( $self, $doc, $attachment, $options ) = @_;
my $body < io( $options->{src} );
my $length = length($body);
$options->{type} ||= 'text/plain';
if ( $options->{success} ) {
my $orig = $options->{success};
$options->{success} = sub {
my ($resp) = @_;
$orig->($resp);
$doc->{_id} = $resp->{id};
$doc->{_rev} = $resp->{rev};
$doc->{_attachments} ||= {};
$doc->{_attachments}->{$attachment} = {
'content_type' => $options->{type},
'length' => $length,
'stub' => JSON::true,
};
};
}
else {
$options->{success} = sub {
my ($resp) = @_;
$doc->{_id} = $resp->{id};
$doc->{_rev} = $resp->{rev};
$doc->{_attachments} ||= {};
$doc->{_attachments}->{$attachment} = {
'content_type' => $options->{type},
'length' => $length,
'stub' => JSON::true,
};
};
}
my ( $cv, $cb ) = cvcb( $options, 201, $self->json_encoder );
http_request(
PUT => $self->uri
. uri_escape_utf8( $doc->{_id} ) . "/"
. uri_escape_utf8($attachment)
. $query->( { rev => $doc->{_rev} } ),
headers => $self->_build_headers($options),
body => $body,
$cb
);
$cv;
}
sub open_attachment {
my ( $self, $doc, $attachment, $options ) = @_;
my $cv = AnyEvent->condvar;
# passthrough handler without json encoding
my $success = sub {
$options->{success}->(@_) if ($options->{success});
$cv->send(@_);
};
# error handler that croaks with http headers
my $error = sub {
my $headers = shift;
$options->{error}->(@_) if ($options->{error});
$cv->croak(encode_json $headers);
};
my $cb = sub {
my ($body, $headers) = @_;
if ($headers->{Status} >= 200 and $headers->{Status} < 400) {
$success->(@_);
} else {
$error->($headers);
}
};
http_request(
GET => $self->uri
. uri_escape_utf8( $doc->{_id} ) . "/"
. uri_escape_utf8($attachment),
headers => $self->_build_headers($options),
$cb
);
$cv;
}
sub detach {
my ( $self, $doc, $attachment, $options ) = @_;
if ( $options->{success} ) {
my $orig = $options->{success};
$options->{success} = sub {
my ($resp) = @_;
$orig->($resp);
$doc->{_id} = $resp->{id};
$doc->{_rev} = $resp->{rev};
delete $doc->{_attachments}->{$attachment};
};
}
else {
$options->{success} = sub {
lib/AnyEvent/CouchDB/Database.pm view on Meta::CPAN
sub head {
my ( $self, $path, $options ) = @_;
my ( $cv, undef ) = cvcb( $options, undef, $self->json_encoder );
my $headers = $self->_build_headers($options);
my $uri = $self->uri . "$path" . $query->($options);
http_request(
HEAD => $uri,
headers => $headers,
sub { $cv->send( $_[1] ); }
);
$cv;
}
sub get {
my ( $self, $path, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
my $headers = $self->_build_headers($options);
my $uri = $self->uri . "$path" . $query->($options);
http_request(
GET => $uri,
headers => $headers,
$cb
);
$cv;
}
sub post {
my ( $self, $path, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
my $headers = $self->_build_headers($options);
my $uri = $self->uri . "$path";
http_request(
POST => $uri,
headers => $headers,
body => $query->($options),
$cb
);
$cv;
}
sub delete {
my ( $self, $path, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
my $headers = $self->_build_headers($options);
my $uri = $self->uri . "$path" . $query->($options);
http_request(
DELETE => $uri,
headers => $headers,
$cb
);
$cv;
}
sub put {
my ( $self, $path, $options ) = @_;
my ( $cv, $cb ) = cvcb( $options, undef, $self->json_encoder );
my $headers = $self->_build_headers($options);
my $uri = $self->uri . "$path";
http_request(
PUT => $uri,
headers => $headers,
body => $query->($options),
$cb
);
$cv;
}
__END__
=head1 NAME
AnyEvent::CouchDB::Database - an object representing a CouchDB database
=head1 SYNOPSIS
use AnyEvent::CouchDB;
$db = couchdb('bavl');
my $map = 'function(doc){
if(doc.type == "Phrase"){ emit(null, doc) }
}';
my $phrases = $db->query($map)->recv;
my $recordings = $db->view('recordings/all')->recv;
=head1 DESCRIPTION
Objects of this class represent a single CouchDB database. This object is used
create and drop databases as well as operate on the documents within the database.
=head1 API
=head2 General
=head3 $db = AnyEvent::CouchDB::Database->new($name, $uri)
This method takes a name and a URI, and constructs an object representing a
CouchDB database. The name should be conservative in the characters it uses,
because it needs to be both URI friendly and portable across filesystems.
Also, the URI that you pass in should contain a trailing slash.
=head3 $db->name
This method returns the name of the database.
=head3 $db->uri
This method returns the base URI of the database.
=head3 $db->json_encoder([ $json_encoder ])
This method is a mutator for setting a custom JSON encoder. You should
pass in an object that responds to C<encode> and C<decode>. Instances of
L<JSON> and L<JSON::XS> are good candidates.
=head2 Options
All the methods that accept an optional hashref of options can set an "headers"
key, wich will be added to all the requests. So you can add basic
authentication to your requests if needed:
( run in 0.729 second using v1.01-cache-2.11-cpan-e93a5daba3e )