]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher.pm
getting rid of TONS of unused generated functions
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Storage / Publisher.pm
1 package OpenILS::Application::Storage::Publisher;
2 use base qw/OpenILS::Application::Storage/;
3 our $VERSION = 1;
4
5 use Digest::MD5 qw/md5_hex/;
6 use OpenSRF::EX qw/:try/;
7 use OpenSRF::Utils;
8 use OpenSRF::Utils::Logger qw/:level/;
9 use OpenILS::Utils::Fieldmapper;
10
11 my $log = 'OpenSRF::Utils::Logger';
12
13
14 sub register_method {
15         my $class = shift;
16         my %args = @_;
17         my %dup_args = %args;
18
19         $class = ref($class) || $class;
20
21         $args{package} ||= $class;
22         __PACKAGE__->SUPER::register_method( %args );
23
24         if (exists($dup_args{cachable}) and $dup_args{cachable}) {
25                 (my $name = $dup_args{api_name}) =~ s/^open-ils\.storage/open-ils.storage.cachable/o;
26                 if ($name ne $dup_args{api_name}) {
27                         $dup_args{real_api_name} = $dup_args{api_name};
28                         $dup_args{method} = 'cachable_wrapper';
29                         $dup_args{api_name} = $name;
30                         $dup_args{package} = __PACKAGE__;
31                         __PACKAGE__->SUPER::register_method( %dup_args );
32                 }
33         }
34
35         if ($dup_args{real_api_name} =~ /^open-ils\.storage\.direct\..+\.search.+/o ||
36             $dup_args{api_name} =~ /^open-ils\.storage\.direct\..+\.search.+/o) {
37                 $dup_args{api_name} = $dup_args{real_api_name} if ($dup_args{real_api_name});
38
39                 (my $name = $dup_args{api_name}) =~ s/\.direct\./.id_list./o;
40
41                 $dup_args{notes} = $dup_args{real_api_name};
42                 $dup_args{real_api_name} = $dup_args{api_name};
43                 $dup_args{method} = 'search_ids';
44                 $dup_args{api_name} = $name;
45                 $dup_args{package} = __PACKAGE__;
46
47                 __PACKAGE__->SUPER::register_method( %dup_args );
48         }
49 }
50
51 sub cachable_wrapper {
52         my $self = shift;
53         my $client = shift;
54         my @args = @_;
55
56         my %cache_args = (
57                 limit           => 100,
58                 offset          => 0,
59                 timeout         => 7200,
60                 cache_page_size => 1000,
61         );
62
63         my @real_args;
64         my $key_string = $self->api_name;
65         for (my $ind = 0; $ind < scalar(@args); $ind++) {
66                 if (    $args[$ind] eq 'limit' ||
67                         $args[$ind] eq 'offset' ||
68                         $args[$ind] eq 'cache_page_size' ||
69                         $args[$ind] eq 'timeout' ) {
70
71                         my $key_ind = $ind;
72                         $ind++;
73                         my $value_ind = $ind;
74                         $cache_args{$args[$key_ind]} = $args[$value_ind];
75                         $log->debug("Cache limiter value for $args[$key_ind] is $args[$value_ind]", INTERNAL);
76                         next;
77                 }
78                 $key_string .= $args[$ind];
79                 $log->debug("Partial cache key value is $args[$ind]", INTERNAL);
80                 push @real_args, $args[$ind];
81         }
82
83         my $cache_page = int($cache_args{offset} / $cache_args{cache_page_size});
84         my $cache_key;
85         {       use bytes;
86                 $cache_key = md5_hex($key_string.$cache_page);
87         }
88
89         $log->debug("Key string for cache lookup is $key_string -> $cache_key", DEBUG);
90         $log->debug("Cache page is $cache_page", DEBUG);
91
92         my $cached_res = OpenSRF::Utils::Cache->new->get_cache( $cache_key );
93         if (defined $cached_res) {
94                 $log->debug("Found ".scalar(@$cached_res)." records in the cache", INFO);
95                 $log->debug("Values from cache: ".join(', ', @$cached_res), INTERNAL);
96                 my $start = int($cache_args{offset} - ($cache_page * $cache_args{cache_page_size}));
97                 my $end = int($start + $cache_args{limit} - 1);
98                 $log->debug("Responding with values from ".$start.' to '.$end,DEBUG);
99                 $client->respond( $_ ) for ( grep { defined } @$cached_res[ $start .. $end ]);
100                 return undef;
101         }
102
103         my $method = $self->method_lookup($self->{real_api_name});
104         my @res = $method->run(@real_args);
105
106
107         $client->respond( $_ ) for ( grep { defined } @res[$cache_args{offset} .. int($cache_args{offset} + $cache_args{limit} - 1)] );
108
109         $log->debug("Saving values from ".int($cache_page * $cache_args{cache_page_size})." to ".
110                 int(($cache_page + 1) * $cache_args{cache_page_size}). "to the cache", INTERNAL);
111         try {
112                 OpenSRF::Utils::Cache->new->put_cache(
113                         $cache_key =>
114                         [@res[int($cache_page * $cache_args{cache_page_size}) .. int(($cache_page + 1) * $cache_args{cache_page_size}) ]] =>
115                         OpenSRF::Utils->interval_to_seconds( $cache_args{timeout} )
116                 );
117         } catch Error with {
118                 my $e = shift;
119                 $log->error("Cache seems to be down, $e");
120         };
121
122         return undef;
123 }
124
125 sub retrieve_node {
126         my $self = shift;
127         my $client = shift;
128         my @ids = @_;
129
130         my $cdbi = $self->{cdbi};
131
132         for my $id ( @ids ) {
133                 next unless ($id);
134
135                 my ($rec) = $cdbi->fast_fieldmapper($id);
136                 if ($self->api_name !~ /batch/o) {
137                         return $rec if ($rec);
138                 }
139                 $client->respond($rec);
140         }
141         return undef;
142 }
143
144 sub search_ids {
145         my $self = shift;
146         my $client = shift;
147         my @args = @_;
148
149         my @res = $self->method_lookup($self->{real_api_name})->run(@args);
150
151         if (ref($res[0]) eq 'ARRAY') {
152                 return [ map { $_->id } @{ $res[0] } ];
153         }
154
155         $client->respond($_) for ( map { $_->id } @res );
156         return undef;
157 }
158
159 sub search_where {
160         my $self = shift;
161         my $client = shift;
162         my @args = @_;
163
164         if (ref($args[0]) eq 'HASH') {
165                 if ($args[1]) {
166                         $args[1]{limit_dialect} = $self->{cdbi}->db_Main;
167                 } else {
168                         $args[1] = {limit_dialect => $self->{cdbi}->db_Main };
169                 }
170         } else {
171                 $args[0] = { @args };
172                 $args[1] = {limit_dialect => $self->{cdbi} };
173         }
174
175         my $cdbi = $self->{cdbi};
176
177         for my $obj ($cdbi->search_where(@args)) {
178                 next unless ref($obj);
179                 $client->respond( $obj->to_fieldmapper );
180         }
181         return undef;
182 }
183
184 sub search {
185         my $self = shift;
186         my $client = shift;
187         my @args = @_;
188
189         my $cdbi = $self->{cdbi};
190
191         (my $search_type = $self->api_name) =~ s/.*\.(search[^.]*).*/$1/o;
192
193         for my $obj ($cdbi->$search_type(@args)) {
194                 next unless ref($obj);
195                 $client->respond( $obj->to_fieldmapper );
196         }
197         return undef;
198 }
199
200 sub search_one_field {
201         my $self = shift;
202         my $client = shift;
203         my @args = @_;
204
205         (my $field = $self->api_name) =~ s/.*\.([^\.]+)$/$1/o;
206
207         return search( $self, $client, $field, @args );
208 }
209
210 sub old_search_one_field {
211         my $self = shift;
212         my $client = shift;
213         my @terms = @_;
214
215         (my $search_type = $self->api_name) =~ s/.*\.(search[^.]*).*/$1/o;
216         (my $col = $self->api_name) =~ s/.*\.$search_type\.([^.]+).*/$1/;
217         my $cdbi = $self->{cdbi};
218
219         my $like = 0;
220         $like = 1 if ($search_type =~ /like$/o);
221         $like = 2 if ($search_type =~ /fts$/o);
222         $like = 3 if ($search_type =~ /regex$/o);
223
224         for my $term (@terms) {
225                 $log->debug("Searching $cdbi for $col using type $search_type, value '$term'",DEBUG);
226                 if (@terms == 1) {
227                         return [ $cdbi->fast_fieldmapper($term,$col,$like) ];
228                 }
229                 $client->respond( [ $cdbi->fast_fieldmapper($term,$col,$like) ] );
230         }
231         return undef;
232 }
233
234
235 sub create_node {
236         my $self = shift;
237         my $client = shift;
238         my $node = shift;
239
240         local $OpenILS::Application::Storage::WRITE = 1;
241
242         my $cdbi = $self->{cdbi};
243
244         my $success;
245         try {
246                 my $rec = $cdbi->create($node);
247                 $success = $rec->id if ($rec);
248         } catch Error with {
249                 $success = 0;
250         };
251
252         return $success;
253 }
254
255 sub update_node {
256         my $self = shift;
257         my $client = shift;
258         my $node = shift;
259
260         local $OpenILS::Application::Storage::WRITE = 1;
261
262         my $cdbi = $self->{cdbi};
263
264         return $cdbi->update($node);
265 }
266
267 sub mass_delete {
268         my $self = shift;
269         my $client = shift;
270         my $search = shift;
271
272         local $OpenILS::Application::Storage::WRITE = 1;
273
274         my $where = 'WHERE ';
275
276         my $cdbi = $self->{cdbi};
277         my $table = $cdbi->table;
278
279         my @keys = sort keys %$search;
280         
281         my @binds;
282         my @wheres;
283         for my $col ( @keys ) {
284                 if (ref($$search{$col}) and ref($$search{$col}) =~ /ARRAY/o) {
285                         push @wheres, "$col IN (" . join(',', map { '?' } @{ $$search{$col} }) . ')';
286                         push @binds, map { "$_" } @{ $$search{$col} };
287                 } else {
288                         push @wheres, "$col = ?";
289                         push @binds, $$search{$col};
290                 }
291         }
292         $where .= join ' AND ', @wheres;
293
294         my $delete = "DELETE FROM $table $where";
295
296         $log->debug("Performing MASS deletion : $delete",DEBUG);
297
298         my $dbh = $cdbi->db_Main;
299         my $success = 1;
300         try {
301                 my $sth = $dbh->prepare($delete);
302                 $sth->execute( @binds );
303                 $sth->finish;
304                 $log->debug("MASS Delete succeeded",DEBUG);
305         } catch Error with {
306                 $log->debug("MASS Delete FAILED : ".shift(),DEBUG);
307                 $success = 0;
308         };
309         return $success;
310 }
311
312 sub remote_update_node {
313         my $self = shift;
314         my $client = shift;
315         my $keys = shift;
316         my $vals = shift;
317
318         local $OpenILS::Application::Storage::WRITE = 1;
319
320         my $cdbi = $self->{cdbi};
321
322         my $success = 1;
323         try {
324                 $success = $cdbi->remote_update($keys,$vals);
325         } catch Error with {
326                 $success = 0;
327         };
328         return $success;
329 }
330
331 sub merge_node {
332         my $self = shift;
333         my $client = shift;
334         my $keys = shift;
335         my $vals = shift;
336
337         local $OpenILS::Application::Storage::WRITE = 1;
338
339         my $cdbi = $self->{cdbi};
340
341         my $success = 1;
342         try {
343                 $success = $cdbi->merge($keys,$vals)->id;
344         } catch Error with {
345                 $success = 0;
346         };
347         return $success;
348 }
349
350 sub delete_node {
351         my $self = shift;
352         my $client = shift;
353         my $node = shift;
354
355         local $OpenILS::Application::Storage::WRITE = 1;
356
357         my $cdbi = $self->{cdbi};
358
359         my $success = 1;
360         try {
361                 $success = $cdbi->delete($node);
362         } catch Error with {
363                 $success = 0;
364         };
365         return $success;
366 }
367
368 sub batch_call {
369         my $self = shift;
370         my $client = shift;
371         my @nodes = @_;
372
373         my $unwrap = $self->{unwrap};
374
375         my $cdbi = $self->{cdbi};
376         my $api_name = $self->api_name;
377         (my $single_call_api_name = $api_name) =~ s/batch\.//o;
378
379         $log->debug("Default $api_name looking up $single_call_api_name...",INTERNAL);
380         my $method = $self->method_lookup($single_call_api_name);
381
382         my @success;
383         while ( my $node = shift(@nodes) ) {
384                 my ($res) = $method->run( ($unwrap ? (@$node) : ($node)) ); 
385                 push(@success, 1) if ($res >= 0);
386         }
387
388         my $insert_total = 0;
389         $insert_total += $_ for (@success);
390
391         return $insert_total;
392 }
393
394
395 # --------------------- End of generic methods -----------------------
396
397
398 for my $pkg ( qw/actor action asset biblio config metabib authority money permission container/ ) {
399         "OpenILS::Application::Storage::Publisher::$pkg"->use;
400         if ($@) {
401                 $log->debug("ARG! Couldn't load $pkg class Publisher: $@", ERROR);
402                 throw OpenSRF::EX::ERROR ("ARG! Couldn't load $pkg class Publisher: $@");
403         }
404 }
405
406 for my $fmclass ( (Fieldmapper->classes) ) {
407
408         $log->debug("Generating methods for Fieldmapper class $fmclass", DEBUG);
409
410         next if ($fmclass->is_virtual);
411
412         (my $cdbi = $fmclass) =~ s/^Fieldmapper:://o;
413         (my $class = $cdbi) =~ s/::.*//o;
414         (my $api_class = $cdbi) =~ s/::/./go;
415         my $registration_class = __PACKAGE__ . "::$class";
416         my $api_prefix = 'open-ils.storage.direct.'.$api_class;
417
418         # Create the search methods
419         unless ( __PACKAGE__->is_registered( $api_prefix.'.search' ) ) {
420                 __PACKAGE__->register_method(
421                         api_name        => $api_prefix.'.search',
422                         method          => 'search',
423                         api_level       => 1,
424                         argc            => 2,
425                         stream          => 1,
426                         cdbi            => $cdbi,
427                         cachable        => 1,
428                 );
429         }
430
431         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_where' ) ) {
432                 __PACKAGE__->register_method(
433                         api_name        => $api_prefix.'.search_where',
434                         method          => 'search_where',
435                         api_level       => 1,
436                         stream          => 1,
437                         argc            => 1,
438                         cdbi            => $cdbi,
439                         cachable        => 1,
440                 );
441         }
442
443 =comment
444
445         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_like' ) ) {
446                 __PACKAGE__->register_method(
447                         api_name        => $api_prefix.'.search_like',
448                         method          => 'search',
449                         api_level       => 1,
450                         stream          => 1,
451                         cdbi            => $cdbi,
452                         cachable        => 1,
453                         argc            => 2,
454                 );
455         }
456
457         if (\&Class::DBI::search_fts and $cdbi->columns('FTS')) {
458                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search_fts' ) ) {
459                         __PACKAGE__->register_method(
460                                 api_name        => $api_prefix.'.search_fts',
461                                 method          => 'search',
462                                 api_level       => 1,
463                                 stream          => 1,
464                                 cdbi            => $cdbi,
465                                 cachable        => 1,
466                                 argc            => 2,
467                         );
468                 }
469         }
470
471         if (\&Class::DBI::search_regex) {
472                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search_regex' ) ) {
473                         __PACKAGE__->register_method(
474                                 api_name        => $api_prefix.'.search_regex',
475                                 method          => 'search',
476                                 api_level       => 1,
477                                 stream          => 1,
478                                 cdbi            => $cdbi,
479                                 cachable        => 1,
480                                 argc            => 2,
481                         );
482                 }
483         }
484
485         if (\&Class::DBI::search_ilike) {
486                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search_ilike' ) ) {
487                         __PACKAGE__->register_method(
488                                 api_name        => $api_prefix.'.search_ilike',
489                                 method          => 'search',
490                                 api_level       => 1,
491                                 stream          => 1,
492                                 cdbi            => $cdbi,
493                                 cachable        => 1,
494                                 argc            => 2,
495                         );
496                 }
497         }
498
499 =cut
500
501         # Create the retrieve method
502         unless ( __PACKAGE__->is_registered( $api_prefix.'.retrieve' ) ) {
503                 __PACKAGE__->register_method(
504                         api_name        => $api_prefix.'.retrieve',
505                         method          => 'retrieve_node',
506                         api_level       => 1,
507                         cdbi            => $cdbi,
508                         cachable        => 1,
509                         argc            => 1,
510                 );
511         }
512
513         # Create the batch retrieve method
514         unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.retrieve' ) ) {
515                 __PACKAGE__->register_method(
516                         api_name        => $api_prefix.'.batch.retrieve',
517                         method          => 'retrieve_node',
518                         api_level       => 1,
519                         stream          => 1,
520                         cdbi            => $cdbi,
521                         cachable        => 1,
522                         argc            => 1,
523                 );
524         }
525
526         for my $field ($fmclass->real_fields) {
527                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search.'.$field ) ) {
528                         __PACKAGE__->register_method(
529                                 api_name        => $api_prefix.'.search.'.$field,
530                                 method          => 'search_one_field',
531                                 api_level       => 1,
532                                 cdbi            => $cdbi,
533                                 cachable        => 1,
534                                 stream          => 1,
535                                 argc            => 1,
536                         );
537                 }
538
539 =comment
540
541                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search_like.'.$field ) ) {
542                         __PACKAGE__->register_method(
543                                 api_name        => $api_prefix.'.search_like.'.$field,
544                                 method          => 'search_one_field',
545                                 api_level       => 1,
546                                 cdbi            => $cdbi,
547                                 cachable        => 1,
548                                 stream          => 1,
549                                 argc            => 1,
550                         );
551                 }
552                 if (\&Class::DBI::search_fts and grep { $field eq $_ } $cdbi->columns('FTS')) {
553                         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_fts.'.$field ) ) {
554                                 __PACKAGE__->register_method(
555                                         api_name        => $api_prefix.'.search_fts.'.$field,
556                                         method          => 'search_one_field',
557                                         api_level       => 1,
558                                         cdbi            => $cdbi,
559                                         cachable        => 1,
560                                         stream          => 1,
561                                         argc            => 1,
562                                 );
563                         }
564                 }
565                 if (\&Class::DBI::search_regex) {
566                         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_regex.'.$field ) ) {
567                                 __PACKAGE__->register_method(
568                                         api_name        => $api_prefix.'.search_regex.'.$field,
569                                         method          => 'search_one_field',
570                                         api_level       => 1,
571                                         cdbi            => $cdbi,
572                                         cachable        => 1,
573                                         stream          => 1,
574                                         argc            => 1,
575                                 );
576                         }
577                 }
578                 if (\&Class::DBI::search_ilike) {
579                         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_ilike.'.$field ) ) {
580                                 __PACKAGE__->register_method(
581                                         api_name        => $api_prefix.'.search_ilike.'.$field,
582                                         method          => 'search_one_field',
583                                         api_level       => 1,
584                                         cdbi            => $cdbi,
585                                         cachable        => 1,
586                                         stream          => 1,
587                                         argc            => 1,
588                                 );
589                         }
590                 }
591
592 =cut
593
594         }
595
596
597         unless ($fmclass->is_readonly) {
598                 # Create the create method
599                 unless ( __PACKAGE__->is_registered( $api_prefix.'.create' ) ) {
600                         __PACKAGE__->register_method(
601                                 api_name        => $api_prefix.'.create',
602                                 method          => 'create_node',
603                                 api_level       => 1,
604                                 cdbi            => $cdbi,
605                                 argc            => 1,
606                         );
607                 }
608
609                 # Create the batch create method
610                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.create' ) ) {
611                         __PACKAGE__->register_method(
612                                 api_name        => $api_prefix.'.batch.create',
613                                 method          => 'batch_call',
614                                 api_level       => 1,
615                                 cdbi            => $cdbi,
616                                 argc            => 1,
617                         );
618                 }
619
620                 # Create the update method
621                 unless ( __PACKAGE__->is_registered( $api_prefix.'.update' ) ) {
622                         __PACKAGE__->register_method(
623                                 api_name        => $api_prefix.'.update',
624                                 method          => 'update_node',
625                                 api_level       => 1,
626                                 cdbi            => $cdbi,
627                                 argc            => 1,
628                         );
629                 }
630
631                 # Create the batch update method
632                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.update' ) ) {
633                         __PACKAGE__->register_method(
634                                 api_name        => $api_prefix.'.batch.update',
635                                 method          => 'batch_call',
636                                 api_level       => 1,
637                                 cdbi            => $cdbi,
638                                 argc            => 1,
639                         );
640                 }
641
642                 # Create the delete method
643                 unless ( __PACKAGE__->is_registered( $api_prefix.'.delete' ) ) {
644                         __PACKAGE__->register_method(
645                                 api_name        => $api_prefix.'.delete',
646                                 method          => 'delete_node',
647                                 api_level       => 1,
648                                 cdbi            => $cdbi,
649                                 argc            => 1,
650                         );
651                 }
652
653                 # Create the batch delete method
654                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.delete' ) ) {
655                         __PACKAGE__->register_method(
656                                 api_name        => $api_prefix.'.batch.delete',
657                                 method          => 'batch_call',
658                                 api_level       => 1,
659                                 cdbi            => $cdbi,
660                                 argc            => 1,
661                         );
662                 }
663
664                 # Create the merge method
665                 unless ( __PACKAGE__->is_registered( $api_prefix.'.merge' ) ) {
666                         __PACKAGE__->register_method(
667                                 api_name        => $api_prefix.'.merge',
668                                 method          => 'merge_node',
669                                 api_level       => 1,
670                                 cdbi            => $cdbi,
671                                 argc            => 1,
672                         );
673                 }
674
675                 # Create the batch merge method
676                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.merge' ) ) {
677                         __PACKAGE__->register_method(
678                                 api_name        => $api_prefix.'.batch.merge',
679                                 method          => 'batch_call',
680                                 unwrap          => 1,
681                                 api_level       => 1,
682                                 cdbi            => $cdbi,
683                                 argc            => 1,
684                         );
685                 }
686
687                 # Create the remote_update method
688                 unless ( __PACKAGE__->is_registered( $api_prefix.'.remote_update' ) ) {
689                         __PACKAGE__->register_method(
690                                 api_name        => $api_prefix.'.remote_update',
691                                 method          => 'remote_update_node',
692                                 api_level       => 1,
693                                 cdbi            => $cdbi,
694                                 argc            => 1,
695                         );
696                 }
697
698                 # Create the batch remote_update method
699                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.remote_update' ) ) {
700                         __PACKAGE__->register_method(
701                                 api_name        => $api_prefix.'.batch.remote_update',
702                                 method          => 'batch_call',
703                                 api_level       => 1,
704                                 unwrap          => 1,
705                                 cdbi            => $cdbi,
706                                 argc            => 1,
707                         );
708                 }
709
710                 # Create the search-based mass delete method
711                 unless ( __PACKAGE__->is_registered( $api_prefix.'.mass_delete' ) ) {
712                         __PACKAGE__->register_method(
713                                 api_name        => $api_prefix.'.mass_delete',
714                                 method          => 'mass_delete',
715                                 api_level       => 1,
716                                 cdbi            => $cdbi,
717                                 argc            => 1,
718                         );
719                 }
720         }
721 }
722
723 1;