File Coverage

blib/lib/RDF/Query/Algebra/Update.pm
Criterion Covered Total %
statement 72 122 59.0
branch 13 52 25.0
condition 0 10 0.0
subroutine 19 24 79.1
pod 12 12 100.0
total 116 220 52.7


line stmt bran cond sub pod time code
1             # RDF::Query::Algebra::Update
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Query::Algebra::Update - Algebra class for UPDATE operations
7              
8             =head1 VERSION
9              
10             This document describes RDF::Query::Algebra::Update version 2.916.
11              
12             =cut
13              
14             package RDF::Query::Algebra::Update;
15              
16 36     36   197 use strict;
  36         73  
  36         906  
17 36     36   177 use warnings;
  36         67  
  36         980  
18 36     36   174 no warnings 'redefine';
  36         60  
  36         1217  
19 36     36   175 use base qw(RDF::Query::Algebra);
  36         71  
  36         2575  
20              
21 36     36   183 use Data::Dumper;
  36         78  
  36         1773  
22 36     36   189 use Log::Log4perl;
  36         70  
  36         267  
23 36     36   1610 use Scalar::Util qw(refaddr);
  36         72  
  36         1721  
24 36     36   175 use Carp qw(carp croak confess);
  36         76  
  36         2065  
25 36     36   182 use Scalar::Util qw(blessed reftype refaddr);
  36         76  
  36         1820  
26 36     36   185 use Time::HiRes qw(gettimeofday tv_interval);
  36         79  
  36         252  
27 36     36   4101 use RDF::Trine::Iterator qw(smap sgrep swatch);
  36         68  
  36         3359  
