1 package OpenILS::Application::Search::Biblio;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
6 use OpenILS::Utils::Fieldmapper;
7 use OpenILS::Utils::ModsParser;
8 use OpenSRF::Utils::SettingsClient;
10 use OpenILS::Application::AppUtils;
12 use Time::HiRes qw(time);
13 use OpenSRF::EX qw(:try);
14 use Digest::MD5 qw(md5_hex);
16 # Houses biblio search utilites
18 __PACKAGE__->register_method(
19 method => "biblio_search_marc",
20 api_name => "open-ils.search.biblio.marc",
22 note => "Searches biblio information by marc tag",
25 sub biblio_search_marc {
27 my( $self, $client, $search_hash, $string ) = @_;
29 warn "Building biblio marc session\n";
30 my $session = OpenSRF::AppSession->create("open-ils.storage");
32 warn "Sending biblio marc request\n";
33 my $request = $session->request(
34 "open-ils.storage.direct.metabib.full_rec.search_fts.index_vector",
35 $search_hash, $string );
37 warn "Waiting complete\n";
38 $request->wait_complete();
40 warn "Calling recv\n";
41 my $response = $request->recv(20);
44 if($response and UNIVERSAL::isa($response,"OpenSRF::EX")) {
45 throw $response ($response->stringify);
50 if($response and UNIVERSAL::can($response,"content")) {
51 $data = $response->content;
53 warn "finishing request\n";
57 $session->disconnect();
67 # ---------------------------------------------------------------------------
68 # takes a list of record id's and turns the docs into friendly
69 # mods structures. Creates one MODS structure for each doc id.
70 # ---------------------------------------------------------------------------
71 sub _records_to_mods {
77 my $session = OpenSRF::AppSession->create("open-ils.storage");
78 my $request = $session->request(
79 "open-ils.storage.direct.biblio.record_marc.batch.retrieve", @ids );
81 my $last_content = undef;
83 while( my $response = $request->recv() ) {
86 my $u = OpenILS::Utils::ModsParser->new();
87 $u->start_mods_batch( $last_content->marc );
88 my $mods = $u->finish_mods_batch();
89 $mods->{doc_id} = $last_content->id();
90 warn "Turning doc " . $mods->{doc_id} . " into MODS\n";
91 $last_content = undef;
95 next unless $response;
97 if($response->isa("OpenSRF::EX")) {
98 throw $response ($response->stringify);
101 $last_content = $response->content;
105 if( $last_content ) {
106 my $u = OpenILS::Utils::ModsParser->new();
107 $u->start_mods_batch( $last_content->marc );
108 my $mods = $u->finish_mods_batch();
109 $mods->{doc_id} = $last_content->id();
110 push @results, $mods;
115 $session->disconnect();
121 __PACKAGE__->register_method(
122 method => "record_id_to_mods",
123 api_name => "open-ils.search.biblio.record.mods.retrieve",
125 note => "Provide ID, we provide the mods"
128 # converts a record into a mods object with copy counts attached
129 sub record_id_to_mods {
131 my( $self, $client, $org_id, $id ) = @_;
133 my $mods_list = _records_to_mods( $id );
134 my $mods_obj = $mods_list->[0];
135 my $cmethod = $self->method_lookup(
136 "open-ils.search.biblio.record.copy_count");
137 my ($count) = $cmethod->run($org_id, $id);
138 $mods_obj->{copy_count} = $count;
144 __PACKAGE__->register_method(
145 method => "record_id_to_mods_slim",
146 api_name => "open-ils.search.biblio.record.mods_slim.retrieve",
148 note => "Provide ID, we provide the mods"
151 # converts a record into a mods object with NO copy counts attached
152 sub record_id_to_mods_slim {
154 my( $self, $client, $id ) = @_;
155 warn "Retrieving MODS object for record $id\n";
156 return undef unless(defined $id);
158 my $mods_list = _records_to_mods( $id );
159 my $mods_obj = $mods_list->[0];
164 # Returns the number of copies attached to a record based on org location
165 __PACKAGE__->register_method(
166 method => "record_id_to_copy_count",
167 api_name => "open-ils.search.biblio.record.copy_count",
169 note => "Provide ID, we provide the copy count"
172 sub record_id_to_copy_count {
173 my( $self, $client, $org_id, $record_id ) = @_;
175 my $session = OpenSRF::AppSession->create("open-ils.storage");
176 warn "copy_count retrieve $record_id\n";
177 return undef unless(defined $record_id);
179 my $request = $session->request(
180 "open-ils.storage.direct.biblio.record_copy_count", $org_id, $record_id );
182 warn "copy_count wait $record_id\n";
183 $request->wait_complete;
185 warn "copy_count recv $record_id\n";
186 my $response = $request->recv();
187 return undef unless $response;
189 warn "copy_count after recv $record_id\n";
191 if( $response and UNIVERSAL::isa($response, "Error")) {
192 throw $response ($response->stringify);
195 my $count = $response->content;
199 $session->disconnect();
205 # used for cat search classes
206 my $cat_search_hash = {
209 { tag => "100", subfield => "a"} ,
210 { tag => "700", subfield => "a"},
214 { tag => "245", subfield => "a"},
215 { tag => "242", subfield => "a"},
216 { tag => "240", subfield => "a"},
217 { tag => "210", subfield => "a"},
221 { tag => "650", subfield => "_" },
225 { tag => "035", subfield => "_" },
231 __PACKAGE__->register_method(
232 method => "cat_biblio_search_tcn",
233 api_name => "open-ils.search.cat.biblio.tcn",
235 note => "Searches biblio information by search class",
238 sub cat_biblio_search_tcn {
240 my( $self, $client, $tcn ) = @_;
242 $tcn =~ s/.*?(\w+)\s*$/$1/o;
243 warn "Searching TCN $tcn\n";
245 my $session = OpenSRF::AppSession->create( "open-ils.storage" );
246 my $request = $session->request(
247 "open-ils.storage.direct.biblio.record_entry.search.tcn_value", $tcn );
248 warn "tcn going into recv\n";
249 my $response = $request->recv();
252 unless ($response) { return []; }
254 if(UNIVERSAL::isa($response,"OpenSRF::EX")) {
255 warn "Received exception for tcn search\n";
256 throw $response ($response->stringify);
259 my $record_entry = $response->content;
261 for my $record (@$record_entry) {
262 push @ids, $record->id;
265 warn "received ID's for tcn search @ids\n";
268 my $record_list = _records_to_mods( @ids );
270 for my $rec (@$record_list) {
271 $client->respond($rec);
278 __PACKAGE__->register_method(
279 method => "cat_biblio_search_class",
280 api_name => "open-ils.search.cat.biblio.class",
282 note => "Searches biblio information by search class",
285 sub cat_biblio_search_class {
287 my( $self, $client, $org_id, $class, $sort, $string ) = @_;
289 throw OpenSRF::EX::InvalidArg
290 ("Not enough args to open-ils.search.cat.biblio.class")
291 unless( defined($org_id) and $class and $sort and $string );
296 my $method = $self->method_lookup("open-ils.search.biblio.marc");
298 throw OpenSRF::EX::PANIC
299 ("Can't lookup method 'open-ils.search.biblio.marc'");
302 my ($records) = $method->run( $cat_search_hash->{$class}, $string );
305 for my $i (@$records) { push @ids, $i->[0]; }
307 my $mods_list = _records_to_mods( @ids );
308 return undef unless (ref($mods_list) eq "ARRAY");
310 # ---------------------------------------------------------------
311 # append copy count information to the mods objects
312 my $session = OpenSRF::AppSession->create("open-ils.storage");
314 my $request = $session->request(
315 "open-ils.storage.direct.biblio.record_copy_count.batch", $org_id, @ids );
319 warn "receiving copy counts for doc $id\n";
321 my $response = $request->recv();
322 next unless $response;
324 if( $response and UNIVERSAL::isa($response, "Error")) {
325 throw $response ($response->stringify);
328 my $count = $response->content;
329 my $mods_obj = undef;
330 for my $m (@$mods_list) {
331 $mods_obj = $m if ($m->{doc_id} == $id)
334 $mods_obj->{copy_count} = $count;
337 $client->respond( $mods_obj );
343 $session->disconnect();
345 # ---------------------------------------------------------------
352 __PACKAGE__->register_method(
353 method => "cat_biblio_search_class_id",
354 api_name => "open-ils.search.cat.biblio.class.id",
356 note => "Searches biblio information by search class and returns the IDs",
359 sub cat_biblio_search_class_id {
361 my( $self, $client, $org_id, $class, $string, $limit, $offset ) = @_;
368 $string = OpenILS::Application::Search->filter_search($string);
369 if(!$string) { return undef; }
371 warn "Searching cat.biblio.class.id string: $string offset: $offset limit: $limit\n";
373 throw OpenSRF::EX::InvalidArg
374 ("Not enough args to open-ils.search.cat.biblio.class")
375 unless( defined($org_id) and $class and $string );
380 my $cache_key = md5_hex( $org_id . $class . $string );
381 my $id_array = OpenILS::Application::SearchCache->get_cache($cache_key);
384 warn "Return search from cache\n";
385 my $size = @$id_array;
386 my @ids = @$id_array[ $offset..($offset+$limit) ];
387 warn "Returning cat.biblio.class.id $string\n";
388 return { count => $size, ids => \@ids };
391 my $method = $self->method_lookup("open-ils.search.biblio.marc");
393 throw OpenSRF::EX::PANIC
394 ("Can't lookup method 'open-ils.search.biblio.marc'");
397 my ($records) = $method->run( $cat_search_hash->{$class}, $string );
401 for my $i (@$records) { push @cache_ids, $i->[0]; }
402 my @ids = @cache_ids[ $offset..($offset+$limit) ];
403 my $size = @$records;
405 OpenILS::Application::SearchCache->put_cache(
406 $cache_key, \@cache_ids, $size );
408 warn "Returning cat.biblio.class.id $string\n";
409 return { count =>$size, ids => \@ids };