File Coverage

blib/lib/SignalWire/Agents/DataMap.pm
Criterion Covered Total %
statement 102 117 87.1
branch 32 46 69.5
condition 3 5 60.0
subroutine 16 18 88.8
pod 0 14 0.0
total 153 200 76.5


line stmt bran cond sub pod time code
1             package SignalWire::Agents::DataMap;
2 1     1   102190 use strict;
  1         3  
  1         31  
3 1     1   3 use warnings;
  1         2  
  1         68  
4 1     1   389 use Moo;
  1         9437  
  1         4  
5 1     1   1278 use JSON ();
  1         3  
  1         3182  
6              
7             has 'function_name' => (
8             is => 'ro',
9             required => 1,
10             );
11              
12             has '_purpose' => (
13             is => 'rw',
14             default => sub { '' },
15             );
16              
17             has '_parameters' => (
18             is => 'rw',
19             default => sub { {} },
20             );
21              
22             has '_required_params' => (
23             is => 'rw',
24             default => sub { [] },
25             );
26              
27             has '_expressions' => (
28             is => 'rw',
29             default => sub { [] },
30             );
31              
32             has '_webhooks' => (
33             is => 'rw',
34             default => sub { [] },
35             );
36              
37             has '_output' => (
38             is => 'rw',
39             default => sub { undef },
40             );
41              
42             has '_error_keys' => (
43             is => 'rw',
44             default => sub { [] },
45             );
46              
47             # Constructor shortcut: DataMap->new("name") or DataMap->new(function_name => "name")
48             around BUILDARGS => sub {
49             my ($orig, $class, @args) = @_;
50             if (@args == 1 && !ref $args[0]) {
51             return $class->$orig(function_name => $args[0]);
52             }
53             return $class->$orig(@args);
54             };
55              
56             sub purpose {
57 11     11 0 90 my ($self, $desc) = @_;
58 11         83 $self->_purpose($desc);
59 11         45 return $self;
60             }
61              
62             sub description {
63 1     1 0 816 my ($self, $desc) = @_;
64 1         4 return $self->purpose($desc);
65             }
66              
67             sub parameter {
68 7     7 0 821 my ($self, $name, $type, $description, %opts) = @_;
69 7   50     32 my $required = $opts{required} // 0;
70 7         18 my $enum = $opts{enum};
71              
72 7         33 my %param_def = (
73             type => $type,
74             description => $description,
75             );
76 7 100       24 $param_def{enum} = $enum if $enum;
77              
78 7         26 $self->_parameters->{$name} = \%param_def;
79              
80 7 50       23 if ($required) {
81 7         21 my $req = $self->_required_params;
82 7 50       40 push @$req, $name unless grep { $_ eq $name } @$req;
  0         0  
83             }
84              
85 7         63 return $self;
86             }
87              
88             sub expression {
89 2     2 0 18 my ($self, $test_value, $pattern, $output, %opts) = @_;
90 2         5 my $nomatch_output = $opts{nomatch_output};
91              
92             # If pattern is a compiled regex, extract the string
93 2 50       10 if (ref $pattern eq 'Regexp') {
94 0         0 $pattern = "$pattern";
95             # Strip Perl regex delimiters: (?^:...) or (?^u:...)
96 0         0 $pattern =~ s/^\(\?[\^a-z]*://;
97 0         0 $pattern =~ s/\)$//;
98             }
99              
100 2         10 my %expr = (
101             string => $test_value,
102             pattern => $pattern,
103             output => $output->to_hash,
104             );
105 2 50       9 $expr{'nomatch-output'} = $nomatch_output->to_hash if $nomatch_output;
106              
107 2         3 push @{ $self->_expressions }, \%expr;
  2         9  
108 2         33 return $self;
109             }
110              
111             sub webhook {
112 8     8 0 1328 my ($self, $method, $url, %opts) = @_;
113 8         20 my $headers = $opts{headers};
114 8         17 my $form_param = $opts{form_param};
115 8         20 my $input_args_as_params = $opts{input_args_as_params};
116 8         15 my $require_args = $opts{require_args};
117              
118 8         37 my %wh = (
119             url => $url,
120             method => uc($method),
121             );
122 8 100       46 $wh{headers} = $headers if $headers;
123 8 50       24 $wh{form_param} = $form_param if $form_param;
124 8 50       20 $wh{input_args_as_params} = JSON::true if $input_args_as_params;
125 8 50       21 $wh{require_args} = $require_args if $require_args;
126              
127 8         13 push @{ $self->_webhooks }, \%wh;
  8         31  
128 8         131 return $self;
129             }
130              
131             sub webhook_expressions {
132 0     0 0 0 my ($self, $expressions) = @_;
133             die "Must add webhook before setting webhook expressions"
134 0 0       0 unless @{ $self->_webhooks };
  0         0  
135 0         0 $self->_webhooks->[-1]{expressions} = $expressions;
136 0         0 return $self;
137             }
138              
139             sub body {
140 3     3 0 23 my ($self, $data) = @_;
141             die "Must add webhook before setting body"
142 3 100       7 unless @{ $self->_webhooks };
  3         26  
143 2         8 $self->_webhooks->[-1]{body} = $data;
144 2         61 return $self;
145             }
146              
147             sub params {
148 0     0 0 0 my ($self, $data) = @_;
149             die "Must add webhook before setting params"
150 0 0       0 unless @{ $self->_webhooks };
  0         0  
151 0         0 $self->_webhooks->[-1]{params} = $data;
152 0         0 return $self;
153             }
154              
155             sub foreach {
156 3     3 0 557 my ($self, $config) = @_;
157             die "Must add webhook before setting foreach"
158 3 100       7 unless @{ $self->_webhooks };
  3         42  
159 2 50       10 die "foreach_config must be a hashref" unless ref $config eq 'HASH';
160              
161 2         6 for my $key (qw(input_key output_key append)) {
162             die "foreach config missing required key: $key"
163 5 100       26 unless exists $config->{$key};
164             }
165              
166 1         5 $self->_webhooks->[-1]{foreach} = $config;
167 1         4 return $self;
168             }
169              
170             sub output {
171 8     8 0 95 my ($self, $result) = @_;
172             die "Must add webhook before setting output"
173 8 100       16 unless @{ $self->_webhooks };
  8         50  
174 7         38 $self->_webhooks->[-1]{output} = $result->to_hash;
175 7         56 return $self;
176             }
177              
178             sub fallback_output {
179 1     1 0 9 my ($self, $result) = @_;
180 1         6 $self->_output($result->to_hash);
181 1         42 return $self;
182             }
183              
184             sub error_keys {
185 1     1 0 4 my ($self, $keys) = @_;
186 1 50       2 if (@{ $self->_webhooks }) {
  1         7  
187 1         5 $self->_webhooks->[-1]{error_keys} = $keys;
188             } else {
189 0         0 $self->_error_keys($keys);
190             }
191 1         4 return $self;
192             }
193              
194             sub global_error_keys {
195 1     1 0 4 my ($self, $keys) = @_;
196 1         5 $self->_error_keys($keys);
197 1         7 return $self;
198             }
199              
200             sub to_swaig_function {
201 10     10 0 74 my ($self) = @_;
202              
203             # Build parameter schema
204 10         21 my %param_schema;
205 10 100       19 if (keys %{ $self->_parameters }) {
  10         42  
206 6         34 $param_schema{type} = 'object';
207 6         13 $param_schema{properties} = { %{ $self->_parameters } };
  6         27  
208 6 50       13 if (@{ $self->_required_params }) {
  6         26  
209 6         12 $param_schema{required} = [ @{ $self->_required_params } ];
  6         24  
210             }
211             } else {
212 4         18 %param_schema = (type => 'object', properties => {});
213             }
214              
215             # Build data_map
216 10         21 my %data_map;
217 10 100       19 if (@{ $self->_expressions }) {
  10         55  
218 1         6 $data_map{expressions} = $self->_expressions;
219             }
220 10 100       17 if (@{ $self->_webhooks }) {
  10         34  
221 5         19 $data_map{webhooks} = $self->_webhooks;
222             }
223 10 100       47 if (defined $self->_output) {
224 1         5 $data_map{output} = $self->_output;
225             }
226 10 100       18 if (@{ $self->_error_keys }) {
  10         36  
227 1         6 $data_map{error_keys} = $self->_error_keys;
228             }
229              
230             return {
231 10   66     104 function => $self->function_name,
232             description => $self->_purpose || "Execute " . $self->function_name,
233             parameters => \%param_schema,
234             data_map => \%data_map,
235             };
236             }
237              
238             1;