28              
29             ######################################################################
30              
31             our ($VERSION);
32             my %TRIPLE_LABELS;
33             my @node_methods = qw(subject predicate object);
34             BEGIN {
35 36     36   47026 $VERSION = '2.916';
36             }
37              
38             ######################################################################
39              
40             =head1 METHODS
41              
42             Beyond the methods documented below, this class inherits methods from the
43             L<RDF::Query::Algebra> class.
44              
45             =over 4
46              
47             =cut
48              
49             =item C<new ( $delete_template, $insert_template, $pattern, \%dataset, $data_only_flag )>
50              
51             Returns a new UPDATE structure.
52              
53             =cut
54              
55             sub new {
56 10     10 1 22 my $class = shift;
57 10         17 my $delete = shift;
58 10         17 my $insert = shift;
59 10         18 my $pat = shift;
60 10         16 my $dataset = shift;
61 10         16 my $data = shift;
62 10         42 return bless([$delete, $insert, $pat, $dataset, $data], $class);
63             }
64              
65             =item C<< construct_args >>
66              
67             Returns a list of arguments that, passed to this class' constructor,
68             will produce a clone of this algebra pattern.
69              
70             =cut
71              
72             sub construct_args {
73 38     38 1 52 my $self = shift;
74 38         87 return ($self->delete_template, $self->insert_template, $self->pattern);
75             }
76              
77             =item C<< sse >>
78              
79             Returns the SSE string for this algebra expression.
80              
81             =cut
82              
83             sub sse {
84 8     8 1 15 my $self = shift;
85 8         16 my $context = shift;
86 8         12 my $indent = shift;
87            
88 8         12 my $string;
89 8         30 my $delete = $self->delete_template;
90 8         25 my $insert = $self->insert_template;
91 8         27 my $dataset = $self->dataset;
92 8 100       14 my @ds_keys = keys %{ $dataset || {} };
  8         52  
93 8 100       25 if (@ds_keys) {
94 1 50       3 my @defaults = sort map { $_->sse } @{ $dataset->{default} || [] };
  1         4  
  1         6  
95 1 50       14 my @named = sort map { $_->sse } values %{ $dataset->{named} || {} };
  0         0  
  1         10  
96 1         3 my @strings;
97 1 50       6 push(@strings, (@defaults) ? '(defaults ' . join(' ', @defaults) . ')' : ());
98 1 50       4 push(@strings, (@named) ? '(named ' . join(' ', @named) . ')' : ());
99            
100 1         4 my $ds_string = '(dataset ' . join(' ', @strings) . ')';
101 1 50       9 return sprintf(
    50          
102             "(update (delete %s) (insert %s) (where %s) %s)",
103             ($delete ? $delete->sse( $context, $indent ) : ''),
104             ($insert ? $insert->sse( $context, $indent ) : ''),
105             $self->pattern->sse( $context, $indent ),
106             $ds_string,
107             );
108             } else {
109 7 100       58 return sprintf(
    50          
110             "(update (delete %s) (insert %s) (where %s))",
111             ($delete ? $delete->sse( $context, $indent ) : ''),
112             ($insert ? $insert->sse( $context, $indent ) : ''),
113             $self->pattern->sse( $context, $indent ),
114             );
115             }
116             }
117              
118             =item C<< as_sparql >>
119              
120             Returns the SPARQL string for this algebra expression.
121              
122             =cut
123              
124             sub as_sparql {
125 0     0 1 0 my $self = shift;
126 0   0     0 my $context = shift || {};
127 0   0     0 my $indent = shift || '';
128 0         0 my $delete = $self->delete_template;
129 0         0 my $insert = $self->insert_template;
130 0         0 my $ggp = $self->pattern;
131            
132 0         0 my $dataset = $self->dataset;
133 0 0       0 my @ds_keys = keys %{ $dataset || {} };
  0         0  
134 0         0 my $ds_string = '';
135 0 0       0 if (@ds_keys) {
136 0 0       0 my @defaults = @{ $dataset->{default} || [] };
  0         0  
137 0 0       0 my %named = %{ $dataset->{named} || {} };
  0         0  
138 0         0 my @strings;
139 0         0 push(@strings, sprintf("USING <%s>", $_->uri_value)) foreach (@defaults);
140 0         0 push(@strings, sprintf("USING NAMED <%s>", $named{$_}->uri_value)) foreach (keys %named);
141 0         0 $ds_string = join("\n${indent}", @strings);
142             }
143            
144 0 0 0     0 if ($insert or $delete) {
145             # TODO: $(delete|insert)->as_sparql here isn't properly serializing GRAPH blocks, because even though they contain Quad objects inside of BGPs, there's no containing NamedGraph object...
146 0 0       0 if ($ds_string) {
147 0         0 $ds_string = "\n${indent}$ds_string";
148             }
149            
150 0 0 0     0 if ($insert and $delete) {
    0          
151 0         0 return sprintf(
152             "DELETE {\n${indent} %s\n${indent}}\n${indent}INSERT {\n${indent} %s\n${indent}}\n${indent}%s\n${indent}WHERE %s",
153             $delete->as_sparql( $context, "${indent} " ),
154             $insert->as_sparql( $context, "${indent} " ),
155             $ds_string,
156             $ggp->as_sparql( { %$context, force_ggp_braces => 1 }, ${indent} ),
157             );
158             } elsif ($insert) {
159 0         0 return sprintf(
160             "INSERT {\n${indent} %s\n${indent}}\n${indent}%s\n${indent}WHERE %s",
161             $insert->as_sparql( $context, "${indent} " ),
162             $ds_string,
163             $ggp->as_sparql( { %$context, force_ggp_braces => 1 }, ${indent} ),
164             );
165             } else {
166 0         0 return sprintf(
167             "DELETE {\n${indent} %s\n${indent}}\n${indent}%s\n${indent}WHERE %s",
168             $delete->as_sparql( $context, "${indent} " ),
169             $ds_string,
170             $ggp->as_sparql( { %$context, force_ggp_braces => 1 }, ${indent} ),
171             );
172             }
173             } else {
174 0         0 my @pats = $ggp->patterns;
175 0 0       0 my $op = ($delete) ? 'DELETE' : 'INSERT';
176 0 0       0 my $temp = ($delete) ? $delete : $insert;
177 0 0       0 my $temps = ($temp->isa('RDF::Query::Algebra::GroupGraphPattern'))
178             ? $temp->as_sparql( $context, "${indent} " )
179             : "{\n${indent} " . $temp->as_sparql( $context, "${indent} " ) . "\n${indent}}";
180 0 0       0 if (scalar(@pats) == 0) {
181 0         0 return sprintf(
182             "${op} DATA %s",
183             $temps
184             );
185             } else {
186 0 0       0 if ($ds_string) {
187 0         0 $ds_string = "\n${indent}$ds_string\n${indent}";
188             } else {
189 0         0 $ds_string = ' ';
190             }
191 0         0 return sprintf(
192             "${op} %s%sWHERE %s",
193             $temps,
194             $ds_string,
195             $ggp->as_sparql( { %$context, force_ggp_braces => 1 }, "${indent}" ),
196             );
197             }
198             }
199             }
200              
201             =item C<< referenced_blanks >>
202              
203             Returns a list of the blank node names used in this algebra expression.
204              
205             =cut
206              
207             sub referenced_blanks {
208 0     0 1 0 my $self = shift;
209 0         0 return;
210             }
211              
212             =item C<< referenced_variables >>
213              
214             =cut
215              
216             sub referenced_variables {
217 0     0 1 0 my $self = shift;
218 0         0 return;
219             }
220              
221             =item C<< delete_template >>
222              
223             =cut
224              
225             sub delete_template {
226 54     54 1 77 my $self = shift;
227 54         145 return $self->[0];
228             }
229              
230             =item C<< insert_template >>
231              
232             =cut
233              
234             sub insert_template {
235 54     54 1 67 my $self = shift;
236 54         165 return $self->[1];
237             }
238              
239             =item C<< pattern >>
240              
241             =cut
242              
243             sub pattern {
244 54     54 1 78 my $self = shift;
245 54         243 return $self->[2];
246             }
247              
248             =item C<< dataset >>
249              
250             =cut
251              
252             sub dataset {
253 16     16 1 28 my $self = shift;
254 16         59 return $self->[3];
255             }
256              
257             =item C<< data_only >>
258              
259             =cut
260              
261             sub data_only {
262 0     0 1   my $self = shift;
263 0           return $self->[4];
264             }
265              
266             =item C<< check_duplicate_blanks >>
267              
268             Returns true if blank nodes respect the SPARQL rule of no blank-label re-use
269             across BGPs, otherwise throws a RDF::Query::Error::QueryPatternError exception.
270              
271             =cut
272              
273             sub check_duplicate_blanks {
274 0     0 1   my $self = shift;
275 0 0         unless ($self->data_only) {
276             # if self isn't an INSERT/DELETE DATA operation, then we need to check the template patterns, too
277 0 0         if ($self->delete_template) {
278 0           $self->delete_template->check_duplicate_blanks;
279             }
280            
281 0 0         if ($self->insert_tempalte) {
282 0           $self->insert_tempalte->check_duplicate_blanks;
283             }
284             }
285 0           return $self->pattern->check_duplicate_blanks;
286             }
287              
288             1;
289              
290             __END__
291              
292             =back
293              
294             =head1 AUTHOR
295              
296             Gregory Todd Williams <gwilliams@cpan.org>
297              
298             =cut