Anansi-DatabaseComponent

 view release on metacpan or  search on metacpan

lib/Anansi/DatabaseComponent.pm  view on Meta::CPAN



sub addChannel {
    my ($self, %parameters) = @_;
    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);

lib/Anansi/DatabaseComponent.pm  view on Meta::CPAN


    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.

lib/Anansi/DatabaseComponent.pm  view on Meta::CPAN

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)>



( run in 3.111 seconds using v1.01-cache-2.11-cpan-2398b32b56e )