[Koha-patches] [PATCH] bug 2503 [9/9]: refactoring and bugfixing on create_koc_db.pl
Andrew Moore
andrew.moore at liblime.com
Mon Aug 18 22:58:55 CEST 2008
This is the script that generates the patron and holdings database for the offline circ module. I
touched up a few parts of it:
* fixed the database syntax to squash a bug or two
* extracted some methods for readability and reuse
* added some documentation
* added a --file and --force command line argument
Here's an example crontab line that will generate the borrowers.db file each midnight.
0 0 * * * create_koc_db.pl --file /tmp/borrowers.db
---
offline_circ/create_koc_db.pl | 442 +++++++++++++++++++++++++++--------------
1 files changed, 295 insertions(+), 147 deletions(-)
diff --git a/offline_circ/create_koc_db.pl b/offline_circ/create_koc_db.pl
index 12db544..8b3c88d 100755
--- a/offline_circ/create_koc_db.pl
+++ b/offline_circ/create_koc_db.pl
@@ -1,202 +1,350 @@
#!/usr/bin/perl -w
-## FIXME: if there is an existing borrowers.db file it needs to be deleted before this script is ran.
+# 2008 Kyle Hall <kyle.m.hall at gmail.com>
+
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+#
+
+=head1 NAME
+
+create_koc_db.pl - create a database file for the offline circulation tool
+
+=head1 SYNOPSIS
+
+create_koc_db.pl
+
+ Options:
+ -help brief help message
+ -man full documentation
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<--help>
+
+Print a brief help message and exits.
+
+=item B<--man>
+
+Prints the manual page and exits.
+
+=item B<--file>
+
+the filename that we should use for the database file that we produce. Defaults to "borrowers.db"
+
+=item B<--force>
+
+Forcefully overwrite any existing db file. Defaults to false, so
+program will terminate prematurely if the file already exists.
+
+=back
+
+=head1 DESCRIPTION
+
+This script generates a sqlite database file full of patron and
+holdings data that can be used by an offline circulation tool.
+
+=head1 USAGE EXAMPLES
+
+This program could be run from cron to occasionally refresh the
+offline circulation database. For instance:
+
+C<0 0 * * * create_koc_db.pl>
+
+=head1 SEE ALSO
+
+This program was originally created to interact with Kyle Hall's
+offline circulation tool, which is available from
+L<http://kylehall.info/index.php/projects/koha-tools/koha-offline-circulation/>,
+but any similar tool could use the database that is produced.
+
+=cut
+
+use strict;
+use warnings;
use DBI;
+use Getopt::Long;
+use Pod::Usage;
use C4::Context;
-use strict;
+my $verbose = 0;
+my $help = 0;
+my $man = 0;
+my $filename = 'borrowers.db';
+my $force = 0;
+
+GetOptions(
+ 'verbose' => \$verbose,
+ 'help' => \$help,
+ 'man' => \$man,
+ 'file=s' => \$filename,
+ 'force' => \$force,
+) or pod2usage(2);
+pod2usage(1) if $help;
+pod2usage( -verbose => 2 ) if $man;
+
+prepare_file_for_writing($filename)
+ or die "file: '$filename' already exists. Use --force to overwrite\n";
## Create DB Connections
my $dbh_mysql = C4::Context->dbh;
-my $dbh_sqlite = DBI->connect("dbi:SQLite:dbname=borrowers.db","","");
+my $dbh_sqlite = DBI->connect( "dbi:SQLite:dbname=$filename", "", "" );
-## Create sqlite borrowers table to mirror the koha borrowers table structure
-my $sth_mysql = $dbh_mysql->prepare("DESCRIBE borrowers");
-$sth_mysql->execute();
+create_borrowers_table();
+populate_borrowers_table();
-my $sqlite_create_sql = "CREATE TABLE borrowers ( \n";
+create_issues_table();
+populate_issues_table();
-my $result = $sth_mysql->fetchrow_hashref();
-my $field = $result->{'Field'};
-my $type = $result->{'Type'};
-$sqlite_create_sql .= " $field $type ";
-
-while ( my $result = $sth_mysql->fetchrow_hashref() ) {
- $field = $result->{'Field'};
- $type = $result->{'Type'};
- $sqlite_create_sql .= " , \n $field $type ";
-}
-$sth_mysql->finish();
+=head1 INTERNAL METHODS
-$sqlite_create_sql .= " , \n total_fines decimal(28,6) "; ## Extra field to store the total fines for a borrower in.
-$sqlite_create_sql .= " ) ";
+=head2 prepare_file_for_writing
-my $sth_sqlite = $dbh_sqlite->prepare( $sqlite_create_sql );
-$sth_sqlite->execute();
-$sth_sqlite->finish();
+pass in the filename that we're considering using for the SQLite db.
-## Import the data from the koha.borrowers table into our sqlite table
-$sth_mysql = $dbh_mysql->prepare("SELECT * FROM borrowers ORDER BY borrowernumber DESC");
-my $fields_count = $sth_mysql->execute();
+returns true if we can use it.
-print "Number of Borrowers: $fields_count\n";
+returns false if we can't. For example, if it alredy exists and we
+don't have --force or don't have permissions to unlink it.
-while ( my $borrower = $sth_mysql->fetchrow_hashref ) {
- my @keys;
- my @values;
+=cut
- print "Working on Borrower # $borrower->{'borrowernumber'} \n";
+sub prepare_file_for_writing {
+ my $filename = shift;
+ if ( -e $filename ) {
- my $sql = "INSERT INTO borrowers ( ";
-
- my $firstLine = 1;
- foreach my $key (keys %$borrower) {
- if ( $firstLine ) {
- $sql .= '?';
- $firstLine = 0;
- } else {
- $sql .= ', ?';
+ # this file exists. remove it if --force.
+ if ($force) {
+ return unlink $filename;
+ } else {
+ return;
+ }
}
- push( @keys, $key );
- }
-
- $sql .= " ) VALUES ( ";
-
- $firstLine = 1;
- foreach my $key (keys %$borrower) {
- my $data = $borrower->{$key};
+ return $filename;
+}
+
+=head2 create_borrowers_table
+
+Create sqlite borrowers table to mirror the koha borrowers table structure
+
+=cut
+
+sub create_borrowers_table {
+
+ my %borrowers_info = get_columns_and_types_of_table( 'borrowers' );
+ my $sqlite_create_sql = "CREATE TABLE borrowers ( \n";
+
+ $sqlite_create_sql .= join(',', map{ $_ . ' ' . $borrowers_info{$_} } keys %borrowers_info);
- if ( $firstLine ) {
- $sql .= '?';
- $firstLine = 0;
- } else {
- $sql .= ', ?';
+ $sqlite_create_sql .= " , \n total_fines decimal(28,6) "; ## Extra field to store the total fines for a borrower in.
+ $sqlite_create_sql .= " ) ";
+
+ my $return = $dbh_sqlite->do($sqlite_create_sql);
+ unless ( $return ) {
+ warn 'unable to create borrowers table: ' . $dbh_sqlite->errstr();
}
- push( @values, $data );
- }
+ return $return;
+
+}
+
+=head2 populate_borrowers_table
- $sql .= " ) ";
+Import the data from the koha.borrowers table into our sqlite table
-print "\n$sql\n";
+=cut
- $sth_sqlite = $dbh_sqlite->prepare( $sql );
- $sth_sqlite->execute( @keys, @values );
- $sth_sqlite->finish();
+sub populate_borrowers_table {
+
+ my @borrower_fields = get_columns_of_table( 'borrowers' );
+
+ my $sql = "INSERT INTO borrowers ( ";
+ $sql .= join( ',', @borrower_fields );
+ $sql .= " ) VALUES ( ";
+ $sql .= join( ',', map { '?' } @borrower_fields );
+ $sql .= " ) ";
+ warn "$sql\n" if $verbose;
+ my $sth_sqlite = $dbh_sqlite->prepare($sql);
+
+ my $sth_mysql = $dbh_mysql->prepare("SELECT * FROM borrowers ORDER BY borrowernumber DESC");
+ my $fields_count = $sth_mysql->execute();
+ warn "Number of Borrowers: $fields_count\n" if $verbose;
+
+ while ( my $borrower = $sth_mysql->fetchrow_hashref ) {
+ warn "Working on Borrower # $borrower->{'borrowernumber'} \n" if $verbose;
+ $sth_sqlite->execute( @$borrower{ @borrower_fields } );
+ $sth_sqlite->finish();
+ }
+ add_fines_to_borrowers_table();
}
-## Import the fines from koha.accountlines into the sqlite db
-$sth_mysql = $dbh_mysql->prepare( "SELECT DISTINCT borrowernumber, SUM( amountoutstanding ) AS total_fines
+=head2 add_fines_to_borrowers_table
+
+Import the fines from koha.accountlines into the sqlite db
+
+=cut
+
+sub add_fines_to_borrowers_table {
+
+ my $sth_mysql = $dbh_mysql->prepare(
+ "SELECT DISTINCT borrowernumber, SUM( amountoutstanding ) AS total_fines
FROM accountlines
- GROUP BY borrowernumber" );
-while ( my $result = $sth_mysql->fetchrow_hashref() ) {
- my $borrowernumber = $result->{'borrowernumber'};
- my $total_fines = $result->{'total_fines'};
-
- print "Fines for Borrower # $borrowernumber are \$ $total_fines \n";
-
- my $sql = "UPDATE borrowers SET total_fines = ? WHERE borrowernumber = ?";
-
- $sth_sqlite = $dbh_sqlite->prepare( $sql );
- $sth_sqlite->execute( $total_fines, $borrowernumber );
- $sth_sqlite->finish();
+ GROUP BY borrowernumber"
+ );
+ $sth_mysql->execute();
+ while ( my $result = $sth_mysql->fetchrow_hashref() ) {
+ my $borrowernumber = $result->{'borrowernumber'};
+ my $total_fines = $result->{'total_fines'};
+
+ warn "Fines for Borrower # $borrowernumber are \$ $total_fines \n" if $verbose;
+
+ my $sql = "UPDATE borrowers SET total_fines = ? WHERE borrowernumber = ?";
+
+ my $sth_sqlite = $dbh_sqlite->prepare($sql);
+ $sth_sqlite->execute( $total_fines, $borrowernumber );
+ $sth_sqlite->finish();
+ }
}
-## Create sqlite issues table with minimal information needed from koha tables issues, items, biblio, biblioitems
-my $fields = GetIssuesFields();
+=head2 create_issue_table
-$sqlite_create_sql = "CREATE TABLE issues ( \n";
+Create sqlite issues table with minimal information needed from koha tables issues, items, biblio, biblioitems
-my $firstField = 1;
-foreach my $key (keys %$fields) {
- my $field = $key;
- my $type = $fields->{$key};
+=cut
+
+sub create_issues_table {
+
+ my $fields = get_columns_for_issues_table();
+
+ my $sqlite_create_sql = "CREATE TABLE issues ( \n";
+
+ my $firstField = 1;
+ foreach my $key ( keys %$fields ) {
+ my $field = $key;
+ my $type = $fields->{$key};
+
+ if ($firstField) {
+ $sqlite_create_sql .= " $field $type ";
+ $firstField = 0;
+ } else {
+ $sqlite_create_sql .= ", \n $field $type ";
+ }
+ }
+ $sqlite_create_sql .= " ) ";
+ warn $sqlite_create_sql if $verbose;
+
+ my $sth_sqlite = $dbh_sqlite->prepare($sqlite_create_sql);
+ $sth_sqlite->execute();
+ $sth_sqlite->finish();
- if ( $firstField ) {
- $sqlite_create_sql .= " $field, $type ";
- $firstField = 0;
- } else {
- $sqlite_create_sql .= ", \n $field, $type ";
- }
}
-$sqlite_create_sql .= " ) ";
-$sth_sqlite = $dbh_sqlite->preapre( $sqlite_create_sql );
-$sth_sqlite->execute();
-$sth_sqlite->finish();
+=head2 populate_issues_table
+
+Import open issues from the koha database
-## Import open issues from the koha database
-$sth_mysql = $dbh_mysql->prepare( "SELECT * FROM issues, items, biblioitems, biblio
+=cut
+
+sub populate_issues_table {
+
+ my $sth_mysql = $dbh_mysql->prepare(
+ "SELECT * FROM issues, items, biblioitems, biblio
WHERE issues.itemnumber = items.itemnumber
AND items.biblionumber = biblioitems.biblionumber
AND items.biblionumber = biblio.biblionumber
AND returndate IS NULL
- ORDER By borrowernumber DESC" );
+ ORDER By borrowernumber DESC"
+ );
+ $sth_mysql->execute();
-while ( my $result = $sth_mysql->fetchrow_hashref ) {
- my @keys;
- my @values;
+ while ( my $result = $sth_mysql->fetchrow_hashref ) {
- print "Adding issue for Borrower # $result->{'borrowernumber'} \n";
+ # my @keys;
+ # my @values;
- my $sql = "INSERT INTO issues ( ";
-
- my $firstLine = 1;
- foreach my $key (keys %$result) {
- if ( $firstLine ) {
- $sql .= '?';
- $firstLine = 0;
- } else {
- $sql .= ', ?';
- }
- push( @keys, $key );
- }
-
- $sql .= " ) VALUES ( ";
-
- $firstLine = 1;
- foreach my $key (keys %$result) {
- my $data = $result->{$key};
-
- if ( $firstLine ) {
- $sql .= '?';
- $firstLine = 0;
- } else {
- $sql .= ', ?';
+ warn "Adding issue for Borrower # $result->{'borrowernumber'} \n" if $verbose;
+
+ my $sql = "INSERT INTO issues ( ";
+ $sql .= join( ',', keys %$result );
+ $sql .= " ) VALUES ( ";
+ $sql .= join( ',', map { '?' } keys %$result );
+ $sql .= " ) ";
+
+ warn "$sql\n" if $verbose;
+
+ my $sth_sqlite = $dbh_sqlite->prepare($sql);
+ $sth_sqlite->execute( values %$result );
+ $sth_sqlite->finish();
}
- push( @values, $data );
- }
+}
+
+=head2 get_columns_of_table
+
+pass in the name of a database table.
+
+returns list of column names in that table.
+
+=cut
+
+sub get_columns_of_table {
+ my $table_name = shift;
+
+ my %column_info = get_columns_and_types_of_table( $table_name );
+ my @columns = keys %column_info;
+ return @columns;
+
+}
+
+=head2 get_columns_and_types_of_table
- $sql .= " ) ";
+pass in the name of a database table
-print "\n$sql\n";
+returns a hash of column names to their types.
+
+=cut
+
+sub get_columns_and_types_of_table {
+ my $table_name = shift;
+
+ my $column_info = $dbh_mysql->selectall_arrayref( "SHOW COLUMNS FROM $table_name" );
+ my %columns = map{ $_->[0] => $_->[1] } @$column_info;
+ return %columns;
- $sth_sqlite = $dbh_sqlite->prepare( $sql );
- $sth_sqlite->execute( @keys, @values );
- $sth_sqlite->finish();
}
+=head2 get_columns_for_issues_table
+
+This sub returns a hashref where the keys are all the fields in the given tables, and the data is the field's type
-## This sub returns a hashref where the keys are all the fields in the given tables, and the data is the field's type
-sub GetIssuesFields {
- my $dbh = C4::Context->dbh;
+=cut
+
+sub get_columns_for_issues_table {
my @tables = ( 'issues', 'items', 'biblioitems', 'biblio' );
- my $fields;
+
+ my %fields;
foreach my $table ( @tables ) {
- my $sth = $dbh->prepare( 'DESCRIBE ?' );
- $sth->execute( $table );
-
- while ( my $result = $sth->fetchrow_hashref ) {
- my $field = $result->{'Field'};
- my $type = $result->{'Type'};
-
- $fields->{$field} = $type;
- }
-
- $sth->finish()
+ my %table_info = get_columns_and_types_of_table( $table );
+ %fields = ( %fields, %table_info );
}
-
- return $fields;
-}
\ No newline at end of file
+ return \%fields;
+}
+
+1;
+__END__
+
--
1.5.6
More information about the Koha-patches
mailing list