1 package OpenILS::Application::Storage::Publisher::authority;
2 use base qw/OpenILS::Application::Storage::Publisher/;
4 use OpenSRF::EX qw/:try/;
5 use OpenILS::Application::Storage::FTS;
6 use OpenILS::Utils::Fieldmapper;
7 use OpenILS::Utils::Normalize qw( naco_normalize );
8 use OpenSRF::Utils::Logger qw/:level/;
9 use OpenSRF::Utils::Cache;
11 use Digest::MD5 qw/md5_hex/;
13 use Time::HiRes qw/time sleep/;
14 use Unicode::Normalize;
16 my $log = 'OpenSRF::Utils::Logger';
20 my $parser = XML::LibXML->new;
27 my @tags = @{$args{tags}};
28 my @searches = @{$args{searches}};
30 my $search_table = authority::full_rec->table;
35 for my $search ( @searches ) {
36 my $sf = $$search{subfield};
37 my $term = naco_normalize($$search{term}, $sf);
39 $tag = [$tag] if (!ref($tag));
41 push @values, $t, $sf, $term;
44 "SELECT record FROM $search_table ".
45 "WHERE tag = ? AND subfield = ? AND value = ?";
49 if ($self->api_name =~ /id_list/) {
50 $sql = 'SELECT DISTINCT record FROM (';
52 $sql = 'SELECT COUNT(DISTINCT record) FROM (';
54 $sql .= 'SELECT record FROM (('.join(') INTERSECT (', @selects).')) AS x ';
55 $sql .= "JOIN $search_table recheck USING (record) WHERE recheck.tag = ? ";
56 $sql .= "GROUP BY 1 HAVING (COUNT(recheck.id) - ?) = 0) AS foo;";
58 if ($self->api_name =~ /id_list/) {
59 my $id_list = authority::full_rec->db_Main->selectcol_arrayref( $sql, {}, @values, $t, scalar(@searches) );
62 my $count = authority::full_rec->db_Main->selectcol_arrayref( $sql, {}, @values, $t, scalar(@searches) )->[0];
63 return $count if ($count > 0);
69 __PACKAGE__->register_method(
70 api_name => "open-ils.storage.authority.validate.tag",
71 method => 'validate_tag',
75 __PACKAGE__->register_method(
76 api_name => "open-ils.storage.authority.validate.tag.id_list",
77 method => 'validate_tag',
82 sub find_authority_marc {
87 my $term = NFD(lc($args{term}));
89 my $subfield = $args{subfield};
90 my $limit = $args{limit} || 100;
91 my $offset = $args{offset} || 0;
94 $limit = "LIMIT $limit";
100 $offset = "OFFSET $offset";
105 my $tag_where = "AND f.tag LIKE '$tag'";
107 $tag_where = "AND f.tag IN ('".join("','",@$tag)."')";
110 my $sf_where = "AND f.subfield = '$subfield'";
112 $sf_where = "AND f.subfield IN ('".join("','",@$subfield)."')";
115 my $search_table = authority::full_rec->table;
116 my $marc_table = authority::record_entry->table;
118 my ($index_col) = authority::full_rec->columns('FTS');
119 $index_col ||= 'value';
121 my $fts = OpenILS::Application::Storage::FTS->compile(default => $term, 'f.value', "f.$index_col");
123 $term =~ s/\W+$//gso;
127 my $fts_where = $fts->sql_where_clause;
128 my $fts_words = join '%', $fts->words;
130 return undef unless ($fts_words);
132 my $fts_words_where = "f.value LIKE '$fts_words\%'";
133 my $fts_start_where = "f.value LIKE '$term\%'";
134 my $fts_eq_where = "f.value = '$term'";
136 my $fts_rank = join '+', $fts->fts_rank;
138 my $select = <<" SQL";
139 SELECT a.marc, sum($fts_rank), count(f.record), first(f.value)
140 FROM $search_table f,
142 WHERE $fts_start_where
147 ORDER BY 2 desc, 3 desc, 4
153 $log->debug("Authority Search SQL :: [$select]",DEBUG);
155 my $recs = authority::full_rec->db_Main->selectcol_arrayref( $select );
157 $log->debug("Search yielded ".scalar(@$recs)." results.",DEBUG);
159 $client->respond($_) for (@$recs);
162 __PACKAGE__->register_method(
163 api_name => "open-ils.storage.authority.search.marc",
164 method => 'find_authority_marc',
172 my $class = shift || 'metabib::full_rec';
174 my $table = $class->table;
176 my ($index_col) = $class->columns('FTS');
177 $index_col ||= 'value';
179 my $fts = OpenILS::Application::Storage::FTS->compile(default => $term, 'm.value', "m.$index_col");
180 my $fts_where = $fts->sql_where_clause;
189 return $class->db_Main->selectcol_arrayref($sql)->[0];
194 sub find_see_from_controlled {
203 (my $class = $self->api_name) =~ s/^.+authority.([^\.]+)\.see.+$/$1/o;
205 $sf = 't' if ($class eq 'title');
207 my @marc = $self->method_lookup('open-ils.storage.authority.search.marc')
208 ->run( term => $term, tag => [400,410,411,430,450,455], subfield => $sf, limit => $limit, offset => $offset );
211 for my $m ( @marc ) {
212 my $doc = $parser->parse_string($m);
213 my @nodes = $doc->documentElement->findnodes('//*[substring(@tag,1,1)="1"]/*[@code="a" or @code="d" or @code="x"]');
214 my $list = [ map { $_->textContent } @nodes ];
215 $client->respond( $list ) if (_empty_check(join(' ',@$list), "metabib::${class}_field_entry"));
219 for my $class ( qw/title author subject keyword series identifier/ ) {
220 __PACKAGE__->register_method(
221 api_name => "open-ils.storage.authority.$class.see_from.controlled",
222 method => 'find_see_from_controlled',
229 sub find_see_also_from_controlled {
236 (my $class = $self->api_name) =~ s/^.+authority.([^\.]+)\.see.+$/$1/o;
238 $sf = 't' if ($class eq 'title');
240 my @marc = $self->method_lookup('open-ils.storage.authority.search.marc')
241 ->run( term => $term, tag => [500,510,511,530,550,555], subfield => $sf, limit => $limit, offset => $offset );
242 for my $m ( @marc ) {
243 my $doc = $parser->parse_string($m);
244 my @nodes = $doc->documentElement->findnodes('//*[substring(@tag,1,1)="1"]/*[@code="a" or @code="d" or @code="x"]');
245 my $list = [ map { $_->textContent } @nodes ];
246 $client->respond( $list ) if (_empty_check(join(' ',@$list), "metabib::${class}_field_entry"));
250 for my $class ( qw/title author subject keyword series identifier/ ) {
251 __PACKAGE__->register_method(
252 api_name => "open-ils.storage.authority.$class.see_also_from.controlled",
253 method => 'find_see_also_from_controlled',