line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
50
|
|
|
50
|
|
753
|
use v5.14; |
|
50
|
|
|
|
|
171
|
|
2
|
50
|
|
|
50
|
|
275
|
use warnings; |
|
50
|
|
|
|
|
135
|
|
|
50
|
|
|
|
|
1823
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
Attean::Expression - SPARQL Expressions |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 VERSION |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
This document describes Attean::Expression version 0.032 |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 SYNOPSIS |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
use v5.14; |
15
|
|
|
|
|
|
|
use Attean; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my $binding = Attean::Result->new(); |
18
|
|
|
|
|
|
|
my $value = Attean::ValueExpression->new( value => Attean::Literal->integer(2) ); |
19
|
|
|
|
|
|
|
my $plus = Attean::BinaryExpression->new( children => [$value, $value], operator => '+' ); |
20
|
|
|
|
|
|
|
my $result = $plus->evaluate($binding); |
21
|
|
|
|
|
|
|
say $result->numeric_value; # 4 |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 DESCRIPTION |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
This is a utility package that defines all the Attean SPARQL expression classes |
26
|
|
|
|
|
|
|
consisting of logical, numeric, and function operators, constant terms, and |
27
|
|
|
|
|
|
|
variables. Expressions may be evaluated in the context of a |
28
|
|
|
|
|
|
|
L<Attean::API::Result> object, and either return a L<Attean::API::Term> object |
29
|
|
|
|
|
|
|
or throw a type error exception. |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
The expression classes are: |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=over 4 |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=cut |
36
|
|
|
|
|
|
|
|
37
|
50
|
|
|
50
|
|
270
|
use Attean::API::Expression; |
|
50
|
|
|
|
|
113
|
|
|
50
|
|
|
|
|
2006
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=item * L<Attean::ValueExpression> |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=cut |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
use Moo; |
44
|
50
|
|
|
50
|
|
258
|
use Types::Standard qw(ConsumerOf); |
|
50
|
|
|
|
|
123
|
|
|
50
|
|
|
|
|
303
|
|
45
|
50
|
|
|
50
|
|
16467
|
use AtteanX::SPARQL::Constants; |
|
50
|
|
|
|
|
136
|
|
|
50
|
|
|
|
|
456
|
|
46
|
50
|
|
|
50
|
|
24920
|
use AtteanX::SPARQL::Token; |
|
50
|
|
|
|
|
131
|
|
|
50
|
|
|
|
|
8812
|
|
47
|
50
|
|
|
50
|
|
379
|
use namespace::clean; |
|
50
|
|
|
|
|
125
|
|
|
50
|
|
|
|
|
1439
|
|
48
|
50
|
|
|
50
|
|
319
|
|
|
50
|
|
|
|
|
114
|
|
|
50
|
|
|
|
|
486
|
|
49
|
|
|
|
|
|
|
with 'Attean::API::SPARQLSerializable'; |
50
|
|
|
|
|
|
|
with 'Attean::API::Expression'; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
has 'value' => (is => 'ro', isa => ConsumerOf['Attean::API::TermOrVariableOrTriplePattern']); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
my $class = shift; |
55
|
1
|
|
|
1
|
0
|
5
|
return $class->SUPER::BUILDARGS(@_, operator => '_value'); |
56
|
|
|
|
|
|
|
} |
57
|
1439
|
|
|
1439
|
0
|
55053
|
|
58
|
1439
|
|
|
|
|
4108
|
|
59
|
|
|
|
|
|
|
return 1; |
60
|
|
|
|
|
|
|
} |
61
|
9
|
|
|
9
|
0
|
26
|
|
62
|
|
|
|
|
|
|
my $self = shift; |
63
|
|
|
|
|
|
|
my $str = $self->value->ntriples_string; |
64
|
0
|
|
|
0
|
0
|
0
|
if ($str =~ m[^"(true|false)"\^\^<http://www[.]w3[.]org/2001/XMLSchema#boolean>$]) { |
65
|
|
|
|
|
|
|
return $1; |
66
|
|
|
|
|
|
|
} elsif ($str =~ m[^"(\d+)"\^\^<http://www[.]w3[.]org/2001/XMLSchema#integer>$]) { |
67
|
|
|
|
|
|
|
return $1 |
68
|
29
|
|
|
29
|
0
|
5262
|
} |
69
|
29
|
|
|
|
|
541
|
return $str; |
70
|
29
|
100
|
|
|
|
877
|
} |
|
|
100
|
|
|
|
|
|
71
|
6
|
|
|
|
|
37
|
|
72
|
|
|
|
|
|
|
my $self = shift; |
73
|
4
|
|
|
|
|
37
|
if ($self->value->does('Attean::API::Variable')) { |
74
|
|
|
|
|
|
|
return $self->value->value; |
75
|
19
|
|
|
|
|
129
|
} |
76
|
|
|
|
|
|
|
return; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
80
|
0
|
0
|
|
|
|
0
|
return $self->value->sparql_tokens; |
81
|
0
|
|
|
|
|
0
|
} |
82
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
0
|
my $self = shift; |
84
|
|
|
|
|
|
|
if ($self->value->does('Attean::API::Variable')) { |
85
|
|
|
|
|
|
|
return $self->value; |
86
|
|
|
|
|
|
|
} |
87
|
22
|
|
|
22
|
0
|
42
|
return; |
88
|
22
|
|
|
|
|
86
|
} |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=item * L<Attean::UnaryExpression> |
92
|
1
|
|
|
1
|
0
|
22
|
|
93
|
1
|
50
|
|
|
|
4
|
=cut |
94
|
1
|
|
|
|
|
14
|
|
95
|
|
|
|
|
|
|
use Moo; |
96
|
0
|
|
|
|
|
0
|
use Types::Standard qw(Enum); |
97
|
|
|
|
|
|
|
use namespace::clean; |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
with 'Attean::API::UnaryExpression', 'Attean::API::Expression', 'Attean::API::UnaryQueryTree'; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
my %map = ('NOT' => '!'); |
102
|
|
|
|
|
|
|
around 'BUILDARGS' => sub { |
103
|
|
|
|
|
|
|
my $orig = shift; |
104
|
|
|
|
|
|
|
my $class = shift; |
105
|
50
|
|
|
50
|
|
151243
|
my $args = $class->$orig(@_); |
|
50
|
|
|
|
|
129
|
|
|
50
|
|
|
|
|
263
|
|
106
|
50
|
|
|
50
|
|
15562
|
my $op = $args->{operator}; |
|
50
|
|
|
|
|
142
|
|
|
50
|
|
|
|
|
320
|
|
107
|
50
|
|
|
50
|
|
22483
|
$args->{operator} = $map{uc($op)} if (exists $map{uc($op)}); |
|
50
|
|
|
|
|
119
|
|
|
50
|
|
|
|
|
255
|
|
108
|
|
|
|
|
|
|
return $args; |
109
|
|
|
|
|
|
|
}; |
110
|
|
|
|
|
|
|
my $self = shift; |
111
|
|
|
|
|
|
|
state $type = Enum[qw(+ - !)]; |
112
|
|
|
|
|
|
|
$type->assert_valid($self->operator); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
my $self = shift; |
117
|
|
|
|
|
|
|
foreach my $c (@{ $self->children }) { |
118
|
|
|
|
|
|
|
return 0 unless ($c->is_stable); |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
return 1; |
121
|
3
|
|
|
3
|
0
|
299
|
} |
122
|
3
|
|
|
|
|
13
|
} |
123
|
3
|
|
|
|
|
1398
|
|
124
|
|
|
|
|
|
|
=item * L<Attean::BinaryExpression> |
125
|
|
|
|
|
|
|
|
126
|
0
|
|
|
0
|
0
|
0
|
=cut |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
use Moo; |
129
|
0
|
|
|
0
|
0
|
0
|
use Types::Standard qw(Enum); |
130
|
0
|
|
|
|
|
0
|
use namespace::clean; |
|
0
|
|
|
|
|
0
|
|
131
|
0
|
0
|
|
|
|
0
|
|
132
|
|
|
|
|
|
|
with 'Attean::API::BinaryExpression'; |
133
|
0
|
|
|
|
|
0
|
|
134
|
|
|
|
|
|
|
my $self = shift; |
135
|
|
|
|
|
|
|
state $type = Enum[qw(+ - * / < <= > >= != = && ||)]; |
136
|
|
|
|
|
|
|
$type->assert_valid($self->operator); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
my $self = shift; |
141
|
|
|
|
|
|
|
foreach my $c (@{ $self->children }) { |
142
|
50
|
|
|
50
|
|
35798
|
return 0 unless ($c->is_stable); |
|
50
|
|
|
|
|
151
|
|
|
50
|
|
|
|
|
248
|
|
143
|
50
|
|
|
50
|
|
15751
|
} |
|
50
|
|
|
|
|
143
|
|
|
50
|
|
|
|
|
286
|
|
144
|
50
|
|
|
50
|
|
20491
|
return 1; |
|
50
|
|
|
|
|
134
|
|
|
50
|
|
|
|
|
262
|
|
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=item * L<Attean::FunctionExpression> |
149
|
39
|
|
|
39
|
0
|
31082
|
|
150
|
39
|
|
|
|
|
115
|
=cut |
151
|
39
|
|
|
|
|
7853
|
|
152
|
|
|
|
|
|
|
use Moo; |
153
|
|
|
|
|
|
|
use Types::Standard qw(Enum ConsumerOf HashRef); |
154
|
3
|
|
|
3
|
0
|
11
|
use Types::Common::String qw(UpperCaseStr); |
155
|
|
|
|
|
|
|
use AtteanX::SPARQL::Constants; |
156
|
|
|
|
|
|
|
use AtteanX::SPARQL::Token; |
157
|
0
|
|
|
0
|
0
|
0
|
use namespace::clean; |
158
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
159
|
0
|
0
|
|
|
|
0
|
has 'operator' => (is => 'ro', isa => UpperCaseStr, coerce => UpperCaseStr->coercion, required => 1); |
160
|
|
|
|
|
|
|
has 'base' => (is => 'rw', isa => ConsumerOf['Attean::IRI'], predicate => 'has_base'); |
161
|
0
|
|
|
|
|
0
|
|
162
|
|
|
|
|
|
|
with 'Attean::API::NaryExpression'; |
163
|
|
|
|
|
|
|
with 'Attean::API::SPARQLSerializable'; |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
around 'BUILDARGS' => sub { |
167
|
|
|
|
|
|
|
my $orig = shift; |
168
|
|
|
|
|
|
|
my $class = shift; |
169
|
|
|
|
|
|
|
my $args = $class->$orig(@_); |
170
|
50
|
|
|
50
|
|
31504
|
if ($args->{operator} eq 'ISURI') { |
|
50
|
|
|
|
|
158
|
|
|
50
|
|
|
|
|
242
|
|
171
|
50
|
|
|
50
|
|
15273
|
$args->{operator} = 'ISIRI'; |
|
50
|
|
|
|
|
159
|
|
|
50
|
|
|
|
|
308
|
|
172
|
50
|
|
|
50
|
|
57238
|
} |
|
50
|
|
|
|
|
1036769
|
|
|
50
|
|
|
|
|
585
|
|
173
|
50
|
|
|
50
|
|
22844
|
$args->{operator} = UpperCaseStr->coercion->($args->{operator}); |
|
50
|
|
|
|
|
127
|
|
|
50
|
|
|
|
|
7542
|
|
174
|
50
|
|
|
50
|
|
334
|
return $args; |
|
50
|
|
|
|
|
108
|
|
|
50
|
|
|
|
|
904
|
|
175
|
50
|
|
|
50
|
|
250
|
}; |
|
50
|
|
|
|
|
106
|
|
|
50
|
|
|
|
|
390
|
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
my $self = shift; |
178
|
|
|
|
|
|
|
state $type = Enum[qw(INVOKE IN NOTIN STR LANG LANGMATCHES DATATYPE BOUND IRI URI BNODE RAND ABS CEIL FLOOR ROUND CONCAT SUBSTR STRLEN REPLACE UCASE LCASE ENCODE_FOR_URI CONTAINS STRSTARTS STRENDS STRBEFORE STRAFTER YEAR MONTH DAY HOURS MINUTES SECONDS TIMEZONE TZ NOW UUID STRUUID MD5 SHA1 SHA256 SHA384 SHA512 COALESCE IF STRLANG STRDT SAMETERM ISIRI ISBLANK ISLITERAL ISNUMERIC REGEX TRIPLE ISTRIPLE SUBJECT PREDICATE OBJECT)]; |
179
|
|
|
|
|
|
|
$type->assert_valid($self->operator); |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
my $self = shift; |
184
|
|
|
|
|
|
|
return 0 if ($self->operator =~ m/^(?:RAND|BNODE|UUID|STRUUID|NOW)$/); |
185
|
|
|
|
|
|
|
foreach my $c (@{ $self->children }) { |
186
|
|
|
|
|
|
|
return 0 unless ($c->is_stable); |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
return 1; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
my $self = shift; |
192
|
|
|
|
|
|
|
my $func = AtteanX::SPARQL::Token->keyword($self->operator); |
193
|
|
|
|
|
|
|
my $lparen = AtteanX::SPARQL::Token->lparen; |
194
|
|
|
|
|
|
|
my $rparen = AtteanX::SPARQL::Token->rparen; |
195
|
|
|
|
|
|
|
my $comma = AtteanX::SPARQL::Token->comma; |
196
|
6
|
|
|
6
|
0
|
1100
|
|
197
|
6
|
|
|
|
|
72
|
my @tokens; |
198
|
6
|
|
|
|
|
6131
|
push(@tokens, $func, $lparen); |
199
|
|
|
|
|
|
|
foreach my $t (@{ $self->children }) { |
200
|
|
|
|
|
|
|
push(@tokens, $t->sparql_tokens->elements); |
201
|
0
|
|
|
0
|
0
|
0
|
push(@tokens, $comma); |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
if (scalar(@tokens) > 2) { |
204
|
0
|
|
|
0
|
0
|
0
|
pop(@tokens); # remove the last comma |
205
|
0
|
0
|
|
|
|
0
|
} |
206
|
0
|
|
|
|
|
0
|
push(@tokens, $rparen); |
|
0
|
|
|
|
|
0
|
|
207
|
0
|
0
|
|
|
|
0
|
return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' ); |
208
|
|
|
|
|
|
|
} |
209
|
0
|
|
|
|
|
0
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
use Moo; |
212
|
|
|
|
|
|
|
use Types::Standard qw(Bool Enum Str HashRef ConsumerOf Maybe); |
213
|
3
|
|
|
3
|
0
|
6
|
use Types::Common::String qw(UpperCaseStr); |
214
|
3
|
|
|
|
|
14
|
use AtteanX::SPARQL::Constants; |
215
|
3
|
|
|
|
|
140
|
use AtteanX::SPARQL::Token; |
216
|
3
|
|
|
|
|
119
|
use namespace::clean; |
217
|
3
|
|
|
|
|
137
|
|
218
|
|
|
|
|
|
|
around 'BUILDARGS' => sub { |
219
|
3
|
|
|
|
|
122
|
my $orig = shift; |
220
|
3
|
|
|
|
|
10
|
my $class = shift; |
221
|
3
|
|
|
|
|
6
|
my $args = $class->$orig(@_); |
|
3
|
|
|
|
|
13
|
|
222
|
3
|
|
|
|
|
12
|
$args->{operator} = UpperCaseStr->coercion->($args->{operator}); |
223
|
3
|
|
|
|
|
12
|
return $args; |
224
|
|
|
|
|
|
|
}; |
225
|
3
|
50
|
|
|
|
12
|
state $type = Enum[qw(COUNT SUM MIN MAX AVG GROUP_CONCAT SAMPLE RANK CUSTOM)]; |
226
|
3
|
|
|
|
|
7
|
$type->assert_valid(shift->operator); |
227
|
|
|
|
|
|
|
} |
228
|
3
|
|
|
|
|
4
|
has 'custom_iri' => (is => 'ro', isa => Maybe[Str]); |
229
|
3
|
|
|
|
|
51
|
has 'operator' => (is => 'ro', isa => UpperCaseStr, coerce => UpperCaseStr->coercion, required => 1); |
230
|
|
|
|
|
|
|
has 'scalar_vars' => (is => 'ro', isa => HashRef, default => sub { +{} }); |
231
|
|
|
|
|
|
|
has 'distinct' => (is => 'ro', isa => Bool, default => 0); |
232
|
|
|
|
|
|
|
has 'variable' => (is => 'ro', isa => ConsumerOf['Attean::API::Variable'], required => 1); |
233
|
|
|
|
|
|
|
|
234
|
50
|
|
|
50
|
|
158841
|
with 'Attean::API::AggregateExpression'; |
|
50
|
|
|
|
|
130
|
|
|
50
|
|
|
|
|
351
|
|
235
|
50
|
|
|
50
|
|
16388
|
with 'Attean::API::SPARQLSerializable'; |
|
50
|
|
|
|
|
139
|
|
|
50
|
|
|
|
|
411
|
|
236
|
50
|
|
|
50
|
|
58128
|
|
|
50
|
|
|
|
|
124
|
|
|
50
|
|
|
|
|
212
|
|
237
|
50
|
|
|
50
|
|
16642
|
|
|
50
|
|
|
|
|
131
|
|
|
50
|
|
|
|
|
6781
|
|
238
|
50
|
|
|
50
|
|
342
|
my $self = shift; |
|
50
|
|
|
|
|
111
|
|
|
50
|
|
|
|
|
830
|
|
239
|
50
|
|
|
50
|
|
241
|
foreach my $expr (@{ $self->groups }, values %{ $self->aggregates }) { |
|
50
|
|
|
|
|
105
|
|
|
50
|
|
|
|
|
266
|
|
240
|
|
|
|
|
|
|
return 0 unless ($expr->is_stable); |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
return 1; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
my $self = shift; |
246
|
|
|
|
|
|
|
my $distinct = AtteanX::SPARQL::Token->keyword('DISTINCT'); |
247
|
|
|
|
|
|
|
my $func = AtteanX::SPARQL::Token->keyword($self->operator); |
248
|
|
|
|
|
|
|
my $lparen = AtteanX::SPARQL::Token->lparen; |
249
|
9
|
|
|
9
|
0
|
2055
|
my $rparen = AtteanX::SPARQL::Token->rparen; |
250
|
9
|
|
|
|
|
4134
|
my $comma = AtteanX::SPARQL::Token->comma; |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
my @tokens; |
253
|
|
|
|
|
|
|
push(@tokens, $func); |
254
|
|
|
|
|
|
|
push(@tokens, $lparen); |
255
|
|
|
|
|
|
|
if ($self->distinct) { |
256
|
|
|
|
|
|
|
push(@tokens, $distinct); |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
foreach my $t (@{ $self->children }) { |
259
|
|
|
|
|
|
|
push(@tokens, $t->sparql_tokens->elements); |
260
|
|
|
|
|
|
|
push(@tokens, $comma); |
261
|
0
|
|
|
0
|
0
|
0
|
} |
262
|
|
|
|
|
|
|
if (scalar(@tokens) > 2) { |
263
|
|
|
|
|
|
|
pop(@tokens); # remove the last comma |
264
|
0
|
|
|
0
|
0
|
0
|
} |
265
|
0
|
|
|
|
|
0
|
my $vars = $self->scalar_vars; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
266
|
0
|
0
|
|
|
|
0
|
my @keys = keys %$vars; |
267
|
|
|
|
|
|
|
if (scalar(@keys)) { |
268
|
0
|
|
|
|
|
0
|
die "TODO: Implement SPARQL serialization for aggregate scalar vars"; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
push(@tokens, $rparen); |
271
|
|
|
|
|
|
|
return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' ); |
272
|
1
|
|
|
1
|
0
|
2
|
} |
273
|
1
|
|
|
|
|
5
|
} |
274
|
1
|
|
|
|
|
49
|
|
275
|
1
|
|
|
|
|
43
|
use Moo; |
276
|
1
|
|
|
|
|
45
|
use Types::Standard qw(Enum ConsumerOf); |
277
|
1
|
|
|
|
|
41
|
use AtteanX::SPARQL::Constants; |
278
|
|
|
|
|
|
|
use AtteanX::SPARQL::Token; |
279
|
1
|
|
|
|
|
41
|
use namespace::clean; |
280
|
1
|
|
|
|
|
4
|
|
281
|
1
|
|
|
|
|
3
|
with 'Attean::API::SPARQLSerializable'; |
282
|
1
|
50
|
|
|
|
6
|
with 'Attean::API::UnaryExpression', 'Attean::API::Expression', 'Attean::API::UnaryQueryTree'; |
283
|
0
|
|
|
|
|
0
|
|
284
|
|
|
|
|
|
|
has 'datatype' => (is => 'ro', isa => ConsumerOf['Attean::API::IRI']); |
285
|
1
|
|
|
|
|
3
|
my $class = shift; |
|
1
|
|
|
|
|
6
|
|
286
|
1
|
|
|
|
|
4
|
return $class->SUPER::BUILDARGS(@_, operator => '_cast'); |
287
|
1
|
|
|
|
|
5
|
} |
288
|
|
|
|
|
|
|
my $self = shift; |
289
|
1
|
50
|
|
|
|
5
|
state $type = Enum[map { "http://www.w3.org/2001/XMLSchema#$_" } qw(integer decimal float double string boolean dateTime)]; |
290
|
1
|
|
|
|
|
3
|
$type->assert_valid($self->datatype->value); |
291
|
|
|
|
|
|
|
} |
292
|
1
|
|
|
|
|
4
|
|
293
|
1
|
|
|
|
|
4
|
|
294
|
1
|
50
|
|
|
|
4
|
my $self = shift; |
295
|
0
|
|
|
|
|
0
|
foreach my $c (@{ $self->children }) { |
296
|
|
|
|
|
|
|
return 0 unless ($c->is_stable); |
297
|
1
|
|
|
|
|
2
|
} |
298
|
1
|
|
|
|
|
18
|
return 1; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
my $self = shift; |
302
|
|
|
|
|
|
|
my $dt = AtteanX::SPARQL::Token->fast_constructor( IRI, -1, -1, -1, -1, [$self->datatype->value] ), |
303
|
50
|
|
|
50
|
|
156603
|
my $lparen = AtteanX::SPARQL::Token->lparen; |
|
50
|
|
|
|
|
134
|
|
|
50
|
|
|
|
|
283
|
|
304
|
50
|
|
|
50
|
|
16227
|
my $rparen = AtteanX::SPARQL::Token->rparen; |
|
50
|
|
|
|
|
122
|
|
|
50
|
|
|
|
|
359
|
|
305
|
50
|
|
|
50
|
|
39668
|
my $comma = AtteanX::SPARQL::Token->comma; |
|
50
|
|
|
|
|
129
|
|
|
50
|
|
|
|
|
6835
|
|
306
|
50
|
|
|
50
|
|
309
|
|
|
50
|
|
|
|
|
124
|
|
|
50
|
|
|
|
|
794
|
|
307
|
50
|
|
|
50
|
|
243
|
my @tokens; |
|
50
|
|
|
|
|
111
|
|
|
50
|
|
|
|
|
263
|
|
308
|
|
|
|
|
|
|
push(@tokens, $dt, $lparen); |
309
|
|
|
|
|
|
|
foreach my $t (@{ $self->children }) { |
310
|
|
|
|
|
|
|
push(@tokens, $t->sparql_tokens->elements); |
311
|
|
|
|
|
|
|
push(@tokens, $comma); |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
if (scalar(@tokens) > 2) { |
314
|
2
|
|
|
2
|
0
|
5017
|
pop(@tokens); # remove the last comma |
315
|
2
|
|
|
|
|
18
|
} |
316
|
|
|
|
|
|
|
push(@tokens, $rparen); |
317
|
|
|
|
|
|
|
return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' ); |
318
|
2
|
|
|
2
|
0
|
354
|
} |
319
|
2
|
|
|
|
|
7
|
} |
|
14
|
|
|
|
|
40
|
|
320
|
2
|
|
|
|
|
2922
|
|
321
|
|
|
|
|
|
|
use Moo; |
322
|
|
|
|
|
|
|
use AtteanX::SPARQL::Constants; |
323
|
0
|
|
|
0
|
0
|
0
|
use AtteanX::SPARQL::Token; |
324
|
|
|
|
|
|
|
use Types::Standard qw(ConsumerOf); |
325
|
|
|
|
|
|
|
use namespace::clean; |
326
|
0
|
|
|
0
|
0
|
0
|
|
327
|
0
|
|
|
|
|
0
|
with 'Attean::API::SPARQLSerializable'; |
|
0
|
|
|
|
|
0
|
|
328
|
0
|
0
|
|
|
|
0
|
with 'Attean::API::Expression'; |
329
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
0
|
my $class = shift; |
331
|
|
|
|
|
|
|
return $class->SUPER::BUILDARGS(@_, operator => '_exists'); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
has 'pattern' => (is => 'ro', isa => ConsumerOf['Attean::API::Algebra']); |
334
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
335
|
1
|
|
|
|
|
10
|
my $sparql = $self->pattern->as_sparql; |
336
|
|
|
|
|
|
|
$sparql =~ s/\s+/ /g; |
337
|
1
|
|
|
|
|
42
|
return "EXISTS { $sparql }"; |
338
|
1
|
|
|
|
|
41
|
} |
339
|
|
|
|
|
|
|
|
340
|
1
|
|
|
|
|
38
|
|
341
|
1
|
|
|
|
|
3
|
my $self = shift; |
342
|
1
|
|
|
|
|
2
|
# TODO: need deep analysis of exists pattern to tell if this is stable |
|
1
|
|
|
|
|
7
|
|
343
|
1
|
|
|
|
|
4
|
# (there might be an unstable filter expression deep inside the pattern) |
344
|
1
|
|
|
|
|
5
|
return 0; |
345
|
|
|
|
|
|
|
} |
346
|
1
|
50
|
|
|
|
6
|
|
347
|
1
|
|
|
|
|
2
|
my $self = shift; |
348
|
|
|
|
|
|
|
my $exists = AtteanX::SPARQL::Token->keyword('EXISTS'); |
349
|
1
|
|
|
|
|
4
|
my $lbrace = AtteanX::SPARQL::Token->lbrace; |
350
|
1
|
|
|
|
|
16
|
my $rbrace = AtteanX::SPARQL::Token->rbrace; |
351
|
|
|
|
|
|
|
my $child = $self->pattern; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
my @tokens; |
354
|
|
|
|
|
|
|
push(@tokens, $exists, $lbrace); |
355
|
50
|
|
|
50
|
|
143283
|
push(@tokens, $child->sparql_tokens->elements); |
|
50
|
|
|
|
|
124
|
|
|
50
|
|
|
|
|
282
|
|
356
|
50
|
|
|
50
|
|
15709
|
push(@tokens, $rbrace); |
|
50
|
|
|
|
|
134
|
|
|
50
|
|
|
|
|
6976
|
|
357
|
50
|
|
|
50
|
|
352
|
return Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::SPARQL::Token' ); |
|
50
|
|
|
|
|
108
|
|
|
50
|
|
|
|
|
1094
|
|
358
|
50
|
|
|
50
|
|
254
|
} |
|
50
|
|
|
|
|
101
|
|
|
50
|
|
|
|
|
290
|
|
359
|
50
|
|
|
50
|
|
23146
|
|
|
50
|
|
|
|
|
135
|
|
|
50
|
|
|
|
|
247
|
|
360
|
|
|
|
|
|
|
my $self = shift; |
361
|
|
|
|
|
|
|
return map { Attean::Variable->new($_) } $self->pattern->in_scope_variables; |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
} |
364
|
0
|
|
|
0
|
0
|
0
|
|
365
|
|
|
|
|
|
|
use Moo; |
366
|
1
|
|
|
1
|
0
|
2425
|
use Types::Standard qw(ConsumerOf); |
367
|
1
|
|
|
|
|
8
|
use namespace::clean; |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
with 'Attean::API::Expression'; |
370
|
|
|
|
|
|
|
my $class = shift; |
371
|
0
|
|
|
0
|
0
|
0
|
return $class->SUPER::BUILDARGS(@_, operator => '_existsplan'); |
372
|
0
|
|
|
|
|
0
|
} |
373
|
0
|
|
|
|
|
0
|
has 'plan' => (is => 'ro', isa => ConsumerOf['Attean::API::BindingSubstitutionPlan']); |
374
|
0
|
|
|
|
|
0
|
my $self = shift; |
375
|
|
|
|
|
|
|
# TODO: implement as_string for EXISTS patterns |
376
|
|
|
|
|
|
|
return "Attean::ExistsPlanExpression { ... }"; |
377
|
0
|
|
|
0
|
0
|
0
|
} |
378
|
|
|
|
|
|
|
my $self = shift; |
379
|
|
|
|
|
|
|
my %args = @_; |
380
|
0
|
|
|
0
|
0
|
0
|
my $level = $args{level} // 0; |
381
|
|
|
|
|
|
|
my $sp = $args{indent} // ' '; |
382
|
|
|
|
|
|
|
my $indent = $sp x $level; |
383
|
0
|
|
|
|
|
0
|
|
384
|
|
|
|
|
|
|
# TODO: implement as_string for EXISTS patterns |
385
|
|
|
|
|
|
|
return "EXISTS { " . $self->pattern->as_sparql( level => $level+1, indent => $sp ) . " }"; |
386
|
|
|
|
|
|
|
} |
387
|
1
|
|
|
1
|
0
|
17
|
|
388
|
1
|
|
|
|
|
5
|
|
389
|
1
|
|
|
|
|
66
|
my $self = shift; |
390
|
1
|
|
|
|
|
42
|
# TODO: need deep analysis of exists pattern to tell if this is stable |
391
|
1
|
|
|
|
|
41
|
# (there might be an unstable filter expression deep inside the pattern) |
392
|
|
|
|
|
|
|
return 0; |
393
|
1
|
|
|
|
|
3
|
} |
394
|
1
|
|
|
|
|
2
|
|
395
|
1
|
|
|
|
|
4
|
my $self = shift; |
396
|
1
|
|
|
|
|
4
|
die "unaggregated_variables cannot be called on Attean::ExistsPlanExpression"; |
397
|
1
|
|
|
|
|
17
|
} |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
|
401
|
0
|
|
|
0
|
0
|
|
1; |
402
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=back |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=head1 BUGS |
407
|
50
|
|
|
50
|
|
144764
|
|
|
50
|
|
|
|
|
108
|
|
|
50
|
|
|
|
|
271
|
|
408
|
50
|
|
|
50
|
|
15512
|
Please report any bugs or feature requests to through the GitHub web interface |
|
50
|
|
|
|
|
131
|
|
|
50
|
|
|
|
|
299
|
|
409
|
50
|
|
|
50
|
|
22110
|
at L<https://github.com/kasei/attean/issues>. |
|
50
|
|
|
|
|
141
|
|
|
50
|
|
|
|
|
276
|
|
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=head1 SEE ALSO |
412
|
0
|
|
|
0
|
0
|
|
|
413
|
|
|
|
|
|
|
|
414
|
0
|
|
|
0
|
0
|
|
|
415
|
0
|
|
|
|
|
|
=head1 AUTHOR |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
Gregory Todd Williams C<< <gwilliams@cpan.org> >> |
418
|
|
|
|
|
|
|
|
419
|
0
|
|
|
0
|
0
|
|
=head1 COPYRIGHT |
420
|
|
|
|
|
|
|
|
421
|
0
|
|
|
|
|
|
Copyright (c) 2014--2022 Gregory Todd Williams. |
422
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under |
423
|
|
|
|
|
|
|
the same terms as Perl itself. |
424
|
0
|
|
|
0
|
0
|
|
|
425
|
0
|
|
|
|
|
|
=cut |