Alzabo
view release on metacpan or search on metacpan
lib/Alzabo/MethodMaker.pm view on Meta::CPAN
my $name = $self->_make_method
( type => 'lookup_columns',
class => $self->{row_class},
returns => 'scalar value of column',
code =>
sub { my $self = shift;
my $row = $self->rows_by_foreign_key( foreign_key => $fk, @_ );
return unless $row;
return $row->select($col_name) },
foreign_key => $fk,
column => $_,
) or next;
$self->{row_class}->add_method_docs
( Alzabo::MethodDocs->new
( name => $name,
group => 'Methods that follow a lookup table',
description =>
"returns the value of " . (join '.', $fk->table_to->name, $col_name) . " for the given row by following the foreign key relationship",
spec => 'same as Alzabo::Runtime::Table->rows_where',
) );
}
}
sub make_hooks
{
my $self = shift;
my $table = shift;
my $type = shift;
my $class = $type eq 'insert' ? $self->{table_class} : $self->{row_class};
my $pre = "pre_$type";
my $post = "post_$type";
return unless $class->can($pre) || $class->can($post);
my $method = join '::', $class, $type;
{
no strict 'refs';
return if *{$method}{CODE};
}
print STDERR "Making $type hooks method $class\->$type\n"
if Alzabo::Debug::METHODMAKER;
my $meth = "make_$type\_hooks";
$self->$meth($table);
}
sub make_insert_hooks
{
my $self = shift;
my $code = '';
$code .= " return \$s->schema->run_in_transaction( sub {\n";
$code .= " my \$new;\n";
$code .= " \$s->pre_insert(\\\%p);\n" if $self->{table_class}->can('pre_insert');
$code .= " \$new = \$s->SUPER::insert(\%p);\n";
$code .= " \$s->post_insert({\%p, row => \$new});\n" if $self->{table_class}->can('post_insert');
$code .= " return \$new;\n";
$code .= " } );\n";
eval <<"EOF";
{
package $self->{table_class};
sub insert
{
my \$s = shift;
my \%p = \@_;
$code
}
}
EOF
Alzabo::Exception::Eval->throw( error => $@ ) if $@;
my $hooks =
$self->_hooks_doc_string( $self->{table_class}, 'pre_insert', 'post_insert' );
$self->{table_class}->add_class_docs
( Alzabo::ClassDocs->new
( group => 'Hooks',
description => "$hooks",
) );
}
sub _hooks_doc_string
{
my $self = shift;
my ($class, $hook1, $hook2) = @_;
my @hooks;
push @hooks, $hook1 if $class->can($hook1);
push @hooks, $hook2 if $class->can($hook2);
my $hooks = 'has';
$hooks .= @hooks > 1 ? '' : ' a ';
$hooks .= join ' and ', @hooks;
$hooks .= @hooks > 1 ? ' hooks' : ' hook';
return $hooks;
}
sub make_update_hooks
{
my $self = shift;
my $code = '';
$code .= " \$s->schema->run_in_transaction( sub {\n";
$code .= " \$s->pre_update(\\\%p);\n" if $self->{row_class}->can('pre_update');
$code .= " \$s->SUPER::update(\%p);\n";
$code .= " \$s->post_update(\\\%p);\n" if $self->{row_class}->can('post_update');
$code .= " } );\n";
eval <<"EOF";
{
package $self->{row_class};
sub update
{
my \$s = shift;
my \%p = \@_;
$code
}
}
EOF
Alzabo::Exception::Eval->throw( error => $@ ) if $@;
my $hooks =
$self->_hooks_doc_string( $self->{row_class}, 'pre_update', 'post_update' );
$self->{row_class}->add_class_docs
( Alzabo::ClassDocs->new
( group => 'Hooks',
description => "$hooks",
) );
}
sub make_select_hooks
{
my $self = shift;
my ($pre, $post) = ('', '');
$pre = " \$s->pre_select(\\\@cols);\n"
if $self->{row_class}->can('pre_update');
$post = " \$s->post_select(\\\%r);\n"
if $self->{row_class}->can('post_update');
eval <<"EOF";
{
package $self->{row_class};
sub select
{
my \$s = shift;
my \@cols = \@_;
return \$s->schema->run_in_transaction( sub {
$pre
my \@r;
my %r;
if (wantarray)
{
\@r{ \@cols } = \$s->SUPER::select(\@cols);
}
else
{
\$r{ \$cols[0] } = (scalar \$s->SUPER::select(\$cols[0]));
}
$post
return wantarray ? \@r{\@cols} : \$r{ \$cols[0] };
} );
}
sub select_hash
{
my \$s = shift;
my \@cols = \@_;
return \$s->schema->run_in_transaction( sub {
$pre
my \%r = \$s->SUPER::select_hash(\@cols);
$post
return \%r;
} );
}
}
EOF
Alzabo::Exception::Eval->throw( error => $@ ) if $@;
my $hooks =
$self->_hooks_doc_string( $self->{row_class}, 'pre_select', 'post_select' );
$self->{row_class}->add_class_docs
( Alzabo::ClassDocs->new
( group => 'Hooks',
description => "$hooks",
) );
}
sub make_delete_hooks
{
my $self = shift;
my $code = '';
$code .= " \$s->schema->run_in_transaction( sub {\n";
$code .= " \$s->pre_delete(\\\%p);\n" if $self->{row_class}->can('pre_delete');
$code .= " \$s->SUPER::delete(\%p);\n";
$code .= " \$s->post_delete(\\\%p);\n" if $self->{row_class}->can('post_delete');
$code .= " } );\n";
eval <<"EOF";
package $self->{row_class};
sub delete
{
my \$s = shift;
my \%p = \@_;
$code
}
EOF
Alzabo::Exception::Eval->throw( error => $@ ) if $@;
my $hooks =
$self->_hooks_doc_string( $self->{row_class}, 'pre_delete', 'post_delete' );
$self->{row_class}->add_class_docs
( Alzabo::ClassDocs->new
( group => 'Hooks',
description => "$hooks",
) );
}
sub name
{
my $self = shift;
my %p = @_;
return $p{table}->name if $p{type} eq 'table';
return $p{column}->name if $p{type} eq 'table_column';
return $p{column}->name if $p{type} eq 'row_column';
if ( $p{type} eq 'foreign_key' )
{
return $p{foreign_key}->table_to->name;
}
if ( $p{type} eq 'linking_table' )
{
my $method = $p{foreign_key}->table_to->name;
my $tname = $p{foreign_key}->table_from->name;
$method =~ s/^$tname\_?//;
$method =~ s/_?$tname$//;
return $method;
}
return join '_', map { lc $_->name } $p{foreign_key}->table_to, $p{column}
if $p{type} eq 'lookup_columns';
return $p{column}->name if $p{type} eq 'lookup_columns';
return $p{parent} ? 'parent' : 'children'
( run in 0.508 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )