Bug 26922: Regression tests
[koha.git] / Koha / OAI / Server / ListBase.pm
blobf1567dfb47fc96e2da2b284fb73d7ece4fcfccf0
1 package Koha::OAI::Server::ListBase;
3 # Copyright The National Library of Finland, University of Helsinki 2016-2017
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 =head1 NAME
22 Koha::OAI::Server::ListBase - OAI ListIdentifiers/ListRecords shared functionality
24 =head1 DESCRIPTION
26 Koha::OAI::Server::ListBase contains OAI-PMH functions shared by ListIdentifiers and ListRecords.
28 =cut
30 use Modern::Perl;
31 use C4::Biblio;
32 use HTTP::OAI;
33 use Koha::OAI::Server::ResumptionToken;
34 use Koha::OAI::Server::Record;
35 use Koha::OAI::Server::DeletedRecord;
36 use C4::OAI::Sets;
37 use MARC::File::XML;
39 sub GetRecords {
40 my ($class, $self, $repository, $metadata, %args) = @_;
42 my $token = Koha::OAI::Server::ResumptionToken->new( %args );
43 my $dbh = C4::Context->dbh;
44 my $set;
45 if ( defined $token->{'set'} ) {
46 $set = GetOAISetBySpec($token->{'set'});
48 my $offset = $token->{offset};
49 my $deleted = defined $token->{deleted} ? $token->{deleted} : 0;
50 my $deleted_count = defined $token->{deleted_count} ? $token->{deleted_count} : 0;
51 my $max = $repository->{koha_max_count};
52 my $count = 0;
53 my $format = $args{metadataPrefix} || $token->{metadata_prefix};
54 my $include_items = $repository->items_included( $format );
56 # Since creating a union of normal and deleted record tables would be a heavy
57 # operation in a large database, build results in two stages:
58 # first deleted records ($deleted == 1), then normal records ($deleted == 0)
59 STAGELOOP:
60 for ( ; $deleted >= 0; $deleted-- ) {
61 my $table = $deleted ? 'deletedbiblio_metadata' : 'biblio_metadata';
62 my $sql = "
63 SELECT biblionumber
64 FROM $table
65 WHERE (timestamp >= ? AND timestamp <= ?)
67 my @bind_params = ($token->{'from_arg'}, $token->{'until_arg'});
69 if ($include_items) {
70 $sql .= "
71 OR biblionumber IN (SELECT biblionumber from deleteditems WHERE timestamp >= ? AND timestamp <= ?)
73 push @bind_params, ($token->{'from_arg'}, $token->{'until_arg'});
74 if (!$deleted) {
75 $sql .= "
76 OR biblionumber IN (SELECT biblionumber from items WHERE timestamp >= ? AND timestamp <= ?)
78 push @bind_params, ($token->{'from_arg'}, $token->{'until_arg'});
82 $sql .= "
83 ORDER BY biblionumber
86 # Use a subquery for sets since it allows us to use an index in
87 # biblioitems table and is quite a bit faster than a join.
88 if (defined $set) {
89 $sql = "
90 SELECT bi.* FROM ($sql) bi
91 WHERE bi.biblionumber in (SELECT osb.biblionumber FROM oai_sets_biblios osb WHERE osb.set_id = ?)
93 push @bind_params, $set->{'id'};
96 $sql .= "
97 LIMIT " . ($max + 1) . "
98 OFFSET " . ($offset - $deleted_count);
100 my $sth = $dbh->prepare( $sql ) || die( 'Could not prepare statement: ' . $dbh->errstr );
102 if ( $deleted ) {
103 $sql = "
104 SELECT MAX(timestamp)
105 FROM (
106 SELECT timestamp FROM deletedbiblio_metadata WHERE biblionumber = ?
107 UNION
108 SELECT timestamp FROM deleteditems WHERE biblionumber = ?
109 ) bis
111 } else {
112 $sql = "
113 SELECT MAX(timestamp)
114 FROM (
115 SELECT timestamp FROM biblio_metadata WHERE biblionumber = ?
116 UNION
117 SELECT timestamp FROM deleteditems WHERE biblionumber = ?
118 UNION
119 SELECT timestamp FROM items WHERE biblionumber = ?
120 ) bi
123 my $record_sth = $dbh->prepare( $sql ) || die( 'Could not prepare statement: ' . $dbh->errstr );
125 $sth->execute( @bind_params ) || die( 'Could not execute statement: ' . $sth->errstr );
126 while ( my ($biblionumber) = $sth->fetchrow ) {
127 $count++;
128 if ( $count > $max ) {
129 $self->resumptionToken(
130 Koha::OAI::Server::ResumptionToken->new(
131 metadataPrefix => $token->{metadata_prefix},
132 from => $token->{from},
133 until => $token->{until},
134 offset => $token->{offset} + $max,
135 set => $token->{set},
136 deleted => $deleted,
137 deleted_count => $deleted_count
140 last STAGELOOP;
142 my @params = $deleted ? ( $biblionumber, $biblionumber ) : ( $biblionumber, $biblionumber, $biblionumber );
143 $record_sth->execute( @params ) || die( 'Could not execute statement: ' . $sth->errstr );
145 my ($timestamp) = $record_sth->fetchrow;
147 my $oai_sets = GetOAISetsBiblio($biblionumber);
148 my @setSpecs;
149 foreach ( @$oai_sets ) {
150 push @setSpecs, $_->{spec};
152 if ( $metadata ) {
153 my $marcxml = !$deleted ? $repository->get_biblio_marcxml($biblionumber, $format) : undef;
154 if ( $marcxml ) {
155 $self->record( Koha::OAI::Server::Record->new(
156 $repository, $marcxml, $timestamp, \@setSpecs,
157 identifier => $repository->{ koha_identifier } . ':' . $biblionumber,
158 metadataPrefix => $token->{metadata_prefix}
159 ) );
160 } else {
161 $self->record( Koha::OAI::Server::DeletedRecord->new(
162 $timestamp, \@setSpecs, identifier => $repository->{ koha_identifier } . ':' . $biblionumber
163 ) );
165 } else {
166 $timestamp =~ s/ /T/;
167 $timestamp .= 'Z';
168 $self->identifier( HTTP::OAI::Header->new(
169 identifier => $repository->{ koha_identifier} . ':' . $biblionumber,
170 datestamp => $timestamp,
171 status => $deleted ? 'deleted' : undef
172 ) );
175 # Store offset and deleted record count
176 $offset += $count;
177 $deleted_count = $offset if ($deleted);
179 return $count;