Aniki

 view release on metacpan or  search on metacpan

lib/Aniki.pm  view on Meta::CPAN

    my ($self, $table_name, $prefetch, $rows) = @_;
    return unless @$rows;

    $prefetch = [$prefetch] if ref $prefetch eq 'HASH';

    my $relationships = $self->schema->get_table($table_name)->get_relationships;
    for my $key (@$prefetch) {
        if (ref $key && ref $key eq 'HASH') {
            my %prefetch = %$key;
            for my $key (keys %prefetch) {
                $self->_fetch_and_attach_relay_data($relationships, $rows, $key, $prefetch{$key});
            }
        }
        else {
            $self->_fetch_and_attach_relay_data($relationships, $rows, $key, []);
        }
    }
}

sub _fetch_and_attach_relay_data {
    my ($self, $relationships, $rows, $key, $prefetch) = @_;
    my $relationship = $relationships->get($key);
    unless ($relationship) {
        croak "'$key' is not defined as relationship. (maybe possible typo?)";
    }
    $relationship->fetcher->execute($self, $rows, $prefetch);
}

sub select_named {
    my ($self, $sql, $bind, $opt) = @_;
    return $self->select_by_sql(bind_named($sql, $bind), $opt);
}

sub select_by_sql {
    my ($self, $sql, $bind, $opt) = @_;
    $opt //= {};

    local $self->{suppress_row_objects}    = 1 if $opt->{suppress_row_objects};
    local $self->{suppress_result_objects} = 1 if $opt->{suppress_result_objects};

    my $table_name = exists $opt->{table_name}  ? $opt->{table_name} : $self->_guess_table_name($sql);
    my $columns    = exists $opt->{columns}     ? $opt->{columns}    : undef;
    my $prefetch   = exists $opt->{prefetch}    ? $opt->{prefetch}      : [];
       $prefetch   = [$prefetch] if ref $prefetch eq 'HASH';

    my $prefetch_enabled_fg = @$prefetch && !$self->suppress_row_objects && defined wantarray;
    if ($prefetch_enabled_fg) {
        my $txn; $txn = $self->txn_scope(caller => [caller]) unless $self->in_txn;

        my $sth = $self->execute($sql, @$bind);
        my $result = $self->_fetch_by_sth($sth, $table_name, $columns);
        $self->fetch_and_attach_relay_data($table_name, $prefetch, $result->rows);

        $txn->rollback if defined $txn; ## for read only
        return $result;
    }

    my $sth = $self->execute($sql, @$bind);

    # When the return value is never used, should not create object
    # case example: use `FOR UPDATE` query for global locking
    unless (defined wantarray) {
        $sth->finish();
        return;
    }

    return $self->_fetch_by_sth($sth, $table_name, $columns);
}

sub _fetch_by_sth {
    my ($self, $sth, $table_name, $columns) = @_;
    $columns //= $sth->{NAME};
    $columns   = $sth->{NAME} if $columns == $WILDCARD_COLUMNS;

    my @rows;

    my %row;
    $sth->bind_columns(\@row{@$columns});
    push @rows => {%row} while $sth->fetch;
    $sth->finish;

    if ($self->suppress_result_objects) {
        return \@rows if $self->suppress_row_objects;

        my $row_class = $self->guess_row_class($table_name);
        return [
            map {
                $row_class->new(
                    table_name => $table_name,
                    handler    => $self,
                    row_data   => $_,
                )
            } @rows
        ];
    }

    my $result_class = $self->guess_result_class($table_name);
    return $result_class->new(
        table_name           => $table_name,
        handler              => $self,
        row_datas            => \@rows,
        suppress_row_objects => $self->suppress_row_objects,
    );
}

sub execute {
    my ($self, $sql, @bind) = @_;
    $sql = $self->handler->trace_query_set_comment($sql);

    my $sth = $self->use_prepare_cached ? $self->dbh->prepare_cached($sql) : $self->dbh->prepare($sql);
    $self->_bind_to_sth($sth, \@bind);
    eval {
        $sth->execute();
    };
    if ($@) {
        $self->handle_error($sql, \@bind, $@);
    }

    return $sth;
}



( run in 1.444 second using v1.01-cache-2.11-cpan-df04353d9ac )