Anansi-DatabaseComponent
view release on metacpan or search on metacpan
lib/Anansi/DatabaseComponent.pm view on Meta::CPAN
package Anansi::DatabaseComponent;
=head1 NAME
Anansi::DatabaseComponent - A manager template for database drivers.
=head1 SYNOPSIS
package Anansi::Database::Example;
use base qw(Anansi::DatabaseComponent);
sub connect {
my ($self, $channel, %parameters) = @_;
return $self->SUPER::connect(
undef,
INPUT => [
'some text',
{
NAME => 'someParameter',
}, {
INPUT => [
'more text',
{
NAME => 'anotherParameter',
},
'yet more text',
]
}, {
DEFAULT => 'abc',
NAME => 'yetAnotherParameter',
},
],
(%parameters),
);
}
sub validate {
my ($self, $channel, %parameters) = @_;
$parameters{DRIVER} = 'Example';
return Anansi::DatabaseComponent::validate(undef, %parameters);
}
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'AUTOCOMMIT' => 'Anansi::DatabaseComponent::autocommit');
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'COMMIT' => 'Anansi::DatabaseComponent::commit');
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'CONNECT' => 'connect');
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'DISCONNECT' => 'Anansi::DatabaseComponent::disconnect');
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'FINISH' => 'Anansi::DatabaseComponent::finish');
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'HANDLE' => 'Anansi::DatabaseComponent::handle');
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'PREPARE' => 'Anansi::DatabaseComponent::prepare');
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'ROLLBACK' => 'Anansi::DatabaseComponent::rollback');
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'STATEMENT' => 'Anansi::DatabaseComponent::statement');
Anansi::DatabaseComponent::addChannel('Anansi::Database::Example', 'VALIDATE_AS_APPROPRIATE' => 'validate');
1;
package main;
use Anansi::Database;
my $database = Anansi::Database->new();
my $component = $database->addComponent(undef,
DRIVER => 'Example',
);
if(defined($component)) {
if($database->connect(
undef,
$component,
someParameter => 'some data',
anotherParameter => 'more data',
yetAnotherParameter => 'further data',
)) {
my $result = $database->statement(
undef,
$component,
SQL => 'SELECT someThing FROM someTable where modified = ?;',
INPUT => [
{
NAME => 'modified',
},
],
modified => '2011-02-22 00:21:46',
);
if(!defined($result)) {
} elsif(ref($result) =~ /^ARRAY$/i) {
foreach my $record (@{$result}) {
next if(ref($record) !~ /^HASH$/i);
print 'someThing: "'.${$record}{someThing}.'"'."\n";
}
}
}
}
1;
=head1 DESCRIPTION
Manages a database connection providing generic processes to allow it's opening,
closing and various SQL interactions. Uses L<Anansi::Actor>.
=cut
our $VERSION = '0.05';
use base qw(Anansi::Component);
use Anansi::Actor;
=head1 METHODS
=cut
=head2 Anansi::Class
See L<Anansi::Class|Anansi::Class> for details. A parent module of L<Anansi::Component|Anansi::Component>.
=cut
=head3 DESTROY
See L<Anansi::Class::DESTROY|Anansi::Class/"DESTROY"> for details.
=cut
=head3 finalise
See L<Anansi::Class::finalise|Anansi::Class/"finalise"> for details. Overridden by L<Anansi::DatabaseComponent::finalise|Anansi::DatabaseComponent/"finalise">. A virtual method.
=cut
=head3 implicate
lib/Anansi/DatabaseComponent.pm view on Meta::CPAN
return $self->SUPER::addChannel((%parameters));
}
=head2 autoCommit
if(1 == Anansi::DatabaseComponent::autocommit($OBJECT, undef));
if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'AUTOCOMMIT'));
if(1 == $OBJECT->autocommit(undef));
if(1 == $OBJECT->channel('AUTOCOMMIT'));
=over 4
=item self I<(Blessed Hash, Required)>
An object of this namespace.
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
=item parameters I<(Hash, Optional)>
Named parameters.
=back
Attempts to perform a database autocommit. Returns B<1> I<(one)> on success and
B<0> I<(zero)> on failure.
=cut
sub autocommit {
my ($self, $channel, %parameters) = @_;
return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
my $autocommit;
eval {
$autocommit = $self->{HANDLE}->autocommit();
1;
} or do {
return 0;
};
return 0 if(!defined($autocommit));
return 0 if(ref($autocommit) !~ /^$/);
return 0 if($autocommit !~ /^[\+\-]?\d+$/);
return 1 if($autocommit);
return 0;
}
Anansi::DatabaseComponent::addChannel('Anansi::DatabaseComponent', 'AUTOCOMMIT' => 'autocommit');
=head2 bind
if(Anansi::DatabaseComponent::bind($OBJECT,
HANDLE => $HANDLE,
INPUT => [
{
NAME => 'someParameter'
}, {
DEFAULT => 123,
NAME => 'anotherParameter'
}
],
VALUE => {
someParameter => 'abc'
}
));
if($OBJECT->bind(
HANDLE => $HANDLE,
INPUT => [
{
NAME => 'yetAnotherParameter',
TYPE => 'TEXT'
}
],
VALUE => [
yetAnotherParameter => 456
]
));
=over 4
=item self I<(Blessed Hash B<or> String, Required)>
Either an object or a string of this namespace.
=item parameters I<(Hash, Optional)>
Named parameters.
=over 4
=item HANDLE I<(DBI::st, Required)>
The database statement handle.
=item INPUT I<(Array, Required)>
An array of hashes. Each element of the array corresponds to an equivalent B<?>
I<(Question mark)> within the prepared SQL statement. Each hash contains a
I<NAME> key with a value that represents a possible key within the I<VALUE>
parameter. Each hash may also contain a I<DEFAULT> key which contains the value
to use if the equivalent I<VALUE> parameter does not exist and a I<TYPE> key
which contains the SQL type to associate with the assigned value. When no
corresponding I<VALUE> parameter key exists and no I<DEFAULT> key has been
defined then an empty string is used for the value.
=item VALUE I<(Hash, Required)>
A hash of values to assign in the order specified by the I<INPUT> parameter.
=back
=back
Attempts to use the supplied parameters to assign values to a SQL statement that
has already been prepared to accept them. Returns B<0> I<(zero)> on failure and
the database statement handle on success.
=cut
sub bind {
my ($self, %parameters) = @_;
return 0 if(!defined($parameters{HANDLE}));
return 0 if(!defined($parameters{INPUT}));
return 0 if(ref($parameters{INPUT}) !~ /^ARRAY$/i);
return 0 if(!defined($parameters{VALUE}));
return 0 if(ref($parameters{VALUE}) !~ /^HASH$/i);
my $index = 1;
foreach my $input (@{$parameters{INPUT}}) {
if(defined(${$parameters{VALUE}}{${$input}{NAME}})) {
if(defined(${$input}{TYPE})) {
$parameters{HANDLE}->bind_param($index, ${$parameters{VALUE}}{${$input}{NAME}}, ${$input}{TYPE});
} else {
$parameters{HANDLE}->bind_param($index, ${$parameters{VALUE}}{${$input}{NAME}});
}
} elsif(defined(${$input}{DEFAULT})) {
if(defined(${$input}{TYPE})) {
$parameters{HANDLE}->bind_param($index, ${$input}{DEFAULT}, ${$input}{TYPE});
} else {
$parameters{HANDLE}->bind_param($index, ${$input}{DEFAULT});
}
} elsif(defined(${$input}{TYPE})) {
$parameters{HANDLE}->bind_param($index, '', ${$input}{TYPE});
} else {
$parameters{HANDLE}->bind_param($index, '');
}
$index++;
}
return $parameters{HANDLE};
}
=head2 binding
if(1 == Anansi::DatabaseComponent::binding($OBJECT));
if(1 == $OBJECT->binding());
=over 4
=item self I<(Blessed Hash B<or> String, Required)>
Either an object or a string of this namespace.
=item parameters I<(Array, Optional)>
An array of hashes. Each hash should contain a I<NAME> key with a string value.
=back
Verifies that the supplied parameters are all hashes and that they each contain
a I<NAME> key with a string value. Returns B<1> I<(one)> when validity is
confirmed and B<0> I<(zero)> when an invalid structure is determined. Used to
validate the I<INPUT> parameter of the B<bind> method.
=cut
sub binding {
my ($self, @parameters) = @_;
foreach my $parameter (@parameters) {
return 0 if(ref($parameter) !~ /^HASH$/i);
return 0 if(!defined(${$parameter}{NAME}));
return 0 if(ref(${$parameter}{NAME}) !~ /^$/);
return 0 if(${$parameter}{NAME} !~ /^[a-zA-Z_]+(\s*[a-zA-Z0-9_]+)*$/);
}
return 1;
}
=head2 commit
if(1 == Anansi::DatabaseComponent::commit($OBJECT, undef));
if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'COMMIT'));
if(1 == $OBJECT->commit(undef));
if(1 == $OBJECT->channel('COMMIT'));
=over 4
=item self I<(Blessed Hash B<or> String, Required)>
Either an object or a string of this namespace.
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
=item parameters I<(Hash, Optional)>
Named parameters.
=back
Attempts to perform a database commit. Returns B<1> I<(one)> on success and
B<0> I<(zero)> on failure.
=cut
sub commit {
my ($self, $channel, %parameters) = @_;
return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
return 0 if(!defined($self->{HANDLE}));
return 1 if($self->autocommit());
my $commit;
eval {
$commit = $self->{HANDLE}->commit();
1;
} or do {
$self->rollback();
return 0;
};
return 0 if(!defined($commit));
return 0 if(ref($commit) !~ /^$/);
return 0 if($commit !~ /^[\+\-]?\d+$/);
return 1 if($commit);
return 0;
}
Anansi::DatabaseComponent::addChannel('Anansi::DatabaseComponent', 'COMMIT' => 'commit');
=head2 connect
if(1 == Anansi::DatabaseComponent::connect($OBJECT, undef
INPUT => [
'some text',
{
NAME => 'someParameter'
}, {
INPUT => [
'more text',
{
NAME => 'anotherParameter'
},
'yet more text'
]
}, {
DEFAULT => 'abc',
NAME => 'yetAnotherParameter'
}
],
someParameter => 12345,
anotherParameter => 'blah blah blah'
));
if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'CONNECT',
INPUT => [
'blah blah blah',
{
DEFAULT => 123,
NAME => 'someParameter',
}
],
someParameter => 'some text'
));
if(1 == $OBJECT->connect(undef,
INPUT => [
{
INPUT => [
'some text',
{
NAME => 'someParameter'
},
'more text'
]
}
],
someParameter => 'in between'
));
if(1 == $OBJECT->channel('CONNECT',
INPUT => [
{
INPUT => [
{
NAME => 'abc'
}, {
NAME => 'def'
}
},
REF => 'HASH'
}
]
));
=over 4
=item self I<(Blessed Hash, Required)>
An object of this namespace.
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
=item parameters I<(Hash, Required)>
Named parameters.
=over 4
=item HANDLE I<(DBI::db, Optional)>
The database handle of an existing database connection. Used in preference to
the I<INPUT> parameter.
=item INPUT I<(Array B<or> Scalar, Optional)>
An array or single value containing a description of each parameter in the order
that it is passed to the database driver's I<connect> method. Used when the
I<HANDLE> parameter does not exist.
=over 4
=item I<(Non-Hash)>
An element that does not contain a hash value will be used as the corresponding
I<connect> method's parameter value.
=item I<(Hash)>
An element that contains a hash value is assumed to be a description of how to
generate the corresponding I<connect> method's parameter value. when a value
can not be generated, an B<undef> value will be used.
=over 4
=item DEFAULT I<(Optional)>
The value to use if no other value can be determined.
=item INPUT I<(Array B<or> Scalar, Optional)>
Contains a structure like that given in I<INPUT> above with the exception that
any further I<INPUT> keys will be ignored. As this key is only valid when
I<NAME> is undefined and I<REF> either specifies a string or a hash, it's value
will be either a concatenation of all the calculated strings or a hash
containing all of the specified keys and values.
=item NAME I<(String, Optional)>
The name of the parameter that contains the value to use.
=item REF I<(Array B<or> String, Optional)>
The data types used to validate the value to use.
=back
=back
=back
=back
Either uses an existing database connection or attempts to perform a database
connection using the supplied parameters. Returns B<1> I<(one)> on success and
B<0> I<(zero)> on failure.
=cut
sub connect {
my ($self, $channel, %parameters) = @_;
return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
$self->disconnect();
if(defined($parameters{HANDLE})) {
return 0 if(ref($parameters{HANDLE}) !~ /^DBI::db$/);
$self->{HANDLE} = $parameters{HANDLE};
$self->{MANAGE_HANDLE} = 0;
} elsif(!defined($parameters{INPUT})) {
return 0;
} elsif(ref($parameters{INPUT}) !~ /^ARRAY$/i) {
return 0;
} else {
my @inputs;
foreach my $input (@{$parameters{INPUT}}) {
if(ref($input) !~ /^HASH$/i) {
push(@inputs, $input);
next;
}
my $value = undef;
$value = ${$input}{DEFAULT} if(defined(${$input}{DEFAULT}));
if(!defined(${$input}{NAME})) {
if(!defined(${$input}{INPUT})) {
} elsif(ref(${$input}{INPUT}) !~ /^ARRAY$/i) {
} elsif(!defined(${$input}{REF})) {
} elsif(ref(${$input}{REF}) !~ /^$/i) {
} elsif('' eq ${$input}{REF}) {
my @subInputs;
for(my $index = 0; $index < scalar(@{${$input}{INPUT}}); $index++) {
if(ref(${${$input}{INPUT}}[$index]) =~ /^$/i) {
push(@subInputs, ${${$input}{INPUT}}[$index]);
next;
} elsif(ref(${${$input}{INPUT}}[$index]) !~ /^HASH$/) {
next;
}
my $subValue = '';
$subValue = ${${${$input}{INPUT}}[$index]}{DEFAULT} if(defined(${${${$input}{INPUT}}[$index]}{DEFAULT}));
if(!defined(${${${$input}{INPUT}}[$index]}{NAME})) {
} elsif(ref(${${${$input}{INPUT}}[$index]}{NAME}) !~ /^$/) {
} elsif(defined($parameters{${${${$input}{INPUT}}[$index]}{NAME}})) {
if(!defined(${${${$input}{INPUT}}[$index]}{REF})) {
$subValue = $parameters{${${${$input}{INPUT}}[$index]}{NAME}} if('' eq ref($parameters{${${${$input}{INPUT}}[$index]}{NAME}}));
} elsif(ref(${${${$input}{INPUT}}[$index]}{REF}) !~ /^$/) {
} elsif('' ne ${${${$input}{INPUT}}[$index]}{REF}) {
} elsif('' ne ref($parameters{${${${$input}{INPUT}}[$index]}{NAME}})) {
} else {
$subValue = $parameters{${${${$input}{INPUT}}[$index]}{NAME}};
}
}
push(@subInputs, $subValue);
}
$value = join('', @subInputs);
} elsif(${$input}{REF} =~ /^HASH$/i) {
my %subInputs;
foreach my $subInput (@{${$input}{INPUT}}) {
next if(ref($subInput) !~ /^HASH$/i);
my $subValue = undef;
$subValue = ${$subInput}{DEFAULT} if(defined(${$subInput}{DEFAULT}));
if(!defined(${$subInput}{NAME})) {
} elsif(ref(${$subInput}{NAME}) !~ /^$/) {
} elsif(defined($parameters{${$subInput}{NAME}})) {
if(!defined(${$subInput}{REF})) {
} elsif(ref(${$subInput}{REF}) =~ /^ARRAY$/i) {
my %refs = map { $_ => 1 } (@{${$subInput}{REF}});
$subValue = $parameters{${$subInput}{NAME}} if(defined($refs{ref($parameters{${$subInput}{NAME}})}));
} elsif(ref(${$subInput}{REF}) !~ /^$/) {
} elsif(${$subInput}{REF} ne ref($parameters{${$subInput}{NAME}})) {
} else {
$subValue = $parameters{${$subInput}{NAME}};
}
}
$subInputs{${$subInput}{NAME}} = $subValue;
}
$value = \%subInputs;
}
} elsif(ref(${$input}{NAME}) !~ /^$/) {
} elsif(defined($parameters{${$input}{NAME}})) {
if(!defined(${$input}{REF})) {
} elsif(ref(${$input}{REF}) =~ /^ARRAY$/i) {
my %refs = map { $_ => 1 } (@{${$input}{REF}});
if(!defined($refs{ref($parameters{${$input}{NAME}})})) {
} elsif(ref($parameters{${$input}{NAME}}) !~ /^HASH$/i) {
$value = $parameters{${$input}{NAME}};
} else {
if(!defined(${$input}{INPUT})) {
$value = $parameters{${$input}{NAME}};
} elsif(ref(${$input}{INPUT}) !~ /^HASH$/i) {
$value = $parameters{${$input}{NAME}};
} else {
my %subInputs;
foreach my $subInput (keys(%{${$input}{INPUT}})) {
if(ref($subInput) !~ /^HASH$/i) {
$subInputs{$subInput} = $subInput;
next;
}
my $subValue = undef;
$value = ${${${$input}{INPUT}}{$subInput}}{DEFAULT} if(defined(${${${$input}{INPUT}}{$subInput}}{DEFAULT}));
if(!defined(${${${$input}{INPUT}}{$subInput}}{NAME})) {
} elsif(ref(${${${$input}{INPUT}}{$subInput}}{NAME}) !~ /^$/) {
} elsif(defined($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})) {
if(!defined(${${${$input}{INPUT}}{$subInput}}{REF})) {
} elsif(ref(${${${$input}{INPUT}}{$subInput}}{REF}) =~ /^ARRAY$/i) {
my %refs = map { $_ => 1 } (@{${${${$input}{INPUT}}{$subInput}}{REF}});
$subValue = $parameters{${${${$input}{INPUT}}{$subInput}}{NAME}} if(defined($refs{ref($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})}));
} elsif(ref(${${${$input}{INPUT}}{$subInput}}{REF}) !~ /^$/) {
} elsif(${${${$input}{INPUT}}{$subInput}}{REF} ne ref($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})) {
} else {
$subValue = $parameters{${${${$input}{INPUT}}{$subInput}}{NAME}};
}
}
$subInputs{$subInput} = $subValue;
}
$value = \%subInputs;
}
}
} elsif(ref(${$input}{REF}) !~ /^$/) {
} elsif(${$input}{REF} ne ref($parameters{${$input}{NAME}})) {
} elsif(ref($parameters{${$input}{NAME}}) !~ /^HASH$/i) {
$value = $parameters{${$input}{NAME}};
} else {
if(!defined(${$input}{INPUT})) {
$value = $parameters{${$input}{NAME}};
} elsif(ref(${$input}{INPUT}) !~ /^HASH$/i) {
$value = $parameters{${$input}{NAME}};
} else {
my %subInputs;
foreach my $key (keys(%{${$input}{INPUT}})) {
if(ref($subInput) !~ /^HASH$/i) {
push(@subInputs, $subInput);
next;
}
my $subValue = undef;
$value = ${${${$input}{INPUT}}{$subInput}}{DEFAULT} if(defined(${${${$input}{INPUT}}{$subInput}}{DEFAULT}));
if(!defined(${${${$input}{INPUT}}{$subInput}}{NAME})) {
} elsif(ref(${${${$input}{INPUT}}{$subInput}}{NAME}) !~ /^$/) {
} elsif(defined($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})) {
if(!defined(${${${$input}{INPUT}}{$subInput}}{REF})) {
} elsif(ref(${${${$input}{INPUT}}{$subInput}}{REF}) =~ /^ARRAY$/i) {
my %refs = map { $_ => 1 } (@{${${${$input}{INPUT}}{$subInput}}{REF}});
$subValue = $parameters{${${${$input}{INPUT}}{$subInput}}{NAME}} if(defined($refs{ref($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})}));
} elsif(ref(${${${$input}{INPUT}}{$subInput}}{REF}) !~ /^$/) {
} elsif(${${${$input}{INPUT}}{$subInput}}{REF} ne ref($parameters{${${${$input}{INPUT}}{$subInput}}{NAME}})) {
} else {
$subValue = $parameters{${${${$input}{INPUT}}{$subInput}}{NAME}};
}
}
$subInputs{$subInput} = $subValue;
}
$value = \%subInputs;
}
}
}
push(@inputs, $value);
}
return 0 if(0 == scalar(@inputs));
my $handle = DBI->connect(@inputs);
return 0 if(!defined($handle));
$self->{HANDLE} = $handle;
$self->{MANAGE_HANDLE} = 1;
}
return 1;
}
Anansi::DatabaseComponent::addChannel('Anansi::DatabaseComponent', 'CONNECT' => 'connect');
=head2 disconnect
if(1 == Anansi::DatabaseComponent::disconnect($OBJECT, undef));
if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'DISCONNECT'));
if(1 == $OBJECT->disconnect(undef));
if(1 == $OBJECT->channel('DISCONNECT'));
=over 4
=item self I<(Blessed Hash B<or> String, Required)>
Either an object or a string of this namespace.
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
=item parameters I<(Hash, Optional)>
Named parameters.
=back
Attempts to perform a database disconnection. Returns B<1> I<(one)> on success
and B<0> I<(zero)> on failure.
=cut
sub disconnect {
my ($self, $channel, %parameters) = @_;
return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
return 0 if(!defined($self->{HANDLE}));
if(!defined($self->{MANAGE_HANDLE})) {
$self->{MANAGE_HANDLE} = 0;
lib/Anansi/DatabaseComponent.pm view on Meta::CPAN
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
=item handle I<(DBI::db, Optional)>
A replacement database handle.
=back
Attempts to redefine an existing database handle when a handle is supplied.
Either returns the database handle or B<undef> on failure.
=cut
sub handle {
my ($self, $channel, $handle) = @_;
return if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
if(defined($handle)) {
if(defined($self->{HANDLE})) {
$self->finish();
$self->disconnect();
}
return if(ref($handle) !~ /^DBI::db$/);
$self->{HANDLE} = $handle;
$self->{MANAGE_HANDLE} = 0;
}
return $self->{HANDLE} if(defined($self->{HANDLE}));
return;
}
Anansi::DatabaseComponent::addChannel('Anansi::DatabaseComponent', 'HANDLE' => 'handle');
=head2 initialise
Overrides L<Anansi::Class::initialise|Anansi::Class/"initialise">. A virtual method.
=cut
sub initialise {
my ($self, %parameters) = @_;
Anansi::Actor->new(
PACKAGE => 'DBI',
);
$self->{STATEMENT} = {};
}
=head2 prepare
my $PREPARATION = if(1 == Anansi::DatabaseComponent::prepare($OBJECT, undef,
STATEMENT => 'an associated name'
);
if(defined($PREPARATION));
if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'PREPARE',
INPUT => [
{
NAME => 'someParameter'
}
],
SQL => 'SELECT abc, def FROM some_table WHERE ghi = ?',
STATEMENT => 'another associated name'
));
if(1 == $OBJECT->prepare(undef,
INPUT => [
{
NAME => 'abc'
}, {
NAME => 'def'
}, {
NAME => 'ghi'
}
],
SQL => 'INSERT INTO some_table (abc, def, ghi) VALUES (?, ?, ?);',
STATEMENT => 'yet another name'
));
if(1 == $OBJECT->channel('PREPARE',
INPUT => [
{
NAME => ''
}
],
SQL => '',
STATEMENT => 'and another',
));
=over 4
=item self I<(Blessed Hash, Required)>
Either an object or a string of this namespace.
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
=item parameters I<(Hash, Required)>
Named parameters.
=over 4
=item INPUT I<Array, Optional>
An array of hashes. Each hash should contain a I<NAME> key with a string value
that represents the name of a parameter to associate with the corresponding B<?>
I<(Question mark)>. See the I<bind> method for details.
=item SQL I<(String, Optional)>
The SQL statement to prepare.
=item STATEMENT I<(String, Required)>
The name to associate with the prepared SQL statement.
=back
=back
Attempts to prepare a SQL statement to accept named parameters in place of B<?>
I<(Question mark)>s as required. Either returns all of the preparation data
required to fulfill the SQL statement when called as a namespace method or B<1>
I<(one)> when called through a channel on success and B<0> I<(zero)> on failure.
=cut
sub prepare {
my ($self, $channel, %parameters) = @_;
return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
$self->{STATEMENTS} = {} if(!defined($self->{STATEMENTS}));
return 0 if(!defined($parameters{STATEMENT}));
return 0 if(ref($parameters{STATEMENT}) !~ /^$/);
if(!defined(${$self->{STATEMENTS}}{$parameters{STATEMENT}})) {
return 0 if(!defined($parameters{SQL}));
return 0 if(ref($parameters{SQL}) !~ /^$/);
$parameters{SQL} =~ s/^\s*(.*)|(.*)\s*$/$1/g;
my $questionMarks = $parameters{SQL};
my $questionMarks = $questionMarks =~ s/\?/$1/sg;
if(0 == $questionMarks) {
return 0 if(defined($parameters{INPUT}));
} elsif(!defined($parameters{INPUT})) {
return 0;
} elsif(ref($parameters{INPUT}) !~ /^ARRAY$/i) {
return 0;
} elsif(scalar(@{$parameters{INPUT}}) != $questionMarks) {
return 0;
} else {
return 0 if(!$self->binding((@{$parameters{INPUT}})));
}
my $handle;
eval {
$handle = $self->{HANDLE}->prepare($parameters{SQL});
1;
} or do {
$self->rollback();
return 0;
};
my %statement = (
HANDLE => $handle,
SQL => $parameters{SQL},
);
$statement{INPUT} = $parameters{INPUT} if(defined($parameters{INPUT}));
${$self->{STATEMENTS}}{$parameters{STATEMENT}} = \%statement;
}
return 1 if(defined($channel));
return ${$self->{STATEMENTS}}{$parameters{STATEMENT}};
}
Anansi::DatabaseComponent::addChannel('Anansi::DatabaseComponent', 'PREPARE' => 'prepare');
=head2 removeChannel
Overrides L<Anansi::Component::removeChannel|Anansi::Component/"removeChannel">.
=cut
sub removeChannel {
my ($self, %parameters) = @_;
return $self->SUPER::removeChannel((%parameters));
}
=head2 rollback
if(1 == Anansi::DatabaseComponent::rollback($OBJECT, undef));
if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'ROLLBACK'));
if(1 == $OBJECT->rollback(undef));
if(1 == $OBJECT->channel('ROLLBACK'));
=over 4
=item self I<(Blessed Hash, Required)>
Either an object or a string of this namespace.
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
=item parameters I<(Hash, Optional)>
Named parameters.
=back
Attempts to undo all of the database changes since the last database I<commit>.
Returns B<1> I<(one)> on success and B<0> I<(zero)> on failure.
=cut
sub rollback {
my ($self, $channel, %parameters) = @_;
return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
return 0 if($self->autocommit());
my $rollback;
eval {
lib/Anansi/DatabaseComponent.pm view on Meta::CPAN
=item self I<(Blessed Hash, Required)>
Either an object or a string of this namespace.
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
=item parameters I<(Hash, Required)>
Named parameters.
=over 4
=item SCRIPT I<(Array, Required)>
The SQL statements, control structures and external process triggers that are
iterated through in sequence.
=over 4
=item I<(Array)>
A sequence of statements like the I<SCRIPT> parameter.
=item I<(Hash)>
Either a SQL statement, control structure or external process trigger.
=over 4
=item COMMAND I<(String, Required)>
A script command.
=over 4
=item B<"LOOP">
Describes how to iterate over the subsequent sequence statement.
=item B<"RUN">
Describes how to perform an external subroutine.
=item B<"SET">
Describes how to define or redefine script variables.
=item B<"SQL">
Describes a specific SQL statement and it's interaction requirements.
=item B<"TEST">
Describes whether to perform the subsequent sequence statement.
=back
=item INPUT I<(Array B<or> String, Optional)>
An array of strings or a string containing the variables or variable data. Only
used when I<COMMAND> contains B<"LOOP">, B<"RUN"> or B<"SQL">.
=item NAME I<(String, Optional)
A sequence name associated with the SQL statement, control structure or external
process trigger. When I<COMMAND> is B<"LOOP">, represents the name of a script
variable hash that will contain the current I<ITERATION> of the loop starting at
B<0> I<(zero)>, how many I<ITERATIONS> the loop is expected to perform a B<1>
I<(one)> or greater or a B<0> I<(zero)> for indeterminate and the I<INPUT> value
to use in the iteration or B<undef> if indeterminate. When I<COMMAND> is B<"RUN">
, represents the name of a script variable that will contain the results of the
trigger. When I<COMMAND> is B<"TEST">, represents the name of a script variable
that will either contain the result of the current test or the name of a script
variable that should be used to determine whether the sequence statement should
be performed.
=item SQL I<(String, Optional)>
A SQL statement like that described in the I<statement> method's I<SQL>
parameter. Only used when I<COMMAND> contains B<"SQL">.
=item STATEMENT I<(String, Optional)>
The name associated with a SQL statement like that described in the I<statement>
method's I<STATEMENT> parameter. Only used when I<COMMAND> contains B<"SQL">.
=item TRIGGER I<(String, Optional)>
N/A
=item VALUE I<Array B<or> Hash, Optional>
Either an array of hashes or a hash representing specific script variables and
variable data. Only used when I<COMMAND> contains B<"LOOP">, B<"SET"> or B<"TEST">.
When I<COMMAND> is B<"LOOP">, all of the referenced script variables must equate
to the referenced values for the body of the loop to iterate. When I<COMMAND>
is B<"SET">, all of the referenced script variables are either declared or
redeclared to contain the referenced values. When I<COMMAND> is B<"TEST">, all of
the referenced script variables must equate to the referenced values for the
body of the if to iterate.
=back
=back
=back
=back
Combines SQL statements together with a way to process them dynamically, making
it possible to perform compound database tasks without needing to resort to
using database functions or Perl subroutines.
#=cut
sub script {
my ($self, $channel, %parameters) = @_;
my ($VARIABLES);
sub scriptCommand {
}
sub scriptLocalBegin {
$VARIABLES = [] if(!defined($VARIABLES));
$VARIABLES = [] if(ref($VARIABLES) !~ /^ARRAY$/i);
for(my $index = 0; $index < scalar(@{$VARIABLES}); $index++) {
$VARIABLES[$index] = {} if(ref($VARIABLES[$index]) !~ /^HASH$/i);
}
lib/Anansi/DatabaseComponent.pm view on Meta::CPAN
}
sub scriptValidate {
}
sub scriptVariable {
}
sub block {
my (undef, @commands) = @_;
${$_[0]}{'_'} = [] if(!defined(${$_[0]}{'_'}));
push(@{${$_[0]}{'_'}}, {});
${${${$_[0]}{'_'}}[-1]}{COMMANDS} = [( @commands )];
for(my $index = 0; $index < scalar(@commands); $index++) {
my $command = $commands[$index];
if(ref($command) =~ /^ARRAY$/i) {
${${${$_[0]}{'_'}}[-1]}{INDEX} = $INDEX;
block($_[0], (@{$command}));
}
next if(ref($command) !~ /^HASH$/i);
next if(!defined($command{COMMAND}));
next if(ref($command{COMMAND}) !~ /^$/);
if(!defined($command{NAME})) {
} elsif(ref($command{NAME}) !~ /^$/) {
delete $command{NAME};
} elsif($command{NAME} =~ /^\s*$/) {
delete $command{NAME};
} elsif(0 == 1) {
} else {
${${${$_[0]}{'_'}}[-1]}{NAME} = $command{NAME};
}
if($command{COMMAND} =~ /^LOOP$/i) {
} elsif($command{COMMAND} =~ /^RUN$/i) {
} elsif($command{COMMAND} =~ /^SET$/i) {
} elsif($command{COMMAND} =~ /^SQL$/i) {
} elsif($command{COMMAND} =~ /^TEST$/i) {
}
}
pop(@{${$_[0]}{'_'}});
delete ${$_[0]}{'_'} if(0 == scalar(@{${$_[0]}{'_'}}));
}
return if(!defined($parameters{SCRIPT}));
return if(ref($parameters{SCRIPT}) !~ /^ARRAY$/i);
my $variables = {};
foreach my $key (keys(%parameters)) {
$variables{$key} = $parameters{$key};
}
block($variables, (@{$parameters{SCRIPT}}));
}
Anansi::DatabaseComponent::addChannel('Anansi::DatabaseComponent', 'SCRIPT' => 'script');
################################################################################
=end comment
=head2 statement
my $result = Anansi::DatabaseComponent::statement($OBJECT, undef,
INPUT => [
'hij' => 'someParameter',
'klm' => 'anotherParameter'
],
SQL => 'SELECT abc, def FROM some_table WHERE hij = ? AND klm = ?;',
STATEMENT => 'someStatement',
someParameter => 123,
anotherParameter => 456
);
my $result = Anansi::DatabaseComponent::channel($OBJECT, 'STATEMENT',
STATEMENT => 'someStatement',
someParameter => 234,
anotherParameter => 'abc'
);
my $result = $OBJECT->statement(
undef,
STATEMENT => 'someStatement',
someParameter => 345,
anotherParameter => 789
);
my $result = $OBJECT->channel('STATEMENT',
STATEMENT => 'someStatement',
someParameter => 456,
anotherParameter => 'def'
);
=over 4
=item self I<(Blessed Hash, Required)>
Either an object or a string of this namespace.
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
=item parameters I<(Hash, Optional)>
Named parameters.
=over 4
=item INPUT I<(Array, Optional)>
An array of hashes with each element corresponding to an equivalent B<?>
I<(Question mark)> found within the supplied I<SQL>. If the number of elements
is not the same as the number of B<?> I<(Question mark)>s found in the statement
then the statement is invalid. See the I<bind> method for details.
=item SQL I<(String, Optional)>
The SQL statement to execute.
=item STATEMENT I<(String, Optional)>
The name associated with a prepared SQL statement. This is interchangeable with
the SQL parameter but helps to speed up repetitive database interaction.
=back
=back
Attempts to execute the supplied I<SQL> with the supplied named parameters.
Either returns an array of retrieved record data or a B<1> I<(one)> on success
and a B<0> I<(zero)> on failure as appropriate to the SQL statement.
=cut
sub statement {
my ($self, $channel, %parameters) = @_;
return 0 if(ref($self) =~ /^(|ARRAY|CODE|FORMAT|GLOB|HASH|IO|LVALUE|REF|Regexp|SCALAR|VSTRING)$/i);
my $prepared = $self->prepare(undef, (%parameters));
my $handle;
if($prepared) {
$handle = ${$prepared}{HANDLE};
if(defined(${$prepared}{INPUT})) {
my $bound = $self->bind(
HANDLE => $handle,
INPUT => ${$prepared}{INPUT},
VALUE => \%parameters,
);
return 0 if(!$bound);
}
} else {
eval {
$handle = $self->{HANDLE}->prepare($parameters{SQL});
1;
} or do {
$self->rollback();
return 0;
};
my $questionMarks = $parameters{SQL};
my $questionMarks = $questionMarks =~ s/\?/$1/sg;
if(0 == $questionMarks) {
if(defined($parameters{INPUT})) {
$self->rollback();
return 0;
}
} elsif(!defined($parameters{INPUT})) {
$self->rollback();
return 0;
} elsif(ref($parameters{INPUT}) !~ /^ARRAY$/i) {
$self->rollback();
return 0;
} elsif(scalar(@{$parameters{INPUT}}) != $questionMarks) {
$self->rollback();
return 0;
} else {
if(!$self->bind(
HANDLE => $handle,
INPUT => $parameters{INPUT},
VALUE => \%parameters,
)) {
$self->rollback();
return 0;
}
}
}
eval {
$handle->execute();
1;
} or do {
$handle->rollback();
return 0;
};
if(!defined($handle->{NUM_OF_FIELDS})) {
return 1;
} elsif(undef == $handle->{NUM_OF_FIELDS}) {
return 1;
} elsif(0 == $handle->{NUM_OF_FIELDS}) {
return 1;
}
my $result = [];
while(my $row = $handle->fetchrow_hashref()) {
push(@{$result}, $row);
}
$handle->finish() if(!$prepared);
return $result;
}
Anansi::DatabaseComponent::addChannel('Anansi::DatabaseComponent', 'STATEMENT' => 'statement');
=head2 validate
if(1 == Anansi::DatabaseComponent::validate($OBJECT, undef));
if(1 == Anansi::DatabaseComponent::channel($OBJECT, 'VALIDATE_AS_APPROPRIATE'));
if(1 == Anansi::DatabaseComponent->validate(undef, DRIVERS => ['some::driver::module', 'anotherDriver']));
if(1 == Anansi::DatabaseComponent->channel('VALIDATE_AS_APPROPRIATE'));
if(1 == $OBJECT->validate(undef, DRIVER => 'Example'));
if(1 == $OBJECT->channel('VALIDATE_AS_APPROPRIATE', DRIVER => 'Example'));
if(1 == Anansi::DatabaseComponent->validate(undef, DRIVER => 'Example', DRIVERS => 'some::driver'));
if(1 == Anansi::DatabaseComponent->channel('VALIDATE_AS_APPROPRIATE', DRIVER => 'Example'));
=over 4
=item self I<(Blessed Hash B<or> String, Required)>
Either an object or a string of this namespace.
=item channel I<(String, Required)>
The abstract identifier of a subroutine.
( run in 1.873 second using v1.01-cache-2.11-cpan-e93a5daba3e )