/usr/local/CPAN/Keystone-Resolver/Keystone/Resolver/ResultSet.pm


# $Id: ResultSet.pm,v 1.4 2008-04-30 16:37:05 mike Exp $

package Keystone::Resolver::ResultSet;
use strict;
use warnings;
use Encode;


sub new {
    my $class = shift();
    my($site, $findclass, %query) = @_;
    $findclass = "Keystone::Resolver::DB::$findclass" if $findclass !~ /::/;

    my $sort = delete $query{_sort};
    $sort = join(", ", $findclass->sort_fields()) if !$sort;

    # Discard empty elements and those whose names begin with "_"
    %query = map { ($_, $query{$_} ) }
	grep { !/^_/ && defined $query{$_} && $query{$_} ne "" } keys %query;

    # Replace all "'" with "''"; whole terms may still need quoting
    foreach my $key (keys %query) {
	$query{$key} =~ s/['']/''/g;
    }

    # Rather than building a condition by hand here, we should call
    # directly into a Database method that accepts %query whole;
    # unfortunately, that method doesn't exist yet.
    #
    # At the moment, we don't narrow on $site->id() since resolver
    # objects like Services and Providers do not have any concept of
    # ownership -- but that will change.
    my $db = $site->db();
    my $cond = (join(" and ", # "site_id = " . $site->id(),
		     map { $db->quote($_) . " = '" . $query{$_} . "'" } sort keys %query));
    $cond = undef if $cond eq "";
    $site->log(Keystone::Resolver::LogLevel::SQL, 
	       (defined $cond ? "SQL cond: $cond" : "no condition"));

    my($sth, $count, $errmsg) =
	$db->_findcond($findclass, $cond, $sort);
    return (undef, $errmsg) if !defined $sth;
    return bless {
	site => $site,
	class => $findclass,
	db => $db,
	query => \%query,
	sth => $sth,
	count => $count,
	hwm => 0,		# 1-based index of last record read
	objects => [],		# cache of objects made from records read
    }, $class;
}


sub class { shift()->{class} }
sub query { shift()->{query} }
sub count { shift()->{count} }


# Fetches the $i'th object in the RS, where $i is a 1-based index
sub fetch {
    my $this = shift();
    my($i) = @_;

    die "fetch($this) called with non-positive index $i"
	if $i < 1;
    die "fetch($this) called with out-of-range index $i (max=" .
	$this->count() . ")"
	if $i > $this->count();

    my $class = $this->class();
    while ($this->{hwm} < $i) {
	my $ref = $this->{sth}->fetchrow_arrayref();
	if (!defined $ref) {
	    my $errmsg = $this->{sth}->errstr();
	    return (undef, $errmsg)
		if defined $errmsg;
	    die "unexpected end of result-set after " . $this->{hwm} .
		" of " . $this->count() . " records";
	}
	my $object = $class->new($this->{db}, map { decode_utf8($_) } @$ref);
	$this->{objects}->[$this->{hwm}++] = $object;
    }

    return $this->{objects}->[$i-1];
}


1;