File Coverage

lib/Web/DataService/IRequest.pm
Criterion Covered Total %
statement 18 290 6.2
branch 0 164 0.0
condition 0 84 0.0
subroutine 6 63 9.5
pod 0 54 0.0
total 24 655 3.6


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   17 use Carp 'croak';
  2         6  
  2         135  
12 2     2   14 use Scalar::Util 'reftype';
  2         6  
  2         93  
13 2     2   1292 use JSON 'decode_json';
  2         20924  
  2         13  
14 2     2   347 use Try::Tiny;
  2         6  
  2         122  
15              
16 2     2   14 use Moo::Role;
  2         4  
  2         22  
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 body starts and ends with '{' or '[', assume the format is JSON regardless of content type.
341            
342 0 0         if ( $request->{raw_body} =~ / ^ [{] .* [}] $ | ^ [\[] .* [\]] $ /xsi )
    0          
343             {
344             try {
345 0 0   0     unless ( defined $request->{decoded_body} )
346             {
347             # print STDERR "About to decode\n";
348 0           $request->{decoded_body} = JSON->new->utf8->relaxed->decode($request->{raw_body});
349             # print STDERR "Decoded: " . $request->{decoded_body} . "\n";
350             }
351             }
352            
353             catch {
354 0     0     $request->{decoded_body} = '';
355 0           $request->{body_error} = $_;
356 0           $request->{body_error} =~ s{ at /.*}{};
357             # print STDERR "Error: $request->{body_error}\n";
358 0           };
359            
360 0           return ($request->{decoded_body}, $request->{body_error});
361             }
362            
363             # If the content type is application/x-www-form-urlencoded, then unpack it as a single record.
364              
365             elsif ( $content_type =~ qr{^application/x-www-form-urlencoded}xsi )
366             {
367 0           my @chunks = split(/&/, $request->{raw_body});
368 0           $request->{decoded_body} = { };
369            
370 0           foreach my $chunk ( @chunks )
371             {
372 0           my ($var, $value) = split(/=/, $chunk, 2);
373              
374 0           $var =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  0            
375 0           $value =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  0            
376              
377 0           $request->{decoded_body}{$var} = $value;
378             }
379            
380 0           return $request->{decoded_body};
381             }
382            
383             # Otherwise, split into rows and return.
384            
385             else
386             {
387 0           my @lines = split(/[\r\n]+/, $request->{raw_body});
388 0           $request->{decoded_body} = \@lines;
389            
390 0           return $request->{decoded_body};
391             }
392             }
393              
394              
395             # exception ( code, message )
396             #
397             # Return an exception object with the specified HTTP result code and
398             # message. This can be used to return an error result.
399              
400             sub exception {
401            
402 0     0 0   my ($request, $code, $message) = @_;
403            
404 0 0 0       croak "Bad exception code '$code', must be an HTTP result code"
405             unless defined $code && $code =~ qr{^\d\d\d$};
406            
407 0 0         unless ( $message )
408             {
409 0 0         if ( $code eq '400' )
    0          
410             {
411 0           $message = 'Parameter error';
412             }
413            
414             elsif ( $code eq '404' )
415             {
416 0           $message = 'Not found';
417             }
418            
419             else
420             {
421 0           $message = 'Internal error: please contact the website administrator';
422             }
423             }
424            
425 0           my $exception = { code => $code, message => $message };
426 0           return bless $exception, 'Web::DataService::Exception';
427             }
428              
429              
430             # output_field_list ( )
431             #
432             # Return the output field list for this request. This is the actual list, not
433             # a copy, so it can be manipulated.
434              
435             sub output_field_list {
436            
437 0     0 0   my ($request) = @_;
438 0           return $request->{field_list};
439             }
440              
441              
442             # delete_output_field ( field_name )
443             #
444             # Delete the named field from the output list. This can be called from the
445             # operation method if it becomes clear at some point that certain fields will
446             # not be needed. This can be especially useful for text-format output.
447              
448             sub delete_output_field {
449            
450 0     0 0   my ($request, $field_name) = @_;
451            
452 0 0 0       return unless defined $field_name && $field_name ne '';
453            
454 0           my $list = $request->{field_list};
455            
456 0           foreach my $i ( 0..$#$list )
457             {
458 2     2   4104 no warnings 'uninitialized';
  2         6  
  2         4705  
459 0 0         if ( $request->{field_list}[$i]{field} eq $field_name )
460             {
461 0           splice(@$list, $i, 1);
462 0           return;
463             }
464             }
465             }
466              
467              
468             # debug ( )
469             #
470             # Return true if we are in debug mode.
471              
472             sub debug {
473            
474 0     0 0   my ($request) = @_;
475            
476 0           return $Web::DataService::DEBUG;
477             }
478              
479              
480             # debug_line ( )
481             #
482             # Output the specified line(s) of text for debugging purposes.
483              
484             sub debug_line {
485              
486 0 0   0 0   print STDERR "$_[1]\n" if $Web::DataService::DEBUG;
487             }
488              
489              
490             # _process_record ( record, steps )
491             #
492             # Process the specified record using the specified steps.
493              
494             sub _process_record {
495            
496 0     0     my ($request, $record, $steps) = @_;
497 0           my $ds = $request->{ds};
498            
499 0           return $ds->process_record($request, $record, $steps);
500             }
501              
502              
503             # result_limit ( )
504             #
505             # Return the result limit specified for this request, or undefined if
506             # it is 'all'.
507              
508             sub result_limit {
509            
510 0   0 0 0   return defined $_[0]->{result_limit} && $_[0]->{result_limit} ne 'all' && $_[0]->{result_limit};
511             }
512              
513              
514             # result_offset ( will_handle )
515             #
516             # Return the result offset specified for this request, or zero if none was
517             # specified. If the parameter $will_handle is true, then auto-offset is
518             # suppressed.
519              
520             sub result_offset {
521            
522 0     0 0   my ($request, $will_handle) = @_;
523            
524 0 0         $request->{offset_handled} = 1 if $will_handle;
525            
526 0   0       return $request->{result_offset} || 0;
527             }
528              
529              
530             # sql_limit_clause ( will_handle )
531             #
532             # Return a string that can be added to an SQL statement in order to limit the
533             # results in accordance with the parameters specified for this request. If
534             # the parameter $will_handle is true, then auto-offset is suppressed.
535              
536             sub sql_limit_clause {
537            
538 0     0 0   my ($request, $will_handle) = @_;
539            
540 0 0         $request->{offset_handled} = $will_handle ? 1 : 0;
541            
542 0           my $limit = $request->{result_limit};
543 0   0       my $offset = $request->{result_offset} || 0;
544            
545 0 0 0       if ( $offset > 0 )
    0          
546             {
547 0           $offset += 0;
548 0 0         $limit = $limit eq 'all' ? 100000000 : $limit + 0;
549 0           return "LIMIT $offset,$limit";
550             }
551            
552             elsif ( defined $limit and $limit ne 'all' )
553             {
554 0           return "LIMIT " . ($limit + 0);
555             }
556            
557             else
558             {
559 0           return '';
560             }
561             }
562              
563              
564             # require_preprocess ( arg )
565             #
566             # If the argument is true, then the result set will be processed before
567             # output. This will mean that the entire result set will be held in the memory
568             # of the dataservice process before being sent to the client, no matter how
569             # big it is.
570             #
571             # If the argument is '2', then this will only be done if row counts were
572             # requested and not otherwise.
573              
574             sub require_preprocess {
575            
576 0     0 0   my ($request, $arg) = @_;
577            
578 0 0 0       croak "you must provide a defined argument, either 0, 1, or 2"
      0        
579             unless defined $arg && ($arg eq '0' || $arg eq '1' || $arg eq '2');
580            
581 0 0         if ( $arg eq '2' )
    0          
    0          
582             {
583 0           $request->{process_before_count} = 1;
584 0           $request->{preprocess} = 0;
585             }
586            
587             elsif ( $arg eq '1' )
588             {
589 0           $request->{preprocess} = 1;
590             }
591            
592             elsif ( $arg eq '0' )
593             {
594 0           $request->{process_before_count} = 0;
595 0           $request->{preprocess} = 0;
596             }
597             }
598              
599              
600             # sql_count_clause ( )
601             #
602             # Return a string that can be added to an SQL statement to generate a result
603             # count in accordance with the parameters specified for this request.
604              
605             sub sql_count_clause {
606            
607 0 0   0 0   return $_[0]->{display_counts} ? 'SQL_CALC_FOUND_ROWS' : '';
608             }
609              
610              
611             # sql_count_rows ( )
612             #
613             # If we were asked to get the result count, execute an SQL statement that will
614             # do so.
615              
616             sub sql_count_rows {
617            
618 0     0 0   my ($request) = @_;
619            
620 0 0         if ( $request->{display_counts} )
621             {
622 0           ($request->{result_count}) = $request->{dbh}->selectrow_array("SELECT FOUND_ROWS()");
623             }
624            
625 0           return $request->{result_count};
626             }
627              
628              
629             # set_result_count ( count )
630             #
631             # This method should be called if the backend database does not implement the
632             # SQL FOUND_ROWS() function. The database should be queried as to the result
633             # count, and the resulting number passed as a parameter to this method.
634              
635             sub set_result_count {
636            
637 0     0 0   my ($request, $count) = @_;
638            
639 0           $request->{result_count} = $count;
640             }
641              
642              
643             # add_warning ( message )
644             #
645             # Add a warning message to this request object, which will be returned as part
646             # of the output.
647              
648             sub add_warning {
649              
650 0     0 0   my $request = shift;
651            
652 0           foreach my $m (@_)
653             {
654 0 0 0       push @{$request->{warnings}}, $m if defined $m && $m ne '';
  0            
655             }
656             }
657              
658              
659             # warnings
660             #
661             # Return any warning messages that have been set for this request object.
662              
663             sub warnings {
664              
665 0     0 0   my ($request) = @_;
666            
667 0 0         return unless ref $request->{warnings} eq 'ARRAY';
668 0           return @{$request->{warnings}};
  0            
669             }
670              
671              
672             sub add_caution {
673              
674 0     0 0   my ($self, $error_msg) = @_;
675            
676 0 0         $self->{cautions} = [] unless ref $self->{cautions} eq 'ARRAY';
677 0           push @{$self->{cautions}}, $error_msg;
  0            
678             }
679              
680              
681             sub cautions {
682            
683 0     0 0   my ($self) = @_;
684            
685 0 0         return @{$self->{cautions}} if ref $self->{cautions} eq 'ARRAY';
  0            
686 0           return;
687             }
688              
689              
690             sub add_error {
691            
692 0     0 0   my ($self, $error_msg) = @_;
693            
694 0 0         $self->{errors} = [] unless ref $self->{errors} eq 'ARRAY';
695 0           push @{$self->{errors}}, $error_msg;
  0            
696             }
697              
698              
699             sub errors {
700              
701 0     0 0   my ($self) = @_;
702            
703 0 0         return @{$self->{errors}} if ref $self->{errors} eq 'ARRAY';
  0            
704 0           return;
705             }
706              
707              
708             # display_header
709             #
710             # Return true if we should display optional header material, false
711             # otherwise. The text formats respect this setting, but JSON does not.
712              
713             sub display_header {
714            
715 0     0 0   return $_[0]->{display_header};
716             }
717              
718              
719             # display_datainfo
720             #
721             # Return true if the data soruce should be displayed, false otherwise.
722              
723             sub display_datainfo {
724            
725 0     0 0   return $_[0]->{display_datainfo};
726             }
727              
728              
729             # display_counts
730             #
731             # Return true if the result count should be displayed along with the data,
732             # false otherwise.
733              
734             sub display_counts {
735              
736 0     0 0   return $_[0]->{display_counts};
737             }
738              
739              
740             # params_for_display
741             #
742             # Return a list of (parameter, value) pairs for use in constructing response
743             # headers. These are the cleaned parameter values, not the raw ones.
744              
745             sub params_for_display {
746            
747 0     0 0   my $request = $_[0];
748 0           my $ds = $request->{ds};
749 0           my $validator = $ds->{validator};
750 0           my $rs_name = $request->{ruleset};
751 0           my $path = $request->{path};
752            
753             # First get the list of all parameters allowed for this result. We will
754             # then go through them in order to ensure a known order of presentation.
755            
756 0           my @param_list = $ds->list_ruleset_params($rs_name);
757            
758             # We skip some of the special parameter names, specifically those that do
759             # not affect the content of the result.
760            
761 0           my %skip;
762            
763 0 0         $skip{$ds->{special}{datainfo}} = 1 if $ds->{special}{datainfo};
764 0 0         $skip{$ds->{special}{linebreak}} = 1 if $ds->{special}{linebreak};
765 0 0         $skip{$ds->{special}{count}} = 1 if $ds->{special}{count};
766 0 0         $skip{$ds->{special}{header}} = 1 if $ds->{special}{header};
767 0 0         $skip{$ds->{special}{save}} = 1 if $ds->{special}{save};
768            
769             # Now filter this list. For each parameter that has a value, add its name
770             # and value to the display list.
771            
772 0           my @display;
773            
774 0           foreach my $p ( @param_list )
775             {
776             # Skip parameters that don't have a value, or that we have noted above.
777            
778 0 0         next unless defined $request->{clean_params}{$p};
779 0 0         next if $skip{$p};
780            
781             # Others get included along with their value(s).
782            
783 0           my @values = $request->clean_param_list($p);
784            
785             # Go through the values; if any one is an object with a 'regenerate'
786             # method, then call it.
787            
788 0           foreach my $v (@values)
789             {
790 0 0 0       if ( ref $v && $v->can('regenerate' ) )
791             {
792 0           $v = $v->regenerate;
793             }
794             }
795            
796 0           push @display, $p, join(q{,}, @values);
797             }
798            
799 0           return @display;
800             }
801              
802              
803             # result_counts
804             #
805             # Return a hashref containing the following values:
806             #
807             # found the total number of records found by the main query
808             # returned the number of records actually returned
809             # offset the number of records skipped before the first returned one
810             #
811             # These counts reflect the values given for the 'limit' and 'offset' parameters in
812             # the request, or whichever substitute parameter names were configured for
813             # this data service.
814             #
815             # If no counts are available, empty strings are returned for all values.
816              
817             sub result_counts {
818              
819 0     0 0   my ($request) = @_;
820            
821             # Start with a default hashref with empty fields. This is what will be returned
822             # if no information is available.
823            
824             my $r = { found => $request->{result_count} // '',
825             returned => $request->{result_count} // '',
826 0   0       offset => $request->{result_offset} // '' };
      0        
      0        
827            
828             # If no result count was given, just return the default hashref.
829            
830 0 0         return $r unless defined $request->{result_count};
831            
832             # Otherwise, figure out the start and end of the output window.
833            
834             my $window_start = defined $request->{result_offset} && $request->{result_offset} > 0 ?
835 0 0 0       $request->{result_offset} : 0;
836            
837 0           my $window_end = $request->{result_count};
838            
839             # If the offset and limit together don't stretch to the end of the result
840             # set, adjust the window end.
841            
842 0 0 0       if ( defined $request->{result_limit} && $request->{result_limit} ne 'all' &&
      0        
843             $window_start + $request->{result_limit} < $window_end )
844             {
845 0           $window_end = $window_start + $request->{result_limit};
846             }
847            
848             # The number of records actually returned is the length of the output
849             # window.
850            
851 0           $r->{returned} = $window_end - $window_start;
852            
853 0           return $r;
854             }
855              
856              
857             # linebreak
858             #
859             # Return the linebreak sequence that should be used for the output of this request.
860              
861             sub linebreak {
862              
863             return $_[0]->{output_linebreak} eq 'cr' ? "\r"
864 0 0   0 0   : $_[0]->{output_linebreak} eq 'lf' ? "\n"
    0          
865             : "\r\n";
866             }
867              
868              
869              
870             # get_config ( )
871             #
872             # Return a hashref providing access to the configuration directives for this
873             # data service.
874              
875             sub get_config {
876            
877 0     0 0   my ($request) = @_;
878            
879 0           return $request->{ds}->get_config;
880             }
881              
882              
883             # get_connection ( )
884             #
885             # Get a database handle, assuming that the proper directives are present in
886             # the config.yml file to allow a connection to be made.
887              
888             sub get_connection {
889            
890 0     0 0   my ($request) = @_;
891            
892 0 0         return $request->{dbh} if ref $request->{dbh};
893            
894 0           $request->{dbh} = $request->{ds}{backend_plugin}->get_connection($request->{ds});
895 0           return $request->{dbh};
896             }
897              
898              
899              
900             # set_cors_header ( arg )
901             #
902             # Set the CORS access control header according to the argument.
903              
904             sub set_cors_header {
905              
906 0     0 0   my ($request, $arg) = @_;
907            
908 0           $Web::DataService::FOUNDATION->set_cors_header($request, $arg);
909             }
910              
911              
912             # set_content_type ( type )
913             #
914             # Set the content type according to the argument.
915              
916             sub set_content_type {
917            
918 0     0 0   my ($request, $type) = @_;
919            
920 0           $Web::DataService::FOUNDATION->set_content_type($request, $type);
921             }
922              
923              
924             # summary_data ( record )
925             #
926             # Add a set of summary data to the result. The argument must be a single hashref.
927              
928             sub summary_data {
929            
930 0     0 0   my ($request, $summary) = @_;
931            
932 0 0         croak 'summary_data: the argument must be a hashref' unless ref $summary eq 'HASH';
933 0           $request->{summary_data} = $summary;
934             }
935              
936              
937             # single_result ( record )
938             #
939             # Set the result of this operation to the single specified record. Any
940             # previously specified results will be removed.
941              
942             sub single_result {
943              
944 0     0 0   my ($request, $record) = @_;
945            
946 0           $request->clear_result;
947 0 0         return unless defined $record;
948            
949 0 0 0       croak "single_result: the argument must be a hashref\n"
950             unless ref $record && reftype $record eq 'HASH';
951            
952 0           $request->{main_record} = $record;
953             }
954              
955              
956             # list_result ( record_list )
957             #
958             # Set the result of this operation to the specified list of results. Any
959             # previously specified results will be removed.
960              
961             sub list_result {
962            
963 0     0 0   my $request = shift;
964            
965 0           $request->clear_result;
966 0 0         return unless @_;
967            
968             # If we were given a single listref, just use that.
969            
970 0 0 0       if ( scalar(@_) == 1 && ref $_[0] && reftype $_[0] eq 'ARRAY' )
      0        
971             {
972 0           $request->{main_result} = $_[0];
973 0           return;
974             }
975            
976             # Otherwise, go through the arguments one by one.
977            
978 0           my @result;
979            
980 0           while ( my $item = shift )
981             {
982 0 0         next unless defined $item;
983 0 0 0       croak "list_result: arguments must be hashrefs or listrefs\n"
      0        
984             unless ref $item && (reftype $item eq 'ARRAY' or reftype $item eq 'HASH');
985            
986 0 0         if ( reftype $item eq 'ARRAY' )
987             {
988 0           push @result, @$item;
989             }
990            
991             else
992             {
993 0           push @result, $item;
994             }
995             }
996            
997 0           $request->{main_result} = \@result;
998             }
999              
1000              
1001             # data_result ( data )
1002             #
1003             # Set the result of this operation to the value of the specified scalar. Any
1004             # previously specified results will be removed.
1005              
1006             sub data_result {
1007            
1008 0     0 0   my ($request, $data) = @_;
1009            
1010 0           $request->clear_result;
1011 0 0         return unless defined $data;
1012            
1013 0 0 0       croak "data_result: the argument must be either a scalar or a scalar ref\n"
1014             if ref $data && reftype $data ne 'SCALAR';
1015            
1016 0 0         $request->{main_data} = ref $data ? $$data : $data;
1017             }
1018              
1019              
1020             # values_result ( values_list )
1021             #
1022             # Set the result of this operation to the specified list of data values. Each
1023             # value should be a scalar.
1024              
1025             sub values_result {
1026            
1027 0     0 0   my $request = shift;
1028            
1029 0           $request->clear_result;
1030            
1031 0 0         if ( ref $_[0] eq 'ARRAY' )
1032             {
1033 0           $request->{main_values} = $_[0];
1034             }
1035            
1036             else
1037             {
1038 0           $request->{main_values} = [ @_ ];
1039             }
1040             }
1041              
1042              
1043             # sth_result ( sth )
1044             #
1045             # Set the result of this operation to the specified DBI statement handle. Any
1046             # previously specified results will be removed.
1047              
1048             sub sth_result {
1049            
1050 0     0 0   my ($request, $sth) = @_;
1051            
1052 0           $request->clear_result;
1053 0 0         return unless defined $sth;
1054            
1055 0 0 0       croak "sth_result: the argument must be an object that implements 'fetchrow_hashref'\n"
1056             unless ref $sth && $sth->can('fetchrow_hashref');
1057            
1058 0           $request->{main_sth} = $sth;
1059             }
1060              
1061              
1062             # add_result ( record... )
1063             #
1064             # Add the specified record(s) to the list of result records for this operation.
1065             # Any result previously specified by any method other than 'add_result' or
1066             # 'list_result' will be cleared.
1067              
1068             sub add_result {
1069            
1070 0     0 0   my $request = shift;
1071            
1072 0 0         $request->clear_result unless ref $request->{main_result} eq 'ARRAY';
1073 0 0         return unless @_;
1074            
1075 0 0 0       croak "add_result: arguments must be hashrefs\n"
1076             unless ref $_[0] && reftype $_[0] eq 'HASH';
1077            
1078 0           push @{$request->{main_result}}, @_;
  0            
1079             }
1080              
1081              
1082             # clear_result
1083             #
1084             # Clear all results that have been specified for this operation.
1085              
1086             sub clear_result {
1087            
1088 0     0 0   my ($request) = @_;
1089            
1090 0           delete $request->{main_result};
1091 0           delete $request->{main_record};
1092 0           delete $request->{main_data};
1093 0           delete $request->{main_sth};
1094             }
1095              
1096              
1097             # skip_output_record
1098             #
1099             # This method should only be called from a before_record_hook. It directs that the record about to
1100             # be output should be skipped.
1101              
1102             sub skip_output_record {
1103              
1104 0     0 0   my ($request) = @_;
1105            
1106 0           $request->{_skip_record} = 1;
1107             }
1108              
1109              
1110             1;