[open-ils-commits] r12354 - in trunk/Open-ILS: examples src/perlmods/OpenILS/Application src/perlmods/OpenILS/Application/Search src/sql/Pg (miker)

svn at svn.open-ils.org svn at svn.open-ils.org
Mon Mar 2 14:24:18 EST 2009


Author: miker
Date: 2009-03-02 14:24:15 -0500 (Mon, 02 Mar 2009)
New Revision: 12354

Modified:
   trunk/Open-ILS/examples/fm_IDL.xml
   trunk/Open-ILS/src/perlmods/OpenILS/Application/Ingest.pm
   trunk/Open-ILS/src/perlmods/OpenILS/Application/Search/Biblio.pm
   trunk/Open-ILS/src/sql/Pg/040.schema.asset.sql
   trunk/Open-ILS/src/sql/Pg/210.schema.serials.sql
   trunk/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
Log:
initial addition of Conifer-sponsored electronic serials support.  tests and docs to come

Modified: trunk/Open-ILS/examples/fm_IDL.xml
===================================================================
--- trunk/Open-ILS/examples/fm_IDL.xml	2009-03-02 18:01:30 UTC (rev 12353)
+++ trunk/Open-ILS/examples/fm_IDL.xml	2009-03-02 19:24:15 UTC (rev 12354)
@@ -1486,6 +1486,33 @@
             </actions>
         </permacrud>
 	</class>
+	<class id="auri" controller="open-ils.cstore" oils_obj:fieldmapper="asset::uri" oils_persist:tablename="asset.uri" reporter:label="Electronic Access URI">
+		<fields oils_persist:primary="id" oils_persist:sequence="asset.uri_id_seq">
+			<field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
+			<field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
+			<field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
+			<field reporter:label="URI ID" name="id" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="id"/>
+			<field reporter:label="URI" name="href" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="text"/>
+			<field reporter:label="Label" name="label" oils_obj:array_position="5" oils_persist:virtual="false" reporter:datatype="text"/>
+			<field reporter:label="Use Information" name="use" oils_obj:array_position="6" oils_persist:virtual="false" reporter:datatype="text"/>
+			<field reporter:label="Active" name="active" oils_obj:array_position="7" oils_persist:virtual="false" reporter:datatype="bool"/>
+		</fields>
+		<links/>
+	</class>
+	<class id="auricnm" controller="open-ils.cstore" oils_obj:fieldmapper="asset::uri_call_number_map" oils_persist:tablename="asset.uri_call_number_map" reporter:label="Electronic Access URI to Call Number Map">
+		<fields oils_persist:primary="id" oils_persist:sequence="asset.uri_id_seq">
+			<field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />
+			<field name="ischanged" oils_obj:array_position="1" oils_persist:virtual="true" />
+			<field name="isdeleted" oils_obj:array_position="2" oils_persist:virtual="true" />
+			<field reporter:label="ID" name="id" oils_obj:array_position="3" oils_persist:virtual="false" reporter:datatype="id"/>
+			<field reporter:label="URI" name="uri" oils_obj:array_position="4" oils_persist:virtual="false" reporter:datatype="int"/>
+			<field reporter:label="Call Number" name="call_number" oils_obj:array_position="5" oils_persist:virtual="false" reporter:datatype="text"/>
+		</fields>
+		<links>
+			<link field="uri" reltype="has_a" key="id" map="" class="auri"/>
+			<link field="call_number" reltype="has_a" key="id" map="" class="acn"/>
+		</links>
+	</class>
 	<class id="cst" controller="open-ils.cstore" oils_obj:fieldmapper="config::standing" oils_persist:tablename="config.standing">
 		<fields oils_persist:primary="id" oils_persist:sequence="config.standing_id_seq">
 			<field name="isnew" oils_obj:array_position="0" oils_persist:virtual="true" />

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Ingest.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Ingest.pm	2009-03-02 18:01:30 UTC (rev 12353)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Ingest.pm	2009-03-02 19:24:15 UTC (rev 12354)
@@ -129,9 +129,64 @@
 	my $cstore = OpenSRF::AppSession->connect('open-ils.cstore');
 
 	my $xact = $cstore->request('open-ils.cstore.transaction.begin')->gather(1);
+    my $tmp;
 
+	# update uri stuff ...
+
+    # gather URI call numbers for this record
+    my $uri_cns = $u->{call_number} = $cstore->request(
+        'open-ils.cstore.direct.asset.call_number.id_list.atomic' => { record => $bib->id, label => '##URI##' }
+    )->gather(1);
+
+    # gather the maps for those call numbers
+    my $uri_maps = $u->{call_number} = $cstore->request(
+        'open-ils.cstore.direct.asset.uri_call_number_map.id_list.atomic' => { call_number => $uri_cns }
+    )->gather(1);
+
+    # delete the old maps
+    $cstore->request( 'open-ils.cstore.direct.asset.uri_call_number_map.delete' => $_ )->gather(1) for (@$uri_maps);
+
+    # and delete the call numbers if there are no more URIs
+    if (!@{ $blob->{uri} }) {
+        $cstore->request( 'open-ils.cstore.direct.asset.call_number.delete' => $_ )->gather(1) for (@$uri_cns);
+    }
+
+    # now, add CNs, URIs and maps
+    my %new_cns_by_owner;
+    my %new_uris_by_owner;
+    for my $u ( @{ $blob->{uri} } ) {
+
+        my $owner = $u->{call_number}->owning_lib;
+
+        if ($u->{call_number}->isnew) {
+            if ($new_cns_by_owner{$owner}) {
+                $u->{call_number} = $new_cns_by_owner{$owner};
+            } else {
+    	        $u->{call_number} = $new_cns_by_owner{$owner} = $cstore->request(
+                    'open-ils.cstore.direct.asset.call_number.create' => $u->{call_number}
+                )->gather(1);
+            }
+        }
+
+        if ($u->{uri}->isnew) {
+            if ($new_uris_by_owner{$owner}) {
+	            $u->{uri} = $new_uris_by_owner{$owner};
+            } else {
+	            $u->{uri} = $new_uris_by_owner{$owner} = $cstore->request(
+                    'open-ils.cstore.direct.asset.uri.create' => $u->{uri}
+                )->gather(1);
+            }
+        }
+
+        my $umap = Fieldmapper::asset::uri_call_number_map->new;
+        $umap->uri($u->{uri}->id);
+        $umap->call_number($u->{call_number}->id);
+
+	    $cstore->request( 'open-ils.cstore.direct.asset.uri_call_number_map.create' => $umap )->gather(1) if (!$tmp);
+    }
+
 	# update full_rec stuff ...
-	my $tmp = $cstore->request(
+	$tmp = $cstore->request(
 		'open-ils.cstore.direct.metabib.full_rec.id_list.atomic',
 		{ record => $bib->id }
 	)->gather(1);
@@ -346,6 +401,7 @@
 
 	my $document = $parser->parse_string($xml);
 
+	my @uris = $self->method_lookup("open-ils.ingest.856_uri.object")->run($bib);
 	my @mfr = $self->method_lookup("open-ils.ingest.flat_marc.biblio.xml")->run($document);
 	my @mXfe = $self->method_lookup("open-ils.ingest.extract.field_entry.all.xml")->run($document);
 	my ($fp) = $self->method_lookup("open-ils.ingest.fingerprint.xml")->run($xml);
@@ -355,7 +411,7 @@
 	$_->record($bib->id) for (@mfr);
 	$rd->record($bib->id) if ($rd);
 
-	return { full_rec => \@mfr, field_entries => \@mXfe, fingerprint => $fp, descriptor => $rd };
+	return { full_rec => \@mfr, field_entries => \@mXfe, fingerprint => $fp, descriptor => $rd, uri => \@uris };
 }
 __PACKAGE__->register_method(  
 	api_name	=> "open-ils.ingest.full.biblio.object.readonly",
@@ -1019,7 +1075,134 @@
 	stream		=> 1,
 );                      
 
+
 # --------------------------------------------------------------------------------
+# URI extraction
+
+package OpenILS::Application::Ingest::Biblio::URI;
+use base qw/OpenILS::Application::Ingest/;
+use Unicode::Normalize;
+use OpenSRF::EX qw/:try/;
+
+
+sub _extract_856_uris {
+
+    my $recid   = shift;
+	my $marcxml = shift;
+	my @objects;
+	
+	my @nodes = $marcxml->findnodes('//*[local-name()="datafield" and @tag="856" and (@ind1="4" or @ind1="1") and (@ind2="0" or @ind2="1")]');
+
+    my $cstore = OpenSRF::AppSession->connect('open-ils.cstore');
+
+    for my $node (@nodes) {
+        # first, is there a URI?
+        my $href = $node->findvalue('[local-name()="subfield" and @code="u"]/text()');
+        next unless ($href);
+
+        # now, find the best possible label
+        my $label = $node->findvalue('[local-name()="subfield" and @code="y"]/text()');
+        $label ||= $node->findvalue('[local-name()="subfield" and @code="3"]/text()');
+        $label ||= $href;
+
+        # look for use info
+        my $use = $node->findvalue('[local-name()="subfield" and @code="z"]/text()');
+        $use ||= $node->findvalue('[local-name()="subfield" and @code="2"]/text()');
+        $use ||= $node->findvalue('[local-name()="subfield" and @code="n"]/text()');
+
+        # moving on to the URI owner
+        my $owner = $node->findvalue('[local-name()="subfield" and @code="w"]/text()');
+        $owner ||= $node->findvalue('[local-name()="subfield" and @code="n"]/text()');
+        $owner ||= $node->findvalue('[local-name()="subfield" and @code="9"]/text()'); # Evergreen special sauce
+
+        $owner =~ s/^.*?\((\w+)\).*$/$1/o; # unwrap first paren-enclosed string and then ...
+
+        # no owner? skip it :(
+        next unless ($owner);
+
+    	my $org = $cstore
+            ->request( 'open-ils.cstore.direct.actor.org_unit.search' => { shortname => $owner} )
+			->gather(1);
+
+        next unless ($org);
+
+        # now we can construct the uri object
+    	my $uri = $cstore
+            ->request( 'open-ils.cstore.direct.asset.uri.search' => { label => $label, href => $href, use => $use, active => 't' } )
+			->gather(1);
+
+        if (!$uri) {
+            $uri = Fieldmapper::asset::uri->new;
+            $uri->isnew( 1 );
+            $uri->label($label);
+            $uri->href($href);
+            $uri->use($use);
+        }
+
+        # see if we need to create a call number
+    	my $cn = $cstore
+            ->request( 'open-ils.cstore.direct.asset.call_number.search' => { owner => $org->id, record => $recid, label => '##URI##' } )
+			->gather(1);
+
+        if (!$cn) {
+            $cn = Fieldmapper::asset::call_number->new;
+            $cn->isnew( 1 );
+            $cn->owner( $org->id );
+            $cn->record( $recid );
+            $cn->label( '##URI##' );
+        }
+
+        push @objects, { uri => $uri, call_number => $cn };
+    }
+
+	$log->debug("Returning ".scalar(@objects)." URI nodes for record $recid");
+	return @objects;
+}
+
+sub get_uris_record {
+	my $self = shift;
+	my $client = shift;
+	my $rec = shift;
+
+	OpenILS::Application::Ingest->post_init();
+	my $r = OpenSRF::AppSession
+			->create('open-ils.cstore')
+			->request( "open-ils.cstore.direct.biblio.record_entry.retrieve" => $rec )
+			->gather(1);
+
+	return undef unless ($r and $r->marc);
+
+	$client->respond($_) for (_extract_856_uris($r->id, $r->marc));
+	return undef;
+}
+__PACKAGE__->register_method(  
+	api_name	=> "open-ils.ingest.856_uri.record",
+	method		=> "get_uris_record",
+	api_level	=> 1,
+	argc		=> 1,
+	stream		=> 1,
+);                      
+
+sub get_uris_object {
+	my $self = shift;
+	my $client = shift;
+	my $obj = shift;
+
+	return undef unless ($obj and $obj->marc);
+
+	$client->respond($_) for (_extract_856_uris($obj->id, $obj->marc));
+	return undef;
+}
+__PACKAGE__->register_method(  
+	api_name	=> "open-ils.ingest.856_uri.object",
+	method		=> "get_uris_object",
+	api_level	=> 1,
+	argc		=> 1,
+	stream		=> 1,
+);                      
+
+
+# --------------------------------------------------------------------------------
 # Fingerprinting
 
 package OpenILS::Application::Ingest::Biblio::Fingerprint;

Modified: trunk/Open-ILS/src/perlmods/OpenILS/Application/Search/Biblio.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/OpenILS/Application/Search/Biblio.pm	2009-03-02 18:01:30 UTC (rev 12353)
+++ trunk/Open-ILS/src/perlmods/OpenILS/Application/Search/Biblio.pm	2009-03-02 19:24:15 UTC (rev 12354)
@@ -238,6 +238,72 @@
 
 
 __PACKAGE__->register_method(
+	method	=> "biblio_id_to_uris",
+	api_name=> "open-ils.search.asset.uri.retrieve_by_bib",
+	argc	=> 2, 
+    stream  => 1,
+    signature => q#
+        @param BibID Which bib record contains the URIs
+        @param OrgID Where to look for URIs
+        @param OrgDepth Range adjustment for OrgID
+        @return A stream or list of 'auri' objects
+    #
+
+);
+sub biblio_id_to_uris { 
+	my( $self, $client, $bib, $org, $depth ) = @_;
+    die "Org ID required" unless defined($org);
+    die "Bib ID required" unless defined($bib);
+
+    my @params;
+    push @params, $depth if (defined $depth);
+
+	my $ids = $U->cstorereq( "open-ils.cstore.json_query.atomic",
+        {   select  => { auri => [ 'id' ] },
+            from    => {
+                acn => {
+                    auricnm => {
+                        field   => 'call_number',
+                        fkey    => 'id',
+                        join    => {
+                            auri    => {
+                                field => 'id',
+                                fkey => 'uri',
+                                filter  => { active => 't' }
+                            }
+                        }
+                    }
+                }
+            },
+            where   => {
+                '+acn'  => {
+                    record      => $bib,
+                    owning_lib  => {
+                        in  => {
+                            select  => { aou => [ { column => 'id', transform => 'actor.org_unit_descendants', params => \@params, result_field => 'id' } ] },
+                            from    => 'aou',
+                            where   => { id => $org },
+                            distinct=> 1
+                        }
+                    }
+                }
+            },
+            distinct=> 1,
+        }
+    );
+
+	my $uris = $U->cstorereq(
+		"open-ils.cstore.direct.asset.uri.search.atomic",
+        { id => [ map { (values %$_) } @$ids ] }
+    );
+
+    $client->respond($_) for (@$uris);
+
+    return undef;
+}
+
+
+__PACKAGE__->register_method(
 	method	=> "copy_retrieve", 
 	api_name	=> "open-ils.search.asset.copy.retrieve",);
 sub copy_retrieve {

Modified: trunk/Open-ILS/src/sql/Pg/040.schema.asset.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/040.schema.asset.sql	2009-03-02 18:01:30 UTC (rev 12353)
+++ trunk/Open-ILS/src/sql/Pg/040.schema.asset.sql	2009-03-02 19:24:15 UTC (rev 12354)
@@ -133,6 +133,14 @@
 	value		TEXT				NOT NULL
 );
 
