DBIx-DBO

 view release on metacpan or  search on metacpan

lib/DBIx/DBO/Row.pm  view on Meta::CPAN

package DBIx::DBO::Row;

use 5.014;
use warnings;
use DBIx::DBO;

use Carp 'croak';
use Scalar::Util qw(blessed weaken);
use Storable ();

use overload '@{}' => sub {${$_[0]}->{array} || []}, '%{}' => sub {${$_[0]}->{hash}}, fallback => 1;

sub query_class { ${$_[0]}->{DBO}->query_class }

*_isa = \&DBIx::DBO::DBD::_isa;

=head1 NAME

DBIx::DBO::Row - An OO interface to SQL queries and results.  Encapsulates a fetched row of data in an object.

=head1 SYNOPSIS

  # Create a Row object for the `users` table
  my $row = $dbo->row('users');
  
  # Load my record
  $row->load(login => 'vlyon') or die "Where am I?";
  
  # Double my salary :)
  $row->update(salary => {FUNC => '? * 2', COL => 'salary'});
  
  # Print my email address
  print $row->{email};
  
  # Delete my boss
  $row->load(id => $row->{boss_id})->delete or die "Can't kill the boss";

=head1 METHODS

=head3 C<new>

  DBIx::DBO::Row->new($dbo, $table);
  DBIx::DBO::Row->new($dbo, $query_object);

Create and return a new C<Row> object.
The object returned represents rows in the given table/query.
Can take the same arguments as L<DBIx::DBO::Query/new> or a L<Query|DBIx::DBO::Query> object can be used.

=cut

sub new {
    my $proto = shift;
    eval { $_[0]->isa('DBIx::DBO') } or croak 'Invalid DBO Object for new Row';
    my $class = ref($proto) || $proto;
    $class->_init(@_);
}

sub _init {
    my($class, $dbo, @args) = @_;

    my $me = bless \{ DBO => $dbo, array => undef, hash => {} }, $class;
    my $parent = (@args == 1 and _isa($args[0], 'DBIx::DBO::Query'))
    ? $args[0]
    : $me->query_class->new($dbo, @args);

    if ($parent->isa('DBIx::DBO::Query')) {
        croak 'This query is from a different DBO connection' if $parent->{DBO} != $dbo;
        # We must weaken this to avoid a circular reference
        $$me->{Parent} = $parent;
        weaken $$me->{Parent};
        # Add a weak ref onto the list of attached_rows to release freed rows
        push @{ $$me->{Parent}{attached_rows} }, $me;
        weaken $$me->{Parent}{attached_rows}[-1];
    } else {
        croak 'Invalid parent for new Row';
    }
    return wantarray ? ($me, $me->tables) : $me;
}

sub _build_data {
    ${$_[0]}->{build_data} // ${$_[0]}->{Parent}{build_data};
}

=head3 C<tables>

Return a list of L<Table|DBIx::DBO::Table> objects for this row.

=cut

sub tables {
    my $me = $_[0];
    return @{ ${exists $$me->{Parent} ? $$me->{Parent} : $$me}{Tables} };
}

sub _table_idx {
    my($me, $tbl) = @_;
    my $tables = ${exists $$me->{Parent} ? $$me->{Parent} : $$me}{Tables};
    for my $i (0 .. $#$tables) {
        return $i if $tbl == $tables->[$i];
    }
    return undef;
}

sub _table_alias {
    my($me, $tbl) = @_;
    return undef if $tbl == $me;
    my $i = $me->_table_idx($tbl);
    croak 'The table is not in this query' unless defined $i;
    return $me->tables > 1 ? 't'.($i + 1) : ();
}

=head3 C<columns>

Return a list of column names.

=cut

sub columns {
    my($me) = @_;

    return $$me->{Parent}->columns if exists $$me->{Parent};

    $$me->{Columns} //= [
        @{$me->_build_data->{select}}
        ? map {
                _isa($_, 'DBIx::DBO::Table', 'DBIx::DBO::Query') ? ($_->columns) : $me->_build_col_val_name(@$_)
            } @{$me->_build_data->{select}}
        : map { $_->columns } $me->tables
    ];

    @{$$me->{Columns}};
}



( run in 2.812 seconds using v1.01-cache-2.11-cpan-5c0b1e786e0 )