]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher/authority.pm
9e3b1f25189a5a44271c2b2c2130c4deb616fc04
[working/Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Storage / Publisher / authority.pm
1 package OpenILS::Application::Storage::Publisher::authority;
2 use base qw/OpenILS::Application::Storage::Publisher/;
3 use vars qw/$VERSION/;
4 use OpenSRF::EX qw/:try/;
5 use OpenILS::Application::Storage::FTS;
6 use OpenILS::Utils::Fieldmapper;
7 use OpenSRF::Utils::Logger qw/:level/;
8 use OpenSRF::Utils::Cache;
9 use Data::Dumper;
10 use Digest::MD5 qw/md5_hex/;
11 use XML::LibXML;
12 use Time::HiRes qw/time sleep/;
13 use Unicode::Normalize;
14
15 my $log = 'OpenSRF::Utils::Logger';
16
17 $VERSION = 1;
18
19 my $parser = XML::LibXML->new;
20
21 sub validate_tag {
22         my $self = shift;
23         my $client = shift;
24         my %args = @_;
25         
26         my @tags = @{$args{tags}};
27         my @searches = @{$args{searches}};
28
29         my $search_table = authority::full_rec->table;
30
31         my @values;
32         my @selects;
33         for my $t ( @tags ) {
34                 for my $search ( @searches ) {
35                         my $sf = $$search{subfield};
36                         my $term = NFD(lc($$search{term}));
37
38                         $term =~ s/\pM+//sgo;
39                         $term =~ s/\pC+//sgo;
40                         $term =~ s/\W+$//o;
41
42                         $tag = [$tag] if (!ref($tag));
43
44                         push @values, $t, $sf, $term;
45
46                         push @selects,
47                                 "SELECT record FROM $search_table ".
48                                 "WHERE tag = ? AND subfield = ? AND value = ?";
49                 }
50
51                 my $sql = 'SELECT COUNT(DISTINCT record) FROM (';
52                 $sql .= 'SELECT record FROM (('.join(') INTERSECT (', @selects).')) AS x ';
53                 $sql .= "JOIN $search_table recheck USING (record) WHERE recheck.tag = ? ";
54                 $sql .= "GROUP BY 1 HAVING (COUNT(recheck.id) - ?) = 0) AS foo;";
55
56                 my $count = authority::full_rec->db_Main->selectcol_arrayref( $sql, {}, @values, $t, scalar(@searches) )->[0];
57                 return $count if ($count > 0);
58         }
59
60         return 0;
61 }
62 __PACKAGE__->register_method(
63         api_name        => "open-ils.storage.authority.validate.tag",
64         method          => 'validate_tag',
65         api_level       => 1,
66 );
67
68 sub find_authority_marc {
69         my $self = shift;
70         my $client = shift;
71         my %args = @_;
72         
73         my $term = NFD(lc($args{term}));
74         my $tag = $args{tag};
75         my $subfield = $args{subfield};
76         my $limit = $args{limit} || 100;
77         my $offset = $args{offset} || 0;
78
79         if ($limit) {
80                 $limit = "LIMIT $limit";
81         } else {
82                 $limit = '';
83         }
84
85         if ($offset) {
86                 $offset = "OFFSET $offset";
87         } else {
88                 $offset = '';
89         }
90
91         my $tag_where = "AND f.tag LIKE '$tag'";
92         if (ref $tag) {
93                 $tag_where = "AND f.tag IN ('".join("','",@$tag)."')";
94         }
95
96         my $sf_where = "AND f.subfield = '$subfield'";
97         if (ref $subfield) {
98                 $sf_where = "AND f.subfield IN ('".join("','",@$subfield)."')";
99         }
100
101         my $search_table = authority::full_rec->table;
102         my $marc_table = authority::record_entry->table;
103
104         my ($index_col) = authority::full_rec->columns('FTS');
105         $index_col ||= 'value';
106
107         my $fts = OpenILS::Application::Storage::FTS->compile(default => $term, 'f.value', "f.$index_col");
108
109         $term =~ s/\W+$//gso;
110         $term =~ s/'/''/gso;
111         $term =~ s/\pM//gso;
112
113         my $fts_where = $fts->sql_where_clause;
114         my $fts_words = join '%', $fts->words;
115
116     return undef unless ($fts_words);
117
118         my $fts_words_where = "f.value LIKE '$fts_words\%'";
119         my $fts_start_where = "f.value LIKE '$term\%'";
120         my $fts_eq_where = "f.value = '$term'";
121
122         my $fts_rank = join '+', $fts->fts_rank;
123
124         my $select = <<"        SQL";
125                 SELECT  a.marc, sum($fts_rank), count(f.record), first(f.value)
126                 FROM    $search_table f,
127                         $marc_table a
128                 WHERE   $fts_start_where
129                         $tag_where
130                         $sf_where
131                         AND a.id = f.record
132                         GROUP BY 1
133                         ORDER BY 2 desc, 3 desc, 4
134                         $limit
135                         $offset
136                         
137         SQL
138
139         $log->debug("Authority Search SQL :: [$select]",DEBUG);
140
141         my $recs = authority::full_rec->db_Main->selectcol_arrayref( $select );
142         
143         $log->debug("Search yielded ".scalar(@$recs)." results.",DEBUG);
144
145         $client->respond($_) for (@$recs);
146         return undef;
147 }
148 __PACKAGE__->register_method(
149         api_name        => "open-ils.storage.authority.search.marc",
150         method          => 'find_authority_marc',
151         api_level       => 1,
152         stream          => 1,
153         cachable        => 1,
154 );
155
156 sub _empty_check {
157         my $term = shift;
158         my $class = shift || 'metabib::full_rec';
159
160         my $table = $class->table;
161
162         my ($index_col) = $class->columns('FTS');
163         $index_col ||= 'value';
164
165         my $fts = OpenILS::Application::Storage::FTS->compile(default => $term, 'm.value', "m.$index_col");
166         my $fts_where = $fts->sql_where_clause;
167
168         my $sql = <<"   SQL";
169                 SELECT  TRUE
170                 FROM    $table m
171                 WHERE   $fts_where
172                 LIMIT 1
173         SQL
174
175         return $class->db_Main->selectcol_arrayref($sql)->[0];
176 }
177
178 my $prevtime;
179
180 sub find_see_from_controlled {
181         my $self = shift;
182         my $client = shift;
183         my $term = shift;
184         my $limit = shift;
185         my $offset = shift;
186
187         $prevtime = time;
188
189         (my $class = $self->api_name) =~ s/^.+authority.([^\.]+)\.see.+$/$1/o;
190         my $sf = 'a';
191         $sf = 't' if ($class eq 'title');
192
193         my @marc = $self->method_lookup('open-ils.storage.authority.search.marc')
194                         ->run( term => $term, tag => [400,410,411,430,450,455], subfield => $sf, limit => $limit, offset => $offset );
195
196         
197         for my $m ( @marc ) {
198                 my $doc = $parser->parse_string($m);
199                 my @nodes = $doc->documentElement->findnodes('//*[substring(@tag,1,1)="1"]/*[@code="a" or @code="d" or @code="x"]');
200                 my $list = [ map { $_->textContent } @nodes ];
201                 $client->respond( $list ) if (_empty_check(join(' ',@$list), "metabib::${class}_field_entry"));
202         }
203         return undef;
204 }
205 for my $class ( qw/title author subject keyword series/ ) {
206         __PACKAGE__->register_method(
207                 api_name        => "open-ils.storage.authority.$class.see_from.controlled",
208                 method          => 'find_see_from_controlled',
209                 api_level       => 1,
210                 stream          => 1,
211                 cachable        => 1,
212         );
213 }
214
215 sub find_see_also_from_controlled {
216         my $self = shift;
217         my $client = shift;
218         my $term = shift;
219         my $limit = shift;
220         my $offset = shift;
221
222         (my $class = $self->api_name) =~ s/^.+authority.([^\.]+)\.see.+$/$1/o;
223         my $sf = 'a';
224         $sf = 't' if ($class eq 'title');
225
226         my @marc = $self->method_lookup('open-ils.storage.authority.search.marc')
227                         ->run( term => $term, tag => [500,510,511,530,550,555], subfield => $sf, limit => $limit, offset => $offset );
228         for my $m ( @marc ) {
229                 my $doc = $parser->parse_string($m);
230                 my @nodes = $doc->documentElement->findnodes('//*[substring(@tag,1,1)="1"]/*[@code="a" or @code="d" or @code="x"]');
231                 my $list = [ map { $_->textContent } @nodes ];
232                 $client->respond( $list ) if (_empty_check(join(' ',@$list), "metabib::${class}_field_entry"));
233         }
234         return undef;
235 }
236 for my $class ( qw/title author subject keyword series/ ) {
237         __PACKAGE__->register_method(
238                 api_name        => "open-ils.storage.authority.$class.see_also_from.controlled",
239                 method          => 'find_see_also_from_controlled',
240                 api_level       => 1,
241                 stream          => 1,
242                 cachable        => 1,
243         );
244 }
245
246
247 1;