Alzabo
view release on metacpan or search on metacpan
lib/Alzabo/Runtime/Schema.pm view on Meta::CPAN
@{ $p{select} } : $p{select} ) :
$p{distinct} ?
@{ $p{distinct} } :
@tables );
my $sql = Alzabo::Runtime::sqlmaker( $self, \%p );
my @select_cols;
if ( $p{distinct} )
{
my %distinct = map { $_ => 1 } @{ $p{distinct} };
# hack so distinct is not treated as a function, just a
# bareword in the SQL
@select_cols = ( 'DISTINCT',
map { ( $_->primary_key,
$_->prefetch ?
$_->columns( $_->prefetch ) :
() ) }
@{ $p{distinct} }
);
foreach my $t (@select_tables)
{
next if $distinct{$t};
push @select_cols, $t->primary_key;
push @select_cols, $t->columns( $t->prefetch ) if $t->prefetch;
}
if ( $p{order_by} && $sql->distinct_requires_order_by_in_select )
{
my %select_cols = map { $_ => 1 } @select_cols;
push @select_cols, grep { ref } @{ $p{order_by} };
}
@select_tables = ( @{ $p{distinct} }, grep { ! $distinct{$_} } @select_tables );
}
else
{
@select_cols =
( map { ( $_->primary_key,
$_->prefetch ?
$_->columns( $_->prefetch ) :
() ) }
@select_tables );
}
$sql->select(@select_cols);
$self->_join_all_tables( sql => $sql,
join => $p{join} );
Alzabo::Runtime::process_where_clause( $sql, $p{where} ) if exists $p{where};
Alzabo::Runtime::process_order_by_clause( $sql, $p{order_by} )
if $p{order_by};
$sql->limit( ref $p{limit} ? @{ $p{limit} } : $p{limit} ) if $p{limit};
$sql->debug(\*STDERR) if Alzabo::Debug::SQL;
print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
my $statement = $self->driver->statement( sql => $sql->sql,
bind => $sql->bind );
if (@select_tables == 1)
{
return Alzabo::Runtime::RowCursor->new
( statement => $statement,
table => $select_tables[0]->real_table,
);
}
else
{
return Alzabo::Runtime::JoinCursor->new
( statement => $statement,
tables => [ map { $_->real_table } @select_tables ],
);
}
}
sub row_count
{
my $self = shift;
my %p = @_;
return $self->function( select => Alzabo::Runtime::sqlmaker( $self, \%p )->COUNT('*'),
%p,
);
}
sub function
{
my $self = shift;
my %p = @_;
my $sql = $self->_select_sql(%p);
my $method =
Alzabo::Utils::is_arrayref( $p{select} ) && @{ $p{select} } > 1 ? 'rows' : 'column';
$sql->debug(\*STDERR) if Alzabo::Debug::SQL;
print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
return $self->driver->$method( sql => $sql->sql,
bind => $sql->bind );
}
sub select
{
my $self = shift;
my $sql = $self->_select_sql(@_);
$sql->debug(\*STDERR) if Alzabo::Debug::SQL;
print STDERR Devel::StackTrace->new if Alzabo::Debug::TRACE;
return $self->driver->statement( sql => $sql->sql,
bind => $sql->bind );
}
use constant _SELECT_SQL_SPEC => { join => { type => ARRAYREF | OBJECT,
optional => 1 },
tables => { type => ARRAYREF | OBJECT,
optional => 1 },
select => { type => SCALAR | ARRAYREF | OBJECT,
optional => 1 },
where => { type => ARRAYREF,
optional => 1 },
group_by => { type => ARRAYREF | HASHREF | OBJECT,
optional => 1 },
order_by => { type => ARRAYREF | HASHREF | OBJECT,
optional => 1 },
having => { type => ARRAYREF,
optional => 1 },
limit => { type => SCALAR | ARRAYREF,
optional => 1 },
quote_identifiers => { type => BOOLEAN,
optional => 1 },
};
sub _select_sql
{
my $self = shift;
my %p = validate( @_, _SELECT_SQL_SPEC );
$p{join} ||= delete $p{tables};
$p{join} = [ $p{join} ] unless Alzabo::Utils::is_arrayref( $p{join} );
my @tables;
if ( Alzabo::Utils::is_arrayref( $p{join}->[0] ) )
{
# flattens the nested structure and produces a unique set of
# tables
@tables = values %{ { map { $_ => $_ }
grep { Alzabo::Utils::safe_isa( 'Alzabo::Table', $_ ) }
map { @$_ } @{ $p{join} } } };
}
else
{
@tables = grep { Alzabo::Utils::safe_isa( 'Alzabo::Table', $_ ) } @{ $p{join} };
}
my @funcs = Alzabo::Utils::is_arrayref( $p{select} ) ? @{ $p{select} } : $p{select};
my $sql = ( Alzabo::Runtime::sqlmaker( $self, \%p )->
select(@funcs) );
$self->_join_all_tables( sql => $sql,
join => $p{join} );
Alzabo::Runtime::process_where_clause( $sql, $p{where} )
if exists $p{where};
( run in 1.935 second using v1.01-cache-2.11-cpan-39bf76dae61 )