updated Storage server
authormiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 29 Mar 2005 21:10:37 +0000 (21:10 +0000)
committermiker <miker@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 29 Mar 2005 21:10:37 +0000 (21:10 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@410 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/perlmods/OpenILS/Application/Storage.pm
Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI.pm
Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/biblio.pm
Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/metabib.pm
Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg.pm
Open-ILS/src/perlmods/OpenILS/Application/Storage/Publisher.pm
Open-ILS/src/perlmods/OpenILS/Application/Storage/WORM.pm [new file with mode: 0644]

index 9446909..99adc93 100644 (file)
@@ -12,6 +12,7 @@ use OpenILS::Application::Storage::FTS;
 
 # Suck in the method publishing modules
 use OpenILS::Application::Storage::Publisher;
+use OpenILS::Application::Storage::WORM;
 
 # the easy way to get to the logger...
 my $log = "OpenSRF::Utils::Logger";
@@ -31,7 +32,11 @@ sub initialize {
        $log->debug("Attempting to load $driver ...", DEBUG);
 
        eval "use $driver;";
-       throw OpenILS::EX::PANIC ( "Can't load $driver!  :  $@" ) if ($@);
+       if ($@) {
+               $log->debug( "Can't load $driver!  :  $@", ERROR );
+               $log->error( "Can't load $driver!  :  $@");
+               throw OpenILS::EX::PANIC ( "Can't load $driver!  :  $@" );
+       }
 
        $log->debug("$driver loaded successfully", DEBUG);
 
index 5757130..1ceda15 100644 (file)
@@ -314,10 +314,11 @@ sub import {
        biblio::record_entry->has_many( call_numbers => 'asset::call_number' );
        
        # should we have just one field entry per class for each record???? (xslt vs xpath)
-       #biblio::record_entry->has_a( title_field_entries => 'metabib::title_field_entry' );
-       #biblio::record_entry->has_a( author_field_entries => 'metabib::author_field_entry' );
-       #biblio::record_entry->has_a( subject_field_entries => 'metabib::subject_field_entry' );
-       #biblio::record_entry->has_a( keyword_field_entries => 'metabib::keyword_field_entry' );
+       #biblio::record_entry->has_a( item_type => 'config::item_type_map' );
+       biblio::record_entry->has_many( title_field_entries => 'metabib::title_field_entry' );
+       biblio::record_entry->has_many( author_field_entries => 'metabib::author_field_entry' );
+       biblio::record_entry->has_many( subject_field_entries => 'metabib::subject_field_entry' );
+       biblio::record_entry->has_many( keyword_field_entries => 'metabib::keyword_field_entry' );
        #-------------------------------------------------------------------------------
        biblio::record_node->has_a( owner_doc => 'biblio::record_entry' );
        #biblio::record_node->has_a(
@@ -330,18 +331,18 @@ sub import {
        metabib::full_rec->has_a( record => 'biblio::record_entry' );
        #-------------------------------------------------------------------------------
        metabib::metarecord->has_a( master_record => 'biblio::record_entry' );
-       metabib::metarecord->has_many( source_records => [ 'metabib::metarecord_source_map' => 'source_record'] );
+       metabib::metarecord->has_many( source_records => [ 'metabib::metarecord_source_map' => 'source'] );
        #-------------------------------------------------------------------------------
-       metabib::title_field_entry->has_many( source_records => [ 'metabib::title_field_entry_source_map' => 'source_record'] );
+       metabib::title_field_entry->has_many( source_records => [ 'metabib::title_field_entry_source_map' => 'source'] );
        metabib::title_field_entry->has_a( field => 'config::metabib_field' );
        #-------------------------------------------------------------------------------
-       metabib::author_field_entry->has_many( source_records => [ 'metabib::author_field_entry_source_map' => 'source_record'] );
+       metabib::author_field_entry->has_many( source_records => [ 'metabib::author_field_entry_source_map' => 'source'] );
        metabib::author_field_entry->has_a( field => 'config::metabib_field' );
        #-------------------------------------------------------------------------------
-       metabib::subject_field_entry->has_many( source_records => [ 'metabib::title_field_entry_source_map' => 'source_record'] );
+       metabib::subject_field_entry->has_many( source_records => [ 'metabib::title_field_entry_source_map' => 'source'] );
        metabib::subject_field_entry->has_a( field => 'config::metabib_field' );
        #-------------------------------------------------------------------------------
-       metabib::keyword_field_entry->has_many( source_records => [ 'metabib::keyword_field_entry_source_map' => 'source_record'] );
+       metabib::keyword_field_entry->has_many( source_records => [ 'metabib::keyword_field_entry_source_map' => 'source'] );
        metabib::keyword_field_entry->has_a( field => 'config::metabib_field' );
        #-------------------------------------------------------------------------------
        metabib::metarecord_source_map->has_a( metarecord => 'metabib::metarecord' );
@@ -350,21 +351,21 @@ sub import {
 
 
        # should we have just one field entry per class for each record???? (xslt vs xpath)
-       metabib::title_field_entry_source_map->has_a( field_entry => 'metabib::title_field_entry' );
-       metabib::title_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
-       metabib::title_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
+       #metabib::title_field_entry_source_map->has_a( field_entry => 'metabib::title_field_entry' );
+       #metabib::title_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
+       #metabib::title_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
        #-------------------------------------------------------------------------------
-       metabib::subject_field_entry_source_map->has_a( field_entry => 'metabib::subject_field_entry' );
-       metabib::subject_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
-       metabib::subject_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
+       #metabib::subject_field_entry_source_map->has_a( field_entry => 'metabib::subject_field_entry' );
+       #metabib::subject_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
+       #metabib::subject_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
        #-------------------------------------------------------------------------------
-       metabib::author_field_entry_source_map->has_a( field_entry => 'metabib::author_field_entry' );
-       metabib::author_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
-       metabib::author_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
+       #metabib::author_field_entry_source_map->has_a( field_entry => 'metabib::author_field_entry' );
+       #metabib::author_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
+       #metabib::author_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
        #-------------------------------------------------------------------------------
-       metabib::keyword_field_entry_source_map->has_a( field_entry => 'metabib::keyword_field_entry' );
-       metabib::keyword_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
-       metabib::keyword_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
+       #metabib::keyword_field_entry_source_map->has_a( field_entry => 'metabib::keyword_field_entry' );
+       #metabib::keyword_field_entry_source_map->has_a( source_record => 'biblio::record_entry' );
+       #metabib::keyword_field_entry_source_map->has_a( metarecord => 'metabib::metarecord' );
        #-------------------------------------------------------------------------------
        $VERSION = 1;
 }
index fe21111..a73e573 100644 (file)
@@ -11,7 +11,7 @@ use base qw/biblio/;
 
 biblio::record_entry->table( 'biblio_record_entry' );
 biblio::record_entry->columns( All => qw/id tcn_source tcn_value creator
-                                        editor create_date edit_date
+                                        editor create_date edit_date item_type
                                         source active deleted last_xact_id/ );
 
 #-------------------------------------------------------------------------------
index e6e1869..22fe035 100644 (file)
@@ -18,7 +18,7 @@ use base qw/metabib/;
 
 metabib::title_field_entry->table( 'metabib_title_field_entry' );
 metabib::title_field_entry->columns( Primary => qw/id/ );
-metabib::title_field_entry->columns( Others => qw/field value/ );
+metabib::title_field_entry->columns( Others => qw/field value source/ );
 
 
 #-------------------------------------------------------------------------------
@@ -27,7 +27,7 @@ use base qw/metabib/;
 
 metabib::author_field_entry->table( 'metabib_author_field_entry' );
 metabib::author_field_entry->columns( Primary => qw/id/ );
-metabib::author_field_entry->columns( Others => qw/field value/ );
+metabib::author_field_entry->columns( Others => qw/field value source/ );
 
 
 #-------------------------------------------------------------------------------
@@ -36,7 +36,7 @@ use base qw/metabib/;
 
 metabib::subject_field_entry->table( 'metabib_subject_field_entry' );
 metabib::subject_field_entry->columns( Primary => qw/id/ );
-metabib::subject_field_entry->columns( Others => qw/field value/ );
+metabib::subject_field_entry->columns( Others => qw/field value source/ );
 
 
 #-------------------------------------------------------------------------------
@@ -45,47 +45,47 @@ use base qw/metabib/;
 
 metabib::keyword_field_entry->table( 'metabib_keyword_field_entry' );
 metabib::keyword_field_entry->columns( Primary => qw/id/ );
-metabib::keyword_field_entry->columns( Others => qw/field value/ );
+metabib::keyword_field_entry->columns( Others => qw/field value source/ );
 
 #-------------------------------------------------------------------------------
-package metabib::title_field_entry_source_map;
-use base qw/metabib/;
-
-metabib::title_field_entry_source_map->table( 'metabib_title_field_entry_source_map' );
-metabib::title_field_entry_source_map->columns( Primary => qw/id/ );
-metabib::title_field_entry_source_map->columns( Others => qw/field_entry metarecord source_record/ );
-
+#package metabib::title_field_entry_source_map;
+#use base qw/metabib/;
+#
+#metabib::title_field_entry_source_map->table( 'metabib_title_field_entry_source_map' );
+#metabib::title_field_entry_source_map->columns( Primary => qw/id/ );
+#metabib::title_field_entry_source_map->columns( Others => qw/field_entry metarecord source_record/ );
+#
 #-------------------------------------------------------------------------------
-package metabib::author_field_entry_source_map;
-use base qw/metabib/;
-
-metabib::author_field_entry_source_map->table( 'metabib_author_field_entry_source_map' );
-metabib::author_field_entry_source_map->columns( Primary => qw/id/ );
-metabib::author_field_entry_source_map->columns( Others => qw/field_entry metarecord source_record/ );
-
+#package metabib::author_field_entry_source_map;
+#use base qw/metabib/;
+#
+#metabib::author_field_entry_source_map->table( 'metabib_author_field_entry_source_map' );
+#metabib::author_field_entry_source_map->columns( Primary => qw/id/ );
+#metabib::author_field_entry_source_map->columns( Others => qw/field_entry metarecord source_record/ );
+#
 #-------------------------------------------------------------------------------
-package metabib::subject_field_entry_source_map;
-use base qw/metabib/;
-
-metabib::subject_field_entry_source_map->table( 'metabib_subject_field_entry_source_map' );
-metabib::subject_field_entry_source_map->columns( Primary => qw/id/ );
-metabib::subject_field_entry_source_map->columns( Others => qw/field_entry metarecord source_record/ );
-
+#package metabib::subject_field_entry_source_map;
+#use base qw/metabib/;
+#
+#metabib::subject_field_entry_source_map->table( 'metabib_subject_field_entry_source_map' );
+#metabib::subject_field_entry_source_map->columns( Primary => qw/id/ );
+#metabib::subject_field_entry_source_map->columns( Others => qw/field_entry metarecord source_record/ );
+#
 #-------------------------------------------------------------------------------
-package metabib::keyword_field_entry_source_map;
-use base qw/metabib/;
-
-metabib::keyword_field_entry_source_map->table( 'metabib_keyword_field_entry_source_map' );
-metabib::keyword_field_entry_source_map->columns( Primary => qw/id/ );
-metabib::keyword_field_entry_source_map->columns( Others => qw/field_entry metarecord source_record/ );
-
+#package metabib::keyword_field_entry_source_map;
+#use base qw/metabib/;
+#
+#metabib::keyword_field_entry_source_map->table( 'metabib_keyword_field_entry_source_map' );
+#metabib::keyword_field_entry_source_map->columns( Primary => qw/id/ );
+#metabib::keyword_field_entry_source_map->columns( Others => qw/field_entry metarecord source_record/ );
+#
 #-------------------------------------------------------------------------------
 package metabib::metarecord_source_map;
 use base qw/metabib/;
 
 metabib::metarecord_source_map->table( 'metabib_metarecord_source_map' );
 metabib::metarecord_source_map->columns( Primary => qw/id/ );
-metabib::metarecord_source_map->columns( Others => qw/metarecord source_record/ );
+metabib::metarecord_source_map->columns( Others => qw/metarecord source/ );
 
 #-------------------------------------------------------------------------------
 package metabib::full_rec;
index 4992278..dc143dc 100644 (file)
@@ -90,6 +90,8 @@
        my $log = 'OpenSRF::Utils::Logger';
 
        __PACKAGE__->set_sql( retrieve_limited => 'SELECT * FROM __TABLE__ ORDER BY id LIMIT ?' );
+       __PACKAGE__->set_sql( copy_start => 'COPY %s (%s) FROM STDIN;' );
+       __PACKAGE__->set_sql( copy_end => '\.' );
 
        my $master_db;
        my @slave_dbs;
        sub pg_commit_xaction {
                my $self = shift;
 
+               my $xact_id = $pg->current_xact_id;
 
                try {
                        $log->debug("Committing trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
                argc            => 0,
        );
 
+       sub copy_create {
+               my $self = shift;
+               my $client = shift;
+               my @fm_nodes = @_;
+
+               warn 'Inside copy_create...';
+
+               return undef unless ($pg->current_xact_session);
+
+               my $cdbi = $self->{cdbi};
+
+               my $pri = $cdbi->columns('Primary');
+
+               my @cols = grep {$_ ne $pri} $cdbi->columns('All');
+
+               my $col_list = join ',', @cols;
+
+               $log->debug('Starting COPY import for '.$cdbi->table, DEBUG);
+               $cdbi->sql_copy_start($cdbi->table, $col_list)->execute;
+
+               my $dbh = $cdbi->db_Main;
+               for my $node ( @fm_nodes ) {
+                       next unless ($node);
+                       my $line = join("\t", map { defined($node->$_()) ? $node->$_() : '\N' } @cols);
+                       $log->debug("COPY line: [$line]",DEBUG);
+                       $dbh->func($line."\n", 'putline');
+               }
+
+               $dbh->func('endcopy');
+
+               return scalar(@fm_nodes);
+       }
+
 }
 
 {
 #              before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
 #      );
 
+       OpenILS::Application::Storage->register_method(
+               api_name        => 'open-ils.storage.metabib.title_field_entry.batch.create',
+               method          => 'copy_create',
+               api_level       => 1,
+               'package'       => 'OpenILS::Application::Storage',
+               cdbi            => 'metabib::title_field_entry',
+       );
+
        #-------------------------------------------------------------------------------
 
        #-------------------------------------------------------------------------------
        metabib::author_field_entry->sequence( 'metabib.author_field_entry_id_seq' );
        metabib::author_field_entry->columns( 'FTS' => 'index_vector' );
 
+       OpenILS::Application::Storage->register_method(
+               api_name        => 'open-ils.storage.metabib.author_field_entry.batch.create',
+               method          => 'copy_create',
+               api_level       => 1,
+               'package'       => 'OpenILS::Application::Storage',
+               cdbi            => 'metabib::author_field_entry',
+       );
+
        #-------------------------------------------------------------------------------
 
        #-------------------------------------------------------------------------------
        metabib::subject_field_entry->sequence( 'metabib.subject_field_entry_id_seq' );
        metabib::subject_field_entry->columns( 'FTS' => 'index_vector' );
 
+       OpenILS::Application::Storage->register_method(
+               api_name        => 'open-ils.storage.metabib.subject_field_entry.batch.create',
+               method          => 'copy_create',
+               api_level       => 1,
+               'package'       => 'OpenILS::Application::Storage',
+               cdbi            => 'metabib::subject_field_entry',
+       );
+
        #-------------------------------------------------------------------------------
 
        #-------------------------------------------------------------------------------
        metabib::keyword_field_entry->sequence( 'metabib.keyword_field_entry_id_seq' );
        metabib::keyword_field_entry->columns( 'FTS' => 'index_vector' );
 
+       OpenILS::Application::Storage->register_method(
+               api_name        => 'open-ils.storage.metabib.keyword_field_entry.batch.create',
+               method          => 'copy_create',
+               api_level       => 1,
+               'package'       => 'OpenILS::Application::Storage',
+               cdbi            => 'metabib::keyword_field_entry',
+       );
+
        #-------------------------------------------------------------------------------
 
        #-------------------------------------------------------------------------------
-       package metabib::title_field_entry_source_map;
+       #package metabib::title_field_entry_source_map;
 
-       metabib::title_field_entry_source_map->table( 'metabib.title_field_entry_source_map' );
+       #metabib::title_field_entry_source_map->table( 'metabib.title_field_entry_source_map' );
 
        #-------------------------------------------------------------------------------
 
        #-------------------------------------------------------------------------------
-       package metabib::author_field_entry_source_map;
+       #package metabib::author_field_entry_source_map;
 
-       metabib::author_field_entry_source_map->table( 'metabib.author_field_entry_source_map' );
+       #metabib::author_field_entry_source_map->table( 'metabib.author_field_entry_source_map' );
 
        #-------------------------------------------------------------------------------
 
        #-------------------------------------------------------------------------------
-       package metabib::subject_field_entry_source_map;
+       #package metabib::subject_field_entry_source_map;
 
-       metabib::subject_field_entry_source_map->table( 'metabib.subject_field_entry_source_map' );
+       #metabib::subject_field_entry_source_map->table( 'metabib.subject_field_entry_source_map' );
 
        #-------------------------------------------------------------------------------
 
        #-------------------------------------------------------------------------------
-       package metabib::keyword_field_entry_source_map;
+       #package metabib::keyword_field_entry_source_map;
 
-       metabib::keyword_field_entry_source_map->table( 'metabib.keyword_field_entry_source_map' );
+       #metabib::keyword_field_entry_source_map->table( 'metabib.keyword_field_entry_source_map' );
 
        #-------------------------------------------------------------------------------
 
        #-------------------------------------------------------------------------------
        package metabib::metarecord_source_map;
 
-       metabib::metarecord_source_map->table( 'metabib.full_rec' );
+       metabib::metarecord_source_map->table( 'metabib.metarecord_source_map' );
 
        #-------------------------------------------------------------------------------
 
        metabib::full_rec->sequence( 'metabib.full_rec_id_seq' );
        metabib::full_rec->columns( 'FTS' => 'index_vector' );
 
+       OpenILS::Application::Storage->register_method(
+               api_name        => 'open-ils.storage.metabib.full_rec.batch.create',
+               method          => 'copy_create',
+               api_level       => 1,
+               'package'       => 'OpenILS::Application::Storage',
+               cdbi            => 'metabib::full_rec',
+       );
+
+
        #-------------------------------------------------------------------------------
 }
 
index af71611..e04600f 100644 (file)
@@ -1,6 +1,7 @@
 package OpenILS::Application::Storage::Publisher;
 use base qw/OpenILS::Application::Storage/;
 our $VERSION = 1;
+my $pg = 'OpenILS::Application::Storage::Driver::Pg';
 
 use OpenSRF::EX qw/:try/;;
 use OpenSRF::Utils::Logger;
@@ -102,6 +103,42 @@ sub update_node {
        return $cdbi->update($node);
 }
 
+sub mass_delete {
+       my $self = shift;
+       my $client = shift;
+       my $search = shift;
+
+       my $where = 'WHERE ';
+
+       my $cdbi = $self->{cdbi};
+       my $table = $cdbi->table;
+
+       my @keys = sort keys %$search;
+       
+       my @wheres;
+       for my $col ( @keys ) {
+               push @wheres, "$col = ?";
+       }
+       $where .= join ' AND ', @wheres;
+
+       my $delete = "DELETE FROM $table $where";
+
+       $log->debug("Performing MASS deletion : $delete",DEBUG);
+
+       my $dbh = $cdbi->db_Main;
+       my $success = 1;
+       try {
+               my $sth = $dbh->prepare($delete);
+               $sth->execute( map { "$_" } @$search{@keys} );
+               $sth->finish;
+               $log->debug("MASS Delete succeeded",DEBUG);
+       } catch Error with {
+               $log->debug("MASS Delete FAILED : ".shift(),DEBUG);
+               $success = 0;
+       };
+       return $success;
+}
+
 sub delete_node {
        my $self = shift;
        my $client = shift;
@@ -261,6 +298,16 @@ for my $fmclass ( Fieldmapper->classes ) {
                );
        }
 
+       # Create the search-based mass delete method
+       unless ( __PACKAGE__->is_registered( $api_prefix.'.mass_delete' ) ) {
+               __PACKAGE__->register_method(
+                       api_name        => $api_prefix.'.mass_delete',
+                       method          => 'mass_delete',
+                       api_level       => 1,
+                       cdbi            => $cdbi,
+               );
+       }
+
 }
 
 1;
diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Storage/WORM.pm b/Open-ILS/src/perlmods/OpenILS/Application/Storage/WORM.pm
new file mode 100644 (file)
index 0000000..9d42d41
--- /dev/null
@@ -0,0 +1,362 @@
+package OpenILS::Application::Storage::WORM;
+use base qw/OpenILS::Application::Storage/;
+use strict; use warnings;
+
+use OpenSRF::EX qw/:try/;
+
+use OpenILS::Utils::FlatXML;
+use OpenILS::Utils::Fieldmapper;
+use JSON;
+
+use XML::LibXML;
+use XML::LibXSLT;
+use Time::HiRes qw(time);
+
+my $xml_util   = OpenILS::Utils::FlatXML->new();
+
+my $parser             = XML::LibXML->new();
+my $xslt                       = XML::LibXSLT->new();
+my $xslt_doc   =       $parser->parse_file( "/home/miker/cvs/OpenILS/app_server/stylesheets/MARC21slim2MODS.xsl" );
+#my $xslt_doc  = $parser->parse_file( "/pines/cvs/ILS/Open-ILS/xsl/MARC21slim2MODS.xsl" );
+my $mods_sheet = $xslt->parse_stylesheet( $xslt_doc );
+
+use open qw/:utf8/;
+
+
+sub child_init {
+       #try {
+       #       __PACKAGE__->method_lookup('i.do.not.exist');
+       #} catch Error with {
+       #       warn shift();
+       #};
+}
+
+
+# get me from the database
+my $xpathset = {
+
+       title => {
+
+               abbreviated => 
+                       "//mods:mods/mods:titleInfo[mods:title and (\@type='abreviated')]",
+
+               translated =>
+                       "//mods:mods/mods:titleInfo[mods:title and (\@type='translated')]",
+
+               uniform =>
+                       "//mods:mods/mods:titleInfo[mods:title and (\@type='uniform')]",
+
+               proper =>
+                       "//mods:mods/mods:titleInfo[mods:title and not (\@type)]",
+       },
+
+       author => {
+
+               corporate => 
+                       "//mods:mods/mods:name[\@type='corporate']/mods:namePart".
+                               "[../mods:role/mods:text[text()='creator']][1]",
+
+               personal => 
+                       "//mods:mods/mods:name[\@type='personal']/mods:namePart".
+                               "[../mods:role/mods:text[text()='creator']][1]",
+
+               conference => 
+                       "//mods:mods/mods:name[\@type='conference']/mods:namePart".
+                               "[../mods:role/mods:text[text()='creator']][1]",
+
+               other => 
+                       "//mods:mods/mods:name[\@type='personal']/mods:namePart",
+       },
+
+       subject => {
+
+               geographic => 
+                       "//mods:mods/mods:subject/mods:geographic",
+
+               name => 
+                       "//mods:mods/mods:subject/mods:name",
+
+               temporal => 
+                       "//mods:mods/mods:subject/mods:temporal",
+
+               topic => 
+                       "//mods:mods/mods:subject/mods:topic",
+
+               genre => 
+                       "//mods:mods/mods:genre",
+
+       },
+
+       keyword => { keyword => "//mods:mods/*[not(local-name()='originInfo')]", },
+
+};
+
+
+# --------------------------------------------------------------------------------
+
+__PACKAGE__->register_method( 
+       api_name        => "open-ils.worm.wormize",
+       method          => "wormize",
+       api_level       => 1,
+       argc            => 1,
+);
+
+sub wormize {
+
+       my( $self, $client, $docid ) = @_;
+
+       # step -1: grab the doc from storage
+       my $meth = $self->method_lookup('open-ils.storage.biblio.record_marc.retrieve');
+       my ($marc) = $meth->run($docid);
+       return undef unless ($marc);
+       return $self->wormize_marc( $client, $docid, $marc->marc );
+}
+
+
+__PACKAGE__->register_method( 
+       api_name        => "open-ils.worm.wormize.marc",
+       method          => "wormize",
+       api_level       => 1,
+       argc            => 1,
+);
+
+my $rm_old_fr;
+my $rm_old_tr;
+my $rm_old_ar;
+my $rm_old_sr;
+my $rm_old_kr;
+
+my $fr_create;
+my $create = {};
+
+my $begin;
+my $commit;
+my $rollback;
+
+sub wormize_marc {
+       my( $self, $client, $docid, $xml) = @_;
+
+       $rm_old_fr = $self->method_lookup( 'open-ils.storage.metabib.full_rec.mass_delete')
+               unless ($rm_old_fr);
+
+       $rm_old_tr = $self->method_lookup( 'open-ils.storage.metabib.title_field_entry.mass_delete')
+               unless ($rm_old_tr);
+
+       $rm_old_ar = $self->method_lookup( 'open-ils.storage.metabib.author_field_entry.mass_delete')
+               unless ($rm_old_ar);
+
+       $rm_old_sr = $self->method_lookup( 'open-ils.storage.metabib.subject_field_entry.mass_delete')
+               unless ($rm_old_sr);
+
+       $rm_old_kr = $self->method_lookup( 'open-ils.storage.metabib.keyword_field_entry.mass_delete')
+               unless ($rm_old_kr);
+
+       $fr_create = $self->method_lookup( 'open-ils.storage.metabib.full_rec.batch.create')
+               unless ($fr_create);
+       $$create{title} = $self->method_lookup( 'open-ils.storage.metabib.title_field_entry.batch.create')
+               unless ($$create{title});
+       $$create{author} = $self->method_lookup( 'open-ils.storage.metabib.author_field_entry.batch.create')
+               unless ($$create{author});
+       $$create{subject} = $self->method_lookup( 'open-ils.storage.metabib.subject_field_entry.batch.create')
+               unless ($$create{subject});
+       $$create{keyword} = $self->method_lookup( 'open-ils.storage.metabib.keyword_field_entry.batch.create')
+               unless ($$create{keyword});
+
+       $begin = $self->method_lookup( 'open-ils.storage.transaction.begin')
+               unless ($begin);
+       $commit = $self->method_lookup( 'open-ils.storage.transaction.commit')
+               unless ($commit);
+       $rollback = $self->method_lookup( 'open-ils.storage.transaction.rollback')
+               unless ($rollback);
+
+
+       my ($br) = $begin->run($client);
+       unless (defined $br) {
+               $rollback->run;
+               throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!")
+       }
+
+       # step 0: turn the doc into marcxml and delete old entries
+       my $marcdoc = $parser->parse_string($xml);
+
+       my ($res) = $rm_old_fr->run( { record => $docid } );
+       throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::full_rec entries!")
+               unless (defined $res);
+
+       undef $res;
+       ($res) = $rm_old_tr->run( { source => $docid } );
+       throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::title_field_entry entries!")
+               unless (defined $res);
+
+       undef $res;
+       ($res) = $rm_old_ar->run( { source => $docid } );
+       throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::author_field_entry entries!")
+               unless (defined $res);
+
+       undef $res;
+       ($res) = $rm_old_sr->run( { source => $docid } );
+       throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::subject_field_entry entries!")
+               unless (defined $res);
+
+       undef $res;
+       ($res) = $rm_old_kr->run( { source => $docid } );
+       throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::keyword_field_entry entries!")
+               unless (defined $res);
+
+       # step 2: build the KOHA rows
+       my @ns_list = _marcxml_to_full_rows( $marcdoc );
+       $_->record( $docid ) for (@ns_list);
+
+
+       my ($fr) = $fr_create->run(@ns_list);
+       unless (defined $fr) {
+               $rollback->run;
+               throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.metabib.full_rec.batch.create!")
+       }
+
+       # step 4: get the MODS based metadata
+       my $data = $self->modsdoc_to_values( $mods_sheet->transform($marcdoc) );
+
+       # step 5: insert the new metadata
+       for my $class ( keys %$data ) {
+                       
+               my $fm_constructor = "Fieldmapper::metabib::${class}_field_entry";
+               my @md_list = ();
+               for my $row ( keys %{ $$data{$class} } ) {
+                       next unless (exists $$data{$class}{$row});
+                       next unless ($$data{$class}{$row});
+                       my $fm_obj = $fm_constructor->new;
+                       $fm_obj->value( $$data{$class}{$row} );
+                       $fm_obj->source( $docid );
+
+                       # XXX This needs to be a real thing once the xpath is in the DB
+                       $fm_obj->field( 1 );
+
+                       push @md_list, $fm_obj;
+               }
+                       
+               my ($cr) = $$create{$class}->run(@md_list);
+               unless (defined $cr) {
+                       $rollback->run;
+                       throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.metabib.${class}_field_entry.batch.create!")
+               }
+       }
+
+       my ($c) = $commit->run;
+       unless (defined $c) {
+               $rollback->run;
+               throw OpenSRF::EX::PANIC ("Couldn't COMMIT changes!")
+       }
+
+       return 1;
+
+}
+
+
+
+# --------------------------------------------------------------------------------
+
+
+sub _marcxml_to_full_rows {
+
+       my $marcxml = shift;
+
+       my @ns_list;
+       
+       my $root = $marcxml->documentElement;
+
+       for my $tagline ( @{$root->getChildrenByTagName("leader")} ) {
+               next unless $tagline;
+
+               my $ns = new Fieldmapper::metabib::full_rec;
+
+               $ns->tag( 'LDR' );
+               my $val = $tagline->textContent;
+               $val =~ s/(\pM)//gso;
+               $ns->value( $val );
+
+               push @ns_list, $ns;
+       }
+
+       for my $tagline ( @{$root->getChildrenByTagName("controlfield")} ) {
+               next unless $tagline;
+
+               my $ns = new Fieldmapper::metabib::full_rec;
+
+               $ns->tag( $tagline->getAttribute( "tag" ) );
+               my $val = $tagline->textContent;
+               $val =~ s/(\pM)//gso;
+               $ns->value( $val );
+
+               push @ns_list, $ns;
+       }
+
+       for my $tagline ( @{$root->getChildrenByTagName("datafield")} ) {
+               next unless $tagline;
+
+               for my $data ( @{$tagline->getChildrenByTagName("subfield")} ) {
+                       next unless $tagline;
+
+                       my $ns = new Fieldmapper::metabib::full_rec;
+
+                       $ns->tag( $tagline->getAttribute( "tag" ) );
+                       $ns->ind1( $tagline->getAttribute( "ind1" ) );
+                       $ns->ind2( $tagline->getAttribute( "ind2" ) );
+                       $ns->subfield( $data->getAttribute( "code" ) );
+                       my $val = $data->textContent;
+                       $val =~ s/(\pM)//gso;
+                       $ns->value( lc($val) );
+
+                       push @ns_list, $ns;
+               }
+       }
+       return @ns_list;
+}
+
+sub _get_field_value {
+
+       my( $mods, $xpath ) = @_;
+
+       my $string = "";
+       my $root = $mods->documentElement;
+       $root->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
+
+       # grab the set of matching nodes
+       my @nodes = $root->findnodes( $xpath );
+       for my $value (@nodes) {
+
+               # grab all children of the node
+               my @children = $value->childNodes();
+               for my $child (@children) {
+
+                       # add the childs content to the growing buffer
+                       my $content = quotemeta($child->textContent);
+                       next if ($string =~ /$content/);  # uniquify the values
+                       $string .= $child->textContent . " ";
+               }
+               if( ! @children ) {
+                       $string .= $value->textContent . " ";
+               }
+       }
+       $string =~ s/(\pM)//gso;
+       return lc($string);
+}
+
+
+sub modsdoc_to_values {
+       my( $self, $mods ) = @_;
+       my $data = {};
+       for my $class (keys %$xpathset) {
+               $data->{$class} = {};
+               for my $type(keys %{$xpathset->{$class}}) {
+                       my $value = _get_field_value( $mods, $xpathset->{$class}->{$type} );
+                       $data->{$class}->{$type} = $value;
+               }
+       }
+       return $data;
+}
+
+
+1;
+
+