File Coverage

blib/lib/OpenSearch/Client/Role/Client/Direct.pm
Criterion Covered Total %
statement 88 108 81.4
branch 28 50 56.0
condition 14 34 41.1
subroutine 14 18 77.7
pod 0 1 0.0
total 144 211 68.2


line stmt bran cond sub pod time code
1             # OpenSearch::Client is an unofficial client for OpenSearch.
2             # It is derived from Search::Elasticsearch version 7.714
3             # License details from the original work are contained in the
4             # NOTICE file distributed with this work.
5             #
6             #-----------------------------------------------------------------------
7             # OpenSearch::Client
8             #-----------------------------------------------------------------------
9             # Copyright 2026 Mark Dootson
10             #
11             # Licensed under the Apache License, Version 2.0 (the "License");
12             # you may not use this file except in compliance with the License.
13             # You may obtain a copy of the License at
14             #
15             # http://www.apache.org/licenses/LICENSE-2.0
16             #
17             # Unless required by applicable law or agreed to in writing, software
18             # distributed under the License is distributed on an "AS IS" BASIS,
19             # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20             # See the License for the specific language governing permissions and
21             # limitations under the License.
22              
23             package OpenSearch::Client::Role::Client::Direct;
24             $OpenSearch::Client::Role::Client::Direct::VERSION = '3.007005';
25 56     56   33965 use Moo::Role;
  56         126  
  56         416  
26             with 'OpenSearch::Client::Role::Client';
27 56     56   24107 use OpenSearch::Client::Util qw(load_plugin is_compat throw);
  56         126  
  56         460  
28              
29 56     56   21022 use Try::Tiny;
  56         100  
  56         3633  
30 56     56   257 use Package::Stash 0.34 ();
  56         1247  
  56         1214  
31 56     56   20318 use Any::URI::Escape qw(uri_escape);
  56         165326  
  56         4384  
32 56     56   358 use namespace::clean;
  56         99  
  56         423  
