DBIx-FlexibleBinding
view release on metacpan or search on metacpan
lib/DBIx/FlexibleBinding.pm view on Meta::CPAN
use strict;
use warnings;
use MRO::Compat 'c3';
package DBIx::FlexibleBinding;
our $VERSION = '2.0.4'; # VERSION
# ABSTRACT: Greater statement placeholder and data-binding flexibility.
use DBI ();
use Exporter ();
use Message::String ();
use Scalar::Util ( 'reftype', 'blessed', 'weaken' );
use Sub::Util ( 'set_subname' );
use namespace::clean;
use Params::Callbacks ( 'callback' );
use message << 'EOF';
CRIT_EXP_AREF_AFTER Expected a reference to an ARRAY after argument (%s)
CRIT_UNEXP_ARG Unexpected argument (%s)
CRIT_EXP_SUB_NAMES Expected a sub name, or reference to an array of sub names
CRIT_EXP_HANDLE Expected a %s::database or statement handle
CRIT_DBI A DBI error occurred\n%s
CRIT_PROXY_UNDEF Handle (%s) undefined
EOF
our @ISA = qw(DBI Exporter);
our @EXPORT = qw(callback);
our $AUTO_BINDING_ENABLED = 1;
sub _is_arrayref
{
return ref( $_[0] ) && reftype( $_[0] ) eq 'ARRAY';
}
sub _is_hashref
{
return ref( $_[0] ) && reftype( $_[0] ) eq 'HASH';
}
sub _as_list_or_ref
{
return wantarray ? @{ $_[0] } : $_[0]
if defined $_[0];
return wantarray ? () : undef;
}
sub _create_namespace_alias
{
my ( $package, $ns_alias ) = @_;
return $package unless $ns_alias;
no strict 'refs';
for ( '', 'db', 'st' ) {
my $ext .= $_ ? "\::$_" : $_;
$ext .= '::';
*{ $ns_alias . $ext } = *{ $package . $ext };
}
return $package;
}
sub _create_dbi_handle_proxies
{
my ( $package, $caller, $list_of_sub_names ) = @_;
return $package unless $list_of_sub_names;
if ( ref $list_of_sub_names ) {
CRIT_EXP_SUB_NAMES
unless _is_arrayref( $list_of_sub_names );
for my $sub_name ( @$list_of_sub_names ) {
$package->_create_dbi_handle_proxy( $caller, $sub_name );
}
}
else {
$package->_create_dbi_handle_proxy( $caller, $list_of_sub_names );
}
return $package;
}
our %proxies;
sub _create_dbi_handle_proxy
{
# A DBI Handle Proxy is a subroutine masquerading as a database or
# statement handle object in the calling package namespace. They're
# intended to function as a pure convenience if that convenience is
# wanted.
my ( $package, $caller, $sub_name ) = @_;
my $fqpi = "$caller\::$sub_name";
no strict 'refs';
*$fqpi = set_subname(
$sub_name => sub {
unshift @_, ( $package, $fqpi );
goto &_service_call_to_a_dbi_handle_proxy;
}
);
$proxies{$fqpi} = undef;
return $package;
}
sub _service_call_to_a_dbi_handle_proxy
{
# This is the handler servicing calls to a DBI Handle Proxy. It
# imparts a set of overloaded behaviours on the object, each
# triggered by a different usage context.
my ( $package, $fqpi, @args ) = @_;
return $proxies{$fqpi}
unless @args;
if ( @args == 1 ) {
unless ( $args[0] ) {
undef $proxies{$fqpi};
return $proxies{$fqpi};
}
if ( blessed( $args[0] ) ) {
if ( $args[0]->isa( "$package\::db" ) ) {
weaken( $proxies{$fqpi} = $args[0] );
}
elsif ( $args[0]->isa( "$package\::st" ) ) {
weaken( $proxies{$fqpi} = $args[0] );
}
else {
CRIT_EXP_HANDLE( $package );
}
return $proxies{$fqpi};
}
}
if ( $args[0] =~ m{^dbi:}i ) {
$proxies{$fqpi} = $package->connect( @args )
or CRIT_DBI( $DBI::errstr );
}
else {
CRIT_PROXY_UNDEF( $fqpi )
unless $proxies{$fqpi};
my $proxy = $proxies{$fqpi};
$proxy->execute( @args )
if $proxy->isa( "$package\::st" );
return $proxy->getrows( @args );
}
return $proxies{$fqpi};
}
sub import
{
my ( $package, @args ) = @_;
my $caller = caller;
@_ = ( $package );
while ( @args ) {
my $arg = shift( @args );
if ( substr( $arg, 0, 1 ) eq '-' ) {
if ( $arg eq '-alias' || $arg eq '-as' ) {
my $ns_alias = shift @args;
$package->_create_namespace_alias( $ns_alias );
}
elsif ( $arg eq '-subs' ) {
my $list_of_sub_names = shift @args;
$package->_create_dbi_handle_proxies( $caller, $list_of_sub_names );
}
else {
CRIT_UNEXP_ARG( $arg );
}
}
else {
push @_, $arg;
}
}
goto &Exporter::import;
}
sub connect
{
my ( $invocant, $dsn, $user, $pass, $attr ) = @_;
$attr = {}
unless defined $attr;
$attr->{RootClass} = ref( $invocant ) || $invocant
unless defined $attr->{RootClass};
return $invocant->next::method( $dsn, $user, $pass, $attr );
( run in 0.896 second using v1.01-cache-2.11-cpan-54e63673c56 )