File Coverage

blib/lib/OpenSearch/Client/Role/Client/Direct.pm
Criterion Covered Total %
statement 31 108 28.7
branch 4 50 8.0
condition 0 34 0.0
subroutine 8 18 44.4
pod 0 1 0.0
total 43 211 20.3


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.007002';
25 55     55   33345 use Moo::Role;
  55         127  
  55         351  
26             with 'OpenSearch::Client::Role::Client';
27 55     55   22910 use OpenSearch::Client::Util qw(load_plugin is_compat throw);
  55         94  
  55         377  
28              
29 55     55   20590 use Try::Tiny;
  55         98  
  55         3440  
30 55     55   260 use Package::Stash 0.34 ();
  55         1265  
  55         1169  
31 55     55   19249 use Any::URI::Escape qw(uri_escape);
  55         162368  
  55         4491  
32 55     55   357 use namespace::clean;
  55         97  
  55         1825  
33              
34             #===================================
35             sub parse_request {
36             #===================================
37 0     0 0 0 my $self = shift;
38 0   0     0 my $defn = shift || {};
39 0 0       0 my $params = { ref $_[0] ? %{ shift() } : @_ };
  0         0  
40              
41 0         0 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 0   0 0   0 qs => $self->_parse_qs( $defn->{qs}, $params ),
      0        
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 0         0 };
57 0         0 return $request;
58             }
59              
60             #===================================
61             sub _parse_method {
62             #===================================
63 0     0   0 my ( $self, $defn, $params ) = @_;
64            
65 0   0     0 my $method = $defn->{method} || 'GET';
66 0 0       0 return $method unless( $method eq 'detect' );
67 0         0 my $dp = $defn->{detect};
68 0         0 $method = $dp->{method};
69            
70 0 0 0     0 return $method unless(defined($params) && ref($params) eq 'HASH');
71            
72             ## is there a body param
73 0 0       0 if ( $dp->{check}->{body} ) {
74 0 0 0     0 return $dp->{alternate} if(exists($params->{body}) && defined($params->{body}));
75             }
76            
77             ## are there any optional params
78 0 0 0     0 if ( $dp->{check}->{paths}
      0        
      0        
79             && exists($defn->{parts})
80             && defined($defn->{parts})
81             && ref($defn->{parts}) eq 'HASH'
82             ) {
83            
84 0         0 my @pathparts = keys %{ $defn->{parts} };
  0         0  
85            
86 0         0 for my $pathpart ( @pathparts ) {
87 0 0       0 next if $defn->{parts}->{$pathpart}->{required};
88 0 0 0     0 return $dp->{alternate} if(exists($params->{$pathpart}) && defined($params->{$pathpart}));
89             }
90             }
91            
92 0         0 return $method;
93              
94             }
95              
96              
97             #===================================
98             sub _parse_path {
99             #===================================
100 0     0   0 my ( $self, $defn, $params ) = @_;
101             return delete $params->{path}
102 0 0       0 if $params->{path};
103 0         0 my $paths = $defn->{paths};
104 0         0 my $parts = $defn->{parts};
105              
106 0         0 my %args;
107 0         0 keys %$parts;
108 55     55   36767 no warnings 'uninitialized';
  55         100  
  55         40460  
109 0         0 while ( my ( $key, $req ) = each %$parts ) {
110 0         0 my $val = delete $params->{$key};
111 0 0       0 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 0 0       0 if ( !length $val ) {
117             die "Missing required param ($key)\n"
118 0 0       0 if $req->{required};
119 0         0 next;
120             }
121 0         0 utf8::encode($val);
122 0         0 $args{$key} = uri_escape($val);
123             }
124 0         0 PATH: for my $path (@$paths) {
125 0         0 my @keys = keys %{ $path->[0] };
  0         0  
126 0 0       0 next PATH unless @keys == keys %args;
127 0         0 for (@keys) {
128 0 0       0 next PATH unless exists $args{$_};
129             }
130 0         0 my ( $pos, @parts ) = @$path;
131 0         0 for ( keys %$pos ) {
132 0         0 $parts[ $pos->{$_} ] = $args{$_};
133             }
134 0         0 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 0     0   0 my ( $self, $defn, $params ) = @_;
148 0 0       0 if ( defined $defn ) {
149             die("Missing required param (body)\n")
150 0 0 0     0 if $defn->{required} && !$params->{body};
151 0         0 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 0     0   0 my ( $self, $handlers, $params ) = @_;
161 0 0       0 die "No (qs) defined\n" unless $handlers;
162 0         0 my %qs;
163              
164 0 0       0 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 0         0 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 0         0 return \%qs;
176             }
177              
178             #===================================
179             sub _install_api {
180             #===================================
181 55     55   182 my ( $class, $group ) = @_;
182 55         278 my $defns = $class->api;
183 55         651 my $stash = Package::Stash->new($class);
184              
185 55 50       2647 my $group_qr = $group ? qr/$group\./ : qr//;
186 55         5432 for my $action ( keys %$defns ) {
187 26620 100       58422 my ($name) = ( $action =~ /^$group_qr([^.]+)$/ )
188             or next;
189 2365 50       10375 next if $stash->has_symbol( '&' . $name );
190              
191 2365         6278 my %defn = ( name => $name, %{ $defns->{$action} } );
  2365         11357  
192             $stash->add_symbol(
193             '&' . $name => sub {
194 0     0     shift->perform_request( \%defn, @_ );
195             }
196 2365         28034 );
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__