33              
34             #===================================
35             sub parse_request {
36             #===================================
37 8     8 0 4337 my $self = shift;
38 8   50     23 my $defn = shift || {};
39 8 50       17 my $params = { ref $_[0] ? %{ shift() } : @_ };
  8         18  
40              
41 8         10 my $request;
42             try {
43             $request = {
44             ignore => delete $params->{ignore} || [],
45             method => $self->_parse_method ( $defn, $params ),
46             serialize => $defn->{serialize} || 'std',
47             path => $self->_parse_path( $defn, $params ),
48             body => $self->_parse_body( $defn->{body}, $params ),
49 8   50 8   309 qs => $self->_parse_qs( $defn->{qs}, $params ),
      50        
50             };
51             }
52             catch {
53 0     0   0 chomp $_;
54 0   0     0 my $name = $defn->{name} || '';
55 0         0 $self->logger->throw_error( 'Param', "$_ in ($name) request. " );
56 8         66 };
57 8         151 return $request;
58             }
59              
60             #===================================
61             sub _parse_method {
62             #===================================
63 8     8   12 my ( $self, $defn, $params ) = @_;
64            
65 8   50     16 my $method = $defn->{method} || 'GET';
66 8 50       18 return $method unless( $method eq 'detect' );
67 8         10 my $dp = $defn->{detect};
68 8         13 $method = $dp->{method};
69            
70 8 50 33     27 return $method unless(defined($params) && ref($params) eq 'HASH');
71            
72             ## is there a body param
73 8 100       17 if ( $dp->{check}->{body} ) {
74 4 100 66     47 return $dp->{alternate} if(exists($params->{body}) && defined($params->{body}));
75             }
76            
77             ## are there any optional params
78 6 50 66     34 if ( $dp->{check}->{paths}
      33        
      33        
79             && exists($defn->{parts})
80             && defined($defn->{parts})
81             && ref($defn->{parts}) eq 'HASH'
82             ) {
83            
84 4         5 my @pathparts = keys %{ $defn->{parts} };
  4         11  
85            
86 4         7 for my $pathpart ( @pathparts ) {
87 8 100       15 next if $defn->{parts}->{$pathpart}->{required};
88 4 100 66     20 return $dp->{alternate} if(exists($params->{$pathpart}) && defined($params->{$pathpart}));
89             }
90             }
91            
92 4         20 return $method;
93              
94             }
95              
96              
97             #===================================
98             sub _parse_path {
99             #===================================
100 8     8   14 my ( $self, $defn, $params ) = @_;
101             return delete $params->{path}
102 8 50       14 if $params->{path};
103 8         14 my $paths = $defn->{paths};
104 8         9 my $parts = $defn->{parts};
105              
106 8         9 my %args;
107 8         10 keys %$parts;
108 56     56   37589 no warnings 'uninitialized';
  56         106  
  56         42242  
109 8         24 while ( my ( $key, $req ) = each %$parts ) {
110 14         68 my $val = delete $params->{$key};
111 14 50       23 if ( ref $val eq 'ARRAY' ) {
112             die "Param ($key) must contain a single value\n"
113 0 0 0     0 if @$val > 1 and not $req->{multi};
114 0         0 $val = join ",", @$val;
115             }
116 14 100       23 if ( !length $val ) {
117             die "Missing required param ($key)\n"
118 2 50       4 if $req->{required};
119 2         6 next;
120             }
121 12         27 utf8::encode($val);
122 12         23 $args{$key} = uri_escape($val);
123             }
124 8         77 PATH: for my $path (@$paths) {
125 10         11 my @keys = keys %{ $path->[0] };
  10         110  
126 10 100       20 next PATH unless @keys == keys %args;
127 8         34 for (@keys) {
128 12 50       20 next PATH unless exists $args{$_};
129             }
130 8         18 my ( $pos, @parts ) = @$path;
131 8         11 for ( keys %$pos ) {
132 12         24 $parts[ $pos->{$_} ] = $args{$_};
133             }
134 8         42 return join "/", '', @parts;
135             }
136              
137             throw(
138 0         0 'Internal',
139             "Couldn't determine path",
140             { params => $params, defn => $defn }
141             );
142             }
143              
144             #===================================
145             sub _parse_body {
146             #===================================
147 8     8   13 my ( $self, $defn, $params ) = @_;
148 8 50       16 if ( defined $defn ) {
149             die("Missing required param (body)\n")
150 8 50 33     20 if $defn->{required} && !$params->{body};
151 8         20 return delete $params->{body};
152             }
153 0 0       0 die("Unknown param (body)\n") if $params->{body};
154 0         0 return undef;
155             }
156              
157             #===================================
158             sub _parse_qs {
159             #===================================
160 8     8   10 my ( $self, $handlers, $params ) = @_;
161 8 50       15 die "No (qs) defined\n" unless $handlers;
162 8         9 my %qs;
163              
164 8 50       18 if ( my $raw = delete $params->{params} ) {
165 0 0       0 die("Arg (params) shoud be a hashref\n")
166             unless ref $raw eq 'HASH';
167 0         0 %qs = %$raw;
168             }
169              
170 8         12 for my $key ( keys %$params ) {
171 0 0       0 my $handler = $handlers->{$key}
172             or die("Unknown param ($key)\n");
173 0         0 $qs{$key} = $handler->( delete $params->{$key} );
174             }
175 8         31 return \%qs;
176             }
177              
178             #===================================
179             sub _install_api {
180             #===================================
181 56     56   3421 my ( $class, $group ) = @_;
182 56         1858 my $defns = $class->api;
183 56         3980 my $stash = Package::Stash->new($class);
184              
185 56 50       1169 my $group_qr = $group ? qr/$group\./ : qr//;
186 56         3790 for my $action ( keys %$defns ) {
187 27104 100       58867 my ($name) = ( $action =~ /^$group_qr([^.]+)$/ )
188             or next;
189 2408 50       7061 next if $stash->has_symbol( '&' . $name );
190              
191 2408         3027 my %defn = ( name => $name, %{ $defns->{$action} } );
  2408         12070  
192             $stash->add_symbol(
193             '&' . $name => sub {
194 0     0     shift->perform_request( \%defn, @_ );
195             }
196 2408         26035 );
197             }
198             }
199              
200             #===================================
201             sub _build_namespace {
202             #===================================
203 0     0     my ( $self, $ns ) = @_;
204 0           my $class = load_plugin( $self->_namespace, [$ns] );
205 0           return $class->new(
206             { transport => $self->transport,
207             logger => $self->logger
208             }
209             );
210             }
211              
212             #===================================
213             sub _build_helper {
214             #===================================
215 0     0     my ( $self, $name, $sub_class ) = @_;
216 0           my $class = load_plugin( 'OpenSearch::Client', $sub_class );
217 0           is_compat( $name . '_helper_class', $self->transport, $class );
218 0           return $class;
219             }
220              
221             1;
222              
223             __END__