ArangoDB

 view release on metacpan or  search on metacpan

lib/ArangoDB/Cursor.pm  view on Meta::CPAN

package ArangoDB::Cursor;
use strict;
use warnings;
use utf8;
use 5.008001;
use Carp qw(croak);
use Scalar::Util qw(weaken);
use ArangoDB::Document;
use ArangoDB::Constants qw(:api);
use Class::Accessor::Lite ( ro => [qw/id count length/], );

BEGIN {
    if ( eval { require Data::Clone; 1; } ) {
        *_clone = \&Data::Clone::clone;
    }
    else {

        # Clone nested ARRAY and HASH reference data structure.
        *_clone = sub {
            my $orig = shift;
            return unless defined $orig;
            my $reftype = ref $orig;
            if ( $reftype eq 'ARRAY' ) {
                return [ map { !ref($_) ? $_ : _clone($_) } @$orig ];
            }
            elsif ( $reftype eq 'HASH' ) {
                return { map { !ref($_) ? $_ : _clone($_) } %$orig };
            }
        };
    }
}

sub new {
    my ( $class, $conn, $cursor ) = @_;
    my $len = 0;
    if ( defined $cursor->{result} && ref( $cursor->{result} ) eq 'ARRAY' ) {
        $len = scalar @{ $cursor->{result} };
    }
    my $self = bless {
        connection => $conn,
        id         => $cursor->{id},
        length     => $len,
        count      => $cursor->{count},
        has_more   => $cursor->{hasMore},
        position   => 0,
        result     => $cursor->{result} || [],
    }, $class;
    if ( $self->{id} ) {
        $self->{_api_path} = API_CURSOR . '/' . $self->{id};
    }
    weaken( $self->{connection} );
    return $self;
}

sub next {
    my $self = shift;
    if ( $self->{position} < $self->{length} || $self->_get_next_batch() ) {
        return ArangoDB::Document->new( $self->{connection}, _clone( $self->{result}->[ $self->{position}++ ] ) );
    }
    return;
}

sub all {
    my $self = shift;
    my @result;
    while ( !@result || $self->_get_next_batch() ) {
        my $last = $self->{length} - 1;
        push @result, ( @{ $self->{result} } )[ 0 .. $last ];
    }
    my $conn = $self->{connection};
    return [ map { ArangoDB::Document->new( $conn, $_ ) } @result ];
}

sub _get_next_batch {
    my $self = shift;
    return unless $self->{has_more};
    eval {
        my $res = $self->{connection}->http_put( $self->{_api_path}, {} );
        $self->{has_more} = $res->{hasMore};
        $self->{length}   = scalar( @{ $res->{result} } );
        $self->{result}   = $res->{result};
        $self->{position} = 0;
    };
    if ($@) {
        $self->_server_error_handler( $@, 'Failed to get next batch cursor(%d)' );
    }
    return 1;
}

sub delete {
    my $self = shift;
    eval { $self->{connection}->http_delete( $self->{_api_path} ) };
    if ($@) {
        $self->_server_error_handler( $@, 'Failed to delete cursor(%d)' );
    }
}

sub _server_error_handler {
    my ( $self, $error, $message ) = @_;
    my $msg = sprintf( $message, $self->id );
    if ( ref($error) && $error->isa('ArangoDB::ServerException') ) {
        $msg .= ':' . ( $error->detail->{errorMessage} || q{} );
    }
    croak $msg;
}

1;
__END__


=pod



( run in 1.318 second using v1.01-cache-2.11-cpan-39bf76dae61 )