[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