Arango-Tango

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

0.019 2023-02-24

     - Collection.pm
       - added: 'cursor' do obtain a generic database cursor
       - modified document_paths to use AQL


0.018 2023-02-24

     - Collection.pm
       - added: 'delete_document' do delete a document

0.017 2023-02-24

Changes  view on Meta::CPAN

0.004  2019-03-30
   - Rewrote REST API calls
   - Validate options with JSON::Schema::Fit

0.003  2019-03-25
   - Added 'collection' method.
   - Reworked tests to delete the testing database if it exists.
     (dangerous, but will keep for now)
   - Testing mechanism for uri parameters under work.
   - Complete support for: _api/version
   - First cursor implementation

0.0002  2019-03-23
   - Require specific version of MIME::Base64 for encode_base64url method. 

0.0001  2019-03-22
   - Basic version. Almost useless. A two hour begining.

lib/Arango/Tango/API.pm  view on Meta::CPAN

    'create_document'    => {
        rest => [ post  => '{{database}}_api/document/{collection}']
    },
    'replace_document'   => {
        rest => [ put => '{{database}}_api/document/{collection}/{key}' ],
    },
    'list_collections'   => {
        rest => [ get   => '{{database}}_api/collection'],
        schema => { excludeSystem => { type => 'boolean' } }
    },
    'cursor_next'        => {
        rest => [ put => '{{database}}_api/cursor/{id}']
    },
    'cursor_delete'      => {
        rest => [ delete => '{{database}}_api/cursor/{id}']
    },
    'accessible_databases' => {
        rest => [ get => '_api/database/user']
    },
    'all_keys' => {
        rest => [ put => '{{database}}_api/simple/all-keys' ],
        schema => { type => { type => 'string' }, collection => { type => 'string' } },
    },
    'create_cursor' => {
        rest => [ post => '{{database}}_api/cursor' ],
        schema => {
            query       => { type => 'string'  },
            count       => { type => 'boolean' },
            batchSize   => { type => 'integer' },
            cache       => { type => 'boolean' },
            memoryLimit => { type => 'integer' },
            ttl         => { type => 'integer' },
            bindVars => { type => 'object', additionalProperties => 1 },
            options  => { type => 'object', additionalProperties => 0, properties => {
                    failOnWarning               => { type => 'boolean' },

lib/Arango/Tango/Collection.pm  view on Meta::CPAN

    my ($self, $documents, %options) = @_;
    $options{type} ||= "list";
    return $self->{arango}->_api( bulk_import_list => {
        database => $self->{database},
        collection => $self->{name},
        _body => $documents,
        _url_parameters => \%options
    })
}

sub document_paths {              ## FIXME: try to get larger cursors whenever possible
    my ($self) = @_;
    my $paths = [];
    my $query = qq!FOR doc IN $self->{name} RETURN CONCAT("/_db/", CURRENT_DATABASE(), "/_api/document/", doc._id)!;
    my $cursor = $self->cursor($query);
    while(my $row = $cursor->next) {
        push @$paths, @$row;
    }
    return $paths;
}

sub create_document {
    my ($self, $body) = @_;
    die "Arango::Tango | Refusing to store undefined body" unless defined($body);
    return $self->{arango}->_api( create_document => { database => $self->{database}, collection => $self->{name}, _body => $body})
}

lib/Arango/Tango/Collection.pm  view on Meta::CPAN

sub clear_access_level {
    my ($self, $username) = @_;
    return $self->{arango}->clear_access_level( $username , $self->{database}, $self->{name} );
}

sub set_access_level {
    my ($self, $username, $grant) = @_;
    return $self->{arango}->set_access_level($username, $grant, $self->{database}, $self->{name});
}

sub cursor {
    my ($self, $aql, %opts) = @_;
    return Arango::Tango::Cursor->_new(arango => $self->{arango}, database => $self->{database}, query => $aql, %opts);
}

1;

__END__

=pod

lib/Arango/Tango/Collection.pm  view on Meta::CPAN

    $db->clear_access_level($user, 'none')

Clears the collection access level for a specific user.

=head2 C<bulk_import>

    $collection->bulk_import([{_key => "something"}, {_key => "something else"}])

Imports a group of documents in a single call.

=head2 C<cursor>

   my $cursor = $collection->cursor( $aql_query, %opt );

Performs AQL queries, returning a cursor. An optional hash of
options can be supplied. Supported hashes corresponds to the different attributes
available in the ArangoDB REST API (L<https://docs.arangodb.com/3.4/HTTP/AqlQueryCursor/AccessingCursors.html>).

=head1 AUTHOR

Alberto Simões <ambs@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2019-2023 by Alberto Simões.

lib/Arango/Tango/Cursor.pm  view on Meta::CPAN

$Arango::Tango::Cursor::VERSION = '0.019';
use warnings;
use strict;

use Data::Dumper;

sub _new {
  my ($class, %opts) = @_;
  my $self = { arango => $opts{arango}, database => $opts{database} };

  my $ans = $self->{arango}->_api('create_cursor', \%opts);

  return bless { %$ans, %$self, __current => 0 } => $class;
}

sub next {
  my $self = shift;

  if (!$self->{error} && $self->{__current} == 0) {
    $self->{__current}++;
    return $self->{result};
  }

  if ($self->{hasMore}) {
    my $ans = $self->{arango}->_api('cursor_next', { database => $self->{database}, id => $self->{id} });
    if (!$ans->{error}) {
      $self->{hasMore} = $ans->{hasMore};
      return $ans->{result};
    }
  }

  return undef;
}

sub finish {
    my ($self) = @_;
    if (exists($self->{id})) {
        $self->{arango}->_api('cursor_delete',  { database => $self->{database}, id => $self->{id} });
    }
    delete $self->{$_} for (keys %$self);
}

sub has_more {
  my ($self) = @_;
  return $self->{hasMore};
}

1;

lib/Arango/Tango/Cursor.pm  view on Meta::CPAN

Returns the next results. On the first call, returns the results
obtained from the first query request.  Subsequent requests will try
to gather more hits if they exists, and the query id is still alive.

=item C<has_more>

Returns a boolean stating if there are more results to be fetched.

=item C<finish>

Deletes the cursor in the server and destroys all the object details.

=back

=head1 AUTHOR

Alberto Simões <ambs@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2019-2023 by Alberto Simões.

lib/Arango/Tango/Database.pm  view on Meta::CPAN

sub _new {
    my ($class, %opts) = @_;
    return bless {%opts} => $class;
}

sub delete {
    my $self = shift;
    return $self->{arango}->delete_database($self->{name});
}

sub cursor {
    my ($self, $aql, %opts) = @_;
    return Arango::Tango::Cursor->_new(arango => $self->{arango}, database => $self->{name}, query => $aql, %opts);
}





sub collection {
   my ($self, $name) = @_;

lib/Arango/Tango/Database.pm  view on Meta::CPAN

Creates a new index of type ttl for the given collection. The
mandatory args are C<type> (must be C<ttl>), C<name> (string,
human name for the index), C<fields> (array ref with the
names of the document fields to be used as expiration timestamps)
and C<expireAfter> (integer, seconds).
Returns an object containing the id of the created index and the
confirmation of the provided arguments (C<type>, C<name>, C<fields>
and C<expireAfter>). If an error occurs the error field will be
true, otherwise false.

=head2 C<cursor>

   my $cursor = $database->cursor( $aql_query, %opt );

Performs AQL queries, returning a cursor. An optional hash of
options can be supplied. Supported hashes corresponds to the different attributes
available in the ArangoDB REST API (L<https://docs.arangodb.com/3.4/HTTP/AqlQueryCursor/AccessingCursors.html>).

=head2 C<delete>

    $db->delete;

Deletes the supplied database.

=head2 C<delete_collection>

t/04-query.t  view on Meta::CPAN

     { name => 'Bamm-Bamm Rubble', gender => 'male' }
];
for my $doc (@$documents) {
    $collection->create_document( $doc );
}

my $list = $collection->document_paths();
is scalar(@$list), 5, "Five documents imported correctly";

my $query = q{FOR p IN collection LIMIT 2 RETURN p};
my $cursor = $db->cursor($query);

isa_ok $cursor, 'Arango::Tango::Cursor';
ok exists($cursor->{result}) => 'Results key exists';
is scalar(@{$cursor->{result}}) => 2 => 'Correct number of hits';


$cursor = $db->cursor($query, count => 1);
isa_ok $cursor, 'Arango::Tango::Cursor';
ok exists($cursor->{count}) => 'Results count exists';

$cursor = $db->cursor($query, batchSize => 1);
is scalar(@{$cursor->{result}}) => 1 => 'Number of hits is batchSize';

ok $cursor->has_more, "Cursor has more hits";

my $results = $cursor->next;
is scalar(@$results), 1, "First batch right size";
$results = $cursor->next;
is scalar(@$results), 1, "Second batch right size";
$results = $cursor->next;
is $results, undef, "No more results";

## Bind vars
#
$cursor = $db->cursor('FOR p IN @@collection RETURN p', bindVars => { '@collection' => 'collection' });
isa_ok $cursor, 'Arango::Tango::Cursor';

## Do t again
$cursor = $db->cursor($query, batchSize => 1);
$cursor->finish;
is $cursor, {}, "Finish removed all data";

$arango->delete_database("tmp_");

done_testing;



( run in 0.270 second using v1.01-cache-2.11-cpan-4d50c553e7e )