|
|
|
#!/usr/bin/perl
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
use Anvil::Tools;
|
|
|
|
use JSON;
|
|
|
|
use Data::Dumper;
|
|
|
|
|
|
|
|
$| = 1;
|
|
|
|
|
|
|
|
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
|
|
|
|
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
|
|
|
|
if (($running_directory =~ /^\./) && ($ENV{PWD}))
|
|
|
|
{
|
|
|
|
$running_directory =~ s/^\./$ENV{PWD}/;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $anvil = Anvil::Tools->new();
|
|
|
|
|
|
|
|
sub is_array
|
|
|
|
{
|
|
|
|
return ref($_[0]) eq "ARRAY";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub is_hash
|
|
|
|
{
|
|
|
|
return ref($_[0]) eq "HASH";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub db_access
|
|
|
|
{
|
|
|
|
my $parameters = shift;
|
|
|
|
my $db_access_mode = $parameters->{db_access_mode};
|
|
|
|
my $db_uuid = $parameters->{db_uuid};
|
|
|
|
my $sql_query = $parameters->{sql_query};
|
|
|
|
|
|
|
|
my $access_parameters = { query => $sql_query, uuid => $db_uuid, source => $THIS_FILE, line => __LINE__ };
|
|
|
|
|
|
|
|
return ($db_access_mode eq "write")
|
|
|
|
? { write_code => $anvil->Database->write($access_parameters) }
|
|
|
|
: $anvil->Database->query($access_parameters);
|
|
|
|
}
|
|
|
|
|
|
|
|
sub call_pre_data_fns
|
|
|
|
{
|
|
|
|
my $parameters = shift;
|
|
|
|
my $fns = $parameters->{fns};
|
|
|
|
|
|
|
|
if (is_array($fns))
|
|
|
|
{
|
|
|
|
foreach my $fn_wrapper ( @{$fns} )
|
|
|
|
{
|
|
|
|
if (is_array($fn_wrapper))
|
|
|
|
{
|
|
|
|
my $pre_chain = @{$fn_wrapper}[0] // "";
|
|
|
|
my @fn_params = @{$fn_wrapper}[1..$#{$fn_wrapper}] // ();
|
|
|
|
my @chain = split(/->|,/, $pre_chain);
|
|
|
|
my $intermediate = $anvil;
|
|
|
|
my $key_index = 0;
|
|
|
|
|
|
|
|
foreach my $key ( @chain )
|
|
|
|
{
|
|
|
|
last if not defined $intermediate->${key};
|
|
|
|
|
|
|
|
if ($key_index == $#chain && $intermediate->can($key))
|
|
|
|
{
|
|
|
|
eval { $intermediate->${key}(@fn_params); };
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$intermediate = $intermediate->${key};
|
|
|
|
}
|
|
|
|
|
|
|
|
$key_index += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub get_anvil_data
|
|
|
|
{
|
|
|
|
my $parameters = shift;
|
|
|
|
my $chain = $parameters->{chain};
|
|
|
|
|
|
|
|
my $source_intermediate = $anvil->data;
|
|
|
|
my $target_intermediate = $parameters->{data};
|
|
|
|
my $key_index = 0;
|
|
|
|
|
|
|
|
foreach my $key ( @{$chain} )
|
|
|
|
{
|
|
|
|
last if not exists $source_intermediate->{$key};
|
|
|
|
|
|
|
|
$source_intermediate = $source_intermediate->{$key};
|
|
|
|
|
|
|
|
if (not exists $target_intermediate->{$key})
|
|
|
|
{
|
|
|
|
$target_intermediate->{$key} = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($key_index < $#{$chain})
|
|
|
|
{
|
|
|
|
$target_intermediate = $target_intermediate->{$key};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$target_intermediate->{$key} = $source_intermediate;
|
|
|
|
}
|
|
|
|
|
|
|
|
$key_index += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub call_fn
|
|
|
|
{
|
|
|
|
my $parameters = shift;
|
|
|
|
my $chain = $parameters->{chain};
|
|
|
|
my $fallback = $parameters->{fallback};
|
|
|
|
my $fn_wrapper = $parameters->{fn};
|
|
|
|
|
|
|
|
if (exists $fn_wrapper->{fn})
|
|
|
|
{
|
|
|
|
my $fn = $fn_wrapper->{fn};
|
|
|
|
my $fn_params = $fn_wrapper->{params};
|
|
|
|
|
|
|
|
$fn_params->{chain} = $chain;
|
|
|
|
|
|
|
|
return $fn->($fn_params);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return $fallback;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub foreach_nested
|
|
|
|
{
|
|
|
|
my $parameters = shift;
|
|
|
|
# Required parameters:
|
|
|
|
my $hash = $parameters->{hash};
|
|
|
|
# Optional parameters:
|
|
|
|
my $chain = exists $parameters->{chain} ? $parameters->{chain} : ();
|
|
|
|
my $depth = exists $parameters->{depth} ? $parameters->{depth} : 0;
|
|
|
|
my $on_key = exists $parameters->{on_key} ? $parameters->{on_key} : {};
|
|
|
|
my $on_chain_end = exists $parameters->{on_chain_end} ? $parameters->{on_chain_end} : {};
|
|
|
|
|
|
|
|
foreach my $key (keys %{$hash})
|
|
|
|
{
|
|
|
|
my $is_continue_chain = 1;
|
|
|
|
my $value = $hash->{$key};
|
|
|
|
|
|
|
|
push(@{$chain}, $key);
|
|
|
|
|
|
|
|
$is_continue_chain = call_fn({ chain => $chain, fallback => $is_continue_chain, fn => $on_key });
|
|
|
|
|
|
|
|
if ( ($is_continue_chain) && is_hash($value) )
|
|
|
|
{
|
|
|
|
foreach_nested({
|
|
|
|
chain => $chain,
|
|
|
|
depth => $depth + 1,
|
|
|
|
hash => $value,
|
|
|
|
on_chain_end => $on_chain_end,
|
|
|
|
on_key => $on_key,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
call_fn({ chain => $chain, fn => $on_chain_end });
|
|
|
|
}
|
|
|
|
|
|
|
|
pop(@{$chain});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$anvil->Get->switches;
|
|
|
|
|
|
|
|
$anvil->Database->connect;
|
|
|
|
$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132" });
|
|
|
|
if (not $anvil->data->{sys}{database}{connections})
|
|
|
|
{
|
|
|
|
# No databases, exit.
|
|
|
|
$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003" });
|
|
|
|
$anvil->nice_exit({ exit_code => 1 });
|
|
|
|
}
|
|
|
|
|
|
|
|
my $data_hash = $anvil->data->{switches}{'data'};
|
|
|
|
my $db_access_mode = defined $anvil->data->{switches}{'mode'} ? $anvil->data->{switches}{'mode'} : "";
|
|
|
|
my $db_uuid = $anvil->data->{switches}{'uuid'};
|
|
|
|
my $pre_data = $anvil->data->{switches}{'predata'};
|
|
|
|
my $sql_query = $anvil->data->{switches}{'query'};
|
|
|
|
my $sub_module_name = defined $anvil->data->{switches}{'sub-module'} ? $anvil->data->{switches}{'sub-module'} : "Database";
|
|
|
|
my $sub_name = defined $anvil->data->{switches}{'sub'} ? $anvil->data->{switches}{'sub'} : "";
|
|
|
|
my $sub_params = defined $anvil->data->{switches}{'sub-params'} ? $anvil->data->{switches}{'sub-params'} : "{}";
|
|
|
|
|
|
|
|
if ($sql_query)
|
|
|
|
{
|
|
|
|
my $results = db_access({ db_uuid => $db_uuid, sql_query => $sql_query, db_access_mode => $db_access_mode });
|
|
|
|
print JSON->new->utf8->encode($results)."\n";
|
|
|
|
}
|
|
|
|
elsif ($anvil->${sub_module_name}->can($sub_name))
|
|
|
|
{
|
|
|
|
my $decoded_sub_params;
|
|
|
|
my $is_decode_sub_params_success = eval { $decoded_sub_params = decode_json($sub_params); };
|
|
|
|
|
|
|
|
if (not $is_decode_sub_params_success)
|
|
|
|
{
|
|
|
|
print STDERR "error: failed to parse subroutine parameters\n";
|
|
|
|
$anvil->nice_exit({ exit_code => 1 });
|
|
|
|
}
|
|
|
|
|
|
|
|
my (@results) = $anvil->${sub_module_name}->${sub_name}($decoded_sub_params);
|
|
|
|
print JSON->new->utf8->encode({ sub_results => scalar(@results) > 1 ? \@results : $results[0] })."\n";
|
|
|
|
}
|
|
|
|
elsif ($data_hash)
|
|
|
|
{
|
|
|
|
if ($pre_data)
|
|
|
|
{
|
|
|
|
my $decoded_pre_data;
|
|
|
|
my $is_decode_pre_data_success = eval { $decoded_pre_data = decode_json($pre_data); };
|
|
|
|
|
|
|
|
if ($is_decode_pre_data_success && is_array($decoded_pre_data))
|
|
|
|
{
|
|
|
|
call_pre_data_fns({ fns => $decoded_pre_data });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my $decoded_data_hash;
|
|
|
|
my $is_decode_data_hash_success = eval { $decoded_data_hash = decode_json($data_hash); };
|
|
|
|
|
|
|
|
if (not $is_decode_data_hash_success)
|
|
|
|
{
|
|
|
|
print STDERR "error: failed to parse data structure\n";
|
|
|
|
$anvil->nice_exit({ exit_code => 1 });
|
|
|
|
}
|
|
|
|
|
|
|
|
my $get_anvil_data_params = { data => {} };
|
|
|
|
|
|
|
|
foreach_nested({
|
|
|
|
hash => $decoded_data_hash,
|
|
|
|
on_chain_end => { fn => \&get_anvil_data, params => $get_anvil_data_params },
|
|
|
|
});
|
|
|
|
|
|
|
|
print JSON->new->utf8->allow_blessed->encode($get_anvil_data_params->{data})."\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
print STDERR "error: missing switches and perhaps their respective parameters; one of --data, --query, or --sub is required\n";
|
|
|
|
$anvil->nice_exit({ exit_code => 1 });
|
|
|
|
}
|
|
|
|
|
|
|
|
$anvil->nice_exit({ exit_code => 0 });
|