+CREATE TABLE asset.uri (
+    id  SERIAL  PRIMARY KEY,
+    href    TEXT    NOT NULL,
+    label   TEXT,
+    use TEXT,
+    active  BOOL    NOT NULL DEFAULT TRUE
+);
+
 CREATE TABLE asset.call_number (
 	id		bigserial PRIMARY KEY,
 	creator		BIGINT				NOT NULL,
@@ -152,6 +160,13 @@
 CREATE UNIQUE INDEX asset_call_number_label_once_per_lib ON asset.call_number (record, owning_lib, label) WHERE deleted IS FALSE;
 CREATE RULE protect_cn_delete AS ON DELETE TO asset.call_number DO INSTEAD UPDATE asset.call_number SET deleted = TRUE WHERE OLD.id = asset.call_number.id;
 
+CREATE TABLE asset.uri_call_number_map (
+    id          BIGSERIAL   PRIMARY KEY,
+    uri         INT         NOT NULL REFERENCES asset.uri (id),
+    call_number INT         NOT NULL REFERENCES asset.call_number (id),
+    CONSTRAINT uri_cn_once UNIQUE (uri,call_number)
+);
+
 CREATE TABLE asset.call_number_note (
 	id		BIGSERIAL			PRIMARY KEY,
 	call_number	BIGINT				NOT NULL,

Modified: trunk/Open-ILS/src/sql/Pg/210.schema.serials.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/210.schema.serials.sql	2009-03-02 18:01:30 UTC (rev 12353)
+++ trunk/Open-ILS/src/sql/Pg/210.schema.serials.sql	2009-03-02 19:24:15 UTC (rev 12354)
@@ -2,16 +2,6 @@
 
 DROP SCHEMA serial CASCADE;
 
-CREATE TABLE asset.uri (
-	id	SERIAL	PRIMARY KEY,
-	href	TEXT	NOT NULL,
-	label	TEXT,
-	use	TEXT,
-	active	BOOL	NOT NULL DEFAULT TRUE
-);
-
-ALTER TABLE asset.call_number ADD COLUMN uri INT REFERENCES asset.uri (id) DEFERRABLE INITIALLY DEFERRED;
-
 BEGIN;
 
 CREATE SCHEMA serial;

Modified: trunk/Open-ILS/src/sql/Pg/300.schema.staged_search.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/300.schema.staged_search.sql	2009-03-02 18:01:30 UTC (rev 12353)
+++ trunk/Open-ILS/src/sql/Pg/300.schema.staged_search.sql	2009-03-02 19:24:15 UTC (rev 12354)
@@ -423,6 +423,40 @@
             CONTINUE;
         END IF;
 
+        PERFORM 1
+          FROM  asset.call_number cn
+                JOIN asset.uri_call_number_map map ON (map.call_number = cn.id)
+                JOIN asset.uri uri ON (map.uri = uri.id)
+          WHERE NOT cn.deleted
+                AND cn.label = '##URI##'
+                AND uri.active
+                AND cn.record IN ( SELECT * FROM search.explode_array( core_result.records ) )
+                AND cn.owning_lib IN ( SELECT * FROM search.explode_array( search_org_list ) )
+          LIMIT 1;
+
+        IF FOUND THEN
+            -- RAISE NOTICE ' % have at least one URI ... ', core_result.records;
+            visible_count := visible_count + 1;
+
+            current_res.id = core_result.id;
+            current_res.rel = core_result.rel;
+
+            tmp_int := 1;
+            IF metarecord THEN
+                SELECT COUNT(DISTINCT s.source) INTO tmp_int FROM metabib.metarecord_source_map s WHERE s.metarecord = core_result.id;
+            END IF;
+
+            IF tmp_int = 1 THEN
+                current_res.record = core_result.records[1];
+            ELSE
+                current_res.record = NULL;
+            END IF;
+
+            RETURN NEXT current_res;
+
+            CONTINUE;
+        END IF;
+
         IF param_statuses IS NOT NULL AND array_upper(param_statuses, 1) > 0 THEN
 
             PERFORM 1



More information about the open-ils-commits mailing list