| 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__ |