Ambrosia
view release on metacpan or search on metacpan
lib/Ambrosia/EntityDataModel.pm view on Meta::CPAN
return new Ambrosia::core::Nil unless $driver;
my $q = $driver->reset()
->source( $self->source_path() )
->update()
->what( $self->fields_mapping() );
foreach ( pare_list($self->key, $self->key_value) )
{
$q->predicate($_->[0], '=', $_->[1]);
}
$q->execute($self->value($self->edit_fields));
}
sub find
{
my $proto = shift;
my $class = ref($proto) || $proto;
my $var = shift || my $entity;
my $driver = storage->driver($class->driver_type, $class->source_name);
assert {$driver} 'Unknown source for find data: ' . ($class->source_name || 'undefined source');
return new Ambrosia::core::Nil unless $driver;
my $source_path = join '_', grep defined $_, $class->source_path();
return Ambrosia::EntityDataModel::_find->new(
edm => $class,
var => \$var,
query => Ambrosia::QL
->from([$class->source_path()], \$var)
->in($driver)
->what($class->fields_mapping)
->select(sub {
my %h = map { my $v = $var->{$_}; s/^${source_path}_//; $_ => $v } keys %$var;
%$var = %h;
if ( my $old = $driver->cache->get($class->get_cache_code($class->id_value_from_hash(\%h))) )
{
return $old;
}
my $e = $class->new(%h);
$driver->cache->set($e->get_cache_code, $e);
$e->after_load;
return $e;
})
);
}
sub link_one2one
{
no strict 'refs';
my $proto = shift;
my %params = @_;
my $type = $params{type};
my $pk = $params{from};
my $yeld = $params{optional}
? sub {new Ambrosia::core::Nil}
: sub {throw Ambrosia::error::Exception shift};
if ( $type->primary_key && $type->primary_key eq $params{to} )
{
*{$proto . '::' . $params{name}} = sub() {
my $self = shift;
return ($self->$pk ? $type->load($self->$pk) : undef)
|| $yeld->('Wrong relationship for ' . $type . ': ' . $pk . '=' . $self->$pk);
};
}
else
{
my @key = ref $params{to} ? @{$params{to}} : $params{to};
my @val = ref $params{from} ? @{$params{from}} : $params{from};
my $condition = sub {shift(), shift()};
while( my $k = shift(@key) )
{
my $v = shift(@val);
my $old = $condition;
$condition = sub { my $self = shift; my $q = shift; $old->($self, $q)->predicate($k, '=', $self->$v); $q; }
}
*{$proto . '::' . $params{name}} = sub() {
my $self = shift;
return
($condition->($self, $type->find())->take(1))[0]
|| $yeld->('Wrong relationship: not found entity of ' . $type . ' for ' . $proto . ': '
. join(',', @key)
. ' [' . join(',', map {$self->$_} (ref $params{from} ? @{$params{from}} : $params{from})) . ']'
);
};
}
}
sub link_one2many
{
no strict 'refs';
my $proto = shift;
my %params = @_;
my $yeld = $params{optional}
? sub {new Ambrosia::core::Nil}
: sub {throw Ambrosia::error::Exception shift};
my @key = ref $params{to} ? @{$params{to}} : $params{to};
my @val = ref $params{from} ? @{$params{from}} : $params{from};
my $condition = sub {shift(), shift()};
while( my $k = shift(@key) )
{
my $v = shift(@val);
my $old = $condition;
$condition = sub { my $self = shift; my $q = shift; $old->($self, $q)->predicate($k, '=', $self->$v); return $q; }
}
*{$proto . '::' . $params{name}} = sub() {
my $self = shift;
my @list = $condition->($self, $params{type}->find())->take();
return scalar @list
? \@list
: $yeld->('Wrong relationship: not found ' . $params{type} . ' for ' . $proto . ': '
. join(',', @key)
. ' [' . join(',', map {$self->$_} (ref $params{from} ? @{$params{from}} : $params{from})) . ']'
);
};
}
package Ambrosia::EntityDataModel::_find;
use Ambrosia::Meta;
class sealed {
public => [qw/edm var query/],
};
sub predicate
{
goto &where;
}
sub where
{
my $self = shift;
my @p = @_;
if ( ref $p[0] eq 'CODE' )
{
$self->query->predicate(sub() {
local $_ = ${$self->var};
$p[0]->();
});
}
else
{
$self->query->predicate(@_);
}
return $self;
}
sub uniq
{
shift->query->uniq(@_);
}
sub skip
{
shift->query->skip(@_);
( run in 0.895 second using v1.01-cache-2.11-cpan-ceb78f64989 )