Class-Usul

 view release on metacpan or  search on metacpan

lib/Class/Usul/TraitFor/ConnectInfo.pm  view on Meta::CPAN

package Class::Usul::TraitFor::ConnectInfo;

use namespace::autoclean;

use Class::Usul::Constants   qw( EXCEPTION_CLASS CONFIG_EXTN FALSE TRUE );
use Class::Usul::Crypt::Util qw( decrypt_from_config );
use Class::Usul::File;
use Class::Usul::Functions   qw( merge_attributes throw );
use File::Spec::Functions    qw( catfile );
use Scalar::Util             qw( blessed );
use Unexpected::Functions    qw( Unspecified );
use Moo::Role;

requires qw( config ); # As a class method

my $_cache = {};

# Private functions
my $_connect_attr = sub {
   return [ qw( class ctlfile ctrldir database dataclass_attr extension
                prefix read_secure salt seed seed_file subspace tempdir ) ];
};

my $_get_cache_key = sub {
   my $param = shift;
   my $db    = $param->{database}
      or throw 'Class [_1] has no database name', [ $param->{class} ];

   return $param->{subspace} ? "${db}.".$param->{subspace} : $db;
};

my $_get_credentials_file = sub {
   my $param = shift; my $file = $param->{ctlfile};

   defined $file and -f $file and return $file;

   my $dir = $param->{ctrldir}; my $db = $param->{database};

      $dir or throw Unspecified, [ 'ctrldir' ];
   -d $dir or throw 'Directory [_1] not found', [ $dir ];
       $db or throw 'Class [_1] has no database name', [ $param->{class} ];

   $file = catfile( $dir, $db.($param->{extension} // CONFIG_EXTN) );

   -f $file and return $file;

   return catfile( $dir, 'connect-info'.($param->{extension} // CONFIG_EXTN) );
};

my $_get_dataclass_schema = sub {
   return Class::Usul::File->dataclass_schema( @_ );
};

my $_unicode_options = sub {
   return { mysql  => { mysql_enable_utf8 => TRUE },
            pg     => { pg_enable_utf8    => TRUE },
            sqlite => { sqlite_unicode    => TRUE }, };
};

my $_dump_config_data = sub {
   my ($param, $cfg_data) = @_;

   my $ctlfile = $_get_credentials_file->( $param );
   my $schema  = $_get_dataclass_schema->( $param->{dataclass_attr} );

   return $schema->dump( { data => $cfg_data, path => $ctlfile } );
};

my $_extract_creds_from = sub {
   my ($param, $cfg_data) = @_; my $key = $_get_cache_key->( $param );

   ($cfg_data->{credentials} and defined $cfg_data->{credentials}->{ $key })
      or throw 'Path [_1] database [_2] no credentials',
               [ $_get_credentials_file->( $param ), $key ];

   return $cfg_data->{credentials}->{ $key };
};

my $_get_connect_options = sub {
   my $creds = shift;
   my $uopt  = $creds->{unicode_option}
            // $_unicode_options->()->{ lc $creds->{driver} } // {};

   return { AutoCommit =>  $creds->{auto_commit  } // TRUE,
            PrintError =>  $creds->{print_error  } // FALSE,
            RaiseError =>  $creds->{raise_error  } // TRUE,
            %{ $uopt }, %{ $creds->{database_attr} // {} }, };
};

my $_load_config_data = sub {
   my $schema = $_get_dataclass_schema->( $_[ 0 ]->{dataclass_attr} );

   return $schema->load( $_get_credentials_file->( $_[ 0 ] ) );
};

# Private methods
my $_merge_attributes = sub {
   return merge_attributes { class => blessed $_[ 0 ] || $_[ 0 ] },
                  $_[ 1 ], ($_[ 2 ] // {}), $_connect_attr->();
};

# Public methods
sub dump_config_data {
   my ($self, $config, $db, $cfg_data) = @_;

   my $param = $self->$_merge_attributes( $config, { database => $db } );

   return $_dump_config_data->( $param, $cfg_data );
}

sub extract_creds_from {
   my ($self, $config, $db, $cfg_data) = @_;

   my $param = $self->$_merge_attributes( $config, { database => $db } );

   return $_extract_creds_from->( $param, $cfg_data );
}

sub get_connect_info {
   my ($self, $app, $param) = @_; $app //= $self; $param //= {};

   merge_attributes $param, $app->config, $self->config, $_connect_attr->();

   my $class    = $param->{class} = blessed $self || $self;
   my $key      = $_get_cache_key->( $param );

   defined $_cache->{ $key } and return $_cache->{ $key };

   my $cfg_data = $_load_config_data->( $param );
   my $creds    = $_extract_creds_from->( $param, $cfg_data );
   my $dsn      = 'dbi:'.$creds->{driver}.':database='.$param->{database};
   my $password = decrypt_from_config $param, $creds->{password};
   my $opts     = $_get_connect_options->( $creds );

   $creds->{host} and $dsn .= ';host='.$creds->{host};
   $creds->{port} and $dsn .= ';port='.$creds->{port};

   return $_cache->{ $key } = [ $dsn, $creds->{user}, $password, $opts ];
}

sub load_config_data {
   my ($self, $config, $db) = @_;



( run in 0.757 second using v1.01-cache-2.11-cpan-39bf76dae61 )