]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher.pm
adding id_list varient to the storage search API
[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         my $cdbi = $self->{cdbi};
241
242         my $success;
243         try {
244                 my $rec = $cdbi->create($node);
245                 $success = $rec->id if ($rec);
246         } catch Error with {
247                 $success = 0;
248         };
249
250         return $success;
251 }
252
253 sub update_node {
254         my $self = shift;
255         my $client = shift;
256         my $node = shift;
257
258         my $cdbi = $self->{cdbi};
259
260         return $cdbi->update($node);
261 }
262
263 sub mass_delete {
264         my $self = shift;
265         my $client = shift;
266         my $search = shift;
267
268         my $where = 'WHERE ';
269
270         my $cdbi = $self->{cdbi};
271         my $table = $cdbi->table;
272
273         my @keys = sort keys %$search;
274         
275         my @binds;
276         my @wheres;
277         for my $col ( @keys ) {
278                 if (ref($$search{$col}) and ref($$search{$col}) =~ /ARRAY/o) {
279                         push @wheres, "$col IN (" . join(',', map { '?' } @{ $$search{$col} }) . ')';
280                         push @binds, map { "$_" } @{ $$search{$col} };
281                 } else {
282                         push @wheres, "$col = ?";
283                         push @binds, $$search{$col};
284                 }
285         }
286         $where .= join ' AND ', @wheres;
287
288         my $delete = "DELETE FROM $table $where";
289
290         $log->debug("Performing MASS deletion : $delete",DEBUG);
291
292         my $dbh = $cdbi->db_Main;
293         my $success = 1;
294         try {
295                 my $sth = $dbh->prepare($delete);
296                 $sth->execute( @binds );
297                 $sth->finish;
298                 $log->debug("MASS Delete succeeded",DEBUG);
299         } catch Error with {
300                 $log->debug("MASS Delete FAILED : ".shift(),DEBUG);
301                 $success = 0;
302         };
303         return $success;
304 }
305
306 sub remote_update_node {
307         my $self = shift;
308         my $client = shift;
309         my $keys = shift;
310         my $vals = shift;
311
312         my $cdbi = $self->{cdbi};
313
314         my $success = 1;
315         try {
316                 $success = $cdbi->remote_update($keys,$vals);
317         } catch Error with {
318                 $success = 0;
319         };
320         return $success;
321 }
322
323 sub merge_node {
324         my $self = shift;
325         my $client = shift;
326         my $keys = shift;
327         my $vals = shift;
328
329         my $cdbi = $self->{cdbi};
330
331         my $success = 1;
332         try {
333                 $success = $cdbi->merge($keys,$vals)->id;
334         } catch Error with {
335                 $success = 0;
336         };
337         return $success;
338 }
339
340 sub delete_node {
341         my $self = shift;
342         my $client = shift;
343         my $node = shift;
344
345         my $cdbi = $self->{cdbi};
346
347         my $success = 1;
348         try {
349                 $success = $cdbi->delete($node);
350         } catch Error with {
351                 $success = 0;
352         };
353         return $success;
354 }
355
356 sub batch_call {
357         my $self = shift;
358         my $client = shift;
359         my @nodes = @_;
360
361         my $unwrap = $self->{unwrap};
362
363         my $cdbi = $self->{cdbi};
364         my $api_name = $self->api_name;
365         (my $single_call_api_name = $api_name) =~ s/batch\.//o;
366
367         $log->debug("Default $api_name looking up $single_call_api_name...",INTERNAL);
368         my $method = $self->method_lookup($single_call_api_name);
369
370         my @success;
371         while ( my $node = shift(@nodes) ) {
372                 my ($res) = $method->run( ($unwrap ? (@$node) : ($node)) ); 
373                 push(@success, 1) if ($res >= 0);
374         }
375
376         my $insert_total = 0;
377         $insert_total += $_ for (@success);
378
379         return $insert_total;
380 }
381
382 OpenILS::Application::Storage::Publisher::actor->use;
383 if ($@) {
384         $log->debug("ARG! Couldn't load actor class Publisher: $@", ERROR);
385         throw OpenSRF::EX::ERROR ("ARG! Couldn't load actor class Publisher: $@");
386 }
387
388 OpenILS::Application::Storage::Publisher::action->use;
389 if ($@) {
390         $log->debug("ARG! Couldn't load action class Publisher: $@", ERROR);
391         throw OpenSRF::EX::ERROR ("ARG! Couldn't load action class Publisher: $@");
392 }
393
394 OpenILS::Application::Storage::Publisher::asset->use;
395 if ($@) {
396         $log->debug("ARG! Couldn't load asset class Publisher: $@", ERROR);
397         throw OpenSRF::EX::ERROR ("ARG! Couldn't load asset class Publisher: $@");
398 }
399
400 OpenILS::Application::Storage::Publisher::biblio->use;
401 if ($@) {
402         $log->debug("ARG! Couldn't load biblio class Publisher: $@", ERROR);
403         throw OpenSRF::EX::ERROR ("ARG! Couldn't load biblio class Publisher: $@");
404 }
405
406 OpenILS::Application::Storage::Publisher::config->use;
407 if ($@) {
408         $log->debug("ARG! Couldn't load config class Publisher: $@", ERROR);
409         throw OpenSRF::EX::ERROR ("ARG! Couldn't load config class Publisher: $@");
410 }
411
412 OpenILS::Application::Storage::Publisher::metabib->use;
413 if ($@) {
414         $log->debug("ARG! Couldn't load metabib class Publisher: $@", ERROR);
415         throw OpenSRF::EX::ERROR ("ARG! Couldn't load metabib class Publisher: $@");
416 }
417
418 OpenILS::Application::Storage::Publisher::authority->use;
419 if ($@) {
420         $log->debug("ARG! Couldn't load authority class Publisher: $@", ERROR);
421         throw OpenSRF::EX::ERROR ("ARG! Couldn't load authority class Publisher: $@");
422 }
423
424 OpenILS::Application::Storage::Publisher::money->use;
425 if ($@) {
426         $log->debug("ARG! Couldn't load money class Publisher: $@", ERROR);
427         throw OpenSRF::EX::ERROR ("ARG! Couldn't load money class Publisher: $@");
428 }
429
430 OpenILS::Application::Storage::Publisher::permission->use;
431 if ($@) {
432         $log->debug("ARG! Couldn't load permission class Publisher: $@", ERROR);
433         throw OpenSRF::EX::ERROR ("ARG! Couldn't load permission class Publisher: $@");
434 }
435
436 OpenILS::Application::Storage::Publisher::container->use;
437 if ($@) {
438         $log->debug("ARG! Couldn't load container class Publisher: $@", ERROR);
439         throw OpenSRF::EX::ERROR ("ARG! Couldn't load container class Publisher: $@");
440 }
441
442
443
444 for my $fmclass ( (Fieldmapper->classes) ) {
445
446         $log->debug("Generating methods for Fieldmapper class $fmclass", DEBUG);
447
448         next if ($fmclass->is_virtual);
449
450         (my $cdbi = $fmclass) =~ s/^Fieldmapper:://o;
451         (my $class = $cdbi) =~ s/::.*//o;
452         (my $api_class = $cdbi) =~ s/::/./go;
453         my $registration_class = __PACKAGE__ . "::$class";
454         my $api_prefix = 'open-ils.storage.direct.'.$api_class;
455
456         # Create the search methods
457         unless ( __PACKAGE__->is_registered( $api_prefix.'.search' ) ) {
458                 __PACKAGE__->register_method(
459                         api_name        => $api_prefix.'.search',
460                         method          => 'search',
461                         api_level       => 1,
462                         argc            => 2,
463                         stream          => 1,
464                         cdbi            => $cdbi,
465                         cachable        => 1,
466                 );
467         }
468
469         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_where' ) ) {
470                 __PACKAGE__->register_method(
471                         api_name        => $api_prefix.'.search_where',
472                         method          => 'search_where',
473                         api_level       => 1,
474                         stream          => 1,
475                         argc            => 1,
476                         cdbi            => $cdbi,
477                         cachable        => 1,
478                 );
479         }
480
481         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_like' ) ) {
482                 __PACKAGE__->register_method(
483                         api_name        => $api_prefix.'.search_like',
484                         method          => 'search',
485                         api_level       => 1,
486                         stream          => 1,
487                         cdbi            => $cdbi,
488                         cachable        => 1,
489                         argc            => 2,
490                 );
491         }
492
493         if (\&Class::DBI::search_fts) {
494                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search_fts' ) ) {
495                         __PACKAGE__->register_method(
496                                 api_name        => $api_prefix.'.search_fts',
497                                 method          => 'search',
498                                 api_level       => 1,
499                                 stream          => 1,
500                                 cdbi            => $cdbi,
501                                 cachable        => 1,
502                                 argc            => 2,
503                         );
504                 }
505         }
506
507         if (\&Class::DBI::search_regex) {
508                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search_regex' ) ) {
509                         __PACKAGE__->register_method(
510                                 api_name        => $api_prefix.'.search_regex',
511                                 method          => 'search',
512                                 api_level       => 1,
513                                 stream          => 1,
514                                 cdbi            => $cdbi,
515                                 cachable        => 1,
516                                 argc            => 2,
517                         );
518                 }
519         }
520
521         if (\&Class::DBI::search_ilike) {
522                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search_ilike' ) ) {
523                         __PACKAGE__->register_method(
524                                 api_name        => $api_prefix.'.search_ilike',
525                                 method          => 'search',
526                                 api_level       => 1,
527                                 stream          => 1,
528                                 cdbi            => $cdbi,
529                                 cachable        => 1,
530                                 argc            => 2,
531                         );
532                 }
533         }
534
535         # Create the retrieve method
536         unless ( __PACKAGE__->is_registered( $api_prefix.'.retrieve' ) ) {
537                 __PACKAGE__->register_method(
538                         api_name        => $api_prefix.'.retrieve',
539                         method          => 'retrieve_node',
540                         api_level       => 1,
541                         cdbi            => $cdbi,
542                         cachable        => 1,
543                         argc            => 1,
544                 );
545         }
546
547         # Create the batch retrieve method
548         unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.retrieve' ) ) {
549                 __PACKAGE__->register_method(
550                         api_name        => $api_prefix.'.batch.retrieve',
551                         method          => 'retrieve_node',
552                         api_level       => 1,
553                         stream          => 1,
554                         cdbi            => $cdbi,
555                         cachable        => 1,
556                         argc            => 1,
557                 );
558         }
559
560         for my $field ($fmclass->real_fields) {
561                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search.'.$field ) ) {
562                         __PACKAGE__->register_method(
563                                 api_name        => $api_prefix.'.search.'.$field,
564                                 method          => 'search_one_field',
565                                 api_level       => 1,
566                                 cdbi            => $cdbi,
567                                 cachable        => 1,
568                                 stream          => 1,
569                                 argc            => 1,
570                         );
571                 }
572                 unless ( __PACKAGE__->is_registered( $api_prefix.'.search_like.'.$field ) ) {
573                         __PACKAGE__->register_method(
574                                 api_name        => $api_prefix.'.search_like.'.$field,
575                                 method          => 'search_one_field',
576                                 api_level       => 1,
577                                 cdbi            => $cdbi,
578                                 cachable        => 1,
579                                 stream          => 1,
580                                 argc            => 1,
581                         );
582                 }
583                 if (\&Class::DBI::search_fts) {
584                         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_fts.'.$field ) ) {
585                                 __PACKAGE__->register_method(
586                                         api_name        => $api_prefix.'.search_fts.'.$field,
587                                         method          => 'search_one_field',
588                                         api_level       => 1,
589                                         cdbi            => $cdbi,
590                                         cachable        => 1,
591                                         stream          => 1,
592                                         argc            => 1,
593                                 );
594                         }
595                 }
596                 if (\&Class::DBI::search_regex) {
597                         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_regex.'.$field ) ) {
598                                 __PACKAGE__->register_method(
599                                         api_name        => $api_prefix.'.search_regex.'.$field,
600                                         method          => 'search_one_field',
601                                         api_level       => 1,
602                                         cdbi            => $cdbi,
603                                         cachable        => 1,
604                                         stream          => 1,
605                                         argc            => 1,
606                                 );
607                         }
608                 }
609                 if (\&Class::DBI::search_ilike) {
610                         unless ( __PACKAGE__->is_registered( $api_prefix.'.search_ilike.'.$field ) ) {
611                                 __PACKAGE__->register_method(
612                                         api_name        => $api_prefix.'.search_ilike.'.$field,
613                                         method          => 'search_one_field',
614                                         api_level       => 1,
615                                         cdbi            => $cdbi,
616                                         cachable        => 1,
617                                         stream          => 1,
618                                         argc            => 1,
619                                 );
620                         }
621                 }
622         }
623
624
625         unless ($fmclass->is_readonly) {
626                 # Create the create method
627                 unless ( __PACKAGE__->is_registered( $api_prefix.'.create' ) ) {
628                         __PACKAGE__->register_method(
629                                 api_name        => $api_prefix.'.create',
630                                 method          => 'create_node',
631                                 api_level       => 1,
632                                 cdbi            => $cdbi,
633                                 argc            => 1,
634                         );
635                 }
636
637                 # Create the batch create method
638                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.create' ) ) {
639                         __PACKAGE__->register_method(
640                                 api_name        => $api_prefix.'.batch.create',
641                                 method          => 'batch_call',
642                                 api_level       => 1,
643                                 cdbi            => $cdbi,
644                                 argc            => 1,
645                         );
646                 }
647
648                 # Create the update method
649                 unless ( __PACKAGE__->is_registered( $api_prefix.'.update' ) ) {
650                         __PACKAGE__->register_method(
651                                 api_name        => $api_prefix.'.update',
652                                 method          => 'update_node',
653                                 api_level       => 1,
654                                 cdbi            => $cdbi,
655                                 argc            => 1,
656                         );
657                 }
658
659                 # Create the batch update method
660                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.update' ) ) {
661                         __PACKAGE__->register_method(
662                                 api_name        => $api_prefix.'.batch.update',
663                                 method          => 'batch_call',
664                                 api_level       => 1,
665                                 cdbi            => $cdbi,
666                                 argc            => 1,
667                         );
668                 }
669
670                 # Create the delete method
671                 unless ( __PACKAGE__->is_registered( $api_prefix.'.delete' ) ) {
672                         __PACKAGE__->register_method(
673                                 api_name        => $api_prefix.'.delete',
674                                 method          => 'delete_node',
675                                 api_level       => 1,
676                                 cdbi            => $cdbi,
677                                 argc            => 1,
678                         );
679                 }
680
681                 # Create the batch delete method
682                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.delete' ) ) {
683                         __PACKAGE__->register_method(
684                                 api_name        => $api_prefix.'.batch.delete',
685                                 method          => 'batch_call',
686                                 api_level       => 1,
687                                 cdbi            => $cdbi,
688                                 argc            => 1,
689                         );
690                 }
691
692                 # Create the merge method
693                 unless ( __PACKAGE__->is_registered( $api_prefix.'.merge' ) ) {
694                         __PACKAGE__->register_method(
695                                 api_name        => $api_prefix.'.merge',
696                                 method          => 'merge_node',
697                                 api_level       => 1,
698                                 cdbi            => $cdbi,
699                                 argc            => 1,
700                         );
701                 }
702
703                 # Create the batch merge method
704                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.merge' ) ) {
705                         __PACKAGE__->register_method(
706                                 api_name        => $api_prefix.'.batch.merge',
707                                 method          => 'batch_call',
708                                 unwrap          => 1,
709                                 api_level       => 1,
710                                 cdbi            => $cdbi,
711                                 argc            => 1,
712                         );
713                 }
714
715                 # Create the remote_update method
716                 unless ( __PACKAGE__->is_registered( $api_prefix.'.remote_update' ) ) {
717                         __PACKAGE__->register_method(
718                                 api_name        => $api_prefix.'.remote_update',
719                                 method          => 'remote_update_node',
720                                 api_level       => 1,
721                                 cdbi            => $cdbi,
722                                 argc            => 1,
723                         );
724                 }
725
726                 # Create the batch remote_update method
727                 unless ( __PACKAGE__->is_registered( $api_prefix.'.batch.remote_update' ) ) {
728                         __PACKAGE__->register_method(
729                                 api_name        => $api_prefix.'.batch.remote_update',
730                                 method          => 'batch_call',
731                                 api_level       => 1,
732                                 unwrap          => 1,
733                                 cdbi            => $cdbi,
734                                 argc            => 1,
735                         );
736                 }
737
738                 # Create the search-based mass delete method
739                 unless ( __PACKAGE__->is_registered( $api_prefix.'.mass_delete' ) ) {
740                         __PACKAGE__->register_method(
741                                 api_name        => $api_prefix.'.mass_delete',
742                                 method          => 'mass_delete',
743                                 api_level       => 1,
744                                 cdbi            => $cdbi,
745                                 argc            => 1,
746                         );
747                 }
748         }
749 }
750
751 1;