sub sth_to_objects {
my ($class, $sth) = @_;
- my @cols = $class->_select_columns;
my @ret;
- while (my @row = $sth->fetchrow_array) {
- push(@ret, $class->_row_to_object(\@cols,\@row));
+ while (my $row = $sth->fetchrow_hashref) {
+ push(@ret, $class->inflate_result($row));
}
return @ret;
}
return $self;
}
-sub _row_to_object {
+sub inflate_result {
my ($class, @rest) = @_;
my $new = $class->next::method(@rest);
if (my $key = $new->ID) {
}
sub _cond_key {
- my ($self, $attrs, $key) = @_;
+ my ($self, $attrs, $key, $alias) = @_;
my $action = $attrs->{_action} || '';
if ($action eq 'convert') {
unless ($key =~ s/^foreign\.//) {
$self->throw("Unable to convert relationship to WHERE clause: invalid key ${key}");
}
- return $key;
+ if (defined (my $alias = $attrs->{_aliases}{foreign})) {
+ return "${alias}.${key}";
+ } else {
+ return $key;
+ }
} elsif ($action eq 'join') {
return $key unless $key =~ /\./;
my ($type, $field) = split(/\./, $key);
sub search_related {
my $self = shift;
- return $self->_query_related('search', @_);
-}
-
-=head2 count_related
-
- My::Table->count_related('relname', $cond, $attrs);
-
-=cut
-
-sub count_related {
- my $self = shift;
- return $self->_query_related('count', @_);
-}
-
-sub _query_related {
- my $self = shift;
- my $meth = shift;
my $rel = shift;
my $attrs = { };
if (@_ > 1 && ref $_[$#_] eq 'HASH') {
#warn $rel_obj->{class}." $meth $cond ".join(', ', @{$attrs->{bind}||[]});
delete $attrs->{_action};
return $self->resolve_class($rel_obj->{class}
- )->$meth($query, $attrs);
+ )->search($query, $attrs);
+}
+
+=head2 count_related
+
+ My::Table->count_related('relname', $cond, $attrs);
+
+=cut
+
+sub count_related {
+ my $self = shift;
+ return $self->search_related(@_)->count;
}
=head2 create_related
$attrs->{as} ||= [ map { m/^me\.(.*)$/ ? $1 : $_ } @{$attrs->{select}} ];
#use Data::Dumper; warn Dumper(@{$attrs}{qw/select as/});
$attrs->{from} ||= [ { 'me' => $source->name } ];
- if ($attrs->{join}) {
- foreach my $j (ref $attrs->{join} eq 'ARRAY'
- ? (@{$attrs->{join}}) : ($attrs->{join})) {
+ if (my $join = delete $attrs->{join}) {
+ foreach my $j (ref $join eq 'ARRAY'
+ ? (@{$join}) : ($join)) {
if (ref $j eq 'HASH') {
$seen{$_} = 1 foreach keys %$j;
} else {
$seen{$j} = 1;
}
}
- push(@{$attrs->{from}}, $source->result_class->_resolve_join($attrs->{join}, 'me'));
+ push(@{$attrs->{from}}, $source->result_class->_resolve_join($join, 'me'));
}
$attrs->{group_by} ||= $attrs->{select} if delete $attrs->{distinct};
- foreach my $pre (@{$attrs->{prefetch} || []}) {
+ foreach my $pre (@{delete $attrs->{prefetch} || []}) {
push(@{$attrs->{from}}, $source->result_class->_resolve_join($pre, 'me'))
unless $seen{$pre};
my @pre =
return $self->search(\$cond, $attrs);
}
+=head2 search_related
+
+ $rs->search_related('relname', $cond?, $attrs?);
+
+=cut
+
+sub search_related { }
+
=head2 cursor
Returns a storage-driven cursor to the given resultset.
my ($self, @row) = @_;
my @cols = @{ $self->{attrs}{as} };
#warn "@cols -> @row";
- @cols = grep { /\(/ or ! /\./ } @cols;
- my $new;
- unless ($self->{attrs}{prefetch}) {
- $new = $self->{source}->result_class->_row_to_object(\@cols, \@row);
- } else {
- my @main = splice(@row, 0, scalar @cols);
- $new = $self->{source}->result_class->_row_to_object(\@cols, \@main);
- PRE: foreach my $pre (@{$self->{attrs}{prefetch}}) {
- my $rel_obj = $self->{source}->result_class->_relationships->{$pre};
- my $pre_class = $self->{source}->result_class->resolve_class($rel_obj->{class});
- my @pre_cols = $pre_class->_select_columns;
- my @vals = splice(@row, 0, scalar @pre_cols);
- my $fetched = $pre_class->_row_to_object(\@pre_cols, \@vals);
- $self->{source}->result_class->throw("No accessor for prefetched $pre")
- unless defined $rel_obj->{attrs}{accessor};
- if ($rel_obj->{attrs}{accessor} eq 'single') {
- foreach my $pri ($rel_obj->{class}->primary_columns) {
- unless (defined $fetched->get_column($pri)) {
- undef $fetched;
- last;
- }
- }
- $new->{_relationship_data}{$pre} = $fetched;
- } elsif ($rel_obj->{attrs}{accessor} eq 'filter') {
- $new->{_inflated_column}{$pre} = $fetched;
- } else {
- $self->{source}->result_class->throw("Don't know how to store prefetched $pre");
- }
+ my (%me, %pre);
+ foreach my $col (@cols) {
+ if ($col =~ /([^\.]+)\.([^\.]+)/) {
+ $pre{$1}{$2} = shift @row;
+ } else {
+ $me{$col} = shift @row;
}
}
+ my $new = $self->{source}->result_class->inflate_result(\%me, \%pre);
$new = $self->{attrs}{record_filter}->($new)
if exists $self->{attrs}{record_filter};
return $new;
return $self->{_column_data}{$column} = $value;
}
-sub _row_to_object {
- my ($class, $cols, $row) = @_;
- my %vals;
- $vals{$cols->[$_]} = $row->[$_] for 0 .. $#$cols;
- my $new = bless({ _column_data => \%vals }, ref $class || $class);
+=head2 inflate_result
+
+ Class->inflate_result(\%me, \%prefetch?)
+
+Called by ResultSet to inflate a result from storage
+
+=cut
+
+sub inflate_result {
+ my ($class, $me, $prefetch) = @_;
+ #use Data::Dumper; print Dumper(@_);
+ my $new = bless({ _column_data => $me }, ref $class || $class);
$new->in_storage(1);
+ PRE: foreach my $pre (keys %{$prefetch||{}}) {
+ my $rel_obj = $class->_relationships->{$pre};
+ my $pre_class = $class->resolve_class($rel_obj->{class});
+ my $fetched = $pre_class->inflate_result($prefetch->{$pre});
+ $class->throw("No accessor for prefetched $pre")
+ unless defined $rel_obj->{attrs}{accessor};
+ if ($rel_obj->{attrs}{accessor} eq 'single') {
+ PRIMARY: foreach my $pri ($rel_obj->{class}->primary_columns) {
+ unless (defined $fetched->get_column($pri)) {
+ undef $fetched;
+ last PRIMARY;
+ }
+ }
+ $new->{_relationship_data}{$pre} = $fetched;
+ } elsif ($rel_obj->{attrs}{accessor} eq 'filter') {
+ $new->{_inflated_column}{$pre} = $fetched;
+ } else {
+ $class->throw("Don't know how to store prefetched $pre");
+ }
+ }
return $new;
}