| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package RDF::AllegroGraph::Repository4; |
|
2
|
|
|
|
|
|
|
|
|
3
|
15
|
|
|
15
|
|
84
|
use strict; |
|
|
15
|
|
|
|
|
217
|
|
|
|
15
|
|
|
|
|
503
|
|
|
4
|
15
|
|
|
15
|
|
79
|
use warnings; |
|
|
15
|
|
|
|
|
28
|
|
|
|
15
|
|
|
|
|
455
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
15
|
|
|
15
|
|
77
|
use base qw(RDF::AllegroGraph::Repository); |
|
|
15
|
|
|
|
|
30
|
|
|
|
15
|
|
|
|
|
2265
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
15
|
|
|
15
|
|
84
|
use Data::Dumper; |
|
|
15
|
|
|
|
|
36
|
|
|
|
15
|
|
|
|
|
969
|
|
|
9
|
15
|
|
|
15
|
|
88
|
use feature "switch"; |
|
|
15
|
|
|
|
|
23
|
|
|
|
15
|
|
|
|
|
1368
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
15
|
|
|
15
|
|
77
|
use JSON; |
|
|
15
|
|
|
|
|
50
|
|
|
|
15
|
|
|
|
|
100
|
|
|
12
|
15
|
|
|
15
|
|
1839
|
use URI::Escape qw/uri_escape_utf8/; |
|
|
15
|
|
|
|
|
30
|
|
|
|
15
|
|
|
|
|
1048
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
15
|
|
|
15
|
|
2038
|
use HTTP::Request::Common; |
|
|
15
|
|
|
|
|
4618
|
|
|
|
15
|
|
|
|
|
10800
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=pod |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 NAME |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
RDF::AllegroGraph::Repository4 - AllegroGraph repository handle for AGv4 |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 INTERFACE |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
Same as L from which we inherit. |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=cut |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub new { |
|
29
|
0
|
|
|
0
|
0
|
|
my $class = shift; |
|
30
|
0
|
|
|
|
|
|
my %options = @_; |
|
31
|
0
|
|
|
|
|
|
my $self = bless \%options, $class; |
|
32
|
0
|
0
|
|
|
|
|
$self->{path} = $self->{CATALOG}->{SERVER}->{ADDRESS} . ($self->{CATALOG}->{NAME} eq '/' |
|
33
|
|
|
|
|
|
|
? '' |
|
34
|
|
|
|
|
|
|
: '/catalogs' . $self->{CATALOG}->{NAME} ) . '/repositories/' . $self->{id}; |
|
35
|
0
|
|
|
|
|
|
return $self; |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=pod |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=over |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=item B |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
This read-only accessor method returns the id of the repository. |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=cut |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub id { |
|
49
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
50
|
0
|
0
|
|
|
|
|
return $self->{CATALOG}->{NAME} eq '/' |
|
51
|
|
|
|
|
|
|
? '/' . $self->{id} |
|
52
|
|
|
|
|
|
|
: $self->{CATALOG}->{NAME} . '/' . $self->{id}; |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=pod |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=item B |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
I<$repo>->disband |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
This method removes the repository from the server. The object cannot be used after that, obviously. |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=cut |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub disband { |
|
66
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
67
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new (DELETE => $self->{path}); |
|
68
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request ($requ); |
|
69
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=pod |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=item B |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
I<$nr_triples> = I<$repo>->size |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
Returns the size of the repository in terms of the number of triples. |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
B: As of time of writing, AllegroGraph counts duplicate triples! |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=cut |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub size { |
|
85
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
86
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($self->{path} . '/size'); |
|
87
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
88
|
0
|
|
|
|
|
|
return $resp->content; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=pod |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=back |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head2 Methods (over those we inherit) |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=over |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=item B (since v0.06) |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
I<$session> = I<$repo>->session |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
This method forks a session out of the current repository session. Unlike a transaction, all changes |
|
104
|
|
|
|
|
|
|
are autocommitted into the mother repository. But AG4 needs a separate connection thread for some |
|
105
|
|
|
|
|
|
|
specific features (SNA, loading Prolog knowledge, etc.) |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=cut |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub session { |
|
110
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
111
|
0
|
|
|
|
|
|
my %opts = @_; |
|
112
|
0
|
|
0
|
|
|
|
$opts{autoCommit} ||= 'true'; # this is - by default - a session, so whatever we do, it will shine through |
|
113
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->post ($self->{path} . '/session', %opts); |
|
114
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
115
|
0
|
|
|
|
|
|
my $url = $resp->content; |
|
116
|
0
|
|
|
|
|
|
$url =~ s/^\"//; $url =~ s/\"$//; # for some very odd reason we get this URI in the content |
|
|
0
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
{ # try to find authentication information inside the repo URL |
|
118
|
0
|
0
|
|
|
|
|
if ($self->{path} =~ m{http://(.+?@)}) { |
|
|
0
|
|
|
|
|
|
|
|
119
|
0
|
|
|
|
|
|
my $auth = $1; |
|
120
|
0
|
|
|
|
|
|
$url =~ s{http://}{http://$auth}; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
|
|
|
|
|
|
} |
|
123
|
0
|
0
|
|
|
|
|
if ($opts{autoCommit} eq 'true') { # we do like 'true' strings ... |
|
124
|
15
|
|
|
15
|
|
18155
|
use RDF::AllegroGraph::Session4; |
|
|
15
|
|
|
|
|
38
|
|
|
|
15
|
|
|
|
|
1158
|
|
|
125
|
0
|
|
|
|
|
|
return new RDF::AllegroGraph::Session4 (path => $url, # the newly returned URL will be its home |
|
126
|
|
|
|
|
|
|
CATALOG => $self->{CATALOG}); # and the catalog will be the same |
|
127
|
|
|
|
|
|
|
} else { |
|
128
|
15
|
|
|
15
|
|
15799
|
use RDF::AllegroGraph::Transaction4; |
|
|
15
|
|
|
|
|
43
|
|
|
|
15
|
|
|
|
|
5670
|
|
|
129
|
0
|
|
|
|
|
|
return new RDF::AllegroGraph::Transaction4 (path => $url, # the newly returned URL will be its home |
|
130
|
|
|
|
|
|
|
CATALOG => $self->{CATALOG}); # and the catalog will be the same |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=pod |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=item B (since v0.06) |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
I<$tx> = I<$repo>->transaction |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
This method forks a transaction out of the current repository session. That transaction is itself a |
|
141
|
|
|
|
|
|
|
repository session (and a session, for that matter). Whatever you do in the transaction, will stay |
|
142
|
|
|
|
|
|
|
in the transaction. With calling the C method (see L), |
|
143
|
|
|
|
|
|
|
you will simply empty the transaction. That is also the default behaviour, if the transaction object |
|
144
|
|
|
|
|
|
|
goes out of scope. |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
To manifest any changes you will have to invoke C on the transaction object. |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=cut |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub transaction { |
|
151
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
152
|
0
|
|
|
|
|
|
return $self->session (autoCommit => 'false'); |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=pod |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=item B (since v0.06) |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
I<@blanks> = I<$repo>->blanks (I) |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
This method asks the server to create a number of blank nodes in the repository. The ids of these |
|
162
|
|
|
|
|
|
|
nodes will be returned. By default, one node will be created, but you can ask for more. |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=cut |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub blanks { |
|
167
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
168
|
0
|
|
0
|
|
|
|
my $amount = shift || 1; |
|
169
|
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->post ($self->{path} . '/blankNodes', |
|
171
|
|
|
|
|
|
|
'Content-Type' => 'application/x-www-form-urlencoded', |
|
172
|
|
|
|
|
|
|
'Accept' => 'application/json', |
|
173
|
|
|
|
|
|
|
'Content' => { 'amount' => $amount }); |
|
174
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
175
|
0
|
|
|
|
|
|
return @{ from_json ($resp->content) }; |
|
|
0
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=pod |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=item B |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
I<$repo>->add ('file://....', ...) |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
I<$repo>->add ('http://....', ...) |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
I<$repo>->add (' triples in N3 ', ...) |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
I<$repo>->add ([ I<$subj_uri>, I<$pred_uri>, I<$obj_uri> ], ...) |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
This method adds triples to the repository. The information can be provided in any of the following |
|
191
|
|
|
|
|
|
|
ways (also mixed): |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=over |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=item file, HTTP, FTP URL |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
If a string looks like an URL, it will be dereferenced, the contents of the resource consulted and |
|
198
|
|
|
|
|
|
|
that shipped to the repository on the server. If the resource cannot be read, an exception C
|
|
199
|
|
|
|
|
|
|
not open> will be raised. Any number of these URLs can be provided as parameter. |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
B: Only N3 files are supported, and also only when the URL ends with the extension C or |
|
202
|
|
|
|
|
|
|
C. |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=item N3 triple string |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
If the string looks like N3 notated triples, that content is shipped to the server. |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=item ARRAY reference |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
The reference is interpreted as one triple (statement), containing 3 URIs. These will be shipped |
|
211
|
|
|
|
|
|
|
as-is to the server. |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=back |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
If the server chokes on any of the above, an exception C is raised. |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
B: There are no precautions for over-large content. Yet. |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
B: Named graphs (aka I) are not handled. Yet. |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=cut |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub add { |
|
226
|
0
|
|
|
0
|
1
|
|
_put_post_stmts ('POST', @_); |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub _put_post_stmts { |
|
230
|
0
|
|
|
0
|
|
|
my $method = shift; |
|
231
|
0
|
|
|
|
|
|
my $self = shift; |
|
232
|
|
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
|
my @stmts; # collect triples there |
|
234
|
|
|
|
|
|
|
my $n3; # collect N3 stuff there |
|
235
|
0
|
|
|
|
|
|
my @files; # collect file names here |
|
236
|
15
|
|
|
15
|
|
101
|
use Regexp::Common qw/URI/; |
|
|
15
|
|
|
|
|
30
|
|
|
|
15
|
|
|
|
|
156
|
|
|
237
|
|
|
|
|
|
|
|
|
238
|
0
|
|
|
|
|
|
foreach my $item (@_) { # walk through what we got |
|
239
|
0
|
0
|
|
|
|
|
if (ref($item) eq 'ARRAY') { # a triple statement |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
240
|
0
|
|
|
|
|
|
push @stmts, $item; |
|
241
|
|
|
|
|
|
|
} elsif (ref ($item)) { |
|
242
|
0
|
|
|
|
|
|
die "don't know what to do with it"; |
|
243
|
|
|
|
|
|
|
} elsif ($item =~ /^$RE{URI}{HTTP}/) { |
|
244
|
0
|
|
|
|
|
|
push @files, $item; |
|
245
|
|
|
|
|
|
|
} elsif ($item =~ /^$RE{URI}{FTP}/) { |
|
246
|
0
|
|
|
|
|
|
push @files, $item; |
|
247
|
|
|
|
|
|
|
} elsif ($item =~ /^$RE{URI}{file}/) { |
|
248
|
0
|
|
|
|
|
|
push @files, $item; |
|
249
|
|
|
|
|
|
|
} else { # scalar => N3 |
|
250
|
0
|
|
|
|
|
|
$n3 .= $item; |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
|
|
254
|
0
|
|
|
|
|
|
my $ua = $self->{CATALOG}->{SERVER}->{ua}; # local handle |
|
255
|
|
|
|
|
|
|
|
|
256
|
0
|
0
|
|
|
|
|
if (@stmts) { # if we have something to say to the server |
|
257
|
0
|
|
|
|
|
|
given ($method) { |
|
258
|
0
|
|
|
|
|
|
when ('POST') { |
|
259
|
0
|
|
|
|
|
|
my $resp = $ua->post ($self->{path} . '/statements', |
|
260
|
|
|
|
|
|
|
'Content-Type' => 'application/json', 'Content' => encode_json (\@stmts) ); |
|
261
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
262
|
|
|
|
|
|
|
} |
|
263
|
0
|
|
|
|
|
|
when ('PUT') { |
|
264
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new (PUT => $self->{path} . '/statements', |
|
265
|
|
|
|
|
|
|
[ 'Content-Type' => 'application/json' ], encode_json (\@stmts)); |
|
266
|
0
|
|
|
|
|
|
my $resp = $ua->request ($requ); |
|
267
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
268
|
|
|
|
|
|
|
} |
|
269
|
0
|
|
|
|
|
|
when ('DELETE') { # DELETE |
|
270
|
|
|
|
|
|
|
# first bulk delete facts, i.e. where there are no wildcards |
|
271
|
0
|
0
|
0
|
|
|
|
my @facts = grep { defined $_->[0] && defined $_->[1] && defined $_->[2] } @stmts; |
|
|
0
|
|
|
|
|
|
|
|
272
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new (POST => $self->{path} . '/statements/delete', |
|
273
|
|
|
|
|
|
|
[ 'Content-Type' => 'application/json' ], encode_json (\@facts)); |
|
274
|
0
|
|
|
|
|
|
my $resp = $ua->request ($requ); |
|
275
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# the delete one by one those with wildcards |
|
278
|
0
|
|
0
|
|
|
|
my @wildcarded = grep { ! defined $_->[0] || ! defined $_->[1] || ! defined $_->[2] } @stmts; |
|
|
0
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
foreach my $w (@wildcarded) { |
|
280
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new (DELETE => _to_uri ($self->{path} . '/statements', $w, {}) ); |
|
281
|
0
|
|
|
|
|
|
my $resp = $ua->request ($requ); |
|
282
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
} |
|
285
|
0
|
|
|
|
|
|
default { die "You should never end here: Unhandled '$method'"; } |
|
|
0
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
} |
|
287
|
|
|
|
|
|
|
} |
|
288
|
0
|
0
|
|
|
|
|
if ($n3) { # if we have something to say to the server |
|
289
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new ($method => $self->{path} . '/statements', [ 'Content-Type' => 'text/plain' ], $n3); |
|
290
|
0
|
|
|
|
|
|
my $resp = $ua->request ($requ); |
|
291
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
292
|
|
|
|
|
|
|
} |
|
293
|
0
|
|
|
|
|
|
for my $file (@files) { # if we have something to say to the server |
|
294
|
15
|
|
|
15
|
|
19535
|
use LWP::Simple; |
|
|
15
|
|
|
|
|
34
|
|
|
|
15
|
|
|
|
|
162
|
|
|
295
|
0
|
0
|
|
|
|
|
my $content = get ($file) or die "Could not open URL '$file'"; |
|
296
|
0
|
|
|
|
|
|
my $mime; # lets guess the mime type |
|
297
|
0
|
|
|
|
|
|
given ($file) { # magic does not normally cope well with RDF/N3, so do it by extension |
|
298
|
0
|
|
|
|
|
|
when (/\.n3$/) { $mime = 'text/plain'; } # well, not really, since its text/n3 |
|
|
0
|
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
when (/\.nt$/) { $mime = 'text/plain'; } |
|
|
0
|
|
|
|
|
|
|
|
300
|
0
|
|
|
|
|
|
when (/\.xml$/) { $mime = 'application/rdf+xml'; } |
|
|
0
|
|
|
|
|
|
|
|
301
|
0
|
|
|
|
|
|
when (/\.rdf$/) { $mime = 'application/rdf+xml'; } |
|
|
0
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
default { die; } |
|
|
0
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
} |
|
304
|
|
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new ($method => $self->{path} . '/statements', [ 'Content-Type' => $mime ], $content); |
|
306
|
0
|
|
|
|
|
|
my $resp = $ua->request ($requ); |
|
307
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
308
|
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
|
$method = 'POST'; # whatever the first was, the others must add to it! |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub _to_uri { |
|
316
|
0
|
|
|
0
|
|
|
my $path = shift; |
|
317
|
0
|
|
|
|
|
|
my $w = shift; |
|
318
|
0
|
|
|
|
|
|
my $options = shift; |
|
319
|
|
|
|
|
|
|
|
|
320
|
0
|
|
|
|
|
|
my $url = new URI ($path); |
|
321
|
0
|
0
|
|
|
|
|
$url->query_form ((defined $w->[0] |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
? ('subj' => $w->[0]) |
|
323
|
|
|
|
|
|
|
: () ), |
|
324
|
|
|
|
|
|
|
(defined $w->[1] |
|
325
|
|
|
|
|
|
|
? ('pred' => $w->[1]) |
|
326
|
|
|
|
|
|
|
: () ), |
|
327
|
|
|
|
|
|
|
(ref ($w->[2]) eq 'ARRAY' |
|
328
|
|
|
|
|
|
|
? ('obj' => $w->[2]->[0], |
|
329
|
|
|
|
|
|
|
'objEnd' => $w->[2]->[1] |
|
330
|
|
|
|
|
|
|
) |
|
331
|
|
|
|
|
|
|
: (defined $w->[2] |
|
332
|
|
|
|
|
|
|
? ('obj' => $w->[2]) |
|
333
|
|
|
|
|
|
|
: () |
|
334
|
|
|
|
|
|
|
)), |
|
335
|
|
|
|
|
|
|
(defined $options->{limit} |
|
336
|
|
|
|
|
|
|
? (limit => $options->{limit}) |
|
337
|
|
|
|
|
|
|
: ()) |
|
338
|
|
|
|
|
|
|
); |
|
339
|
0
|
|
|
|
|
|
return $url; |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=pod |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=item B |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
This method behaves exactly like C, except that any existing content in the repository is wiped |
|
347
|
|
|
|
|
|
|
before adding anything. |
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=cut |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub replace { |
|
352
|
0
|
|
|
0
|
1
|
|
_put_post_stmts ('PUT', @_); |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=pod |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=item B |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
I<$repo>->delete ([ I<$subj_uri>, I<$pred_uri>, I<$obj_uri> ], ...) |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
This method removes the passed in triples from the repository. In that process, any combination of |
|
362
|
|
|
|
|
|
|
the subject URI, the predicate or the object URI can be left C. That is interpreted as |
|
363
|
|
|
|
|
|
|
wildcard which matches anything. |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Example: This deletes anything where the Stephansdom is the subject: |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
$air->delete ([ '', undef, undef ]) |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=cut |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub delete { |
|
372
|
0
|
|
|
0
|
1
|
|
_put_post_stmts ('DELETE', @_); |
|
373
|
|
|
|
|
|
|
} |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=pod |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=item B |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
I<@stmts> = I<$repo>->match ([ I<$subj_uri>, I<$pred_uri>, I<$obj_uri> ], ...) |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
This method returns a list of all statements which match one of the triples provided |
|
382
|
|
|
|
|
|
|
as parameter. Any C as URI within such a triple is interpreted as wildcard, matching |
|
383
|
|
|
|
|
|
|
any other URI. |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
(Since v0.06): The object part can now be a range of values. You simply provide an array reference |
|
386
|
|
|
|
|
|
|
with the lower and the upper bound as values in the array, such as for example |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
$repo->match ([ undef, undef, [ '"1"^^my:type', '"10"^^my:type' ] ]); |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
B: Subject range queries and predicate range queries are not supported as RDF would not allow |
|
391
|
|
|
|
|
|
|
literals at these places anyway. |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
(Since v0.06): For AGv4 there is now a way to configure some options when fetching matching triples: |
|
394
|
|
|
|
|
|
|
Simply provide as first parameter an options hash: |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
$repo->match ({ limit => 10 }, [ undef, .....]); |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
These options will apply to all passed in match patterns SEPARATELY, so that with several patterns |
|
399
|
|
|
|
|
|
|
you might well get more than your limit. |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=cut |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
sub match { |
|
404
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
405
|
0
|
0
|
|
|
|
|
my $options = ref($_[0]) eq 'HASH' ? shift : {}; |
|
406
|
|
|
|
|
|
|
|
|
407
|
0
|
|
|
|
|
|
my @stmts; |
|
408
|
0
|
|
|
|
|
|
my $ua = $self->{CATALOG}->{SERVER}->{ua}; |
|
409
|
0
|
|
|
|
|
|
foreach my $w (@_) { |
|
410
|
0
|
|
|
|
|
|
my $resp = $ua->get (_to_uri ($self->{path} . '/statements', $w, $options)); |
|
411
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
412
|
0
|
|
|
|
|
|
push @stmts, @{ from_json ($resp->content) }; |
|
|
0
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
} |
|
414
|
0
|
|
|
|
|
|
return @stmts; |
|
415
|
|
|
|
|
|
|
} |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
sub _query { |
|
418
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
419
|
0
|
|
|
|
|
|
my $query = shift; |
|
420
|
0
|
|
0
|
|
|
|
my $lang = shift || 'sparql'; |
|
421
|
0
|
|
|
|
|
|
my %options = @_; |
|
422
|
|
|
|
|
|
|
|
|
423
|
0
|
|
0
|
|
|
|
$options{RETURN} ||= 'TUPLE_LIST'; # a good default |
|
424
|
0
|
|
|
|
|
|
my $NAMED = 0; |
|
425
|
0
|
0
|
|
|
|
|
($NAMED, $options{RETURN}) = (1, 'TUPLE_LIST') if $options{RETURN} eq 'NAMED_TUPLE_LIST'; # store the info that we should return the names as well |
|
426
|
|
|
|
|
|
|
|
|
427
|
0
|
|
|
|
|
|
my @params; |
|
428
|
0
|
|
|
|
|
|
push @params, "queryLn=$lang"; |
|
429
|
0
|
|
|
|
|
|
push @params, 'query='.uri_escape_utf8 ($query); |
|
430
|
0
|
0
|
|
|
|
|
push @params, 'infer='.uri_escape_utf8 ($options{INFERENCING}) if defined $options{INFERENCING}; |
|
431
|
|
|
|
|
|
|
|
|
432
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($self->{path} . '?' . join ('&', @params) ); |
|
433
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
434
|
|
|
|
|
|
|
|
|
435
|
0
|
|
|
|
|
|
my $json = from_json ($resp->content); |
|
436
|
0
|
|
|
|
|
|
given ($options{RETURN}) { |
|
437
|
0
|
|
|
|
|
|
when ('TUPLE_LIST') { |
|
438
|
0
|
0
|
|
|
|
|
return $NAMED ? ($json) : @{ $json->{values} }; |
|
|
0
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
} |
|
440
|
0
|
|
|
|
|
|
default { die }; |
|
|
0
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
} |
|
442
|
|
|
|
|
|
|
} |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=pod |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=item B |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
I<@tuples> = I<$repo>->sparql ('SELECT ...') |
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
I<@tuples> = I<$repo>->sparql ('SELECT ...' [, I<$option> => I<$value> ]) |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
This method takes a SPARQL query string and returns a list of tuples which the query produced from |
|
453
|
|
|
|
|
|
|
the repository. |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
B: At the moment only SELECT queries are supported. |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
As additional options are accepted: |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=over |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=item C (default: C) |
|
462
|
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
In the case of C the result will be a sequence of (references to) arrays. All naming of |
|
464
|
|
|
|
|
|
|
the individual columns is hereby lost. C really only returns the data (and not the names |
|
465
|
|
|
|
|
|
|
within SELECT clause). |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
(since v0.08) |
|
468
|
|
|
|
|
|
|
C also returns a hash with the names (list reference) and the result sequence |
|
469
|
|
|
|
|
|
|
(list reference, too). |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=item C (default: undef) |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
[Since v0.08] With this option you can control the degree of inferencing used with this query. |
|
474
|
|
|
|
|
|
|
By default, no inferencing is used, but if you pass in C, then the semantics of those |
|
475
|
|
|
|
|
|
|
properties mentioned in C<.../doc/agraph-introduction.html#reasoning> are honored. |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=back |
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
=cut |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
sub sparql { |
|
482
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
483
|
0
|
|
|
|
|
|
my $query = shift; |
|
484
|
|
|
|
|
|
|
|
|
485
|
0
|
|
|
|
|
|
return _query ($self, $query, 'sparql', @_); |
|
486
|
|
|
|
|
|
|
} |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=pod |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=item B (since v0.06) |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
See C, but this is only supported for AGv4 servers. |
|
493
|
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=cut |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
sub prolog { |
|
497
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
498
|
0
|
|
|
|
|
|
my $query = shift; |
|
499
|
|
|
|
|
|
|
|
|
500
|
0
|
|
|
|
|
|
return _query ($self, $query, 'prolog', @_); |
|
501
|
|
|
|
|
|
|
} |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=pod |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
=back |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head2 Namespace Support |
|
509
|
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=over |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
=item B |
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
I<%ns> = I<$repo>->namespaces |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
This read-only function returns a hash containing the namespaces: keys |
|
517
|
|
|
|
|
|
|
are the prefixes, values are the namespace URIs. |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
B: No AllegroGraph I is honored at the moment. |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
B: My current understanding is that AG does NOT support namespaces when you load data with |
|
522
|
|
|
|
|
|
|
C or C, or try to match it with C. In that case, all URIs must be fully |
|
523
|
|
|
|
|
|
|
expanded. Namespaces seem to work with SPARQL queries, though. |
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
=cut |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
sub namespaces { |
|
528
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
529
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($self->{path} . '/namespaces'); |
|
530
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
531
|
|
|
|
|
|
|
return |
|
532
|
0
|
|
|
|
|
|
map { $_->{prefix} => $_->{namespace} } |
|
|
0
|
|
|
|
|
|
|
|
533
|
0
|
|
|
|
|
|
@{ from_json ($resp->content) }; |
|
534
|
|
|
|
|
|
|
} |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
=pod |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
=item B |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
$uri = $repo->namespace ($prefix) |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
$uri = $repo->namespace ($prefix => $uri) |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
$repo->namespace ($prefix => undef) |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
This method fetches, sets and deletes prefix/uri namespaces. If only the prefix is given, |
|
547
|
|
|
|
|
|
|
it will look up the namespace URI. If the URI is provided as second parameter, it will set/overwrite |
|
548
|
|
|
|
|
|
|
that prefix. If the second parameter is C, it will delete the namespace associated with it. |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
B: No I is honored at the moment. |
|
551
|
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
=cut |
|
553
|
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
sub namespace { |
|
555
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
556
|
0
|
|
|
|
|
|
my $prefix = shift; |
|
557
|
|
|
|
|
|
|
|
|
558
|
0
|
|
|
|
|
|
my $uri = $self->{path} . '/namespaces/' . $prefix; |
|
559
|
0
|
0
|
|
|
|
|
if (scalar @_) { # there was a second argument! |
|
560
|
0
|
0
|
|
|
|
|
if (my $nsuri = shift) { |
|
561
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new ('PUT' => $uri, [ 'Content-Type' => 'text/plain' ], $nsuri); |
|
562
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request ($requ); |
|
563
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
564
|
0
|
|
|
|
|
|
return $nsuri; |
|
565
|
|
|
|
|
|
|
} else { |
|
566
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new ('DELETE' => $uri); |
|
567
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request ($requ); |
|
568
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
569
|
|
|
|
|
|
|
} |
|
570
|
|
|
|
|
|
|
} else { |
|
571
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($uri); |
|
572
|
0
|
0
|
|
|
|
|
return undef if $resp->code == 404; |
|
573
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
574
|
0
|
|
0
|
|
|
|
return $resp->content =~ m/^"?(.*?)"?$/ && $1; |
|
575
|
|
|
|
|
|
|
} |
|
576
|
|
|
|
|
|
|
} |
|
577
|
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
=pod |
|
579
|
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
=back |
|
581
|
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
=head2 GeoSpatial Support |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
=over |
|
585
|
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
=item B |
|
587
|
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
I<@geotypes> = I<$repo>->geotypes |
|
589
|
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
This method returns a list of existing geotypes (in form of specially |
|
591
|
|
|
|
|
|
|
crafted URIs). You need these URIs when you want to create locations |
|
592
|
|
|
|
|
|
|
for them, or when you want to retrieve tuples within a specific area |
|
593
|
|
|
|
|
|
|
(based on the geotype). |
|
594
|
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
=cut |
|
596
|
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub geotypes { |
|
598
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
599
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->get ($self->{path} . '/geo/types'); |
|
600
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
601
|
0
|
|
|
|
|
|
return @{ from_json ($resp->content) }; |
|
|
0
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
} |
|
603
|
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
=pod |
|
605
|
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
=item B |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
I<$coord> = I<$repo>->spherical (C, '5.2 degree'); |
|
609
|
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
This method registers a spherical coordinate system on the server. |
|
611
|
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
B: With this version, no region can be specified (so this is always a complete sphere) and |
|
613
|
|
|
|
|
|
|
only degrees are supported. |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=cut |
|
616
|
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
sub spherical { |
|
618
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
619
|
0
|
|
|
|
|
|
my $region = shift; |
|
620
|
0
|
|
|
|
|
|
my $scale = shift; |
|
621
|
|
|
|
|
|
|
|
|
622
|
15
|
|
|
15
|
|
55127
|
use Regexp::Common; |
|
|
15
|
|
|
|
|
44
|
|
|
|
15
|
|
|
|
|
119
|
|
|
623
|
0
|
0
|
|
|
|
|
die "scale information must be of the form 5 mile, or 10 km, or similar" |
|
624
|
|
|
|
|
|
|
unless ($scale =~ /($RE{num}{real})(\s+(degree|mile|km|radian))?/); |
|
625
|
|
|
|
|
|
|
|
|
626
|
0
|
|
|
|
|
|
my $stripW = $1; |
|
627
|
0
|
0
|
|
|
|
|
my $unit = $3 if $2; # leave it undef otherwise |
|
628
|
|
|
|
|
|
|
|
|
629
|
0
|
|
|
|
|
|
my $url = new URI ($self->{path} . '/geo/types/spherical'); |
|
630
|
0
|
0
|
|
|
|
|
$url->query_form (stripWidth => $stripW, |
|
631
|
|
|
|
|
|
|
($unit |
|
632
|
|
|
|
|
|
|
? (unit => $unit) # be explicit |
|
633
|
|
|
|
|
|
|
: () |
|
634
|
|
|
|
|
|
|
) |
|
635
|
|
|
|
|
|
|
); |
|
636
|
|
|
|
|
|
|
|
|
637
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (POST $url); |
|
638
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
639
|
0
|
|
0
|
|
|
|
return $resp->content =~ m/^"?(.*?)"?$/ && $1; |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
=pod |
|
643
|
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
=item B |
|
645
|
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
I<$uri> = I<$repo>->cartesian ("100x100", I<$stripWidth>); |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
I<$uri> = I<$repo>->cartesian ("100x100+10+10", I<$stripWidth>); |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
I<$uri> = I<$repo>->cartesian (I<$minx>, I<$miny>, I<$maxx>, I<$maxy>, I<$stripWidth>); |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
This method registers one new coordinate system at the server. The returned URI is later used as |
|
653
|
|
|
|
|
|
|
reference to that system. The extensions of the system is provided either |
|
654
|
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
=over |
|
656
|
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
=item in the form C |
|
658
|
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
All numbers being floats. The X,Y offset part can be omitted. |
|
660
|
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=item or, alternatively, as minx, miny, maxx, maxy quadruple |
|
662
|
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
Again all numbers being floats. |
|
664
|
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
=back |
|
666
|
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
The last parameter defines the resolution of the stripes, and gives the server optimization hints. |
|
668
|
|
|
|
|
|
|
(See the general AG description for a deep explanation.) |
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=cut |
|
671
|
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
sub cartesian { |
|
673
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
674
|
|
|
|
|
|
|
|
|
675
|
0
|
|
|
|
|
|
my $url = new URI ($self->{path} . '/geo/types/cartesian'); |
|
676
|
|
|
|
|
|
|
|
|
677
|
15
|
|
|
15
|
|
84793
|
use Regexp::Common; |
|
|
15
|
|
|
|
|
43
|
|
|
|
15
|
|
|
|
|
73
|
|
|
678
|
0
|
0
|
|
|
|
|
if ($_[0] =~ /($RE{num}{real})x($RE{num}{real})(\+($RE{num}{real})\+($RE{num}{real}))?/) { |
|
679
|
0
|
|
|
|
|
|
shift; |
|
680
|
0
|
|
0
|
|
|
|
my ($W, $H, $X, $Y) = ($1, $2, $4||0, $5||0); |
|
|
|
|
0
|
|
|
|
|
|
681
|
0
|
|
|
|
|
|
my $stripW = shift; |
|
682
|
0
|
|
|
|
|
|
$url->query_form (stripWidth => $stripW, xmin => $X, xmax => $X+$W, ymin => $Y, ymax => $Y+$H); |
|
683
|
|
|
|
|
|
|
} else { |
|
684
|
0
|
|
|
|
|
|
my ($X1, $Y1, $X2, $Y2, $stripW) = @_; |
|
685
|
0
|
|
|
|
|
|
$url->query_form (stripWidth => $stripW, xmin => $X1, xmax => $X2, ymin => $Y1, ymax => $Y2); |
|
686
|
|
|
|
|
|
|
} |
|
687
|
|
|
|
|
|
|
|
|
688
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (POST $url); |
|
689
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
690
|
0
|
|
0
|
|
|
|
return $resp->content =~ m/^"?(.*?)"?$/ && $1; |
|
691
|
|
|
|
|
|
|
} |
|
692
|
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
=pod |
|
694
|
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
=item B |
|
696
|
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
I<@ss> = I<$repo>->inBox (I<$geotype>, I<$predicate>, 35, 35, 65, 65, { limit => 10 }); |
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
This method tries to find all triples which lie within a certain bounding box. |
|
700
|
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
The geotype is the one you create with C or C. The bounding box is given by the |
|
702
|
|
|
|
|
|
|
bottom/left and the top/right corner coordinates. The optional C restricts the number of |
|
703
|
|
|
|
|
|
|
triples you request. |
|
704
|
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
For cartesian coordinates you provide the bottom/left corner, and then the top/right one. |
|
706
|
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
For spherical coordinates you provide the longitude/latitude of the bottom/left corner, then |
|
708
|
|
|
|
|
|
|
the longitude/latitude of the top/right one. |
|
709
|
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=cut |
|
711
|
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
sub inBox { |
|
713
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
714
|
0
|
|
|
|
|
|
my $geotype = shift; |
|
715
|
0
|
|
|
|
|
|
my $pred = shift; |
|
716
|
0
|
|
|
|
|
|
my ($xmin, $ymin, $xmax, $ymax) = @_; |
|
717
|
0
|
|
0
|
|
|
|
my $options = $_[4] || {}; |
|
718
|
|
|
|
|
|
|
|
|
719
|
0
|
|
|
|
|
|
my $url = new URI ($self->{path} . '/geo/box'); |
|
720
|
0
|
0
|
|
|
|
|
$url->query_form (type => $geotype, |
|
721
|
|
|
|
|
|
|
predicate => $pred, |
|
722
|
|
|
|
|
|
|
xmin => $xmin, |
|
723
|
|
|
|
|
|
|
ymin => $ymin, |
|
724
|
|
|
|
|
|
|
xmax => $xmax, |
|
725
|
|
|
|
|
|
|
ymax => $ymax, |
|
726
|
|
|
|
|
|
|
(defined $options->{limit} |
|
727
|
|
|
|
|
|
|
? (limit => $options->{limit}) |
|
728
|
|
|
|
|
|
|
: ()) |
|
729
|
|
|
|
|
|
|
); |
|
730
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (GET $url); |
|
731
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
732
|
0
|
|
|
|
|
|
return @{ from_json ($resp->content) }; |
|
|
0
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
} |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
=pod |
|
736
|
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=item B |
|
738
|
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
I<@ss> = I<$repo>->inCircle (I<$geotype>, I<$predicate>, 35, 35, 10, { limit => 10 }); |
|
740
|
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
This method tries to find all triples which lie within a certain bounding circle. |
|
742
|
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
The geotype is the one you create with C or C. The bounding circle is given by |
|
744
|
|
|
|
|
|
|
the center and the radius. The optional C restricts the number of triples you request. |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
For cartesian coordinates you simply provide the X/Y coordinates of the circle center, and the |
|
747
|
|
|
|
|
|
|
radius (in the unit as provided with the geotype. |
|
748
|
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
For spherical coordinates the center is specified with a longitude/latitude pair. The radius is also |
|
750
|
|
|
|
|
|
|
interpreted along the provided geotype. |
|
751
|
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
B: As it seems, the circle MUST be totally within the range you specified for your |
|
753
|
|
|
|
|
|
|
geotype. Otherwise AG will return 0 tuples. |
|
754
|
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
=cut |
|
756
|
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
sub inCircle { |
|
758
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
759
|
0
|
|
|
|
|
|
my $geotype = shift; |
|
760
|
0
|
|
|
|
|
|
my $pred = shift; |
|
761
|
0
|
|
|
|
|
|
my ($x, $y, $radius) = @_; |
|
762
|
0
|
|
0
|
|
|
|
my $options = $_[3] || {}; |
|
763
|
|
|
|
|
|
|
|
|
764
|
0
|
|
|
|
|
|
my $url = new URI ($self->{path} . '/geo/circle'); |
|
765
|
0
|
0
|
|
|
|
|
$url->query_form (type => $geotype, |
|
766
|
|
|
|
|
|
|
predicate => $pred, |
|
767
|
|
|
|
|
|
|
x => $x, |
|
768
|
|
|
|
|
|
|
y => $y, |
|
769
|
|
|
|
|
|
|
radius => $radius, |
|
770
|
|
|
|
|
|
|
(defined $options->{limit} |
|
771
|
|
|
|
|
|
|
? (limit => $options->{limit}) |
|
772
|
|
|
|
|
|
|
: ()) |
|
773
|
|
|
|
|
|
|
); |
|
774
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (GET $url); |
|
775
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
776
|
0
|
|
|
|
|
|
return @{ from_json ($resp->content) }; |
|
|
0
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
} |
|
778
|
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
=pod |
|
780
|
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=item I (since v0.06) |
|
782
|
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
I<@ss> = I<$repo>->inPolygon (I<$coordtype>, I<$preduri>, I<@points>, { I<%options> }) |
|
784
|
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
This method tries to identify all statements where the object is within a polygon defined by the |
|
786
|
|
|
|
|
|
|
C array. Each point is simply an array reference with 2 entries (x,y, of course). |
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
The predicate URI defines which predicates should be considered. Do not leave it C. The |
|
789
|
|
|
|
|
|
|
coordinate type is the one you will have generated before with C. |
|
790
|
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
The optional options can only contain C to restrict the number of tuples to be returned. |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
For spherical coordinates make sure that you (a) provide longitude/latitude pairs and then that the |
|
794
|
|
|
|
|
|
|
polygon is built clockwise. |
|
795
|
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
B: This is a somewhat expensive operation in terms of communication round-trips. |
|
797
|
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
=cut |
|
799
|
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
sub inPolygon { |
|
801
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
802
|
0
|
|
|
|
|
|
my $geotype = shift; |
|
803
|
0
|
|
|
|
|
|
my $pred = shift; |
|
804
|
0
|
|
|
|
|
|
my @points; |
|
805
|
0
|
|
|
|
|
|
while (ref($_[0]) eq 'ARRAY') { |
|
806
|
15
|
|
|
15
|
|
25986
|
use RDF::AllegroGraph::Utils qw(coord2literal); |
|
|
15
|
|
|
|
|
35
|
|
|
|
15
|
|
|
|
|
22066
|
|
|
807
|
0
|
|
|
|
|
|
push @points, coord2literal ($geotype, @{ shift @_ }); |
|
|
0
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
} |
|
809
|
0
|
|
0
|
|
|
|
my $options = shift || {}; |
|
810
|
|
|
|
|
|
|
|
|
811
|
0
|
|
|
|
|
|
my ($blank) = $self->blanks; # get one blank node |
|
812
|
|
|
|
|
|
|
|
|
813
|
0
|
|
|
|
|
|
my $url = new URI ($self->{path} . '/geo/polygon'); # build request to park polygon temporarily |
|
814
|
0
|
|
|
|
|
|
$url->query_form (resource => $blank, # under the blank node |
|
815
|
|
|
|
|
|
|
point => \@points # with these points expanded |
|
816
|
|
|
|
|
|
|
); |
|
817
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (PUT $url); # AGv4 does seem to require to have that URL encoded (with PUT??) |
|
818
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
819
|
|
|
|
|
|
|
|
|
820
|
0
|
|
|
|
|
|
$url = new URI ($self->{path} . '/geo/polygon'); # build request to park polygon temporarily |
|
821
|
0
|
0
|
|
|
|
|
$url->query_form (polygon => $blank, # under the blank node |
|
822
|
|
|
|
|
|
|
type => $geotype, # for this geotype |
|
823
|
|
|
|
|
|
|
predicate => $pred, # and for this predicate |
|
824
|
|
|
|
|
|
|
(defined $options->{limit} |
|
825
|
|
|
|
|
|
|
? (limit => $options->{limit}) |
|
826
|
|
|
|
|
|
|
: ()) |
|
827
|
|
|
|
|
|
|
); |
|
828
|
0
|
|
|
|
|
|
$resp = $self->{CATALOG}->{SERVER}->{ua}->request (GET $url); # now we make the real query |
|
829
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
830
|
0
|
|
|
|
|
|
return @{ from_json ($resp->content) }; |
|
|
0
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
} |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
=pod |
|
835
|
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
=item B |
|
837
|
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
This method will return a list of indices which the repository on the server understands. The list |
|
839
|
|
|
|
|
|
|
contains strings of the form C which identify the bias of the index. See |
|
840
|
|
|
|
|
|
|
L |
|
841
|
|
|
|
|
|
|
for some introduction. |
|
842
|
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
B: These are NOT the indices which are active for that repository. See C for that. |
|
844
|
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
=cut |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
sub valid_indices { |
|
848
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
849
|
0
|
|
|
|
|
|
my $url = new URI ($self->{path} . '/indices?listValid=true'); |
|
850
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (GET $url); |
|
851
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
852
|
0
|
|
|
|
|
|
return @{ from_json ($resp->content) }; |
|
|
0
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
} |
|
854
|
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
=pod |
|
856
|
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
=item B |
|
858
|
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
I<@idxs> = I<$rep>->indices ([ I ]) |
|
860
|
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
This method always returns the current list of applied indices for that repository. |
|
862
|
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
Optionally you can pass in a list of changes you want in terms of indices, I in terms of |
|
864
|
|
|
|
|
|
|
indices you want to add, or to remove. To add, say, a C index you would prefix it with a '+': |
|
865
|
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
$rep->indices ('+spogi') |
|
867
|
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
You can provide any number of such additions. In the same way you would a prefixed '-' to indicate |
|
869
|
|
|
|
|
|
|
that you want an index to be deleted. |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
=cut |
|
872
|
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
sub indices { |
|
874
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
875
|
0
|
|
|
|
|
|
foreach my $sidx (@_) { # in the case we want changes to be made |
|
876
|
0
|
0
|
|
|
|
|
if ($sidx =~ m{\-(.+)}) { # removal of indices |
|
|
|
0
|
|
|
|
|
|
|
877
|
0
|
|
|
|
|
|
my $url = new URI ($self->{path} . '/indices/' . $1); |
|
878
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new (DELETE => $url); |
|
879
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request ($requ); |
|
880
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
881
|
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
} elsif ($sidx =~ m{\+(.+)}) { # adding of indices |
|
883
|
0
|
|
|
|
|
|
my $url = new URI ($self->{path} . '/indices/' . $1); |
|
884
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new (PUT => $url); |
|
885
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request ($requ); |
|
886
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
887
|
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
} else { # not sure what this is => ignorance is bliss |
|
889
|
0
|
|
|
|
|
|
warn "not sure what to do with '$sidx', ignoring ..."; |
|
890
|
|
|
|
|
|
|
} |
|
891
|
|
|
|
|
|
|
} |
|
892
|
|
|
|
|
|
|
# now collect the state of affairs from the server |
|
893
|
0
|
|
|
|
|
|
my $url = new URI ($self->{path} . '/indices'); |
|
894
|
0
|
|
|
|
|
|
my $resp = $self->{CATALOG}->{SERVER}->{ua}->request (GET $url); |
|
895
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
896
|
0
|
|
|
|
|
|
return @{ from_json ($resp->content) }; |
|
|
0
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
} |
|
898
|
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
=pod |
|
901
|
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
=item B |
|
903
|
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
I<$bool> = I<$repo>->bulk_loading_mode (C<1|0>) |
|
905
|
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
This method switches on and off the bulk loading capability of the repository. To enable it, pass in |
|
907
|
|
|
|
|
|
|
C<1>, to turn it off pass in C<0>. In any case the current state is returned where C is |
|
908
|
|
|
|
|
|
|
returned instead of C<0>. |
|
909
|
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
=cut |
|
911
|
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
sub _mode { |
|
913
|
0
|
|
|
0
|
|
|
my $ua = shift; |
|
914
|
0
|
|
|
|
|
|
my $path = shift; |
|
915
|
0
|
|
|
|
|
|
my $val = shift; |
|
916
|
|
|
|
|
|
|
|
|
917
|
0
|
0
|
|
|
|
|
if (defined $val) { |
|
918
|
0
|
0
|
|
|
|
|
if ($val) { |
|
919
|
0
|
|
|
|
|
|
my $resp = $ua->request (PUT $path, 'Content' => $val); |
|
920
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
921
|
|
|
|
|
|
|
} else { |
|
922
|
0
|
|
|
|
|
|
my $requ = HTTP::Request->new (DELETE => $path); |
|
923
|
0
|
|
|
|
|
|
my $resp = $ua->request ($requ); |
|
924
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
925
|
|
|
|
|
|
|
} |
|
926
|
|
|
|
|
|
|
} |
|
927
|
0
|
|
|
|
|
|
my $resp = $ua->get ($path); |
|
928
|
0
|
0
|
|
|
|
|
die "protocol error: ".$resp->status_line.' ('.$resp->content.')' unless $resp->is_success; |
|
929
|
0
|
|
|
|
|
|
return $resp->content eq 'true'; |
|
930
|
|
|
|
|
|
|
} |
|
931
|
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
sub bulk_loading_mode { |
|
933
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
934
|
0
|
|
|
|
|
|
my $val = shift; |
|
935
|
|
|
|
|
|
|
|
|
936
|
0
|
|
|
|
|
|
return _mode ($self->{CATALOG}->{SERVER}->{ua}, $self->{path} . '/bulkMode', $val); |
|
937
|
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
} |
|
939
|
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
=pod |
|
941
|
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
=item B |
|
943
|
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
I<$bool> = I<$repo>->commit_mode (C<1|0>) |
|
945
|
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
Method to control the commit mode of a repository. Parameters and return values are like those for C. |
|
947
|
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
=cut |
|
949
|
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
sub commit_mode { |
|
951
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
952
|
0
|
|
|
|
|
|
my $val = shift; |
|
953
|
|
|
|
|
|
|
|
|
954
|
0
|
0
|
|
|
|
|
return ! _mode ($self->{CATALOG}->{SERVER}->{ua}, $self->{path} . '/noCommit', defined $val ? abs($val-1) : undef); |
|
955
|
|
|
|
|
|
|
} |
|
956
|
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
=pod |
|
958
|
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
=item B |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
I<$bool> = I<$repo>->duplicate_suppression_mode (C<1|0>) |
|
962
|
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
Method to control the duplicate suppression behavior of a repository. Parameters and return values |
|
964
|
|
|
|
|
|
|
are like those for C. |
|
965
|
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
=cut |
|
967
|
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
sub duplicate_suppression_mode { |
|
969
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
970
|
0
|
|
|
|
|
|
my $val = shift; |
|
971
|
|
|
|
|
|
|
|
|
972
|
0
|
|
|
|
|
|
return _mode ($self->{CATALOG}->{SERVER}->{ua}, $self->{path} . '/deleteDuplicates', $val); |
|
973
|
|
|
|
|
|
|
} |
|
974
|
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
=pod |
|
976
|
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
=back |
|
978
|
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=cut |
|
980
|
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
our $VERSION = '0.07'; |
|
982
|
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
1; |
|
984
|
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
__END__ |