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 )