<field reporter:label="Type" name="queue_type" reporter:datatype="text"/>
<field reporter:label="Match Set" name="match_set" reporter:datatype="link"/>
<field reporter:label="Item Import Attribute Definition" name="item_attr_def" reporter:datatype="link"/>
+ <field reporter:label="Match Bucket" name="match_bucket" reporter:datatype="link"/>
</fields>
<links>
<link field="owner" reltype="has_a" key="id" map="" class="aou"/>
<link field="item_attr_def" reltype="has_a" key="id" map="" class="viiad"/>
<link field="match_set" reltype="has_a" key="id" map="" class="vms"/>
+ <link field="match_bucket" reltype="has_a" key="id" map="" class="cbreb"/>
</links>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
<actions>
my $type = shift;
my $match_set = shift;
my $import_def = shift;
+ my $match_bucket = shift;
my $e = new_editor(authtoken => $auth, xact => 1);
$queue->queue_type( $type ) if ($type);
$queue->item_attr_def( $import_def ) if ($import_def);
$queue->match_set($match_set) if $match_set;
+ $queue->match_bucket($match_bucket);
my $new_q = $e->create_vandelay_bib_queue( $queue );
return $e->die_event unless ($new_q);
CREATE TYPE vandelay.match_set_test_result AS (record BIGINT, quality INTEGER);
CREATE OR REPLACE FUNCTION vandelay.match_set_test_marcxml(
- match_set_id INTEGER, record_xml TEXT
+ match_set_id INTEGER, record_xml TEXT, bucket_id INTEGER
) RETURNS SETOF vandelay.match_set_test_result AS $$
DECLARE
tags_rstore HSTORE;
FROM _vandelay_tmp_jrows;
-- add those joins and the where clause to our query.
- query_ := query_ || joins || E'\n' || 'JOIN biblio.record_entry bre ON (bre.id = record) ' || 'WHERE ' || wq || ' AND not bre.deleted';
+ query_ := query_ || joins || E'\n';
+
+ -- join the record bucket
+ IF bucket_id IS NOT NULL THEN
+ query_ := query_ || 'JOIN container.biblio_record_entry_bucket_item ' ||
+ 'brebi ON (brebi.target_biblio_record_entry = record ' ||
+ 'AND brebi.bucket = ' || bucket_id || E')\n';
+ END IF;
+
+ query_ := query_ || 'JOIN biblio.record_entry bre ON (bre.id = record) ' || 'WHERE ' || wq || ' AND not bre.deleted';
-- this will return rows of record,quality
FOR rec IN EXECUTE query_ USING tags_rstore, svf_rstore LOOP
DROP TABLE _vandelay_tmp_jrows;
RETURN;
END;
-
$$ LANGUAGE PLPGSQL;
+
CREATE OR REPLACE FUNCTION vandelay.flatten_marc_hstore(
record_xml TEXT
) RETURNS HSTORE AS $func$
test_result vandelay.match_set_test_result%ROWTYPE;
tmp_rec BIGINT;
match_set INT;
+ match_bucket INT;
BEGIN
IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN
RETURN NEW;
RETURN NEW;
END IF;
+ SELECT q.match_bucket INTO match_bucket FROM vandelay.bib_queue q WHERE q.id = NEW.queue;
+
FOR test_result IN SELECT * FROM
- vandelay.match_set_test_marcxml(match_set, NEW.marc) LOOP
+ vandelay.match_set_test_marcxml(match_set, NEW.marc, match_bucket) LOOP
INSERT INTO vandelay.bib_match ( queued_record, eg_record, match_score, quality )
SELECT
)
);
-
-- seed data
INSERT INTO config.z3950_index_field_map
--- /dev/null
+BEGIN;
+
+-- TODO version check
+
+ALTER TABLE vandelay.bib_queue ADD COLUMN match_bucket
+ INTEGER REFERENCES container.biblio_record_entry_bucket(id);
+
+CREATE OR REPLACE FUNCTION vandelay.match_bib_record() RETURNS TRIGGER AS $func$
+DECLARE
+ incoming_existing_id TEXT;
+ test_result vandelay.match_set_test_result%ROWTYPE;
+ tmp_rec BIGINT;
+ match_set INT;
+ match_bucket INT;
+BEGIN
+ IF TG_OP IN ('INSERT','UPDATE') AND NEW.imported_as IS NOT NULL THEN
+ RETURN NEW;
+ END IF;
+
+ DELETE FROM vandelay.bib_match WHERE queued_record = NEW.id;
+
+ SELECT q.match_set INTO match_set FROM vandelay.bib_queue q WHERE q.id = NEW.queue;
+
+ IF match_set IS NOT NULL THEN
+ NEW.quality := vandelay.measure_record_quality( NEW.marc, match_set );
+ END IF;
+
+ -- Perfect matches on 901$c exit early with a match with high quality.
+ incoming_existing_id :=
+ oils_xpath_string('//*[@tag="901"]/*[@code="c"][1]', NEW.marc);
+
+ IF incoming_existing_id IS NOT NULL AND incoming_existing_id != '' THEN
+ SELECT id INTO tmp_rec FROM biblio.record_entry WHERE id = incoming_existing_id::bigint;
+ IF tmp_rec IS NOT NULL THEN
+ INSERT INTO vandelay.bib_match (queued_record, eg_record, match_score, quality)
+ SELECT
+ NEW.id,
+ b.id,
+ 9999,
+ -- note: no match_set means quality==0
+ vandelay.measure_record_quality( b.marc, match_set )
+ FROM biblio.record_entry b
+ WHERE id = incoming_existing_id::bigint;
+ END IF;
+ END IF;
+
+ IF match_set IS NULL THEN
+ RETURN NEW;
+ END IF;
+
+ SELECT q.match_bucket INTO match_bucket FROM vandelay.bib_queue q WHERE q.id = NEW.queue;
+
+ FOR test_result IN SELECT * FROM
+ vandelay.match_set_test_marcxml(match_set, NEW.marc, match_bucket) LOOP
+
+ INSERT INTO vandelay.bib_match ( queued_record, eg_record, match_score, quality )
+ SELECT
+ NEW.id,
+ test_result.record,
+ test_result.quality,
+ vandelay.measure_record_quality( b.marc, match_set )
+ FROM biblio.record_entry b
+ WHERE id = test_result.record;
+
+ END LOOP;
+
+ RETURN NEW;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+
+DROP FUNCTION IF EXISTS vandelay.match_set_test_marcxml(INTEGER, TEXT);
+
+CREATE OR REPLACE FUNCTION vandelay.match_set_test_marcxml(
+ match_set_id INTEGER, record_xml TEXT, bucket_id INTEGER
+) RETURNS SETOF vandelay.match_set_test_result AS $$
+DECLARE
+ tags_rstore HSTORE;
+ svf_rstore HSTORE;
+ coal TEXT;
+ joins TEXT;
+ query_ TEXT;
+ wq TEXT;
+ qvalue INTEGER;
+ rec RECORD;
+BEGIN
+ tags_rstore := vandelay.flatten_marc_hstore(record_xml);
+ svf_rstore := vandelay.extract_rec_attrs(record_xml);
+
+ CREATE TEMPORARY TABLE _vandelay_tmp_qrows (q INTEGER);
+ CREATE TEMPORARY TABLE _vandelay_tmp_jrows (j TEXT);
+
+ -- generate the where clause and return that directly (into wq), and as
+ -- a side-effect, populate the _vandelay_tmp_[qj]rows tables.
+ wq := vandelay.get_expr_from_match_set(match_set_id, tags_rstore);
+
+ query_ := 'SELECT DISTINCT(record), ';
+
+ -- qrows table is for the quality bits we add to the SELECT clause
+ SELECT ARRAY_TO_STRING(
+ ARRAY_ACCUM('COALESCE(n' || q::TEXT || '.quality, 0)'), ' + '
+ ) INTO coal FROM _vandelay_tmp_qrows;
+
+ -- our query string so far is the SELECT clause and the inital FROM.
+ -- no JOINs yet nor the WHERE clause
+ query_ := query_ || coal || ' AS quality ' || E'\n';
+
+ -- jrows table is for the joins we must make (and the real text conditions)
+ SELECT ARRAY_TO_STRING(ARRAY_ACCUM(j), E'\n') INTO joins
+ FROM _vandelay_tmp_jrows;
+
+ -- add those joins and the where clause to our query.
+ query_ := query_ || joins || E'\n';
+
+ -- join the record bucket
+ IF bucket_id IS NOT NULL THEN
+ query_ := query_ || 'JOIN container.biblio_record_entry_bucket_item ' ||
+ 'brebi ON (brebi.target_biblio_record_entry = record ' ||
+ 'AND brebi.bucket = ' || bucket_id || E')\n';
+ END IF;
+
+ query_ := query_ || 'JOIN biblio.record_entry bre ON (bre.id = record) ' || 'WHERE ' || wq || ' AND not bre.deleted';
+
+ -- this will return rows of record,quality
+ FOR rec IN EXECUTE query_ USING tags_rstore, svf_rstore LOOP
+ RETURN NEXT rec;
+ END LOOP;
+
+ DROP TABLE _vandelay_tmp_qrows;
+ DROP TABLE _vandelay_tmp_jrows;
+ RETURN;
+END;
+$$ LANGUAGE PLPGSQL;
+
+COMMIT;
<input jsId='vlUploadQueueMatchSet'
dojoType='dijit.form.FilteringSelect' labelAttr='name' searchAttr='name'/>
</td>
+ <td>[% l('Limit matches to bucket') %]</td>
+ <td>
+ <input jsId='vlUploadQueueMatchBucket'
+ dojoType='dijit.form.FilteringSelect' labelAttr='name' searchAttr='name'/>
+ </td>
</tr>
<tr>
<td>[% l('Holdings Import Profile') %]</td>
var vlBibSources = [];
var importItemDefs = [];
var matchSets = {biblio : [], authority : []};
+var matchBuckets = {};
var mergeProfiles = [];
var copyStatusCache = {};
var copyLocationCache = {};
}
);
+ fieldmapper.standardRequest(
+ ['open-ils.actor', 'open-ils.actor.container.retrieve_by_class'],
+ { async : true,
+ params : [authtoken, new openils.User().user.id(), 'biblio'],
+ oncomplete : function(r) {
+ var buckets = openils.Util.readResponse(r);
+ // only bib buckets are supported
+ matchBuckets.biblio = buckets;
+ checkInitDone();
+ }
+ }
+ );
+
new openils.PermaCrud().retrieveAll('ccs',
{ async: true,
oncomplete: function(r) {
/**
* Creates a new vandelay queue
*/
-function createQueue(queueName, type, onload, importDefId, matchSet) {
+function createQueue(
+ queueName, type, onload, importDefId, matchSet, matchBucket) {
+
var name = (type=='bib') ? 'bib' : 'authority';
var method = 'open-ils.vandelay.'+ name +'_queue.create'
fieldmapper.standardRequest(
['open-ils.vandelay', method],
{ async: true,
- params: [authtoken, queueName, null, qType, matchSet, importDefId],
+ params: [
+ authtoken, queueName, null,
+ qType, matchSet, importDefId, matchBucket
+ ],
oncomplete : function(r) {
var queue = r.recv().content();
if(e = openils.Event.parse(queue))
} else {
createQueue(queueName, currentType, handleCreateQueue,
vlUploadQueueHoldingsImportProfile.attr('value'),
- vlUploadQueueMatchSet.attr('value')
+ vlUploadQueueMatchSet.attr('value'),
+ vlUploadQueueMatchBucket.attr('value')
);
}
}
vlUploadQueueHoldingsImportProfile.attr('disabled', true);
vlUploadQueueMatchSet.attr('value', queue.match_set() || '');
vlUploadQueueMatchSet.attr('disabled', true);
+ vlUploadQueueMatchBucket.attr('value', queue.match_bucket() || '');
+ vlUploadQueueMatchBucket.attr('disabled', true);
} else {
vlUploadQueueHoldingsImportProfile.attr('value', '');
vlUploadQueueHoldingsImportProfile.attr('disabled', false);
- vlUploadQueueMatchSet.attr('value', '');
- vlUploadQueueMatchSet.attr('disabled', false);
+ vlUploadQueueMatchBucket.attr('value', '');
+ vlUploadQueueMatchBucket.attr('disabled', false);
}
dojo.disconnect(qInput._onchange);
qInput.attr('value', '');
// user entered a new queue name. clear the selector
vlUploadQueueHoldingsImportProfile.attr('disabled', false);
vlUploadQueueMatchSet.attr('disabled', false);
+ vlUploadQueueMatchBucket.attr('disabled', false);
dojo.disconnect(selector._onchange);
selector.attr('value', '');
selector._onchange = dojo.connect(selector, 'onChange', selChange);
}
}
+function vlUpdateMatchBucketSelector(type) {
+ type = (type.match(/bib/)) ? 'biblio' : 'authority';
+ if (type == 'authority') {
+ vlUploadQueueMatchBucket.attr('value', '');
+ vlUploadQueueMatchBucket.attr('disabled', true);
+ } else {
+ vlUploadQueueMatchBucket.attr('disabled', false);
+ vlUploadQueueMatchBucket.store =
+ new dojo.data.ItemFileReadStore(
+ {data:cbreb.toStoreData(matchBuckets[type])});
+ }
+}
+
function vlShowUploadForm() {
displayGlobalDiv('vl-marc-upload-div');
vlFleshQueueSelect(vlUploadQueueSelector, vlUploadRecordType.getValue());
vlUploadQueueHoldingsImportProfile.store =
new dojo.data.ItemFileReadStore({data:viiad.toStoreData(importItemDefs)});
vlUpdateMatchSetSelector(vlUploadRecordType.getValue());
+ vlUpdateMatchBucketSelector(vlUploadRecordType.getValue());
if (vlUploadRecordType.attr('value').match(/auth/) || trashGroups.length == 0) {
openils.Util.hide('vl-trash-groups-row');