line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
50
|
|
|
50
|
|
602
|
use v5.14; |
|
50
|
|
|
|
|
161
|
|
2
|
50
|
|
|
50
|
|
253
|
use warnings; |
|
50
|
|
|
|
|
121
|
|
|
50
|
|
|
|
|
2303
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
Attean::API::Model - RDF Model |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 VERSION |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
This document describes Attean::API::Model version 0.032 |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 DESCRIPTION |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
The Attean::API::Model role defines a common API for all RDF models to conform |
15
|
|
|
|
|
|
|
to. It is provides a consistent interface for probing, counting, and retrieving |
16
|
|
|
|
|
|
|
L<Attean::API::Quad|Attean::API::Binding>s matching a pattern, as well as |
17
|
|
|
|
|
|
|
related functionality such as enumerating the graph names, and extracting |
18
|
|
|
|
|
|
|
structured data from the models' quads. |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 REQUIRED METHODS |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
The following methods are required by the L<Attean::API::Model> role: |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=over 4 |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=item C<< get_quads( $subject, $predicate, $object, $graph ) >> |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> for quads in the model that match the |
29
|
|
|
|
|
|
|
supplied C<< $subject >>, C<< $predicate >>, C<< $object >>, and C<< $graph >>. |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
Any of these terms may be: |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
* An L<Attean::API::Term> object, in which case matching is equality-based |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
* A L<Attean::API::Variable> object or C<< undef >>, in which case that term |
36
|
|
|
|
|
|
|
will be considered as a wildcard for the purposes of matching |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
* An ARRAY reference of L<Attean::API::Term> objects, in which case the |
39
|
|
|
|
|
|
|
matching will be equality-based on the disjunction of the supplied terms |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
The returned iterator conforms to both L<Attean::API::Iterator> and |
42
|
|
|
|
|
|
|
L<Attean::API::QuadIterator>. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=item C<< count_quads( $subject, $predicate, $object, $graph ) >> |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Returns the number of quads in the model matching the supplied pattern |
47
|
|
|
|
|
|
|
(using the same matching semantics as C<< get_quads >>). |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
=item C<< count_quads_estimate( $subject, $predicate, $object, $graph ) >> |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
Returns an estimate of the number of quads in the model matching the supplied |
52
|
|
|
|
|
|
|
pattern (using the same matching semantics as C<< get_quads >>). This estimate |
53
|
|
|
|
|
|
|
is guaranteed to non-zero if the count returned from an equivalent call to |
54
|
|
|
|
|
|
|
`count_quads` would return a non-zero result. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=item C<< get_graphs >> |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of distinct L<Attean::API::Term> objects |
59
|
|
|
|
|
|
|
that are used in the graph position of quads in the model. |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=back |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head1 METHODS |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
The L<Attean::API::Model> role provides default implementations of the |
66
|
|
|
|
|
|
|
following methods: |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=over 4 |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=item C<< get_bindings( $subject, $predicate, $object, $graph ) >> |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of L<Attean::API::Result> objects |
73
|
|
|
|
|
|
|
corresponding to quads in the model matching the supplied pattern. For each |
74
|
|
|
|
|
|
|
L<Attean::API::Variable> in the pattern list, a mapping will be present in the |
75
|
|
|
|
|
|
|
corresponding result object. For example, |
76
|
|
|
|
|
|
|
C<< $model->get_bindings( variable('s') ) >> will return an iterator of results |
77
|
|
|
|
|
|
|
containing just a mapping from C<< 's' >> to subjects of all quads in the |
78
|
|
|
|
|
|
|
model. |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=item C<< get_list( $graph, $head ) >> |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of L<Attean::API::Term> objects that are |
83
|
|
|
|
|
|
|
members of the rdf:List with the specified C<< $head >> (and matching |
84
|
|
|
|
|
|
|
restricted to only the specified C<< $graph >>). |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
To check if a certain term is a list, the C<holds> method may be used, for example: |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
$model->holds($head, iri('http://www.w3.org/1999/02/22-rdf-syntax-ns#first'), undef, $graph)) |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
will return true if a given term C<$head> is a list. |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=item C<< get_sequence( $graph, $head ) >> |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of L<Attean::API::Term> objects that are |
95
|
|
|
|
|
|
|
members of the rdf:Sequence with the specified C<< $head >> (and matching |
96
|
|
|
|
|
|
|
restricted to only the specified C<< $graph >>). |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=item C<< subjects( $predicate, $object, $graph ) >> |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of L<Attean::API::Term> objects of all |
101
|
|
|
|
|
|
|
subjects of quads matching the supplied pattern (using the same matching |
102
|
|
|
|
|
|
|
semantics as C<< get_quads >>). |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
The objects returned will not necessarily be unique. It will instead be |
105
|
|
|
|
|
|
|
equivalent to calling C<< get_quads >> and accessing C<< $quad->subject >> |
106
|
|
|
|
|
|
|
for each C<< $quad >> value returned by the iterator. For an iterator of unique |
107
|
|
|
|
|
|
|
subjects, use C<< $model->subjects->uniq >>. |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=item C<< predicates( $subject, $object, $graph ) >> |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of L<Attean::API::Term> objects of all |
112
|
|
|
|
|
|
|
predicates of quads matching the supplied pattern (using the same matching |
113
|
|
|
|
|
|
|
semantics as C<< get_quads >> with an C<< undef >> predicate). |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
The objects returned will not necessarily be unique |
116
|
|
|
|
|
|
|
(see the note for C<< subjects >> above). |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=item C<< objects( $subject, $predicate, $graph ) >> |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of L<Attean::API::Term> objects of all |
121
|
|
|
|
|
|
|
objects of quads matching the supplied pattern (using the same matching |
122
|
|
|
|
|
|
|
semantics as C<< get_quads >> with an C<< undef >> object). |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
The objects returned will not necessarily be unique |
125
|
|
|
|
|
|
|
(see the note for C<< subjects >> above). |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item C<< graphs( $subject, $predicate, $object ) >> |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of L<Attean::API::Term> objects of all |
130
|
|
|
|
|
|
|
graphs of quads matching the supplied pattern (using the same matching |
131
|
|
|
|
|
|
|
semantics as C<< get_quads >> with an C<< undef >> graph). |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
The objects returned will not necessarily be unique |
134
|
|
|
|
|
|
|
(see the note for C<< subjects >> above). |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=item C<< graph_nodes( $graph ) >> |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of L<Attean::API::Term> objects of unique |
139
|
|
|
|
|
|
|
subjects and objects present in the specified C<< $graph >>. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=item C<< holds($s, $p, $o, $g) >> |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=item C<< holds($triple_pattern) >> |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=item C<< holds($quad_pattern) >> |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Returns true if the triple/quad pattern matches any data in the model, false |
148
|
|
|
|
|
|
|
otherwise. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=item C<< algebra_holds($algebra, $graph) >> |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=item C<< algebra_holds($algebra, \@graphs) >> |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Returns true if the algebra, evaluated with the supplied default graph(s) |
155
|
|
|
|
|
|
|
matches any data in the model, false otherwise. This is equivalent to the |
156
|
|
|
|
|
|
|
result of an ASK query over the supplied algebra. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=item C<< evaluate($algebra, [ $default_graph | \@default_graphs ]) >> |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
Returns an L<Attean::API::Iterator> of L<Attean::Result> objects which result |
161
|
|
|
|
|
|
|
from evaluating the given query algebra (e.g. one obtained from parsing a query |
162
|
|
|
|
|
|
|
with L<AtteanX::Parser::SPARQL>) with the supplied default graph(s) against data |
163
|
|
|
|
|
|
|
in the model. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=cut |
166
|
|
|
|
|
|
|
|
167
|
50
|
|
|
50
|
|
19186
|
use Attean::API::Binding; |
|
50
|
|
|
|
|
161
|
|
|
50
|
|
|
|
|
2203
|
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
use Sub::Install; |
170
|
50
|
|
|
50
|
|
374
|
use Sub::Util qw(set_subname); |
|
50
|
|
|
|
|
106
|
|
|
50
|
|
|
|
|
491
|
|
171
|
50
|
|
|
50
|
|
2094
|
use URI::Namespace; |
|
50
|
|
|
|
|
105
|
|
|
50
|
|
|
|
|
2007
|
|
172
|
50
|
|
|
50
|
|
317
|
use Scalar::Util qw(blessed); |
|
50
|
|
|
|
|
94
|
|
|
50
|
|
|
|
|
1308
|
|
173
|
50
|
|
|
50
|
|
264
|
use List::MoreUtils qw(uniq); |
|
50
|
|
|
|
|
93
|
|
|
50
|
|
|
|
|
1832
|
|
174
|
50
|
|
|
50
|
|
306
|
use Math::Cartesian::Product; |
|
50
|
|
|
|
|
145
|
|
|
50
|
|
|
|
|
287
|
|
175
|
50
|
|
|
50
|
|
69625
|
use Data::Dumper; |
|
50
|
|
|
|
|
33384
|
|
|
50
|
|
|
|
|
2280
|
|
176
|
50
|
|
|
50
|
|
4280
|
|
|
50
|
|
|
|
|
135
|
|
|
50
|
|
|
|
|
2081
|
|
177
|
|
|
|
|
|
|
use Moo::Role; |
178
|
50
|
|
|
50
|
|
273
|
|
|
50
|
|
|
|
|
99
|
|
|
50
|
|
|
|
|
306
|
|
179
|
|
|
|
|
|
|
# get_quads($s, $p, $o, $g) |
180
|
|
|
|
|
|
|
# or: |
181
|
|
|
|
|
|
|
# get_quads([$s1, $s2, ...], \@p, \@o, \@g) |
182
|
|
|
|
|
|
|
requires 'get_quads'; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
my $self = shift; |
185
|
|
|
|
|
|
|
my @nodes = @_; |
186
|
50
|
|
|
50
|
1
|
214
|
my @pos = Attean::API::Quad->variables; |
187
|
50
|
|
|
|
|
121
|
# my %vars; |
188
|
50
|
|
|
|
|
186
|
my %bound; |
189
|
|
|
|
|
|
|
my %projected_vars; |
190
|
50
|
|
|
|
|
121
|
foreach my $i (0 .. $#nodes) { |
191
|
|
|
|
|
|
|
my $n = $nodes[$i]; |
192
|
50
|
|
|
|
|
153
|
$bound{ $pos[ $i ] } = $n; |
193
|
196
|
|
|
|
|
1734
|
if (blessed($n) and $n->does('Attean::API::Binding')) { |
194
|
196
|
|
|
|
|
306
|
foreach my $v ($n->referenced_variables) { |
195
|
196
|
50
|
66
|
|
|
661
|
$projected_vars{ $v }++; |
|
|
100
|
100
|
|
|
|
|
196
|
0
|
|
|
|
|
0
|
} |
197
|
0
|
|
|
|
|
0
|
} elsif (blessed($n) and $n->isa('Attean::Variable')) { |
198
|
|
|
|
|
|
|
my $name = $n->value; |
199
|
|
|
|
|
|
|
# $vars{ $pos[ $i ] } = $name; |
200
|
84
|
|
|
|
|
1848
|
$projected_vars{ $name }++; |
201
|
|
|
|
|
|
|
} |
202
|
84
|
|
|
|
|
234
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
my @patterns; |
205
|
|
|
|
|
|
|
cartesian { |
206
|
50
|
|
|
|
|
778
|
my %bound; |
207
|
|
|
|
|
|
|
foreach my $i (0 .. $#_) { |
208
|
50
|
|
|
50
|
|
3291
|
my $n = $_[$i]; |
209
|
50
|
|
|
|
|
124
|
$bound{ $pos[ $i ] } = $n; |
210
|
196
|
|
|
|
|
230
|
} |
211
|
196
|
|
|
|
|
353
|
push(@patterns, Attean::QuadPattern->new( %bound )); |
212
|
|
|
|
|
|
|
} map { ref($_) eq 'ARRAY' ? $_ : [$_] } @nodes; |
213
|
50
|
|
|
|
|
1106
|
|
214
|
50
|
100
|
|
|
|
269
|
my $quads = $self->get_quads(@nodes); |
|
196
|
|
|
|
|
595
|
|
215
|
|
|
|
|
|
|
unless (blessed($quads)) { |
216
|
50
|
|
|
|
|
2773
|
return Attean::ListIterator->new(values => [], item_type => 'Attean::API::Result', variables => []); |
217
|
50
|
50
|
|
|
|
214
|
} |
218
|
0
|
|
|
|
|
0
|
return $quads->map(sub { |
219
|
|
|
|
|
|
|
my $q = shift; |
220
|
|
|
|
|
|
|
# warn 'model got quad: ' . $q->as_string . "\n"; |
221
|
85
|
|
|
85
|
|
116
|
foreach my $pattern (@patterns) { |
222
|
|
|
|
|
|
|
# warn 'model using pattern: ' . $pattern->as_string . "\n"; |
223
|
85
|
|
|
|
|
155
|
if (my $b = $pattern->unify($q)) { |
224
|
|
|
|
|
|
|
# warn 'unified binding: ' . $b->as_string; |
225
|
85
|
50
|
|
|
|
228
|
my $g = $pattern->ground($b); |
226
|
|
|
|
|
|
|
# warn "get_bindings unification: " . $b->as_string; |
227
|
85
|
|
|
|
|
2011
|
# warn "get_bindings ground: " . $g->as_string; |
228
|
|
|
|
|
|
|
# warn 'project vars: ' . Dumper([keys %projected_vars]); |
229
|
|
|
|
|
|
|
my $p = $b->project(keys %projected_vars); |
230
|
|
|
|
|
|
|
# warn "get_bindings result: " . $p->as_string; |
231
|
85
|
|
|
|
|
2055
|
return $p; |
232
|
|
|
|
|
|
|
} |
233
|
85
|
|
|
|
|
2107
|
} |
234
|
|
|
|
|
|
|
return; |
235
|
|
|
|
|
|
|
}, 'Attean::API::Result', variables => [keys %projected_vars]); |
236
|
0
|
|
|
|
|
0
|
} |
237
|
50
|
|
|
|
|
440
|
|
238
|
|
|
|
|
|
|
requires 'count_quads'; |
239
|
|
|
|
|
|
|
requires 'count_quads_estimate'; |
240
|
|
|
|
|
|
|
requires 'get_graphs'; |
241
|
|
|
|
|
|
|
requires 'holds'; |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
my $self = shift; |
244
|
|
|
|
|
|
|
die "get_list called without a graph name" unless (scalar(@_)); |
245
|
|
|
|
|
|
|
my $graph = shift; |
246
|
2
|
|
|
2
|
1
|
1504
|
die "get_list called without a list head" unless (scalar(@_)); |
247
|
2
|
50
|
|
|
|
8
|
my $head = shift; |
248
|
2
|
|
|
|
|
4
|
my $rdf_first = Attean::IRI->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#first'); |
249
|
2
|
100
|
|
|
|
12
|
my $rdf_rest = Attean::IRI->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#rest'); |
250
|
1
|
|
|
|
|
2
|
my $rdf_nil = Attean::IRI->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'); |
251
|
1
|
|
|
|
|
23
|
my @elements; |
252
|
1
|
|
|
|
|
265
|
my %seen; |
253
|
1
|
|
|
|
|
182
|
while (blessed($head) and not($head->does('Attean::API::IRI') and $head->value eq $rdf_nil->value)) { |
254
|
1
|
|
|
|
|
162
|
if ($seen{ $head->as_string }++) { |
255
|
|
|
|
|
|
|
die "Loop found during rdf:List traversal"; |
256
|
1
|
|
66
|
|
|
11
|
} |
|
|
|
66
|
|
|
|
|
257
|
3
|
50
|
|
|
|
83
|
my @n = $self->objects( $head, $rdf_first )->elements; |
258
|
0
|
|
|
|
|
0
|
if (scalar(@n) != 1) { |
259
|
|
|
|
|
|
|
die "Invalid structure found during rdf:List traversal"; |
260
|
3
|
|
|
|
|
33
|
} |
261
|
3
|
50
|
|
|
|
19
|
push(@elements, @n); |
262
|
0
|
|
|
|
|
0
|
($head) = $self->objects( $head, $rdf_rest )->elements; |
263
|
|
|
|
|
|
|
} |
264
|
3
|
|
|
|
|
8
|
return Attean::ListIterator->new(values => \@elements, item_type => 'Attean::API::Term' ); |
265
|
3
|
|
|
|
|
9
|
} |
266
|
|
|
|
|
|
|
|
267
|
1
|
|
|
|
|
44
|
my $self = shift; |
268
|
|
|
|
|
|
|
my $graph = shift; |
269
|
|
|
|
|
|
|
my $head = shift; |
270
|
|
|
|
|
|
|
my $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; |
271
|
2
|
|
|
2
|
1
|
346
|
my @elements; |
272
|
2
|
|
|
|
|
2
|
my $i = 1; |
273
|
2
|
|
|
|
|
4
|
while (1) { |
274
|
2
|
|
|
|
|
3
|
my $term = Attean::IRI->new("${rdf}_$i"); |
275
|
2
|
|
|
|
|
3
|
my @elem = $self->objects( $head, $term, $graph )->elements; |
276
|
2
|
|
|
|
|
3
|
last unless (scalar(@elem)); |
277
|
2
|
|
|
|
|
3
|
if (scalar(@elem) > 1) { |
278
|
6
|
|
|
|
|
110
|
my $count = scalar(@elem); |
279
|
6
|
|
|
|
|
1135
|
die "Invalid structure found during rdf:Seq access: $count elements found for element $i"; |
280
|
6
|
100
|
|
|
|
36
|
} |
281
|
5
|
100
|
|
|
|
13
|
my $elem = $elem[0]; |
282
|
1
|
|
|
|
|
2
|
last unless (blessed($elem)); |
283
|
1
|
|
|
|
|
15
|
push(@elements, $elem); |
284
|
|
|
|
|
|
|
$i++; |
285
|
4
|
|
|
|
|
8
|
} |
286
|
4
|
50
|
|
|
|
13
|
return Attean::ListIterator->new(values => \@elements, item_type => 'Attean::API::Term' ); |
287
|
4
|
|
|
|
|
8
|
} |
288
|
4
|
|
|
|
|
14
|
|
289
|
|
|
|
|
|
|
{ |
290
|
1
|
|
|
|
|
18
|
# auto-generate methods subjects, predicates, objects, and graphs |
291
|
|
|
|
|
|
|
my @pos = Attean::API::Quad->variables; |
292
|
|
|
|
|
|
|
my %pos = map { $pos[$_] => $_ } (0 .. $#pos); |
293
|
|
|
|
|
|
|
for my $method (@pos) { |
294
|
|
|
|
|
|
|
my $code = sub { |
295
|
|
|
|
|
|
|
my $self = shift; |
296
|
|
|
|
|
|
|
my @nodes = @_; |
297
|
|
|
|
|
|
|
$#nodes = 3; |
298
|
|
|
|
|
|
|
splice(@nodes, $pos{$method}, 0, undef); |
299
|
20
|
|
|
20
|
|
395
|
$#nodes = 3; |
|
|
|
|
20
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
20
|
|
|
|
300
|
20
|
|
|
|
|
44
|
my $iter = $self->get_quads(@nodes); |
301
|
20
|
|
|
|
|
51
|
my $nodes = $iter->map( |
302
|
20
|
|
|
|
|
62
|
sub { $_->$method() }, |
303
|
20
|
|
|
|
|
35
|
'Attean::API::Term', |
304
|
20
|
|
|
|
|
71
|
); |
305
|
|
|
|
|
|
|
return $nodes; |
306
|
33
|
|
|
33
|
|
117
|
}; |
307
|
20
|
|
|
|
|
153
|
Sub::Install::install_sub({ |
308
|
|
|
|
|
|
|
code => set_subname("${method}s", $code), |
309
|
20
|
|
|
|
|
657
|
as => "${method}s" |
310
|
|
|
|
|
|
|
}); |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
my $self = shift; |
315
|
|
|
|
|
|
|
my $graph = shift; |
316
|
|
|
|
|
|
|
my $s = $self->subjects(undef, undef, $graph); |
317
|
|
|
|
|
|
|
my $o = $self->objects(undef, undef, $graph); |
318
|
|
|
|
|
|
|
my $union = Attean::IteratorSequence->new( iterators => [$s, $o], item_type => 'Attean::API::Term' ); |
319
|
2
|
|
|
2
|
1
|
4
|
my %seen; |
320
|
2
|
|
|
|
|
5
|
return $union->grep(sub {not($seen{shift->as_string}++)}); |
321
|
2
|
|
|
|
|
10
|
} |
322
|
2
|
|
|
|
|
9
|
|
323
|
2
|
|
|
|
|
39
|
my $self = shift; |
324
|
2
|
|
|
|
|
61
|
my $algebra = shift || die "No algebra available in evaluate call"; |
325
|
2
|
|
|
12
|
|
34
|
my $default_graphs = shift || die "No default graphs available in evaluate call"; |
|
12
|
|
|
|
|
31
|
|
326
|
|
|
|
|
|
|
$default_graphs = [$default_graphs] if (blessed($default_graphs)); |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
unless (blessed($algebra) and $algebra->does('Attean::API::Algebra')) { |
329
|
2
|
|
|
2
|
1
|
18
|
die "Unexpected argument to evaluate: " . Dumper($algebra); |
330
|
2
|
|
50
|
|
|
11
|
} |
331
|
2
|
|
50
|
|
|
7
|
|
332
|
2
|
50
|
|
|
|
13
|
my $planner = Attean::IDPQueryPlanner->new(); |
333
|
|
|
|
|
|
|
my $plan = $planner->plan_for_algebra($algebra, $self, $default_graphs); |
334
|
2
|
50
|
33
|
|
|
15
|
my $iter = $plan->evaluate($self); |
335
|
0
|
|
|
|
|
0
|
return $iter; |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
2
|
|
|
|
|
64
|
my $self = shift; |
339
|
2
|
|
|
|
|
2983
|
my $algebra = shift || die "No algebra available in algebra_holds call"; |
340
|
2
|
|
|
|
|
14
|
my $default_graphs = shift || die "No default graphs available in algebra_holds call"; |
341
|
2
|
|
|
|
|
107
|
$default_graphs = [$default_graphs] if (blessed($default_graphs)); |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
unless (blessed($algebra) and $algebra->does('Attean::API::Algebra')) { |
344
|
|
|
|
|
|
|
die "Unexpected argument to algebra_holds: " . Dumper($algebra); |
345
|
6
|
|
|
6
|
1
|
17
|
} |
346
|
6
|
|
50
|
|
|
20
|
|
347
|
6
|
|
50
|
|
|
21
|
unless ($algebra->isa('Attean::Algebra::Ask')) { |
348
|
6
|
50
|
|
|
|
31
|
$algebra = Attean::Algebra::Ask->new(children => [$algebra]); |
349
|
|
|
|
|
|
|
} |
350
|
6
|
50
|
33
|
|
|
43
|
my $planner = Attean::IDPQueryPlanner->new(); |
351
|
0
|
|
|
|
|
0
|
my $plan = $planner->plan_for_algebra($algebra, $self, $default_graphs); |
352
|
|
|
|
|
|
|
my $iter = $plan->evaluate($self); |
353
|
|
|
|
|
|
|
my $r = $iter->next; |
354
|
6
|
50
|
|
|
|
227
|
my $ebv = eval { $r->ebv }; |
355
|
6
|
|
|
|
|
92
|
return 0 if ($@); |
356
|
|
|
|
|
|
|
return $ebv; |
357
|
6
|
|
|
|
|
99
|
} |
358
|
6
|
|
|
|
|
5685
|
|
359
|
6
|
|
|
|
|
37
|
my $self = shift; |
360
|
6
|
|
|
|
|
308
|
return 0 unless scalar(@_); |
361
|
6
|
|
|
|
|
14
|
if (not defined($_[0]) or (blessed($_[0]) and $_[0]->does('Attean::API::TermOrVariable'))) { |
|
6
|
|
|
|
|
42
|
|
362
|
6
|
50
|
|
|
|
21
|
# firt argument is undef or a term/variable, so we assume this is a call with up to 3 term/variable/undef args |
363
|
6
|
|
|
|
|
190
|
return ($self->count_quads_estimate(@_) > 0); |
364
|
|
|
|
|
|
|
} elsif (blessed($_[0]) and $_[0]->does('Attean::API::TripleOrQuadPattern')) { |
365
|
|
|
|
|
|
|
my $t = shift; |
366
|
|
|
|
|
|
|
return ($self->count_quads_estimate($t->values) > 0); |
367
|
16
|
|
|
16
|
1
|
1774
|
} else { |
368
|
16
|
50
|
|
|
|
54
|
die "Unexpected argument to holds: " . Dumper($_[0]); |
369
|
16
|
100
|
66
|
|
|
174
|
} |
|
|
50
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
370
|
|
|
|
|
|
|
} |
371
|
13
|
|
|
|
|
427
|
} |
372
|
|
|
|
|
|
|
|
373
|
3
|
|
|
|
|
149
|
|
374
|
3
|
|
|
|
|
18
|
use Attean::RDF; |
375
|
|
|
|
|
|
|
use LWP::UserAgent; |
376
|
0
|
|
|
|
|
0
|
use Encode qw(encode); |
377
|
|
|
|
|
|
|
use Scalar::Util qw(blessed); |
378
|
|
|
|
|
|
|
use Role::Tiny (); |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
use Moo::Role; |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
requires 'add_quad'; |
383
|
50
|
|
|
50
|
|
86744
|
requires 'remove_quad'; |
|
50
|
|
|
|
|
145
|
|
|
50
|
|
|
|
|
415
|
|
384
|
50
|
|
|
50
|
|
67634
|
requires 'create_graph'; |
|
50
|
|
|
|
|
1595194
|
|
|
50
|
|
|
|
|
1832
|
|
385
|
50
|
|
|
50
|
|
584
|
requires 'drop_graph'; |
|
50
|
|
|
|
|
5411
|
|
|
50
|
|
|
|
|
2771
|
|
386
|
50
|
|
|
50
|
|
323
|
requires 'clear_graph'; |
|
50
|
|
|
|
|
102
|
|
|
50
|
|
|
|
|
1574
|
|
387
|
50
|
|
|
50
|
|
381
|
requires 'add_iter'; |
|
50
|
|
|
|
|
91
|
|
|
50
|
|
|
|
|
692
|
|
388
|
|
|
|
|
|
|
|
389
|
50
|
|
|
50
|
|
237
|
with 'Attean::API::Model'; |
|
50
|
|
|
|
|
89
|
|
|
50
|
|
|
|
|
409
|
|
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
my $self = shift; |
392
|
|
|
|
|
|
|
my $graph = shift; |
393
|
|
|
|
|
|
|
my @urls = @_; |
394
|
|
|
|
|
|
|
my $ua = LWP::UserAgent->new(); |
395
|
|
|
|
|
|
|
my $accept = Attean->acceptable_parsers( handles => 'Attean::API::Triple' ); |
396
|
|
|
|
|
|
|
$ua->default_headers->push_header( 'Accept' => $accept ); |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
foreach my $u (@urls) { |
399
|
|
|
|
|
|
|
my $url = blessed($u) ? $u->value : $u; |
400
|
|
|
|
|
|
|
my $resp = $ua->get($url); |
401
|
0
|
|
|
0
|
0
|
0
|
if ($resp->is_success) { |
402
|
0
|
|
|
|
|
0
|
my $ct = $resp->header('Content-Type'); |
403
|
0
|
|
|
|
|
0
|
my $pclass = Attean->get_parser( media_type => $ct, filename => $url ) // Attean->get_parser('ntriples'); |
404
|
0
|
|
|
|
|
0
|
if ($pclass) { |
405
|
0
|
|
|
|
|
0
|
my $p = $pclass->new(base => iri($url)); |
406
|
0
|
|
|
|
|
0
|
my $str = $resp->decoded_content; |
407
|
|
|
|
|
|
|
my $bytes = encode('UTF-8', $str, Encode::FB_CROAK); |
408
|
0
|
|
|
|
|
0
|
my $iter = $p->parse_iter_from_bytes( $bytes ); |
409
|
0
|
0
|
|
|
|
0
|
$self->add_iter($iter->as_quads($graph)); |
410
|
0
|
|
|
|
|
0
|
} else { |
411
|
0
|
0
|
|
|
|
0
|
die "No parser found for content type $ct: $url"; |
412
|
0
|
|
|
|
|
0
|
} |
413
|
0
|
|
0
|
|
|
0
|
} else { |
414
|
0
|
0
|
|
|
|
0
|
die $resp->status_line; |
415
|
0
|
|
|
|
|
0
|
} |
416
|
0
|
|
|
|
|
0
|
} |
417
|
0
|
|
|
|
|
0
|
} |
418
|
0
|
|
|
|
|
0
|
|
419
|
0
|
|
|
|
|
0
|
# $model->load_triples( 'turtle', iri('http://example.org/graph1') => "@prefix foaf: ...", iri('http://example.org/graph2') => "@prefix foaf: ..." ); |
420
|
|
|
|
|
|
|
my $self = shift; |
421
|
0
|
|
|
|
|
0
|
my $format = shift; |
422
|
|
|
|
|
|
|
my $class = Attean->get_parser($format) || die "Failed to load parser for '$format'"; |
423
|
|
|
|
|
|
|
my $parser = $class->new() || die "Failed to construct parser for '$format'"; |
424
|
0
|
|
|
|
|
0
|
while (scalar(@_)) { |
425
|
|
|
|
|
|
|
my ($graph, $string) = splice(@_, 0, 2); |
426
|
|
|
|
|
|
|
my $iter = $parser->parse_iter_from_bytes(encode('UTF-8', $string, Encode::FB_CROAK)); |
427
|
|
|
|
|
|
|
my $quads = $iter->as_quads($graph); |
428
|
|
|
|
|
|
|
$self->add_iter($quads); |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
} |
431
|
6
|
|
|
6
|
1
|
1678
|
|
432
|
6
|
|
|
|
|
13
|
my $self = shift; |
433
|
6
|
|
50
|
|
|
42
|
my $format = shift; |
434
|
6
|
|
50
|
|
|
114
|
my $class = Attean->get_parser($format) || die "Failed to load parser for '$format'"; |
435
|
6
|
|
|
|
|
261
|
my $parser = $class->new() || die "Failed to construct parser for '$format'"; |
436
|
6
|
|
|
|
|
28
|
while (scalar(@_)) { |
437
|
6
|
|
|
|
|
75
|
my ($graph, $fh) = splice(@_, 0, 2); |
438
|
6
|
|
|
|
|
3302
|
my $iter = $parser->parse_iter_from_io($fh); |
439
|
6
|
|
|
|
|
318
|
my $quads = $iter->as_quads($graph); |
440
|
|
|
|
|
|
|
$self->add_iter($quads); |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
1
|
|
|
1
|
1
|
77
|
my $self = shift; |
445
|
1
|
|
|
|
|
2
|
my $iter = shift; |
446
|
1
|
|
50
|
|
|
9
|
my $type = $iter->item_type; |
447
|
1
|
|
50
|
|
|
37
|
die "Iterator type $type isn't quads" unless (Role::Tiny::does_role($type, 'Attean::API::Quad')); |
448
|
1
|
|
|
|
|
52
|
while (my $q = $iter->next) { |
449
|
1
|
|
|
|
|
4
|
$self->add_quad($q); |
450
|
1
|
|
|
|
|
7
|
} |
451
|
1
|
|
|
|
|
143
|
} |
452
|
1
|
|
|
|
|
54
|
|
453
|
|
|
|
|
|
|
my $self = shift; |
454
|
|
|
|
|
|
|
die "add_list called without a graph name" unless (scalar(@_)); |
455
|
|
|
|
|
|
|
my $graph = shift; |
456
|
|
|
|
|
|
|
my @elements = @_; |
457
|
2
|
|
|
2
|
1
|
50
|
my $rdf_first = Attean::IRI->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#first'); |
458
|
2
|
|
|
|
|
5
|
my $rdf_rest = Attean::IRI->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#rest'); |
459
|
2
|
|
|
|
|
22
|
my $rdf_nil = Attean::IRI->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'); |
460
|
2
|
50
|
|
|
|
10
|
if (scalar(@elements) == 0) { |
461
|
2
|
|
|
|
|
49
|
return $rdf_nil; |
462
|
10
|
|
|
|
|
41
|
} else { |
463
|
|
|
|
|
|
|
my $head = Attean::Blank->new(); |
464
|
|
|
|
|
|
|
my $node = shift(@elements); |
465
|
|
|
|
|
|
|
my $rest = $self->add_list($graph, @elements); |
466
|
|
|
|
|
|
|
$self->add_quad( Attean::Quad->new($head, $rdf_first, $node, $graph) ); |
467
|
5
|
|
|
5
|
1
|
189
|
$self->add_quad( Attean::Quad->new($head, $rdf_rest, $rest, $graph) ); |
468
|
5
|
100
|
|
|
|
22
|
return $head; |
469
|
4
|
|
|
|
|
9
|
} |
470
|
4
|
|
|
|
|
6
|
} |
471
|
4
|
|
|
|
|
64
|
} |
472
|
4
|
|
|
|
|
736
|
|
473
|
4
|
|
|
|
|
743
|
|
474
|
4
|
100
|
|
|
|
635
|
use Moo::Role; |
475
|
1
|
|
|
|
|
6
|
|
476
|
|
|
|
|
|
|
requires 'etag_value_for_quads'; |
477
|
3
|
|
|
|
|
46
|
} |
478
|
3
|
|
|
|
|
166
|
|
479
|
3
|
|
|
|
|
14
|
|
480
|
3
|
|
|
|
|
49
|
use Moo::Role; |
481
|
3
|
|
|
|
|
42
|
|
482
|
3
|
|
|
|
|
17
|
requires 'mtime_for_quads'; |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
use Moo::Role; |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
with 'Attean::API::MutableModel'; |
489
|
50
|
|
|
50
|
|
52805
|
|
|
50
|
|
|
|
|
102
|
|
|
50
|
|
|
|
|
355
|
|
490
|
|
|
|
|
|
|
requires 'begin_bulk_updates'; |
491
|
|
|
|
|
|
|
requires 'end_bulk_updates'; |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
around [qw(load_triples load_triples_from_io add_iter add_list)] => sub { |
494
|
|
|
|
|
|
|
my $orig = shift; |
495
|
|
|
|
|
|
|
my $self = shift; |
496
|
50
|
|
|
50
|
|
17433
|
$self->begin_bulk_updates(); |
|
50
|
|
|
|
|
112
|
|
|
50
|
|
|
|
|
275
|
|
497
|
|
|
|
|
|
|
$self->$orig(@_); |
498
|
|
|
|
|
|
|
$self->end_bulk_updates(); |
499
|
|
|
|
|
|
|
}; |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
# End bulk updates the moment a read operation is performed... |
502
|
|
|
|
|
|
|
before [qw(get_quads get_bindings count_quads count_quads_estimate get_graphs subject predicate object graph)] => sub { |
503
|
50
|
|
|
50
|
|
18379
|
my $self = shift; |
|
50
|
|
|
|
|
207
|
|
|
50
|
|
|
|
|
224
|
|
504
|
|
|
|
|
|
|
$self->end_bulk_updates(); |
505
|
|
|
|
|
|
|
}; |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
use Moo::Role; |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
with 'Attean::API::Model'; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
1; |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=back |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=head1 BUGS |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
Please report any bugs or feature requests to through the GitHub web interface |
523
|
|
|
|
|
|
|
at L<https://github.com/kasei/attean/issues>. |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
=head1 SEE ALSO |
526
|
50
|
|
|
50
|
|
21228
|
|
|
50
|
|
|
|
|
116
|
|
|
50
|
|
|
|
|
220
|
|
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=head1 AUTHOR |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
Gregory Todd Williams C<< <gwilliams@cpan.org> >> |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=head1 COPYRIGHT |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
Copyright (c) 2014--2022 Gregory Todd Williams. |
536
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under |
537
|
|
|
|
|
|
|
the same terms as Perl itself. |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=cut |