File Coverage

lib/Web/DataService/IRequest.pm
Criterion Covered Total %
statement 18 294 6.1
branch 0 170 0.0
condition 0 84 0.0
subroutine 6 66 9.0
pod 0 57 0.0
total 24 671 3.5


line stmt bran cond sub pod time code
1             #
2             # Web::DataService::IRequest
3             #
4             # This is a role whose sole purpose is to be composed into the classes defined
5             # for the various data service operations. It defines the public interface
6             # to a request object.
7              
8              
9             package Web::DataService::IRequest;
10              
11 2     2   15 use Carp 'croak';
  2         6  
  2         135  
12 2     2   13 use Scalar::Util 'reftype';
  2         4  
  2         90  
13 2     2   1388 use JSON 'decode_json';
  2         20523  
  2         13  
14 2     2   318 use Try::Tiny;
  2         4  
  2         116  
15              
16 2     2   12 use Moo::Role;
  2         5  
  2         19  
17              
18              
19             # has_block ( block_key_or_name )
20             #
21             # Return true if the specified block was selected for this request.
22              
23             sub has_block {
24            
25 0     0 0   my ($request, $key_or_name) = @_;
26            
27 0 0         return 1 if $request->{block_hash}{$key_or_name};
28             }
29              
30              
31             # output_block ( name )
32             #
33             # Return true if the named block is selected for the current request.
34              
35             sub block_selected {
36              
37 0     0 0   return $_[0]->{block_hash}{$_[1]};
38             }
39              
40              
41             # substitute_select ( substitutions ... )
42             #
43             # Make the specified substitutions in the select and tables hashes for this
44             # request. You can pass either a list such as ( a => 'b', c => 'd' ) or a
45             # hashref.
46              
47             sub substitute_select {
48              
49 0     0 0   my $request = shift;
50            
51 0           my $subst;
52            
53             # First unpack the arguments.
54            
55 0 0         if ( ref $_[0] eq 'HASH' )
56             {
57 0 0         croak "substitute_select: you must pass either a single hashref or a list of substitutions\n"
58             if @_ > 1;
59            
60 0           $subst = shift;
61             }
62            
63             else
64             {
65 0           $subst = { @_ };
66             }
67            
68             # Keep a count of the number of substitutions.
69            
70 0           my $count = 0;
71            
72             # Then substitute the field values, if there are any for this request.
73            
74 0 0         if ( ref $request->{select_list} eq 'ARRAY' )
75             {
76 0           foreach my $f ( @{$request->{select_list}} )
  0            
77             {
78 0 0         $f =~ s/\$(\w+)/$subst->{$1}||"\$$1"/eog and $count++;
  0 0          
79             }
80             }
81            
82             # Then substitute the table keys, if there are any for this request.
83            
84 0 0         if ( ref $request->{tables_hash} eq 'HASH' )
85             {
86 0           foreach my $k ( keys %{$request->{tables_hash}} )
  0            
87             {
88 0 0         if ( $k =~ qr{ ^ \$ (\w+) $ }xs )
89             {
90 0           $request->{tables_hash}{$subst->{$1}} = $request->{tables_hash}{$k};
91 0           delete $request->{tables_hash}{$k};
92 0           $count++;
93             }
94             }
95             }
96            
97             # Return the number of substitutions made.
98            
99 0           return $count;
100             }
101              
102              
103             # select_list ( subst )
104             #
105             # Return a list of strings derived from the 'select' records passed to
106             # define_output. The parameter $subst, if given, should be a hash of
107             # substitutions to be made on the resulting strings.
108              
109             sub select_list {
110            
111 0     0 0   my ($request, $subst) = @_;
112            
113 0 0         my @fields = @{$request->{select_list}} if ref $request->{select_list} eq 'ARRAY';
  0            
114            
115 0 0 0       if ( defined $subst && ref $subst eq 'HASH' )
116             {
117 0           foreach my $f (@fields)
118             {
119 0 0         $f =~ s/\$(\w+)/$subst->{$1}||"\$$1"/eog;
  0            
120             }
121             }
122            
123 0           return @fields;
124             }
125              
126              
127             # select_hash ( subst )
128             #
129             # Return the same set of strings as select_list, but in the form of a hash.
130              
131             sub select_hash {
132              
133 0     0 0   my ($request, $subst) = @_;
134            
135 0           return map { $_ => 1} $request->select_list($subst);
  0            
136             }
137              
138              
139             # select_string ( subst )
140             #
141             # Return the select list (see above) joined into a comma-separated string.
142              
143             sub select_string {
144            
145 0     0 0   my ($request, $subst) = @_;
146            
147 0           return join(', ', $request->select_list($subst));
148             }
149              
150              
151             # tables_hash ( )
152             #
153             # Return a hashref whose keys are the values of the 'tables' attributes in
154             # 'select' records passed to define_output.
155              
156             sub tables_hash {
157            
158 0     0 0   my ($request) = @_;
159            
160 0           return $request->{tables_hash};
161             }
162              
163              
164             # add_table ( name )
165             #
166             # Add the specified name to the table hash.
167              
168             sub add_table {
169              
170 0     0 0   my ($request, $table_name, $real_name) = @_;
171            
172 0 0         if ( defined $real_name )
173             {
174 0 0         if ( $request->{tables_hash}{"\$$table_name"} )
175             {
176 0           $request->{tables_hash}{$real_name} = 1;
177             }
178             }
179             else
180             {
181 0           $request->{tables_hash}{$table_name} = 1;
182             }
183             }
184              
185              
186             # filter_hash ( )
187             #
188             # Return a hashref derived from 'filter' records passed to define_output.
189              
190             sub filter_hash {
191            
192 0     0 0   my ($request) = @_;
193            
194 0           return $request->{filter_hash};
195             }
196              
197              
198             # param_keys ( )
199             #
200             # Return a list of strings representing the cleaned parameter keys from this
201             # request. These will often be the same as the original parameter names, but
202             # may be different if 'alias' or 'key' was specified in any of the relevant
203             # validation rules.
204              
205             sub param_keys {
206            
207 0     0 0   my ($request) = @_;
208            
209 0 0         return $request->{valid}->keys() if $request->{valid};
210 0           return;
211             }
212              
213              
214             # clean_param ( name )
215             #
216             # Return the cleaned value of the named parameter, or the empty string if it
217             # doesn't exist.
218              
219             sub clean_param {
220            
221 0     0 0   my ($request, $name) = @_;
222            
223 0 0         return '' unless ref $request->{valid};
224 0   0       return $request->{valid}->value($name) // '';
225             }
226              
227              
228             # clean_param_list ( name )
229             #
230             # Return a list of all the cleaned values of the named parameter, or the empty
231             # list if it doesn't exist.
232              
233             sub clean_param_list {
234            
235 0     0 0   my ($request, $name) = @_;
236            
237 0 0         return unless ref $request->{valid};
238 0           my $clean = $request->{valid}->value($name);
239 0 0         return @$clean if ref $clean eq 'ARRAY';
240 0 0         return unless defined $clean;
241 0           return $clean;
242             }
243              
244              
245             # clean_param_hash ( name )
246             #
247             # Return a hashref whose keys are all of the cleaned values of the named
248             # parameter, or an empty hashref if it doesn't exist.
249              
250             sub clean_param_hash {
251            
252 0     0 0   my ($request, $name) = @_;
253            
254 0 0         return {} unless ref $request->{valid};
255            
256 0           my $clean = $request->{valid}->value($name);
257            
258 0 0 0       if ( ref $clean eq 'ARRAY' )
    0          
259             {
260 0           return { map { $_ => 1 } @$clean };
  0            
261             }
262            
263             elsif ( defined $clean && $clean ne '' )
264             {
265 0           return { $clean => 1 };
266             }
267            
268             else
269             {
270 0           return {};
271             }
272             }
273              
274              
275             # param_given ( )
276             #
277             # Return true if the specified parameter was included in this request, whether
278             # or not it was given a valid value. Return false otherwise.
279              
280             sub param_given {
281              
282 0     0 0   my ($request, $name) = @_;
283            
284 0 0         return unless ref $request->{valid};
285 0           return exists $request->{valid}{clean}{$name};
286             }
287              
288              
289             # validate_params ( ruleset, params )
290             #
291             # Pass the given parameters to the validator, to be validated by the specified ruleset.
292             # Return the validation result object.
293              
294             sub validate_params {
295            
296 0     0 0   my ($request, $rs_name, @params) = @_;
297            
298 0           my $context = { ds => $request->{ds}, request => $request };
299 0           my $result = $request->{ds}{validator}->check_params($rs_name, $context, @params);
300            
301 0           return $result;
302             }
303              
304              
305             # raw_body ( )
306             #
307             # Return the request body as an un-decoded string. If there is none, return the empty string.
308              
309             sub raw_body {
310            
311 0     0 0   my ($request) = @_;
312            
313 0   0       return $request->{ds}{backend_plugin}->get_request_body() // '';
314             }
315              
316              
317             # decode_body ( )
318             #
319             # Determine what format the request body is in, and decode it.
320              
321             sub decode_body {
322            
323 0     0 0   my ($request, $section) = @_;
324            
325             # First grab (and cache) the undecoded request body.
326            
327 0 0         unless ( defined $request->{raw_body} )
328             {
329 0   0       $request->{raw_body} = $request->{ds}{backend_plugin}->get_request_body() // '';
330             }
331            
332             # If this is empty, return the undefined value.
333            
334 0 0 0       return undef unless defined $request->{raw_body} && $request->{raw_body} ne '';
335            
336             # Get the submitted content type.
337            
338 0   0       my $content_type = $request->{ds}{backend_plugin}->get_content_type() // '';
339            
340             # If the content type is application/x-www-form-urlencoded, then it was already unpacked into
341             # a hash ref.
342            
343 0 0         if ( $content_type =~ qr{^application/x-www-form-urlencoded}xsi )
    0          
344             {
345             # my @chunks = split(/&/, $request->{raw_body});
346             # $request->{decoded_body} = { };
347            
348             # foreach my $chunk ( @chunks )
349             # {
350             # my ($var, $value) = split(/=/, $chunk, 2);
351              
352             # $var =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
353             # $value =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
354              
355             # $request->{decoded_body}{$var} = $value;
356             # }
357            
358 0           $request->{decoded_body} = $request->{raw_body};
359            
360 0           return $request->{decoded_body};
361             }
362            
363             # If the body starts and ends with '{' or '[', assume the format is JSON regardless of content type.
364            
365             elsif ( $request->{raw_body} =~ / ^ [{] .* [}] $ | ^ [\[] .* [\]] $ /xsi )
366             {
367             try {
368 0 0   0     unless ( defined $request->{decoded_body} )
369             {
370             # print STDERR "About to decode\n";
371 0           $request->{decoded_body} = JSON->new->utf8->relaxed->decode($request->{raw_body});
372             # print STDERR "Decoded: " . $request->{decoded_body} . "\n";
373             }
374             }
375            
376             catch {
377 0     0     $request->{decoded_body} = '';
378 0           $request->{body_error} = $_;
379 0           $request->{body_error} =~ s{ at /.*}{};
380             # print STDERR "Error: $request->{body_error}\n";
381 0           };
382            
383 0           return ($request->{decoded_body}, $request->{body_error});
384             }
385            
386             # Otherwise, split into rows and return.
387            
388             else
389             {
390 0           my @lines = split(/[\r\n]+/, $request->{raw_body});
391 0           $request->{decoded_body} = \@lines;
392            
393 0           return $request->{decoded_body};
394             }
395             }
396              
397              
398             # exception ( code, message )
399             #
400             # Return an exception object with the specified HTTP result code and
401             # message. This can be used to return an error result.
402              
403             sub exception {
404            
405 0     0 0   my ($request, $code, $message) = @_;
406            
407 0 0 0       croak "Bad exception code '$code', must be an HTTP result code"
408             unless defined $code && $code =~ qr{^\d\d\d$};
409            
410 0 0         unless ( $message )
411             {
412 0 0         if ( $code eq '400' )
    0          
413             {
414 0           $message = 'Parameter error';
415             }
416            
417             elsif ( $code eq '404' )
418             {
419 0           $message = 'Not found';
420             }
421            
422             else
423             {
424 0           $message = 'Internal error: please contact the website administrator';
425             }
426             }
427            
428 0           my $exception = { code => $code, message => $message };
429 0           return bless $exception, 'Web::DataService::Exception';
430             }
431              
432              
433             # output_field_list ( )
434             #
435             # Return the output field list for this request. This is the actual list, not
436             # a copy, so it can be manipulated.
437              
438             sub output_field_list {
439            
440 0     0 0   my ($request) = @_;
441 0           return $request->{field_list};
442             }
443              
444              
445             # delete_output_field ( field_name )
446             #
447             # Delete the named field from the output list. This can be called from the
448             # operation method if it becomes clear at some point that certain fields will
449             # not be needed. This can be especially useful for text-format output.
450              
451             sub delete_output_field {
452            
453 0     0 0   my ($request, $field_name) = @_;
454            
455 0 0 0       return unless defined $field_name && $field_name ne '';
456            
457 0           my $list = $request->{field_list};
458            
459 0           foreach my $i ( 0..$#$list )
460             {
461 2     2   3655 no warnings 'uninitialized';
  2         5  
  2         4969  
462 0 0         if ( $request->{field_list}[$i]{field} eq $field_name )
463             {
464 0           splice(@$list, $i, 1);
465 0           return;
466             }
467             }
468             }
469              
470              
471             # debug ( )
472             #
473             # Return true if we are in debug mode.
474              
475             sub debug {
476            
477 0     0 0   my ($request) = @_;
478            
479 0           return $Web::DataService::DEBUG;
480             }
481              
482              
483             # debug_line ( )
484             #
485             # Output the specified line(s) of text for debugging purposes.
486              
487             sub debug_line {
488              
489 0 0   0 0   print STDERR "$_[1]\n" if $Web::DataService::DEBUG;
490             }
491              
492              
493             # _process_record ( record, steps )
494             #
495             # Process the specified record using the specified steps.
496              
497             sub _process_record {
498            
499 0     0     my ($request, $record, $steps) = @_;
500 0           my $ds = $request->{ds};
501            
502 0           return $ds->process_record($request, $record, $steps);
503             }
504              
505              
506             # result_limit ( )
507             #
508             # Return the result limit specified for this request, or undefined if
509             # it is 'all'.
510              
511             sub result_limit {
512            
513 0   0 0 0   return defined $_[0]->{result_limit} && $_[0]->{result_limit} ne 'all' && $_[0]->{result_limit};
514             }
515              
516              
517             # result_offset ( will_handle )
518             #
519             # Return the result offset specified for this request, or zero if none was
520             # specified. If the parameter $will_handle is true, then auto-offset is
521             # suppressed.
522              
523             sub result_offset {
524            
525 0     0 0   my ($request, $will_handle) = @_;
526            
527 0 0         $request->{offset_handled} = 1 if $will_handle;
528            
529 0   0       return $request->{result_offset} || 0;
530             }
531              
532              
533             # sql_limit_clause ( will_handle )
534             #
535             # Return a string that can be added to an SQL statement in order to limit the
536             # results in accordance with the parameters specified for this request. If
537             # the parameter $will_handle is true, then auto-offset is suppressed.
538              
539             sub sql_limit_clause {
540            
541 0     0 0   my ($request, $will_handle) = @_;
542            
543 0 0         $request->{offset_handled} = $will_handle ? 1 : 0;
544            
545 0           my $limit = $request->{result_limit};
546 0   0       my $offset = $request->{result_offset} || 0;
547            
548 0 0 0       if ( $offset > 0 )
    0          
549             {
550 0           $offset += 0;
551 0 0         $limit = $limit eq 'all' ? 100000000 : $limit + 0;
552 0           return "LIMIT $offset,$limit";
553             }
554            
555             elsif ( defined $limit and $limit ne 'all' )
556             {
557 0           return "LIMIT " . ($limit + 0);
558             }
559            
560             else
561             {
562 0           return '';
563             }
564             }
565              
566              
567             # require_preprocess ( arg )
568             #
569             # If the argument is true, then the result set will be processed before
570             # output. This will mean that the entire result set will be held in the memory
571             # of the dataservice process before being sent to the client, no matter how
572             # big it is.
573             #
574             # If the argument is '2', then this will only be done if row counts were
575             # requested and not otherwise.
576              
577             sub require_preprocess {
578            
579 0     0 0   my ($request, $arg) = @_;
580            
581 0 0 0       croak "you must provide a defined argument, either 0, 1, or 2"
      0        
582             unless defined $arg && ($arg eq '0' || $arg eq '1' || $arg eq '2');
583            
584 0 0         if ( $arg eq '2' )
    0          
    0          
585             {
586 0           $request->{process_before_count} = 1;
587 0           $request->{preprocess} = 0;
588             }
589            
590             elsif ( $arg eq '1' )
591             {
592 0           $request->{preprocess} = 1;
593             }
594            
595             elsif ( $arg eq '0' )
596             {
597 0           $request->{process_before_count} = 0;
598 0           $request->{preprocess} = 0;
599             }
600             }
601              
602              
603             # sql_count_clause ( )
604             #
605             # Return a string that can be added to an SQL statement to generate a result
606             # count in accordance with the parameters specified for this request.
607              
608             sub sql_count_clause {
609            
610 0 0   0 0   return $_[0]->{display_counts} ? 'SQL_CALC_FOUND_ROWS' : '';
611             }
612              
613              
614             # sql_count_rows ( )
615             #
616             # If we were asked to get the result count, execute an SQL statement that will
617             # do so.
618              
619             sub sql_count_rows {
620            
621 0     0 0   my ($request) = @_;
622            
623 0 0         if ( $request->{display_counts} )
624             {
625 0           ($request->{result_count}) = $request->{dbh}->selectrow_array("SELECT FOUND_ROWS()");
626             }
627            
628 0           return $request->{result_count};
629             }
630              
631              
632             # set_result_count ( count )
633             #
634             # This method should be called if the backend database does not implement the
635             # SQL FOUND_ROWS() function. The database should be queried as to the result
636             # count, and the resulting number passed as a parameter to this method.
637              
638             sub set_result_count {
639            
640 0     0 0   my ($request, $count) = @_;
641            
642 0           $request->{result_count} = $count;
643             }
644              
645              
646             # add_warning ( message )
647             #
648             # Add a warning message to this request object, which will be returned as part
649             # of the output.
650              
651             sub add_warning {
652              
653 0     0 0   my $request = shift;
654            
655 0           foreach my $m (@_)
656             {
657 0 0 0       push @{$request->{warnings}}, $m if defined $m && $m ne '';
  0            
658             }
659             }
660              
661              
662             # warnings
663             #
664             # Return any warning messages that have been set for this request object.
665              
666             sub warnings {
667              
668 0     0 0   my ($request) = @_;
669            
670 0 0         return unless ref $request->{warnings} eq 'ARRAY';
671 0           return @{$request->{warnings}};
  0            
672             }
673              
674              
675             sub add_caution {
676              
677 0     0 0   my ($self, $error_msg) = @_;
678            
679 0 0         $self->{cautions} = [] unless ref $self->{cautions} eq 'ARRAY';
680 0           push @{$self->{cautions}}, $error_msg;
  0            
681             }
682              
683              
684             sub cautions {
685            
686 0     0 0   my ($self) = @_;
687            
688 0 0         return @{$self->{cautions}} if ref $self->{cautions} eq 'ARRAY';
  0            
689 0           return;
690             }
691              
692              
693             sub add_error {
694            
695 0     0 0   my ($self, $error_msg) = @_;
696            
697 0 0         $self->{errors} = [] unless ref $self->{errors} eq 'ARRAY';
698 0           push @{$self->{errors}}, $error_msg;
  0            
699             }
700              
701              
702             sub errors {
703              
704 0     0 0   my ($self) = @_;
705            
706 0 0         return @{$self->{errors}} if ref $self->{errors} eq 'ARRAY';
  0            
707 0           return;
708             }
709              
710              
711             # display_header
712             #
713             # Return true if we should display optional header material, false
714             # otherwise. The text formats respect this setting, but JSON does not.
715              
716             sub display_header {
717            
718 0     0 0   return $_[0]->{display_header};
719             }
720              
721              
722             # display_datainfo
723             #
724             # Return true if the data soruce should be displayed, false otherwise.
725              
726             sub display_datainfo {
727            
728 0     0 0   return $_[0]->{display_datainfo};
729             }
730              
731              
732             # display_counts
733             #
734             # Return true if the result count should be displayed along with the data,
735             # false otherwise.
736              
737             sub display_counts {
738              
739 0     0 0   return $_[0]->{display_counts};
740             }
741              
742              
743             # params_for_display
744             #
745             # Return a list of (parameter, value) pairs for use in constructing response
746             # headers. These are the cleaned parameter values, not the raw ones.
747              
748             sub params_for_display {
749            
750 0     0 0   my $request = $_[0];
751 0           my $ds = $request->{ds};
752 0           my $validator = $ds->{validator};
753 0           my $rs_name = $request->{ruleset};
754 0           my $path = $request->{path};
755            
756             # First get the list of all parameters allowed for this result. We will
757             # then go through them in order to ensure a known order of presentation.
758            
759 0           my @param_list = $ds->list_ruleset_params($rs_name);
760            
761             # We skip some of the special parameter names, specifically those that do
762             # not affect the content of the result.
763            
764 0           my %skip;
765            
766 0 0         $skip{$ds->{special}{datainfo}} = 1 if $ds->{special}{datainfo};
767 0 0         $skip{$ds->{special}{linebreak}} = 1 if $ds->{special}{linebreak};
768 0 0         $skip{$ds->{special}{count}} = 1 if $ds->{special}{count};
769 0 0         $skip{$ds->{special}{header}} = 1 if $ds->{special}{header};
770 0 0         $skip{$ds->{special}{save}} = 1 if $ds->{special}{save};
771            
772             # Now filter this list. For each parameter that has a value, add its name
773             # and value to the display list.
774            
775 0           my @display;
776            
777 0           foreach my $p ( @param_list )
778             {
779             # Skip parameters that don't have a value, or that we have noted above.
780            
781 0 0         next unless defined $request->{clean_params}{$p};
782 0 0         next if $skip{$p};
783            
784             # Others get included along with their value(s).
785            
786 0           my @values = $request->clean_param_list($p);
787            
788             # Go through the values; if any one is an object with a 'regenerate'
789             # method, then call it.
790            
791 0           foreach my $v (@values)
792             {
793 0 0 0       if ( ref $v && $v->can('regenerate' ) )
794             {
795 0           $v = $v->regenerate;
796             }
797             }
798            
799 0           push @display, $p, join(q{,}, @values);
800             }
801            
802 0           return @display;
803             }
804              
805              
806             # result_counts
807             #
808             # Return a hashref containing the following values:
809             #
810             # found the total number of records found by the main query
811             # returned the number of records actually returned
812             # offset the number of records skipped before the first returned one
813             #
814             # These counts reflect the values given for the 'limit' and 'offset' parameters in
815             # the request, or whichever substitute parameter names were configured for
816             # this data service.
817             #
818             # If no counts are available, empty strings are returned for all values.
819              
820             sub result_counts {
821              
822 0     0 0   my ($request) = @_;
823            
824             # Start with a default hashref with empty fields. This is what will be returned
825             # if no information is available.
826            
827             my $r = { found => $request->{result_count} // '',
828             returned => $request->{result_count} // '',
829 0   0       offset => $request->{result_offset} // '' };
      0        
      0        
830            
831             # If no result count was given, just return the default hashref.
832            
833 0 0         return $r unless defined $request->{result_count};
834            
835             # Otherwise, figure out the start and end of the output window.
836            
837             my $window_start = defined $request->{result_offset} && $request->{result_offset} > 0 ?
838 0 0 0       $request->{result_offset} : 0;
839            
840 0           my $window_end = $request->{result_count};
841            
842             # If the offset and limit together don't stretch to the end of the result
843             # set, adjust the window end.
844            
845 0 0 0       if ( defined $request->{result_limit} && $request->{result_limit} ne 'all' &&
      0        
846             $window_start + $request->{result_limit} < $window_end )
847             {
848 0           $window_end = $window_start + $request->{result_limit};
849             }
850            
851             # The number of records actually returned is the length of the output
852             # window.
853            
854 0           $r->{returned} = $window_end - $window_start;
855            
856 0           return $r;
857             }
858              
859              
860             # set_extra_datainfo ( key, value )
861             #
862             # Register a key, with a corresponding value. This key/value pair will be added to the datainfo
863             # list, and presented if the user has asked for it to be displayed. If the output format is JSON,
864             # the value may be a hashref or arrayref. Otherwise, it should be a scalar. If the value is
865             # undefined, nothing will be displayed, and any previously set value for this key will be
866             # removed. Keys will be displayed in the order in which they were first set.
867              
868             sub set_extra_datainfo {
869            
870 0     0 0   my ($request, $key, $title, $value) = @_;
871            
872 0           $request->{extra_datainfo}{$key} = $value;
873 0           $request->{title_datainfo}{$key} = $title;
874 0           push @{$request->{list_datainfo}}, $key;
  0            
875             }
876              
877              
878             # linebreak
879             #
880             # Return the linebreak sequence that should be used for the output of this request.
881              
882             sub linebreak {
883              
884             return $_[0]->{output_linebreak} eq 'cr' ? "\r"
885 0 0   0 0   : $_[0]->{output_linebreak} eq 'lf' ? "\n"
    0          
886             : "\r\n";
887             }
888              
889              
890              
891             # get_config ( )
892             #
893             # Return a hashref providing access to the configuration directives for this
894             # data service.
895              
896             sub get_config {
897            
898 0     0 0   my ($request) = @_;
899            
900 0           return $request->{ds}->get_config;
901             }
902              
903              
904             # get_connection ( )
905             #
906             # Get a database handle, assuming that the proper directives are present in
907             # the config.yml file to allow a connection to be made.
908              
909             sub get_connection {
910            
911 0     0 0   my ($request) = @_;
912            
913 0 0         return $request->{dbh} if ref $request->{dbh};
914            
915 0           $request->{dbh} = $request->{ds}{backend_plugin}->get_connection($request->{ds});
916 0           return $request->{dbh};
917             }
918              
919              
920              
921             # set_cors_header ( arg )
922             #
923             # Set the CORS access control header according to the argument.
924              
925             sub set_cors_header {
926              
927 0     0 0   my ($request, $arg) = @_;
928            
929 0           $Web::DataService::FOUNDATION->set_cors_header($request, $arg);
930             }
931              
932              
933             # set_content_type ( type )
934             #
935             # Set the content type according to the argument.
936              
937             sub set_content_type {
938            
939 0     0 0   my ($request, $type) = @_;
940            
941 0           $Web::DataService::FOUNDATION->set_content_type($request, $type);
942             }
943              
944              
945             # summary_data ( record )
946             #
947             # Add a set of summary data to the result. The argument must be a single hashref.
948              
949             sub summary_data {
950            
951 0     0 0   my ($request, $summary) = @_;
952            
953 0 0         croak 'summary_data: the argument must be a hashref' unless ref $summary eq 'HASH';
954 0           $request->{summary_data} = $summary;
955             }
956              
957              
958             # single_result ( record )
959             #
960             # Set the result of this operation to the single specified record. Any
961             # previously specified results will be removed.
962              
963             sub single_result {
964              
965 0     0 0   my ($request, $record) = @_;
966            
967 0           $request->clear_result;
968 0 0         return unless defined $record;
969            
970 0 0 0       croak "single_result: the argument must be a hashref\n"
971             unless ref $record && reftype $record eq 'HASH';
972            
973 0           $request->{main_record} = $record;
974             }
975              
976              
977             # list_result ( record_list )
978             #
979             # Set the result of this operation to the specified list of results. Any
980             # previously specified results will be removed.
981              
982             sub list_result {
983            
984 0     0 0   my $request = shift;
985            
986 0           $request->clear_result;
987 0 0         return unless @_;
988            
989             # If we were given a single listref, just use that.
990            
991 0 0 0       if ( scalar(@_) == 1 && ref $_[0] && reftype $_[0] eq 'ARRAY' )
      0        
992             {
993 0           $request->{main_result} = $_[0];
994 0           return;
995             }
996            
997             # Otherwise, go through the arguments one by one.
998            
999 0           my @result;
1000            
1001 0           while ( my $item = shift )
1002             {
1003 0 0         next unless defined $item;
1004 0 0 0       croak "list_result: arguments must be hashrefs or listrefs\n"
      0        
1005             unless ref $item && (reftype $item eq 'ARRAY' or reftype $item eq 'HASH');
1006            
1007 0 0         if ( reftype $item eq 'ARRAY' )
1008             {
1009 0           push @result, @$item;
1010             }
1011            
1012             else
1013             {
1014 0           push @result, $item;
1015             }
1016             }
1017            
1018 0           $request->{main_result} = \@result;
1019             }
1020              
1021              
1022             # data_result ( data )
1023             #
1024             # Set the result of this operation to the value of the specified scalar. Any
1025             # previously specified results will be removed.
1026              
1027             sub data_result {
1028            
1029 0     0 0   my ($request, $data) = @_;
1030            
1031 0           $request->clear_result;
1032 0 0         return unless defined $data;
1033            
1034 0 0 0       croak "data_result: the argument must be either a scalar or a scalar ref\n"
1035             if ref $data && reftype $data ne 'SCALAR';
1036            
1037 0 0         $request->{main_data} = ref $data ? $$data : $data;
1038             }
1039              
1040              
1041             # values_result ( values_list )
1042             #
1043             # Set the result of this operation to the specified list of data values. Each
1044             # value should be a scalar.
1045              
1046             sub values_result {
1047            
1048 0     0 0   my $request = shift;
1049            
1050 0           $request->clear_result;
1051            
1052 0 0         if ( ref $_[0] eq 'ARRAY' )
1053             {
1054 0           $request->{main_values} = $_[0];
1055             }
1056            
1057             else
1058             {
1059 0           $request->{main_values} = [ @_ ];
1060             }
1061             }
1062              
1063              
1064             # sth_result ( sth )
1065             #
1066             # Set the result of this operation to the specified DBI statement handle. Any
1067             # previously specified results will be removed.
1068              
1069             sub sth_result {
1070            
1071 0     0 0   my ($request, $sth) = @_;
1072            
1073 0           $request->clear_result;
1074 0 0         return unless defined $sth;
1075            
1076 0 0 0       croak "sth_result: the argument must be an object that implements 'fetchrow_hashref'\n"
1077             unless ref $sth && $sth->can('fetchrow_hashref');
1078            
1079 0           $request->{main_sth} = $sth;
1080             }
1081              
1082              
1083             # add_result ( record... )
1084             #
1085             # Add the specified record(s) to the list of result records for this operation.
1086             # Any result previously specified by any method other than 'add_result' or
1087             # 'list_result' will be cleared.
1088              
1089             sub add_result {
1090            
1091 0     0 0   my $request = shift;
1092            
1093 0 0         $request->clear_result unless ref $request->{main_result} eq 'ARRAY';
1094 0 0         return unless @_;
1095            
1096 0 0 0       croak "add_result: arguments must be hashrefs\n"
1097             unless ref $_[0] && reftype $_[0] eq 'HASH';
1098            
1099 0           push @{$request->{main_result}}, @_;
  0            
1100             }
1101              
1102              
1103             # clear_result
1104             #
1105             # Clear all results that have been specified for this operation.
1106              
1107             sub clear_result {
1108            
1109 0     0 0   my ($request) = @_;
1110            
1111 0           delete $request->{main_result};
1112 0           delete $request->{main_record};
1113 0           delete $request->{main_data};
1114 0           delete $request->{main_sth};
1115             }
1116              
1117              
1118             # skip_output_record
1119             #
1120             # This method should only be called from a before_record_hook. It directs that the record about to
1121             # be output should be skipped.
1122              
1123             sub skip_output_record {
1124              
1125 0     0 0   my ($request, $record) = @_;
1126            
1127 0 0         $record->{_skip_record} = 1 if $record;
1128             }
1129              
1130              
1131             # alternate_output_block ( block_name )
1132             #
1133             # Call this method from a before_record_hook routine to select an alternate output block for the
1134             # record.
1135              
1136             sub alternate_output_block {
1137              
1138 0     0 0   my ($request, $block_name) = @_;
1139              
1140 0           croak "'alternate_output_block' is obsolete.";
1141            
1142             # croak "unknown block '$block_name'" unless $request->{ds}{block}{$block_name};
1143            
1144             # $request->{_alternate_block} = $block_name;
1145              
1146             # unless ( exists $request->{block_field_list}{$block_name} )
1147             # {
1148             # $request->{ds}->configure_block($request, $block_name);
1149             # }
1150             }
1151              
1152              
1153             sub select_output_block {
1154            
1155 0     0 0   my ($request, $record, $block_name) = @_;
1156            
1157 0 0         croak "unknown block '$block_name'" unless $request->{ds}{block}{$block_name};
1158            
1159 0           $record->{_output_block} = $block_name;
1160              
1161 0 0         unless ( exists $request->{block_field_list}{$block_name} )
1162             {
1163 0           $request->{ds}->configure_block($request, $block_name);
1164             }
1165             }
1166              
1167              
1168             1;