Fixed a bug in sort that destroyed resultsets too early
[idzebra-moved-to-github.git] / perl / lib / IDZebra / Resultset.pm
1 # $Id: Resultset.pm,v 1.13 2004-09-16 14:58:47 heikki Exp $
2
3 # Zebra perl API header
4 # =============================================================================
5 package IDZebra::Resultset;
6
7 use strict;
8 use warnings;
9
10 BEGIN {
11     use IDZebra;
12     use IDZebra::Logger qw(:flags :calls);
13     use Scalar::Util qw(weaken);
14     use Carp;
15     our $VERSION = do { my @r = (q$Revision: 1.13 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; 
16     our @ISA = qw(IDZebra::Logger);
17 }
18
19 1;
20 # -----------------------------------------------------------------------------
21 # Class constructors, destructor
22 # -----------------------------------------------------------------------------
23 sub new {
24     my ($proto,$session, %args) = @_;
25     my $class = ref($proto) || $proto;
26     my $self = {};
27     bless ($self, $class);
28     logf(LOG_DEBUG,"creating a Resultset ".$args{name});
29
30     $self->{session} = $session;
31     weaken ($self->{session});
32
33     $self->{odr_stream} = IDZebra::odr_createmem($IDZebra::ODR_DECODE);
34
35     $self->{name}        = $args{name};
36     $self->{query}       = $args{query};
37     $self->{recordCount} = $args{recordCount};
38     $self->{errCode}     = $args{errCode};
39     $self->{errString}   = $args{errString};
40
41     logf(LOG_DEBUG,"created a Resultset ".$self->{name});
42     return ($self);
43 }
44
45 sub recordCount {
46     my ($self) = @_;
47     return ($self->{recordCount});
48 }
49 sub count {
50     my ($self) = @_;
51     return ($self->{recordCount});
52 }
53
54 sub errCode {
55     my ($self) = @_;
56     return ($self->{errCode});
57 }
58
59 sub errString {
60     my ($self) = @_;
61     return ($self->{errCode});
62 }
63
64 ######################
65 # this is disabled, while the term counts are broken by the work done to
66 # rsets. To be reinstantiated some day real soon now...
67 #sub terms {
68 #    use Data::Dumper;
69 #    my ($self) = @_;
70 #    my $count = 0; my $type = 0; my $len = 0;
71 #    my $tc = IDZebra::resultSetTerms($self->{session}{zh},$self->{name},
72 #                                    0, \$count, \$type, "\0", \$len);
73 #
74 #    logf (LOG_LOG,"Got $tc terms");
75 #    
76 #    
77 #    my @res = ();
78 #    for (my $i=0; $i<$tc; $i++) {
79 #       my $len = 1024;
80 #       my $t = {term => "\0" x $len, count => 0, type => 0};
81 #       my $stat = IDZebra::resultSetTerms($self->{session}{zh},$self->{name},
82 #                                          $i, \$t->{count}, \$t->{type}, 
83 #                                          $t->{term}, \$len);
84 #       $t->{term} = substr($t->{term}, 0, $len);
85 #       logf (LOG_LOG,
86 #             "term $i: type $t->{type}, '$t->{term}' ($t->{count})");
87 #       push (@res, $t);
88 #    }
89 #    return (@res);
90 #}
91
92 # =============================================================================
93 sub DESTROY {
94     my $self = shift;
95
96 #    print STDERR "Destroy RS\n";
97     # Deleteresultset?
98     
99     my $stats = 0;
100     logf(LOG_DEBUG, "Destroying a Resultset ". $self->{name});
101     if ($self->{session}{zh}) { 
102         my $r = IDZebra::deleteResultSet($self->{session}{zh},
103                                          0, #Z_DeleteRequest_list,
104                                          1,[$self->{name}],
105                                          $stats);
106     }
107
108     if ($self->{odr_stream}) {
109         IDZebra::odr_reset($self->{odr_stream});
110         IDZebra::odr_destroy($self->{odr_stream});
111         $self->{odr_stream} = undef;  
112     }
113
114     delete($self->{session});
115     logf(LOG_DEBUG, "Destroyed a Resultset ". $self->{name});
116 }
117 # -----------------------------------------------------------------------------
118 sub records {
119     my ($self, %args) = @_;
120
121     unless ($self->{session}{zh}) { 
122         croak ("Session is closed or out of scope");
123     }
124     my $from = $args{from} ? $args{from} : 1;
125     my $to   = $args{to}   ? $args{to}   : $self->{recordCount};
126
127     if (($to-$from) >= 1000) {
128         if ($args{to}) {
129             croak ("Cannot fetch more than 1000 records at a time");
130         } else {
131             $to = $from + 999;
132         }
133     }
134
135     my $elementSet   = $args{elementSet}   ? $args{elementSet}    : 'R';
136     my $schema       = $args{schema}       ? $args{schema}        : '';
137     my $recordSyntax = $args{recordSyntax} ? $args{recordSyntax}  : '';
138     
139     my $class        = $args{class}        ? $args{class}         : '';
140     
141     # ADAM: Reset before we use it (not after)
142     IDZebra::odr_reset($self->{odr_stream});
143
144     my $ro = IDZebra::RetrievalObj->new();
145     IDZebra::records_retrieve($self->{session}{zh},
146                               $self->{odr_stream},
147                               $self->{name},
148                               $elementSet,
149                               $schema,
150                               $recordSyntax,
151                               $from,
152                               $to,
153                               $ro);
154
155     my @res = ();
156
157     for (my $i=$from; $i<=$to; $i++) {
158         my $rec = IDZebra::RetrievalRecord->new();
159         IDZebra::record_retrieve($ro, $self->{odr_stream}, $rec, $i-$from+1);
160         if ($class) {
161             
162         } else {
163             push (@res, $rec); 
164         }
165     }
166
167     return (@res);
168 }
169
170 # ============================================================================
171 sub sort {
172     my ($self, $sortspec, $setname) = @_;
173
174     unless ($self->{session}{zh}) { 
175         croak ("Session is closed or out of scope");
176     }
177
178     if (!$setname) {
179         $setname=$self->{session}->_new_setname();
180     }
181     return ($self->{session}->sortResultsets($sortspec, 
182                                          $setname, ($self)));
183 #    unless ($setname) {
184 #       return ($_[0] = $self->{session}->sortResultsets($sortspec, 
185 #                        $self->{session}->_new_setname, ($self)));
186 #       return ($_[0]);
187 #    } else {
188 #       return ($self->{session}->sortResultsets($sortspec, 
189 #                                                $setname, ($self)));
190 #    }
191 }
192
193 # ============================================================================
194 __END__
195
196 =head1 NAME
197
198 IDZebra::Resultset - Representation of Zebra search results
199
200 =head1 SYNOPSIS
201
202   $count = $rs->count;
203
204   printf ("RS Status is %d (%s)\n", $rs->errCode, $rs->errString);
205
206   my @recs = $rs->records(from => 1,
207                           to   => 10);
208
209 =head1 DESCRIPTION
210
211 The I<Resultset> object represents results of a Zebra search. Contains number of hits, search status, and can be used to sort and retrieve the records.
212
213 =head1 PROPERTIES
214
215 The folowing properties are available, trough object methods and the object hash reference:
216
217 =over 4
218
219 =item B<errCode>
220
221 The error code returned from search, resulting the Resultset object.
222
223 =item B<errString>
224
225 The optional error string
226
227 =item B<recordCount>
228
229 The number of hits (records available) in the resultset
230
231 =item B<count>
232
233 Just the synonym for I<recordCount>
234
235 =back
236
237 =head1 RETRIEVING RECORDS
238
239 In order to retrieve records, use the I<records> method:
240
241   my @recs = $rs->records();
242
243 By default this is going to return an array of IDZebra::RetrievalRecord objects. The possible arguments are:
244
245 =over 4
246
247 =item B<from>
248
249 Retrieve records from the given position. The first record corresponds to position 1. If not specified, retrieval starts from the first record.
250
251 =item B<to>
252
253 The last record position to be fetched. If not specified, all records are going to be fetched, starting from position I<from>.
254
255 =item B<elementSet>
256
257 The element set used for retrieval. If not specified 'I<R>' is used, which will return the "record" in the original format (ie.: without extraction, just as the original file, or data buffer in the update call).
258
259 =item B<schema>
260
261 The schema used for retrieval. The default is "".
262
263 =item B<recordSyntax>
264
265 The record syntax for retrieval. The default is SUTRS.
266
267 =back
268
269 =head1 SORTING
270
271 You can sort resultsets by calling:
272
273   $rs1->sort($sort_expr);
274
275 or create a new sorted resultset:
276
277   $rs2 = $rs1->sort($sort_expr);
278
279 The sort expression has the same format as described in the I<yaz_client> documentation. For example:
280
281   $rs1->sort('1=4 id');
282
283 will sort thr results by title, in a case insensitive way, in descending order, while
284
285   $rs1->sort('1=4 a');
286
287 will sort ascending by titles.
288
289 =head1 COPYRIGHT
290
291 Fill in
292
293 =head1 AUTHOR
294
295 Peter Popovics, pop@technomat.hu
296
297 =head1 SEE ALSO
298
299 Zebra documentation, IDZebra::ResultSet, IDZebra::RetrievalRecord manpages.
300
301 =cut