File Coverage

blib/lib/Arango/DB/API.pm
Criterion Covered Total %
statement 30 59 50.8
branch 0 20 0.0
condition 0 8 0.0
subroutine 10 12 83.3
pod n/a
total 40 99 40.4


line stmt bran cond sub pod time code
1             # ABSTRACT: Internal module with the API specification
2             package Arango::DB::API;
3             $Arango::DB::API::VERSION = '0.006';
4 5     5   2049 use Arango::DB::Database;
  5         13  
  5         147  
5 5     5   2193 use Arango::DB::Collection;
  5         13  
  5         138  
6              
7 5     5   43 use strict;
  5         10  
  5         99  
8 5     5   21 use warnings;
  5         10  
  5         108  
9 5     5   3490 use HTTP::Tiny;
  5         257483  
  5         210  
10 5     5   3303 use JSON;
  5         61430  
  5         40  
11 5     5   2739 use Clone 'clone';
  5         11051  
  5         324  
12 5     5   2195 use MIME::Base64 3.11 'encode_base64url';
  5         3026  
  5         301  
13 5     5   2331 use URI::Encode qw(uri_encode);
  5         57836  
  5         329  
14 5     5   2352 use JSON::Schema::Fit 0.02;
  5         20755  
  5         4281  
15              
16             my %API = (
17             create_document => { method => 'post', uri => '{database}_api/document/{collection}' },
18             delete_collection => { method => 'delete', uri => '{database}_api/collection/{name}' },
19             delete_database => { method => 'delete', uri => '_api/database/{name}' },
20             list_collections => { method => 'get', uri => '{database}_api/collection' },
21             cursor_next => { method => 'put', uri => '{database}_api/cursor/{id}' },
22             cursor_delete => { method => 'delete', uri => '{database}_api/cursor/{id}' },
23             list_databases => { method => 'get', uri => '_api/database' },
24             status => { method => 'get', uri => '_admin/status' },
25             time => { method => 'get', uri => '_admin/time' },
26             statistics => { method => 'get', uri => '_admin/statistics' },
27             statistics_description => { method => 'get', uri => '_admin/statistics-description' },
28             'create_database' => {
29             method => 'post',
30             uri => '_api/database',
31             params => { name => { type => 'string' }},
32             builder => sub {
33             my ($self, %params) = @_;
34             return Arango::DB::Database->_new(arango => $self, 'name' => $params{name});
35             },
36             },
37             'create_collection' => {
38             method => 'post',
39             uri => '{database}_api/collection',
40             params => { name => { type => 'string' }},
41             builder => sub {
42             my ($self, %params) = @_;
43             return Arango::DB::Collection->_new(arango => $self, database => $params{database}, 'name' => $params{name});
44             },
45             },
46             'all_keys' => {
47             method => 'put',
48             uri => '{database}_api/simple/all-keys',
49             params => { type => { type => 'string' }, collection => { type => 'string' } },
50             },
51             'version' => {
52             method => 'get',
53             uri => '_api/version',
54             params => { details => { type => 'boolean' } } ,
55             },
56             'create_cursor' => {
57             method => 'post',
58             uri => '{database}_api/cursor',
59             params => {
60             query => { type => 'string' },
61             count => { type => 'boolean' },
62             batchSize => { type => 'integer' },
63             cache => { type => 'boolean' },
64             memoryLimit => { type => 'integer' },
65             ttl => { type => 'integer' },
66             bindVars => { type => 'object', additionalProperties => 1 },
67             options => { type => 'object', additionalProperties => 0, properties => {
68             failOnWarning => { type => 'boolean' },
69             profile => { type => 'integer', maximum => 2, minimum => 0 }, # 0, 1, 2
70             maxTransactionSize => { type => 'integer' },
71             stream => { type => 'boolean' },
72             skipInaccessibleCollections => { type => 'boolean' },
73             maxWarningCount => { type => 'integer' },
74             intermediateCommitCount => { type => 'integer' },
75             satelliteSyncWait => { type => 'integer' },
76             fullCount => { type => 'boolean' },
77             intermediateCommitSize => { type => 'integer' },
78             'optimizer.rules' => { type => 'string' },
79             maxPlans => { type => 'integer' },
80             }
81             },
82             },
83             },
84             delete_user => { method => 'delete', uri => '_api/user/{username}' },
85             create_user => {
86             method => 'post',
87             uri => '_api/user',
88             params => {
89             password => { type => 'string' },
90             active => { type => 'boolean' },
91             user => { type => 'string' },
92             extra => { type => 'object', additionalProperties => 1 },
93             }
94             },
95             );
96              
97              
98              
99             sub _check_options {
100 0     0     my ($params, $properties) = @_;
101 0           my $schema = { type => 'object', additionalProperties => 0, properties => $properties };
102 0           my $prepared_data = JSON::Schema::Fit->new()->get_adjusted($params, $schema);
103 0           return $prepared_data;
104             }
105              
106             sub _api {
107 0     0     my ($self, $action, $params) = @_;
108            
109 0           my $uri = $API{$action}{uri};
110              
111 0           my $params_copy = clone $params;
112              
113 0 0         $uri =~ s!\{database\}! defined $params->{database} ? "_db/$params->{database}/" : "" !e;
  0            
114 0           $uri =~ s/\{([^}]+)\}/$params->{$1}/g;
115            
116 0           my $url = "http://" . $self->{host} . ":" . $self->{port} . "/" . $uri;
117              
118 0 0 0       my $body = ref($params) eq "HASH" && exists $params->{body} ? $params->{body} : undef;
119 0 0         my $opts = ref($params) eq "HASH" ? $params : {};
120              
121 0 0         $opts = exists($API{$action}{params}) ? _check_options($opts, $API{$action}{params}) : {};
122              
123 0 0 0       if ($API{$action}{method} eq 'get' && scalar(keys %$opts)) {
124 0           $url .= "?" . join("&", map { "$_=" . uri_encode($opts->{$_} )} keys %$opts);
  0            
125             } else {
126 0 0 0       if ($body && ref($body) eq "HASH") {
    0          
127 0           $opts = { content => encode_json $body }
128             }
129             elsif (defined($body)) { # JSON
130 0           $opts = { content => $body }
131             }
132             else {
133 0           $opts = { content => encode_json $opts }
134             }
135             }
136            
137             #use Data::Dumper;
138             # print STDERR "\n -- $API{$action}{method} | $url\n";
139             #print STDERR "\n\nOPTS:\n\n", Dumper($opts);
140            
141              
142 0           my $response = $self->{http}->request($API{$action}{method}, $url, $opts);
143              
144 0 0         if ($response->{success}) {
145 0           my $ans = decode_json($response->{content});
146 0 0         if ($ans->{error}) {
    0          
147 0           return $ans;
148             } elsif (exists($API{$action}{builder})) {
149 0           return $API{$action}{builder}->( $self, %$params_copy );
150             } else {
151 0           return $ans;
152             }
153             }
154             else {
155 0           die "Arango::DB | ($response->{status}) $response->{reason}";
156             }
157             }
158              
159              
160              
161             1;
162              
163             __END__