BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1263', :eg_version); -- berick/csharp/gmcharlt
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1264', :eg_version); -- mrylander/sandbergja/rhamby/gmcharlt
CREATE TABLE config.bib_source (
id SERIAL PRIMARY KEY,
--- /dev/null
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('1264', :eg_version);
+
+CREATE OR REPLACE FUNCTION unapi.bre (
+ obj_id BIGINT,
+ format TEXT,
+ ename TEXT,
+ includes TEXT[],
+ org TEXT,
+ depth INT DEFAULT NULL,
+ slimit HSTORE DEFAULT NULL,
+ soffset HSTORE DEFAULT NULL,
+ include_xmlns BOOL DEFAULT TRUE,
+ pref_lib INT DEFAULT NULL
+)
+RETURNS XML AS $F$
+DECLARE
+ me biblio.record_entry%ROWTYPE;
+ layout unapi.bre_output_layout%ROWTYPE;
+ xfrm config.xml_transform%ROWTYPE;
+ ouid INT;
+ tmp_xml TEXT;
+ top_el TEXT;
+ output XML;
+ hxml XML;
+ axml XML;
+ source XML;
+BEGIN
+
+ IF org = '-' OR org IS NULL THEN
+ SELECT shortname INTO org FROM evergreen.org_top();
+ END IF;
+
+ SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
+
+ IF ouid IS NULL THEN
+ RETURN NULL::XML;
+ END IF;
+
+ IF format = 'holdings_xml' THEN -- the special case
+ output := unapi.holdings_xml( obj_id, ouid, org, depth, includes, slimit, soffset, include_xmlns);
+ RETURN output;
+ END IF;
+
+ SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
+
+ IF layout.name IS NULL THEN
+ RETURN NULL::XML;
+ END IF;
+
+ SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
+
+ SELECT * INTO me FROM biblio.record_entry WHERE id = obj_id;
+
+ -- grab bib_source, if any
+ IF ('cbs' = ANY (includes) AND me.source IS NOT NULL) THEN
+ source := unapi.cbs(me.source,NULL,NULL,NULL,NULL);
+ ELSE
+ source := NULL::XML;
+ END IF;
+
+ -- grab SVF if we need them
+ IF ('mra' = ANY (includes)) THEN
+ axml := unapi.mra(obj_id,NULL,NULL,NULL,NULL);
+ ELSE
+ axml := NULL::XML;
+ END IF;
+
+ -- grab holdings if we need them
+ IF ('holdings_xml' = ANY (includes)) THEN
+ hxml := unapi.holdings_xml(obj_id, ouid, org, depth, array_remove(includes,'holdings_xml'), slimit, soffset, include_xmlns, pref_lib);
+ ELSE
+ hxml := NULL::XML;
+ END IF;
+
+
+ -- generate our item node
+
+
+ IF format = 'marcxml' THEN
+ tmp_xml := me.marc;
+ IF tmp_xml !~ E'<marc:' THEN -- If we're not using the prefixed namespace in this record, then remove all declarations of it
+ tmp_xml := REGEXP_REPLACE(tmp_xml, ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
+ END IF;
+ ELSE
+ tmp_xml := oils_xslt_process(me.marc, xfrm.xslt)::XML;
+ END IF;
+
+ top_el := REGEXP_REPLACE(tmp_xml, E'^.*?<((?:\\S+:)?' || layout.holdings_element || ').*$', E'\\1');
+
+ IF source IS NOT NULL THEN
+ tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', source || '</' || top_el || E'>\\1');
+ END IF;
+
+ IF axml IS NOT NULL THEN
+ tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
+ END IF;
+
+ IF hxml IS NOT NULL THEN -- XXX how do we configure the holdings position?
+ tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
+ END IF;
+
+ IF ('bre.unapi' = ANY (includes)) THEN
+ output := REGEXP_REPLACE(
+ tmp_xml,
+ '</' || top_el || '>(.*?)',
+ XMLELEMENT(
+ name abbr,
+ XMLATTRIBUTES(
+ 'http://www.w3.org/1999/xhtml' AS xmlns,
+ 'unapi-id' AS class,
+ 'tag:open-ils.org:U2@bre/' || obj_id || '/' || org AS title
+ )
+ )::TEXT || '</' || top_el || E'>\\1'
+ );
+ ELSE
+ output := tmp_xml;
+ END IF;
+
+ IF ('bre.extern' = ANY (includes)) THEN
+ output := REGEXP_REPLACE(
+ tmp_xml,
+ '</' || top_el || '>(.*?)',
+ XMLELEMENT(
+ name extern,
+ XMLATTRIBUTES(
+ 'http://open-ils.org/spec/biblio/v1' AS xmlns,
+ me.creator AS creator,
+ me.editor AS editor,
+ me.create_date AS create_date,
+ me.edit_date AS edit_date,
+ me.quality AS quality,
+ me.fingerprint AS fingerprint,
+ me.tcn_source AS tcn_source,
+ me.tcn_value AS tcn_value,
+ me.owner AS owner,
+ me.share_depth AS share_depth,
+ me.active AS active,
+ me.deleted AS deleted
+ )
+ )::TEXT || '</' || top_el || E'>\\1'
+ );
+ ELSE
+ output := tmp_xml;
+ END IF;
+
+ output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
+ RETURN output;
+END;
+$F$ LANGUAGE PLPGSQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.holdings_xml (
+ bid BIGINT,
+ ouid INT,
+ org TEXT,
+ depth INT DEFAULT NULL,
+ includes TEXT[] DEFAULT NULL::TEXT[],
+ slimit HSTORE DEFAULT NULL,
+ soffset HSTORE DEFAULT NULL,
+ include_xmlns BOOL DEFAULT TRUE,
+ pref_lib INT DEFAULT NULL
+)
+RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name holdings,
+ XMLATTRIBUTES(
+ CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ CASE WHEN ('bre' = ANY ($5)) THEN 'tag:open-ils.org:U2@bre/' || $1 || '/' || $3 ELSE NULL END AS id,
+ (SELECT record_has_holdable_copy FROM asset.record_has_holdable_copy($1)) AS has_holdable
+ ),
+ XMLELEMENT(
+ name counts,
+ (SELECT XMLAGG(XMLELEMENT::XML) FROM (
+ SELECT XMLELEMENT(
+ name count,
+ XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+ )::text
+ FROM asset.opac_ou_record_copy_count($2, $1)
+ UNION
+ SELECT XMLELEMENT(
+ name count,
+ XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+ )::text
+ FROM asset.staff_ou_record_copy_count($2, $1)
+ UNION
+ SELECT XMLELEMENT(
+ name count,
+ XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+ )::text
+ FROM asset.opac_ou_record_copy_count($9, $1)
+ ORDER BY 1
+ )x)
+ ),
+ CASE
+ WHEN ('bmp' = ANY ($5)) THEN
+ XMLELEMENT(
+ name monograph_parts,
+ (SELECT XMLAGG(bmp) FROM (
+ SELECT unapi.bmp( id, 'xml', 'monograph_part', array_remove( array_remove($5,'bre'), 'holdings_xml'), $3, $4, $6, $7, FALSE)
+ FROM biblio.monograph_part
+ WHERE NOT deleted AND record = $1
+ )x)
+ )
+ ELSE NULL
+ END,
+ XMLELEMENT(
+ name volumes,
+ (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
+ -- Physical copies
+ SELECT unapi.acn(y.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey
+ FROM evergreen.ranked_volumes($1, $2, $4, $6, $7, $9, $5) AS y
+ UNION ALL
+ -- Located URIs
+ SELECT unapi.acn(uris.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey
+ FROM evergreen.located_uris($1, $2, $9) AS uris
+ )x)
+ ),
+ CASE WHEN ('ssub' = ANY ($5)) THEN
+ XMLELEMENT(
+ name subscriptions,
+ (SELECT XMLAGG(ssub) FROM (
+ SELECT unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
+ FROM serial.subscription
+ WHERE record_entry = $1
+ )x)
+ )
+ ELSE NULL END,
+ CASE WHEN ('acp' = ANY ($5)) THEN
+ XMLELEMENT(
+ name foreign_copies,
+ (SELECT XMLAGG(acp) FROM (
+ SELECT unapi.acp(p.target_copy,'xml','copy',array_remove($5,'acp'), $3, $4, $6, $7, FALSE)
+ FROM biblio.peer_bib_copy_map p
+ JOIN asset.copy c ON (p.target_copy = c.id)
+ WHERE NOT c.deleted AND p.peer_record = $1
+ LIMIT ($6 -> 'acp')::INT
+ OFFSET ($7 -> 'acp')::INT
+ )x)
+ )
+ ELSE NULL END
+ );
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.ssub ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name subscription,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@ssub/' || id AS id,
+ 'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib,
+ start_date AS start, end_date AS end, expected_date_offset
+ ),
+ CASE
+ WHEN ('sdist' = ANY ($4)) THEN
+ XMLELEMENT( name distributions,
+ (SELECT XMLAGG(sdist) FROM (
+ SELECT unapi.sdist( id, 'xml', 'distribution', array_remove($4,'ssub'), $5, $6, $7, $8, FALSE)
+ FROM serial.distribution
+ WHERE subscription = ssub.id
+ )x)
+ )
+ ELSE NULL
+ END
+ )
+ FROM serial.subscription ssub
+ WHERE id = $1
+ GROUP BY id, start_date, end_date, expected_date_offset, owning_lib;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.sdist ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name distribution,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@sdist/' || id AS id,
+ 'tag:open-ils.org:U2@acn/' || receive_call_number AS receive_call_number,
+ 'tag:open-ils.org:U2@acn/' || bind_call_number AS bind_call_number,
+ unit_label_prefix, label, unit_label_suffix, summary_method
+ ),
+ unapi.aou( holding_lib, $2, 'holding_lib', array_remove($4,'sdist'), $5, $6, $7, $8),
+ CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE) ELSE NULL END,
+ CASE
+ WHEN ('sstr' = ANY ($4)) THEN
+ XMLELEMENT( name streams,
+ (SELECT XMLAGG(sstr) FROM (
+ SELECT unapi.sstr( id, 'xml', 'stream', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE)
+ FROM serial.stream
+ WHERE distribution = sdist.id
+ )x)
+ )
+ ELSE NULL
+ END,
+ XMLELEMENT( name summaries,
+ CASE
+ WHEN ('sbsum' = ANY ($4)) THEN
+ (SELECT XMLAGG(sbsum) FROM (
+ SELECT unapi.sbsum( id, 'xml', 'serial_summary', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE)
+ FROM serial.basic_summary
+ WHERE distribution = sdist.id
+ )x)
+ ELSE NULL
+ END,
+ CASE
+ WHEN ('sisum' = ANY ($4)) THEN
+ (SELECT XMLAGG(sisum) FROM (
+ SELECT unapi.sisum( id, 'xml', 'serial_summary', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE)
+ FROM serial.index_summary
+ WHERE distribution = sdist.id
+ )x)
+ ELSE NULL
+ END,
+ CASE
+ WHEN ('sssum' = ANY ($4)) THEN
+ (SELECT XMLAGG(sssum) FROM (
+ SELECT unapi.sssum( id, 'xml', 'serial_summary', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE)
+ FROM serial.supplement_summary
+ WHERE distribution = sdist.id
+ )x)
+ ELSE NULL
+ END
+ )
+ )
+ FROM serial.distribution sdist
+ WHERE id = $1
+ GROUP BY id, label, unit_label_prefix, unit_label_suffix, holding_lib, summary_method, subscription, receive_call_number, bind_call_number;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.sstr ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name stream,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@sstr/' || id AS id,
+ routing_label
+ ),
+ CASE WHEN distribution IS NOT NULL AND ('sdist' = ANY ($4)) THEN unapi.sssum( distribution, 'xml', 'distribtion', array_remove($4,'sstr'), $5, $6, $7, $8, FALSE) ELSE NULL END,
+ CASE
+ WHEN ('sitem' = ANY ($4)) THEN
+ XMLELEMENT( name items,
+ (SELECT XMLAGG(sitem) FROM (
+ SELECT unapi.sitem( id, 'xml', 'serial_item', array_remove($4,'sstr'), $5, $6, $7, $8, FALSE)
+ FROM serial.item
+ WHERE stream = sstr.id
+ )x)
+ )
+ ELSE NULL
+ END
+ )
+ FROM serial.stream sstr
+ WHERE id = $1
+ GROUP BY id, routing_label, distribution;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.siss ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name issuance,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@siss/' || id AS id,
+ create_date, edit_date, label, date_published,
+ holding_code, holding_type, holding_link_id
+ ),
+ CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', array_remove($4,'siss'), $5, $6, $7, $8, FALSE) ELSE NULL END,
+ CASE
+ WHEN ('sitem' = ANY ($4)) THEN
+ XMLELEMENT( name items,
+ (SELECT XMLAGG(sitem) FROM (
+ SELECT unapi.sitem( id, 'xml', 'serial_item', array_remove($4,'siss'), $5, $6, $7, $8, FALSE)
+ FROM serial.item
+ WHERE issuance = sstr.id
+ )x)
+ )
+ ELSE NULL
+ END
+ )
+ FROM serial.issuance sstr
+ WHERE id = $1
+ GROUP BY id, create_date, edit_date, label, date_published, holding_code, holding_type, holding_link_id, subscription;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.sitem ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name serial_item,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@sitem/' || id AS id,
+ 'tag:open-ils.org:U2@siss/' || issuance AS issuance,
+ date_expected, date_received
+ ),
+ CASE WHEN issuance IS NOT NULL AND ('siss' = ANY ($4)) THEN unapi.siss( issuance, $2, 'issuance', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
+ CASE WHEN stream IS NOT NULL AND ('sstr' = ANY ($4)) THEN unapi.sstr( stream, $2, 'stream', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
+ CASE WHEN unit IS NOT NULL AND ('sunit' = ANY ($4)) THEN unapi.sunit( unit, $2, 'serial_unit', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
+ CASE WHEN uri IS NOT NULL AND ('auri' = ANY ($4)) THEN unapi.auri( uri, $2, 'uri', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END
+-- XMLELEMENT( name notes,
+-- CASE
+-- WHEN ('acpn' = ANY ($4)) THEN
+-- (SELECT XMLAGG(acpn) FROM (
+-- SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove($4,'acp'), $5, $6, $7, $8)
+-- FROM asset.copy_note
+-- WHERE owning_copy = cp.id AND pub
+-- )x)
+-- ELSE NULL
+-- END
+-- )
+ )
+ FROM serial.item sitem
+ WHERE id = $1;
+$F$ LANGUAGE SQL STABLE;
+
+
+CREATE OR REPLACE FUNCTION unapi.sssum ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name serial_summary,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@sbsum/' || id AS id,
+ 'sssum' AS type, generated_coverage, textual_holdings, show_generated
+ ),
+ CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
+ )
+ FROM serial.supplement_summary ssum
+ WHERE id = $1
+ GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.sbsum ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name serial_summary,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@sbsum/' || id AS id,
+ 'sbsum' AS type, generated_coverage, textual_holdings, show_generated
+ ),
+ CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
+ )
+ FROM serial.basic_summary ssum
+ WHERE id = $1
+ GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.sisum ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name serial_summary,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@sbsum/' || id AS id,
+ 'sisum' AS type, generated_coverage, textual_holdings, show_generated
+ ),
+ CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
+ )
+ FROM serial.index_summary ssum
+ WHERE id = $1
+ GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.bmp ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name monograph_part,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@bmp/' || id AS id,
+ id AS ident,
+ label,
+ label_sortkey,
+ 'tag:open-ils.org:U2@bre/' || record AS record
+ ),
+ CASE
+ WHEN ('acp' = ANY ($4)) THEN
+ XMLELEMENT( name copies,
+ (SELECT XMLAGG(acp) FROM (
+ SELECT unapi.acp( cp.id, 'xml', 'copy', array_remove($4,'bmp'), $5, $6, $7, $8, FALSE)
+ FROM asset.copy cp
+ JOIN asset.copy_part_map cpm ON (cpm.target_copy = cp.id)
+ WHERE cpm.part = $1
+ AND cp.deleted IS FALSE
+ ORDER BY COALESCE(cp.copy_number,0), cp.barcode
+ LIMIT ($7 -> 'acp')::INT
+ OFFSET ($8 -> 'acp')::INT
+
+ )x)
+ )
+ ELSE NULL
+ END,
+ CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( record, 'marcxml', 'record', array_remove($4,'bmp'), $5, $6, $7, $8, FALSE) ELSE NULL END
+ )
+ FROM biblio.monograph_part
+ WHERE NOT deleted AND id = $1
+ GROUP BY id, label, label_sortkey, record;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.acp ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name copy,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id,
+ create_date, edit_date, copy_number, circulate, deposit,
+ ref, holdable, deleted, deposit_amount, price, barcode,
+ circ_modifier, circ_as_type, opac_visible, age_protect
+ ),
+ unapi.ccs( status, $2, 'status', array_remove($4,'acp'), $5, $6, $7, $8, FALSE),
+ unapi.acl( location, $2, 'location', array_remove($4,'acp'), $5, $6, $7, $8, FALSE),
+ unapi.aou( circ_lib, $2, 'circ_lib', array_remove($4,'acp'), $5, $6, $7, $8),
+ unapi.aou( circ_lib, $2, 'circlib', array_remove($4,'acp'), $5, $6, $7, $8),
+ CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END,
+ CASE
+ WHEN ('acpn' = ANY ($4)) THEN
+ XMLELEMENT( name copy_notes,
+ (SELECT XMLAGG(acpn) FROM (
+ SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
+ FROM asset.copy_note
+ WHERE owning_copy = cp.id AND pub
+ )x)
+ )
+ ELSE NULL
+ END,
+ CASE
+ WHEN ('ascecm' = ANY ($4)) THEN
+ XMLELEMENT( name statcats,
+ (SELECT XMLAGG(ascecm) FROM (
+ SELECT unapi.ascecm( stat_cat_entry, 'xml', 'statcat', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
+ FROM asset.stat_cat_entry_copy_map
+ WHERE owning_copy = cp.id
+ )x)
+ )
+ ELSE NULL
+ END,
+ CASE
+ WHEN ('bre' = ANY ($4)) THEN
+ XMLELEMENT( name foreign_records,
+ (SELECT XMLAGG(bre) FROM (
+ SELECT unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE)
+ FROM biblio.peer_bib_copy_map
+ WHERE target_copy = cp.id
+ )x)
+
+ )
+ ELSE NULL
+ END,
+ CASE
+ WHEN ('bmp' = ANY ($4)) THEN
+ XMLELEMENT( name monograph_parts,
+ (SELECT XMLAGG(bmp) FROM (
+ SELECT unapi.bmp( part, 'xml', 'monograph_part', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
+ FROM asset.copy_part_map
+ WHERE target_copy = cp.id
+ )x)
+ )
+ ELSE NULL
+ END,
+ CASE
+ WHEN ('circ' = ANY ($4)) THEN
+ XMLELEMENT( name current_circulation,
+ (SELECT XMLAGG(circ) FROM (
+ SELECT unapi.circ( id, 'xml', 'circ', array_remove($4,'circ'), $5, $6, $7, $8, FALSE)
+ FROM action.circulation
+ WHERE target_copy = cp.id
+ AND checkin_time IS NULL
+ )x)
+ )
+ ELSE NULL
+ END
+ )
+ FROM asset.copy cp
+ WHERE id = $1
+ AND cp.deleted IS FALSE
+ GROUP BY id, status, location, circ_lib, call_number, create_date,
+ edit_date, copy_number, circulate, deposit, ref, holdable,
+ deleted, deposit_amount, price, barcode, circ_modifier,
+ circ_as_type, opac_visible, age_protect;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.sunit ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name serial_unit,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id,
+ create_date, edit_date, copy_number, circulate, deposit,
+ ref, holdable, deleted, deposit_amount, price, barcode,
+ circ_modifier, circ_as_type, opac_visible, age_protect,
+ status_changed_time, floating, mint_condition,
+ detailed_contents, sort_key, summary_contents, cost
+ ),
+ unapi.ccs( status, $2, 'status', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE),
+ unapi.acl( location, $2, 'location', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE),
+ unapi.aou( circ_lib, $2, 'circ_lib', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8),
+ unapi.aou( circ_lib, $2, 'circlib', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8),
+ CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END,
+ XMLELEMENT( name copy_notes,
+ CASE
+ WHEN ('acpn' = ANY ($4)) THEN
+ (SELECT XMLAGG(acpn) FROM (
+ SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE)
+ FROM asset.copy_note
+ WHERE owning_copy = cp.id AND pub
+ )x)
+ ELSE NULL
+ END
+ ),
+ XMLELEMENT( name statcats,
+ CASE
+ WHEN ('ascecm' = ANY ($4)) THEN
+ (SELECT XMLAGG(ascecm) FROM (
+ SELECT unapi.ascecm( stat_cat_entry, 'xml', 'statcat', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
+ FROM asset.stat_cat_entry_copy_map
+ WHERE owning_copy = cp.id
+ )x)
+ ELSE NULL
+ END
+ ),
+ XMLELEMENT( name foreign_records,
+ CASE
+ WHEN ('bre' = ANY ($4)) THEN
+ (SELECT XMLAGG(bre) FROM (
+ SELECT unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE)
+ FROM biblio.peer_bib_copy_map
+ WHERE target_copy = cp.id
+ )x)
+ ELSE NULL
+ END
+ ),
+ CASE
+ WHEN ('bmp' = ANY ($4)) THEN
+ XMLELEMENT( name monograph_parts,
+ (SELECT XMLAGG(bmp) FROM (
+ SELECT unapi.bmp( part, 'xml', 'monograph_part', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
+ FROM asset.copy_part_map
+ WHERE target_copy = cp.id
+ )x)
+ )
+ ELSE NULL
+ END,
+ CASE
+ WHEN ('circ' = ANY ($4)) THEN
+ XMLELEMENT( name current_circulation,
+ (SELECT XMLAGG(circ) FROM (
+ SELECT unapi.circ( id, 'xml', 'circ', array_remove($4,'circ'), $5, $6, $7, $8, FALSE)
+ FROM action.circulation
+ WHERE target_copy = cp.id
+ AND checkin_time IS NULL
+ )x)
+ )
+ ELSE NULL
+ END
+ )
+ FROM serial.unit cp
+ WHERE id = $1
+ AND cp.deleted IS FALSE
+ GROUP BY id, status, location, circ_lib, call_number, create_date,
+ edit_date, copy_number, circulate, floating, mint_condition,
+ deposit, ref, holdable, deleted, deposit_amount, price,
+ barcode, circ_modifier, circ_as_type, opac_visible,
+ status_changed_time, detailed_contents, sort_key,
+ summary_contents, cost, age_protect;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.acn ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name volume,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@acn/' || acn.id AS id,
+ acn.id AS vol_id, o.shortname AS lib,
+ o.opac_visible AS opac_visible,
+ deleted, label, label_sortkey, label_class, record
+ ),
+ unapi.aou( owning_lib, $2, 'owning_lib', array_remove($4,'acn'), $5, $6, $7, $8),
+ CASE
+ WHEN ('acp' = ANY ($4)) THEN
+ CASE WHEN $6 IS NOT NULL THEN
+ XMLELEMENT( name copies,
+ (SELECT XMLAGG(acp ORDER BY rank_avail) FROM (
+ SELECT unapi.acp( cp.id, 'xml', 'copy', array_remove($4,'acn'), $5, $6, $7, $8, FALSE),
+ evergreen.rank_cp(cp) AS rank_avail
+ FROM asset.copy cp
+ JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5), $6) aoud ON (cp.circ_lib = aoud.id)
+ WHERE cp.call_number = acn.id
+ AND cp.deleted IS FALSE
+ ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode
+ LIMIT ($7 -> 'acp')::INT
+ OFFSET ($8 -> 'acp')::INT
+ )x)
+ )
+ ELSE
+ XMLELEMENT( name copies,
+ (SELECT XMLAGG(acp ORDER BY rank_avail) FROM (
+ SELECT unapi.acp( cp.id, 'xml', 'copy', array_remove($4,'acn'), $5, $6, $7, $8, FALSE),
+ evergreen.rank_cp(cp) AS rank_avail
+ FROM asset.copy cp
+ JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5) ) aoud ON (cp.circ_lib = aoud.id)
+ WHERE cp.call_number = acn.id
+ AND cp.deleted IS FALSE
+ ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode
+ LIMIT ($7 -> 'acp')::INT
+ OFFSET ($8 -> 'acp')::INT
+ )x)
+ )
+ END
+ ELSE NULL
+ END,
+ XMLELEMENT(
+ name uris,
+ (SELECT XMLAGG(auri) FROM (SELECT unapi.auri(uri,'xml','uri', array_remove($4,'acn'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE call_number = acn.id)x)
+ ),
+ unapi.acnp( acn.prefix, 'marcxml', 'prefix', array_remove($4,'acn'), $5, $6, $7, $8, FALSE),
+ unapi.acns( acn.suffix, 'marcxml', 'suffix', array_remove($4,'acn'), $5, $6, $7, $8, FALSE),
+ CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( acn.record, 'marcxml', 'record', array_remove($4,'acn'), $5, $6, $7, $8, FALSE) ELSE NULL END
+ ) AS x
+ FROM asset.call_number acn
+ JOIN actor.org_unit o ON (o.id = acn.owning_lib)
+ WHERE acn.id = $1
+ AND acn.deleted IS FALSE
+ GROUP BY acn.id, o.shortname, o.opac_visible, deleted, label, label_sortkey, label_class, owning_lib, record, acn.prefix, acn.suffix;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.auri ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name uri,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@auri/' || uri.id AS id,
+ use_restriction,
+ href,
+ label
+ ),
+ CASE
+ WHEN ('acn' = ANY ($4)) THEN
+ XMLELEMENT( name copies,
+ (SELECT XMLAGG(acn) FROM (SELECT unapi.acn( call_number, 'xml', 'copy', array_remove($4,'auri'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE uri = uri.id)x)
+ )
+ ELSE NULL
+ END
+ ) AS x
+ FROM asset.uri uri
+ WHERE uri.id = $1
+ GROUP BY uri.id, use_restriction, href, label;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.circ (obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT DEFAULT '-', depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name circ,
+ XMLATTRIBUTES(
+ CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ 'tag:open-ils.org:U2@circ/' || id AS id,
+ xact_start,
+ due_date
+ ),
+ CASE WHEN ('aou' = ANY ($4)) THEN unapi.aou( circ_lib, $2, 'circ_lib', array_remove($4,'circ'), $5, $6, $7, $8, FALSE) ELSE NULL END,
+ CASE WHEN ('acp' = ANY ($4)) THEN unapi.acp( circ_lib, $2, 'target_copy', array_remove($4,'circ'), $5, $6, $7, $8, FALSE) ELSE NULL END
+ )
+ FROM action.circulation
+ WHERE id = $1;
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.mmr_holdings_xml (
+ mid BIGINT,
+ ouid INT,
+ org TEXT,
+ depth INT DEFAULT NULL,
+ includes TEXT[] DEFAULT NULL::TEXT[],
+ slimit HSTORE DEFAULT NULL,
+ soffset HSTORE DEFAULT NULL,
+ include_xmlns BOOL DEFAULT TRUE,
+ pref_lib INT DEFAULT NULL
+)
+RETURNS XML AS $F$
+ SELECT XMLELEMENT(
+ name holdings,
+ XMLATTRIBUTES(
+ CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
+ CASE WHEN ('mmr' = ANY ($5)) THEN 'tag:open-ils.org:U2@mmr/' || $1 || '/' || $3 ELSE NULL END AS id,
+ (SELECT metarecord_has_holdable_copy FROM asset.metarecord_has_holdable_copy($1)) AS has_holdable
+ ),
+ XMLELEMENT(
+ name counts,
+ (SELECT XMLAGG(XMLELEMENT::XML) FROM (
+ SELECT XMLELEMENT(
+ name count,
+ XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+ )::text
+ FROM asset.opac_ou_metarecord_copy_count($2, $1)
+ UNION
+ SELECT XMLELEMENT(
+ name count,
+ XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+ )::text
+ FROM asset.staff_ou_metarecord_copy_count($2, $1)
+ UNION
+ SELECT XMLELEMENT(
+ name count,
+ XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
+ )::text
+ FROM asset.opac_ou_metarecord_copy_count($9, $1)
+ ORDER BY 1
+ )x)
+ ),
+ -- XXX monograph_parts and foreign_copies are skipped in MRs ... put them back some day?
+ XMLELEMENT(
+ name volumes,
+ (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
+ -- Physical copies
+ SELECT unapi.acn(y.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey
+ FROM evergreen.ranked_volumes((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $4, $6, $7, $9, $5) AS y
+ UNION ALL
+ -- Located URIs
+ SELECT unapi.acn(uris.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey
+ FROM evergreen.located_uris((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $9) AS uris
+ )x)
+ ),
+ CASE WHEN ('ssub' = ANY ($5)) THEN
+ XMLELEMENT(
+ name subscriptions,
+ (SELECT XMLAGG(ssub) FROM (
+ SELECT unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
+ FROM serial.subscription
+ WHERE record_entry IN (SELECT source FROM metabib.metarecord_source_map WHERE metarecord = $1)
+ )x)
+ )
+ ELSE NULL END
+ );
+$F$ LANGUAGE SQL STABLE;
+
+CREATE OR REPLACE FUNCTION unapi.mmr (
+ obj_id BIGINT,
+ format TEXT,
+ ename TEXT,
+ includes TEXT[],
+ org TEXT,
+ depth INT DEFAULT NULL,
+ slimit HSTORE DEFAULT NULL,
+ soffset HSTORE DEFAULT NULL,
+ include_xmlns BOOL DEFAULT TRUE,
+ pref_lib INT DEFAULT NULL
+)
+RETURNS XML AS $F$
+DECLARE
+ mmrec metabib.metarecord%ROWTYPE;
+ leadrec biblio.record_entry%ROWTYPE;
+ subrec biblio.record_entry%ROWTYPE;
+ layout unapi.bre_output_layout%ROWTYPE;
+ xfrm config.xml_transform%ROWTYPE;
+ ouid INT;
+ xml_buf TEXT; -- growing XML document
+ tmp_xml TEXT; -- single-use XML string
+ xml_frag TEXT; -- single-use XML fragment
+ top_el TEXT;
+ output XML;
+ hxml XML;
+ axml XML;
+ subxml XML; -- subordinate records elements
+ sub_xpath TEXT;
+ parts TEXT[];
+BEGIN
+
+ -- xpath for extracting bre.marc values from subordinate records
+ -- so they may be appended to the MARC of the master record prior
+ -- to XSLT processing.
+ -- subjects, isbn, issn, upc -- anything else?
+ sub_xpath :=
+ '//*[starts-with(@tag, "6") or @tag="020" or @tag="022" or @tag="024"]';
+
+ IF org = '-' OR org IS NULL THEN
+ SELECT shortname INTO org FROM evergreen.org_top();
+ END IF;
+
+ SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
+
+ IF ouid IS NULL THEN
+ RETURN NULL::XML;
+ END IF;
+
+ SELECT INTO mmrec * FROM metabib.metarecord WHERE id = obj_id;
+ IF NOT FOUND THEN
+ RETURN NULL::XML;
+ END IF;
+
+ -- TODO: aggregate holdings from constituent records
+ IF format = 'holdings_xml' THEN -- the special case
+ output := unapi.mmr_holdings_xml(
+ obj_id, ouid, org, depth,
+ array_remove(includes,'holdings_xml'),
+ slimit, soffset, include_xmlns, pref_lib);
+ RETURN output;
+ END IF;
+
+ SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
+
+ IF layout.name IS NULL THEN
+ RETURN NULL::XML;
+ END IF;
+
+ SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
+
+ SELECT INTO leadrec * FROM biblio.record_entry WHERE id = mmrec.master_record;
+
+ -- Grab distinct MVF for all records if requested
+ IF ('mra' = ANY (includes)) THEN
+ axml := unapi.mmr_mra(obj_id,NULL,NULL,NULL,org,depth,NULL,NULL,TRUE,pref_lib);
+ ELSE
+ axml := NULL::XML;
+ END IF;
+
+ xml_buf = leadrec.marc;
+
+ hxml := NULL::XML;
+ IF ('holdings_xml' = ANY (includes)) THEN
+ hxml := unapi.mmr_holdings_xml(
+ obj_id, ouid, org, depth,
+ array_remove(includes,'holdings_xml'),
+ slimit, soffset, include_xmlns, pref_lib);
+ END IF;
+
+ subxml := NULL::XML;
+ parts := '{}'::TEXT[];
+ FOR subrec IN SELECT bre.* FROM biblio.record_entry bre
+ JOIN metabib.metarecord_source_map mmsm ON (mmsm.source = bre.id)
+ JOIN metabib.metarecord mmr ON (mmr.id = mmsm.metarecord)
+ WHERE mmr.id = obj_id AND NOT bre.deleted
+ ORDER BY CASE WHEN bre.id = mmr.master_record THEN 0 ELSE bre.id END
+ LIMIT COALESCE((slimit->'bre')::INT, 5) LOOP
+
+ IF subrec.id = leadrec.id THEN CONTINUE; END IF;
+ -- Append choice data from the the non-lead records to the
+ -- the lead record document
+
+ parts := parts || xpath(sub_xpath, subrec.marc::XML)::TEXT[];
+ END LOOP;
+
+ SELECT ARRAY_TO_STRING( ARRAY_AGG( DISTINCT p ), '' )::XML INTO subxml FROM UNNEST(parts) p;
+
+ -- append data from the subordinate records to the
+ -- main record document before applying the XSLT
+
+ IF subxml IS NOT NULL THEN
+ xml_buf := REGEXP_REPLACE(xml_buf,
+ '</record>(.*?)$', subxml || '</record>' || E'\\1');
+ END IF;
+
+ IF format = 'marcxml' THEN
+ -- If we're not using the prefixed namespace in
+ -- this record, then remove all declarations of it
+ IF xml_buf !~ E'<marc:' THEN
+ xml_buf := REGEXP_REPLACE(xml_buf,
+ ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
+ END IF;
+ ELSE
+ xml_buf := oils_xslt_process(xml_buf, xfrm.xslt)::XML;
+ END IF;
+
+ -- update top_el to reflect the change in xml_buf, which may
+ -- now be a different type of document (e.g. record -> mods)
+ top_el := REGEXP_REPLACE(xml_buf, E'^.*?<((?:\\S+:)?' ||
+ layout.holdings_element || ').*$', E'\\1');
+
+ IF axml IS NOT NULL THEN
+ xml_buf := REGEXP_REPLACE(xml_buf,
+ '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
+ END IF;
+
+ IF hxml IS NOT NULL THEN
+ xml_buf := REGEXP_REPLACE(xml_buf,
+ '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
+ END IF;
+
+ IF ('mmr.unapi' = ANY (includes)) THEN
+ output := REGEXP_REPLACE(
+ xml_buf,
+ '</' || top_el || '>(.*?)',
+ XMLELEMENT(
+ name abbr,
+ XMLATTRIBUTES(
+ 'http://www.w3.org/1999/xhtml' AS xmlns,
+ 'unapi-id' AS class,
+ 'tag:open-ils.org:U2@mmr/' || obj_id || '/' || org AS title
+ )
+ )::TEXT || '</' || top_el || E'>\\1'
+ );
+ ELSE
+ output := xml_buf;
+ END IF;
+
+ -- remove ignorable whitesace
+ output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
+ RETURN output;
+END;
+$F$ LANGUAGE PLPGSQL STABLE;
+
+CREATE OR REPLACE FUNCTION authority.extract_headings(marc TEXT, restrict INT[] DEFAULT NULL) RETURNS SETOF authority.heading AS $func$
+DECLARE
+ idx authority.heading_field%ROWTYPE;
+ xfrm config.xml_transform%ROWTYPE;
+ prev_xfrm TEXT;
+ transformed_xml TEXT;
+ heading_node TEXT;
+ heading_node_list TEXT[];
+ component_node TEXT;
+ component_node_list TEXT[];
+ raw_text TEXT;
+ normalized_text TEXT;
+ normalizer RECORD;
+ curr_text TEXT;
+ joiner TEXT;
+ type_value TEXT;
+ base_thesaurus TEXT := NULL;
+ output_row authority.heading;
+BEGIN
+
+ -- Loop over the indexing entries
+ FOR idx IN SELECT * FROM authority.heading_field WHERE restrict IS NULL OR id = ANY (restrict) ORDER BY format LOOP
+
+ output_row.field := idx.id;
+ output_row.type := idx.heading_type;
+ output_row.purpose := idx.heading_purpose;
+
+ joiner := COALESCE(idx.joiner, ' ');
+
+ SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format;
+
+ -- See if we can skip the XSLT ... it's expensive
+ IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
+ -- Can't skip the transform
+ IF xfrm.xslt <> '---' THEN
+ transformed_xml := oils_xslt_process(marc, xfrm.xslt);
+ ELSE
+ transformed_xml := marc;
+ END IF;
+
+ prev_xfrm := xfrm.name;
+ END IF;
+
+ IF idx.thesaurus_xpath IS NOT NULL THEN
+ base_thesaurus := ARRAY_TO_STRING(oils_xpath(idx.thesaurus_xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), '');
+ END IF;
+
+ heading_node_list := oils_xpath( idx.heading_xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+
+ FOR heading_node IN SELECT x FROM unnest(heading_node_list) AS x LOOP
+
+ CONTINUE WHEN heading_node !~ E'^\\s*<';
+
+ output_row.variant_type := NULL;
+ output_row.related_type := NULL;
+ output_row.thesaurus := NULL;
+ output_row.heading := NULL;
+
+ IF idx.heading_purpose = 'variant' AND idx.type_xpath IS NOT NULL THEN
+ type_value := ARRAY_TO_STRING(oils_xpath(idx.type_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), '');
+ BEGIN
+ output_row.variant_type := type_value;
+ EXCEPTION WHEN invalid_text_representation THEN
+ RAISE NOTICE 'Do not recognize variant heading type %', type_value;
+ END;
+ END IF;
+ IF idx.heading_purpose = 'related' AND idx.type_xpath IS NOT NULL THEN
+ type_value := ARRAY_TO_STRING(oils_xpath(idx.type_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), '');
+ BEGIN
+ output_row.related_type := type_value;
+ EXCEPTION WHEN invalid_text_representation THEN
+ RAISE NOTICE 'Do not recognize related heading type %', type_value;
+ END;
+ END IF;
+
+ IF idx.thesaurus_override_xpath IS NOT NULL THEN
+ output_row.thesaurus := ARRAY_TO_STRING(oils_xpath(idx.thesaurus_override_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), '');
+ END IF;
+ IF output_row.thesaurus IS NULL THEN
+ output_row.thesaurus := base_thesaurus;
+ END IF;
+
+ raw_text := NULL;
+
+ -- now iterate over components of heading
+ component_node_list := oils_xpath( idx.component_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+ FOR component_node IN SELECT x FROM unnest(component_node_list) AS x LOOP
+ -- XXX much of this should be moved into oils_xpath_string...
+ curr_text := ARRAY_TO_STRING(array_remove(array_remove(
+ oils_xpath( '//text()', -- get the content of all the nodes within the main selected node
+ REGEXP_REPLACE( component_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space
+ ), ' '), ''), -- throw away morally empty (bankrupt?) strings
+ joiner
+ );
+
+ CONTINUE WHEN curr_text IS NULL OR curr_text = '';
+
+ IF raw_text IS NOT NULL THEN
+ raw_text := raw_text || joiner;
+ END IF;
+
+ raw_text := COALESCE(raw_text,'') || curr_text;
+ END LOOP;
+
+ IF raw_text IS NOT NULL THEN
+ output_row.heading := raw_text;
+ normalized_text := raw_text;
+
+ FOR normalizer IN
+ SELECT n.func AS func,
+ n.param_count AS param_count,
+ m.params AS params
+ FROM config.index_normalizer n
+ JOIN authority.heading_field_norm_map m ON (m.norm = n.id)
+ WHERE m.field = idx.id
+ ORDER BY m.pos LOOP
+
+ EXECUTE 'SELECT ' || normalizer.func || '(' ||
+ quote_literal( normalized_text ) ||
+ CASE
+ WHEN normalizer.param_count > 0
+ THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
+ ELSE ''
+ END ||
+ ')' INTO normalized_text;
+
+ END LOOP;
+
+ output_row.normalized_heading := normalized_text;
+
+ RETURN NEXT output_row;
+ END IF;
+ END LOOP;
+
+ END LOOP;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION authority.extract_headings(rid BIGINT, restrict INT[] DEFAULT NULL) RETURNS SETOF authority.heading AS $func$
+DECLARE
+ auth authority.record_entry%ROWTYPE;
+ output_row authority.heading;
+BEGIN
+ -- Get the record
+ SELECT INTO auth * FROM authority.record_entry WHERE id = rid;
+
+ RETURN QUERY SELECT * FROM authority.extract_headings(auth.marc, restrict);
+END;
+$func$ LANGUAGE PLPGSQL;
+
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry (
+ rid BIGINT,
+ default_joiner TEXT,
+ field_types TEXT[],
+ only_fields INT[]
+) RETURNS SETOF metabib.field_entry_template AS $func$
+DECLARE
+ bib biblio.record_entry%ROWTYPE;
+ idx config.metabib_field%ROWTYPE;
+ xfrm config.xml_transform%ROWTYPE;
+ prev_xfrm TEXT;
+ transformed_xml TEXT;
+ xml_node TEXT;
+ xml_node_list TEXT[];
+ facet_text TEXT;
+ display_text TEXT;
+ browse_text TEXT;
+ sort_value TEXT;
+ raw_text TEXT;
+ curr_text TEXT;
+ joiner TEXT := default_joiner; -- XXX will index defs supply a joiner?
+ authority_text TEXT;
+ authority_link BIGINT;
+ output_row metabib.field_entry_template%ROWTYPE;
+ process_idx BOOL;
+BEGIN
+
+ -- Start out with no field-use bools set
+ output_row.browse_field = FALSE;
+ output_row.facet_field = FALSE;
+ output_row.display_field = FALSE;
+ output_row.search_field = FALSE;
+
+ -- Get the record
+ SELECT INTO bib * FROM biblio.record_entry WHERE id = rid;
+
+ -- Loop over the indexing entries
+ FOR idx IN SELECT * FROM config.metabib_field WHERE id = ANY (only_fields) ORDER BY format LOOP
+ CONTINUE WHEN idx.xpath IS NULL OR idx.xpath = ''; -- pure virtual field
+
+ process_idx := FALSE;
+ IF idx.display_field AND 'display' = ANY (field_types) THEN process_idx = TRUE; END IF;
+ IF idx.browse_field AND 'browse' = ANY (field_types) THEN process_idx = TRUE; END IF;
+ IF idx.search_field AND 'search' = ANY (field_types) THEN process_idx = TRUE; END IF;
+ IF idx.facet_field AND 'facet' = ANY (field_types) THEN process_idx = TRUE; END IF;
+ CONTINUE WHEN process_idx = FALSE; -- disabled for all types
+
+ joiner := COALESCE(idx.joiner, default_joiner);
+
+ SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format;
+
+ -- See if we can skip the XSLT ... it's expensive
+ IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
+ -- Can't skip the transform
+ IF xfrm.xslt <> '---' THEN
+ transformed_xml := oils_xslt_process(bib.marc,xfrm.xslt);
+ ELSE
+ transformed_xml := bib.marc;
+ END IF;
+
+ prev_xfrm := xfrm.name;
+ END IF;
+
+ xml_node_list := oils_xpath( idx.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+
+ raw_text := NULL;
+ FOR xml_node IN SELECT x FROM unnest(xml_node_list) AS x LOOP
+ CONTINUE WHEN xml_node !~ E'^\\s*<';
+
+ -- XXX much of this should be moved into oils_xpath_string...
+ curr_text := ARRAY_TO_STRING(array_remove(array_remove(
+ oils_xpath( '//text()', -- get the content of all the nodes within the main selected node
+ REGEXP_REPLACE( xml_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space
+ ), ' '), ''), -- throw away morally empty (bankrupt?) strings
+ joiner
+ );
+
+ CONTINUE WHEN curr_text IS NULL OR curr_text = '';
+
+ IF raw_text IS NOT NULL THEN
+ raw_text := raw_text || joiner;
+ END IF;
+
+ raw_text := COALESCE(raw_text,'') || curr_text;
+
+ -- autosuggest/metabib.browse_entry
+ IF idx.browse_field THEN
+
+ IF idx.browse_xpath IS NOT NULL AND idx.browse_xpath <> '' THEN
+ browse_text := oils_xpath_string( idx.browse_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+ ELSE
+ browse_text := curr_text;
+ END IF;
+
+ IF idx.browse_sort_xpath IS NOT NULL AND
+ idx.browse_sort_xpath <> '' THEN
+
+ sort_value := oils_xpath_string(
+ idx.browse_sort_xpath, xml_node, joiner,
+ ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]
+ );
+ ELSE
+ sort_value := browse_text;
+ END IF;
+
+ output_row.field_class = idx.field_class;
+ output_row.field = idx.id;
+ output_row.source = rid;
+ output_row.value = BTRIM(REGEXP_REPLACE(browse_text, E'\\s+', ' ', 'g'));
+ output_row.sort_value :=
+ public.naco_normalize(sort_value);
+
+ output_row.authority := NULL;
+
+ IF idx.authority_xpath IS NOT NULL AND idx.authority_xpath <> '' THEN
+ authority_text := oils_xpath_string(
+ idx.authority_xpath, xml_node, joiner,
+ ARRAY[
+ ARRAY[xfrm.prefix, xfrm.namespace_uri],
+ ARRAY['xlink','http://www.w3.org/1999/xlink']
+ ]
+ );
+
+ IF authority_text ~ '^\d+$' THEN
+ authority_link := authority_text::BIGINT;
+ PERFORM * FROM authority.record_entry WHERE id = authority_link;
+ IF FOUND THEN
+ output_row.authority := authority_link;
+ END IF;
+ END IF;
+
+ END IF;
+
+ output_row.browse_field = TRUE;
+ -- Returning browse rows with search_field = true for search+browse
+ -- configs allows us to retain granularity of being able to search
+ -- browse fields with "starts with" type operators (for example, for
+ -- titles of songs in music albums)
+ IF idx.search_field THEN
+ output_row.search_field = TRUE;
+ END IF;
+ RETURN NEXT output_row;
+ output_row.browse_field = FALSE;
+ output_row.search_field = FALSE;
+ output_row.sort_value := NULL;
+ END IF;
+
+ -- insert raw node text for faceting
+ IF idx.facet_field THEN
+
+ IF idx.facet_xpath IS NOT NULL AND idx.facet_xpath <> '' THEN
+ facet_text := oils_xpath_string( idx.facet_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+ ELSE
+ facet_text := curr_text;
+ END IF;
+
+ output_row.field_class = idx.field_class;
+ output_row.field = -1 * idx.id;
+ output_row.source = rid;
+ output_row.value = BTRIM(REGEXP_REPLACE(facet_text, E'\\s+', ' ', 'g'));
+
+ output_row.facet_field = TRUE;
+ RETURN NEXT output_row;
+ output_row.facet_field = FALSE;
+ END IF;
+
+ -- insert raw node text for display
+ IF idx.display_field THEN
+
+ IF idx.display_xpath IS NOT NULL AND idx.display_xpath <> '' THEN
+ display_text := oils_xpath_string( idx.display_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+ ELSE
+ display_text := curr_text;
+ END IF;
+
+ output_row.field_class = idx.field_class;
+ output_row.field = -1 * idx.id;
+ output_row.source = rid;
+ output_row.value = BTRIM(REGEXP_REPLACE(display_text, E'\\s+', ' ', 'g'));
+
+ output_row.display_field = TRUE;
+ RETURN NEXT output_row;
+ output_row.display_field = FALSE;
+ END IF;
+
+ END LOOP;
+
+ CONTINUE WHEN raw_text IS NULL OR raw_text = '';
+
+ -- insert combined node text for searching
+ IF idx.search_field THEN
+ output_row.field_class = idx.field_class;
+ output_row.field = idx.id;
+ output_row.source = rid;
+ output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
+
+ output_row.search_field = TRUE;
+ RETURN NEXT output_row;
+ output_row.search_field = FALSE;
+ END IF;
+
+ END LOOP;
+
+END;
+$func$ LANGUAGE PLPGSQL;
+
+-- We no longer need the custom function
+DROP FUNCTION evergreen.array_remove_item_by_value(ANYARRAY, ANYELEMENT);
+
+COMMIT;
+
+++ /dev/null
-BEGIN;
-
-SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
-
-CREATE OR REPLACE FUNCTION unapi.bre (
- obj_id BIGINT,
- format TEXT,
- ename TEXT,
- includes TEXT[],
- org TEXT,
- depth INT DEFAULT NULL,
- slimit HSTORE DEFAULT NULL,
- soffset HSTORE DEFAULT NULL,
- include_xmlns BOOL DEFAULT TRUE,
- pref_lib INT DEFAULT NULL
-)
-RETURNS XML AS $F$
-DECLARE
- me biblio.record_entry%ROWTYPE;
- layout unapi.bre_output_layout%ROWTYPE;
- xfrm config.xml_transform%ROWTYPE;
- ouid INT;
- tmp_xml TEXT;
- top_el TEXT;
- output XML;
- hxml XML;
- axml XML;
- source XML;
-BEGIN
-
- IF org = '-' OR org IS NULL THEN
- SELECT shortname INTO org FROM evergreen.org_top();
- END IF;
-
- SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
-
- IF ouid IS NULL THEN
- RETURN NULL::XML;
- END IF;
-
- IF format = 'holdings_xml' THEN -- the special case
- output := unapi.holdings_xml( obj_id, ouid, org, depth, includes, slimit, soffset, include_xmlns);
- RETURN output;
- END IF;
-
- SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
-
- IF layout.name IS NULL THEN
- RETURN NULL::XML;
- END IF;
-
- SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
-
- SELECT * INTO me FROM biblio.record_entry WHERE id = obj_id;
-
- -- grab bib_source, if any
- IF ('cbs' = ANY (includes) AND me.source IS NOT NULL) THEN
- source := unapi.cbs(me.source,NULL,NULL,NULL,NULL);
- ELSE
- source := NULL::XML;
- END IF;
-
- -- grab SVF if we need them
- IF ('mra' = ANY (includes)) THEN
- axml := unapi.mra(obj_id,NULL,NULL,NULL,NULL);
- ELSE
- axml := NULL::XML;
- END IF;
-
- -- grab holdings if we need them
- IF ('holdings_xml' = ANY (includes)) THEN
- hxml := unapi.holdings_xml(obj_id, ouid, org, depth, array_remove(includes,'holdings_xml'), slimit, soffset, include_xmlns, pref_lib);
- ELSE
- hxml := NULL::XML;
- END IF;
-
-
- -- generate our item node
-
-
- IF format = 'marcxml' THEN
- tmp_xml := me.marc;
- IF tmp_xml !~ E'<marc:' THEN -- If we're not using the prefixed namespace in this record, then remove all declarations of it
- tmp_xml := REGEXP_REPLACE(tmp_xml, ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
- END IF;
- ELSE
- tmp_xml := oils_xslt_process(me.marc, xfrm.xslt)::XML;
- END IF;
-
- top_el := REGEXP_REPLACE(tmp_xml, E'^.*?<((?:\\S+:)?' || layout.holdings_element || ').*$', E'\\1');
-
- IF source IS NOT NULL THEN
- tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', source || '</' || top_el || E'>\\1');
- END IF;
-
- IF axml IS NOT NULL THEN
- tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
- END IF;
-
- IF hxml IS NOT NULL THEN -- XXX how do we configure the holdings position?
- tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
- END IF;
-
- IF ('bre.unapi' = ANY (includes)) THEN
- output := REGEXP_REPLACE(
- tmp_xml,
- '</' || top_el || '>(.*?)',
- XMLELEMENT(
- name abbr,
- XMLATTRIBUTES(
- 'http://www.w3.org/1999/xhtml' AS xmlns,
- 'unapi-id' AS class,
- 'tag:open-ils.org:U2@bre/' || obj_id || '/' || org AS title
- )
- )::TEXT || '</' || top_el || E'>\\1'
- );
- ELSE
- output := tmp_xml;
- END IF;
-
- IF ('bre.extern' = ANY (includes)) THEN
- output := REGEXP_REPLACE(
- tmp_xml,
- '</' || top_el || '>(.*?)',
- XMLELEMENT(
- name extern,
- XMLATTRIBUTES(
- 'http://open-ils.org/spec/biblio/v1' AS xmlns,
- me.creator AS creator,
- me.editor AS editor,
- me.create_date AS create_date,
- me.edit_date AS edit_date,
- me.quality AS quality,
- me.fingerprint AS fingerprint,
- me.tcn_source AS tcn_source,
- me.tcn_value AS tcn_value,
- me.owner AS owner,
- me.share_depth AS share_depth,
- me.active AS active,
- me.deleted AS deleted
- )
- )::TEXT || '</' || top_el || E'>\\1'
- );
- ELSE
- output := tmp_xml;
- END IF;
-
- output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
- RETURN output;
-END;
-$F$ LANGUAGE PLPGSQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.holdings_xml (
- bid BIGINT,
- ouid INT,
- org TEXT,
- depth INT DEFAULT NULL,
- includes TEXT[] DEFAULT NULL::TEXT[],
- slimit HSTORE DEFAULT NULL,
- soffset HSTORE DEFAULT NULL,
- include_xmlns BOOL DEFAULT TRUE,
- pref_lib INT DEFAULT NULL
-)
-RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name holdings,
- XMLATTRIBUTES(
- CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- CASE WHEN ('bre' = ANY ($5)) THEN 'tag:open-ils.org:U2@bre/' || $1 || '/' || $3 ELSE NULL END AS id,
- (SELECT record_has_holdable_copy FROM asset.record_has_holdable_copy($1)) AS has_holdable
- ),
- XMLELEMENT(
- name counts,
- (SELECT XMLAGG(XMLELEMENT::XML) FROM (
- SELECT XMLELEMENT(
- name count,
- XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
- )::text
- FROM asset.opac_ou_record_copy_count($2, $1)
- UNION
- SELECT XMLELEMENT(
- name count,
- XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
- )::text
- FROM asset.staff_ou_record_copy_count($2, $1)
- UNION
- SELECT XMLELEMENT(
- name count,
- XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
- )::text
- FROM asset.opac_ou_record_copy_count($9, $1)
- ORDER BY 1
- )x)
- ),
- CASE
- WHEN ('bmp' = ANY ($5)) THEN
- XMLELEMENT(
- name monograph_parts,
- (SELECT XMLAGG(bmp) FROM (
- SELECT unapi.bmp( id, 'xml', 'monograph_part', array_remove( array_remove($5,'bre'), 'holdings_xml'), $3, $4, $6, $7, FALSE)
- FROM biblio.monograph_part
- WHERE NOT deleted AND record = $1
- )x)
- )
- ELSE NULL
- END,
- XMLELEMENT(
- name volumes,
- (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
- -- Physical copies
- SELECT unapi.acn(y.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey
- FROM evergreen.ranked_volumes($1, $2, $4, $6, $7, $9, $5) AS y
- UNION ALL
- -- Located URIs
- SELECT unapi.acn(uris.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey
- FROM evergreen.located_uris($1, $2, $9) AS uris
- )x)
- ),
- CASE WHEN ('ssub' = ANY ($5)) THEN
- XMLELEMENT(
- name subscriptions,
- (SELECT XMLAGG(ssub) FROM (
- SELECT unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
- FROM serial.subscription
- WHERE record_entry = $1
- )x)
- )
- ELSE NULL END,
- CASE WHEN ('acp' = ANY ($5)) THEN
- XMLELEMENT(
- name foreign_copies,
- (SELECT XMLAGG(acp) FROM (
- SELECT unapi.acp(p.target_copy,'xml','copy',array_remove($5,'acp'), $3, $4, $6, $7, FALSE)
- FROM biblio.peer_bib_copy_map p
- JOIN asset.copy c ON (p.target_copy = c.id)
- WHERE NOT c.deleted AND p.peer_record = $1
- LIMIT ($6 -> 'acp')::INT
- OFFSET ($7 -> 'acp')::INT
- )x)
- )
- ELSE NULL END
- );
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.ssub ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name subscription,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@ssub/' || id AS id,
- 'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib,
- start_date AS start, end_date AS end, expected_date_offset
- ),
- CASE
- WHEN ('sdist' = ANY ($4)) THEN
- XMLELEMENT( name distributions,
- (SELECT XMLAGG(sdist) FROM (
- SELECT unapi.sdist( id, 'xml', 'distribution', array_remove($4,'ssub'), $5, $6, $7, $8, FALSE)
- FROM serial.distribution
- WHERE subscription = ssub.id
- )x)
- )
- ELSE NULL
- END
- )
- FROM serial.subscription ssub
- WHERE id = $1
- GROUP BY id, start_date, end_date, expected_date_offset, owning_lib;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.sdist ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name distribution,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@sdist/' || id AS id,
- 'tag:open-ils.org:U2@acn/' || receive_call_number AS receive_call_number,
- 'tag:open-ils.org:U2@acn/' || bind_call_number AS bind_call_number,
- unit_label_prefix, label, unit_label_suffix, summary_method
- ),
- unapi.aou( holding_lib, $2, 'holding_lib', array_remove($4,'sdist'), $5, $6, $7, $8),
- CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE) ELSE NULL END,
- CASE
- WHEN ('sstr' = ANY ($4)) THEN
- XMLELEMENT( name streams,
- (SELECT XMLAGG(sstr) FROM (
- SELECT unapi.sstr( id, 'xml', 'stream', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE)
- FROM serial.stream
- WHERE distribution = sdist.id
- )x)
- )
- ELSE NULL
- END,
- XMLELEMENT( name summaries,
- CASE
- WHEN ('sbsum' = ANY ($4)) THEN
- (SELECT XMLAGG(sbsum) FROM (
- SELECT unapi.sbsum( id, 'xml', 'serial_summary', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE)
- FROM serial.basic_summary
- WHERE distribution = sdist.id
- )x)
- ELSE NULL
- END,
- CASE
- WHEN ('sisum' = ANY ($4)) THEN
- (SELECT XMLAGG(sisum) FROM (
- SELECT unapi.sisum( id, 'xml', 'serial_summary', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE)
- FROM serial.index_summary
- WHERE distribution = sdist.id
- )x)
- ELSE NULL
- END,
- CASE
- WHEN ('sssum' = ANY ($4)) THEN
- (SELECT XMLAGG(sssum) FROM (
- SELECT unapi.sssum( id, 'xml', 'serial_summary', array_remove($4,'sdist'), $5, $6, $7, $8, FALSE)
- FROM serial.supplement_summary
- WHERE distribution = sdist.id
- )x)
- ELSE NULL
- END
- )
- )
- FROM serial.distribution sdist
- WHERE id = $1
- GROUP BY id, label, unit_label_prefix, unit_label_suffix, holding_lib, summary_method, subscription, receive_call_number, bind_call_number;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.sstr ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name stream,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@sstr/' || id AS id,
- routing_label
- ),
- CASE WHEN distribution IS NOT NULL AND ('sdist' = ANY ($4)) THEN unapi.sssum( distribution, 'xml', 'distribtion', array_remove($4,'sstr'), $5, $6, $7, $8, FALSE) ELSE NULL END,
- CASE
- WHEN ('sitem' = ANY ($4)) THEN
- XMLELEMENT( name items,
- (SELECT XMLAGG(sitem) FROM (
- SELECT unapi.sitem( id, 'xml', 'serial_item', array_remove($4,'sstr'), $5, $6, $7, $8, FALSE)
- FROM serial.item
- WHERE stream = sstr.id
- )x)
- )
- ELSE NULL
- END
- )
- FROM serial.stream sstr
- WHERE id = $1
- GROUP BY id, routing_label, distribution;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.siss ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name issuance,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@siss/' || id AS id,
- create_date, edit_date, label, date_published,
- holding_code, holding_type, holding_link_id
- ),
- CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', array_remove($4,'siss'), $5, $6, $7, $8, FALSE) ELSE NULL END,
- CASE
- WHEN ('sitem' = ANY ($4)) THEN
- XMLELEMENT( name items,
- (SELECT XMLAGG(sitem) FROM (
- SELECT unapi.sitem( id, 'xml', 'serial_item', array_remove($4,'siss'), $5, $6, $7, $8, FALSE)
- FROM serial.item
- WHERE issuance = sstr.id
- )x)
- )
- ELSE NULL
- END
- )
- FROM serial.issuance sstr
- WHERE id = $1
- GROUP BY id, create_date, edit_date, label, date_published, holding_code, holding_type, holding_link_id, subscription;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.sitem ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name serial_item,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@sitem/' || id AS id,
- 'tag:open-ils.org:U2@siss/' || issuance AS issuance,
- date_expected, date_received
- ),
- CASE WHEN issuance IS NOT NULL AND ('siss' = ANY ($4)) THEN unapi.siss( issuance, $2, 'issuance', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
- CASE WHEN stream IS NOT NULL AND ('sstr' = ANY ($4)) THEN unapi.sstr( stream, $2, 'stream', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
- CASE WHEN unit IS NOT NULL AND ('sunit' = ANY ($4)) THEN unapi.sunit( unit, $2, 'serial_unit', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
- CASE WHEN uri IS NOT NULL AND ('auri' = ANY ($4)) THEN unapi.auri( uri, $2, 'uri', array_remove($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END
--- XMLELEMENT( name notes,
--- CASE
--- WHEN ('acpn' = ANY ($4)) THEN
--- (SELECT XMLAGG(acpn) FROM (
--- SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove($4,'acp'), $5, $6, $7, $8)
--- FROM asset.copy_note
--- WHERE owning_copy = cp.id AND pub
--- )x)
--- ELSE NULL
--- END
--- )
- )
- FROM serial.item sitem
- WHERE id = $1;
-$F$ LANGUAGE SQL STABLE;
-
-
-CREATE OR REPLACE FUNCTION unapi.sssum ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name serial_summary,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@sbsum/' || id AS id,
- 'sssum' AS type, generated_coverage, textual_holdings, show_generated
- ),
- CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
- )
- FROM serial.supplement_summary ssum
- WHERE id = $1
- GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.sbsum ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name serial_summary,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@sbsum/' || id AS id,
- 'sbsum' AS type, generated_coverage, textual_holdings, show_generated
- ),
- CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
- )
- FROM serial.basic_summary ssum
- WHERE id = $1
- GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.sisum ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name serial_summary,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@sbsum/' || id AS id,
- 'sisum' AS type, generated_coverage, textual_holdings, show_generated
- ),
- CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
- )
- FROM serial.index_summary ssum
- WHERE id = $1
- GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.bmp ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name monograph_part,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@bmp/' || id AS id,
- id AS ident,
- label,
- label_sortkey,
- 'tag:open-ils.org:U2@bre/' || record AS record
- ),
- CASE
- WHEN ('acp' = ANY ($4)) THEN
- XMLELEMENT( name copies,
- (SELECT XMLAGG(acp) FROM (
- SELECT unapi.acp( cp.id, 'xml', 'copy', array_remove($4,'bmp'), $5, $6, $7, $8, FALSE)
- FROM asset.copy cp
- JOIN asset.copy_part_map cpm ON (cpm.target_copy = cp.id)
- WHERE cpm.part = $1
- AND cp.deleted IS FALSE
- ORDER BY COALESCE(cp.copy_number,0), cp.barcode
- LIMIT ($7 -> 'acp')::INT
- OFFSET ($8 -> 'acp')::INT
-
- )x)
- )
- ELSE NULL
- END,
- CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( record, 'marcxml', 'record', array_remove($4,'bmp'), $5, $6, $7, $8, FALSE) ELSE NULL END
- )
- FROM biblio.monograph_part
- WHERE NOT deleted AND id = $1
- GROUP BY id, label, label_sortkey, record;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.acp ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name copy,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id,
- create_date, edit_date, copy_number, circulate, deposit,
- ref, holdable, deleted, deposit_amount, price, barcode,
- circ_modifier, circ_as_type, opac_visible, age_protect
- ),
- unapi.ccs( status, $2, 'status', array_remove($4,'acp'), $5, $6, $7, $8, FALSE),
- unapi.acl( location, $2, 'location', array_remove($4,'acp'), $5, $6, $7, $8, FALSE),
- unapi.aou( circ_lib, $2, 'circ_lib', array_remove($4,'acp'), $5, $6, $7, $8),
- unapi.aou( circ_lib, $2, 'circlib', array_remove($4,'acp'), $5, $6, $7, $8),
- CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END,
- CASE
- WHEN ('acpn' = ANY ($4)) THEN
- XMLELEMENT( name copy_notes,
- (SELECT XMLAGG(acpn) FROM (
- SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
- FROM asset.copy_note
- WHERE owning_copy = cp.id AND pub
- )x)
- )
- ELSE NULL
- END,
- CASE
- WHEN ('ascecm' = ANY ($4)) THEN
- XMLELEMENT( name statcats,
- (SELECT XMLAGG(ascecm) FROM (
- SELECT unapi.ascecm( stat_cat_entry, 'xml', 'statcat', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
- FROM asset.stat_cat_entry_copy_map
- WHERE owning_copy = cp.id
- )x)
- )
- ELSE NULL
- END,
- CASE
- WHEN ('bre' = ANY ($4)) THEN
- XMLELEMENT( name foreign_records,
- (SELECT XMLAGG(bre) FROM (
- SELECT unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE)
- FROM biblio.peer_bib_copy_map
- WHERE target_copy = cp.id
- )x)
-
- )
- ELSE NULL
- END,
- CASE
- WHEN ('bmp' = ANY ($4)) THEN
- XMLELEMENT( name monograph_parts,
- (SELECT XMLAGG(bmp) FROM (
- SELECT unapi.bmp( part, 'xml', 'monograph_part', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
- FROM asset.copy_part_map
- WHERE target_copy = cp.id
- )x)
- )
- ELSE NULL
- END,
- CASE
- WHEN ('circ' = ANY ($4)) THEN
- XMLELEMENT( name current_circulation,
- (SELECT XMLAGG(circ) FROM (
- SELECT unapi.circ( id, 'xml', 'circ', array_remove($4,'circ'), $5, $6, $7, $8, FALSE)
- FROM action.circulation
- WHERE target_copy = cp.id
- AND checkin_time IS NULL
- )x)
- )
- ELSE NULL
- END
- )
- FROM asset.copy cp
- WHERE id = $1
- AND cp.deleted IS FALSE
- GROUP BY id, status, location, circ_lib, call_number, create_date,
- edit_date, copy_number, circulate, deposit, ref, holdable,
- deleted, deposit_amount, price, barcode, circ_modifier,
- circ_as_type, opac_visible, age_protect;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.sunit ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name serial_unit,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id,
- create_date, edit_date, copy_number, circulate, deposit,
- ref, holdable, deleted, deposit_amount, price, barcode,
- circ_modifier, circ_as_type, opac_visible, age_protect,
- status_changed_time, floating, mint_condition,
- detailed_contents, sort_key, summary_contents, cost
- ),
- unapi.ccs( status, $2, 'status', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE),
- unapi.acl( location, $2, 'location', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE),
- unapi.aou( circ_lib, $2, 'circ_lib', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8),
- unapi.aou( circ_lib, $2, 'circlib', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8),
- CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', array_remove($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END,
- XMLELEMENT( name copy_notes,
- CASE
- WHEN ('acpn' = ANY ($4)) THEN
- (SELECT XMLAGG(acpn) FROM (
- SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove( array_remove($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE)
- FROM asset.copy_note
- WHERE owning_copy = cp.id AND pub
- )x)
- ELSE NULL
- END
- ),
- XMLELEMENT( name statcats,
- CASE
- WHEN ('ascecm' = ANY ($4)) THEN
- (SELECT XMLAGG(ascecm) FROM (
- SELECT unapi.ascecm( stat_cat_entry, 'xml', 'statcat', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
- FROM asset.stat_cat_entry_copy_map
- WHERE owning_copy = cp.id
- )x)
- ELSE NULL
- END
- ),
- XMLELEMENT( name foreign_records,
- CASE
- WHEN ('bre' = ANY ($4)) THEN
- (SELECT XMLAGG(bre) FROM (
- SELECT unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE)
- FROM biblio.peer_bib_copy_map
- WHERE target_copy = cp.id
- )x)
- ELSE NULL
- END
- ),
- CASE
- WHEN ('bmp' = ANY ($4)) THEN
- XMLELEMENT( name monograph_parts,
- (SELECT XMLAGG(bmp) FROM (
- SELECT unapi.bmp( part, 'xml', 'monograph_part', array_remove($4,'acp'), $5, $6, $7, $8, FALSE)
- FROM asset.copy_part_map
- WHERE target_copy = cp.id
- )x)
- )
- ELSE NULL
- END,
- CASE
- WHEN ('circ' = ANY ($4)) THEN
- XMLELEMENT( name current_circulation,
- (SELECT XMLAGG(circ) FROM (
- SELECT unapi.circ( id, 'xml', 'circ', array_remove($4,'circ'), $5, $6, $7, $8, FALSE)
- FROM action.circulation
- WHERE target_copy = cp.id
- AND checkin_time IS NULL
- )x)
- )
- ELSE NULL
- END
- )
- FROM serial.unit cp
- WHERE id = $1
- AND cp.deleted IS FALSE
- GROUP BY id, status, location, circ_lib, call_number, create_date,
- edit_date, copy_number, circulate, floating, mint_condition,
- deposit, ref, holdable, deleted, deposit_amount, price,
- barcode, circ_modifier, circ_as_type, opac_visible,
- status_changed_time, detailed_contents, sort_key,
- summary_contents, cost, age_protect;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.acn ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name volume,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@acn/' || acn.id AS id,
- acn.id AS vol_id, o.shortname AS lib,
- o.opac_visible AS opac_visible,
- deleted, label, label_sortkey, label_class, record
- ),
- unapi.aou( owning_lib, $2, 'owning_lib', array_remove($4,'acn'), $5, $6, $7, $8),
- CASE
- WHEN ('acp' = ANY ($4)) THEN
- CASE WHEN $6 IS NOT NULL THEN
- XMLELEMENT( name copies,
- (SELECT XMLAGG(acp ORDER BY rank_avail) FROM (
- SELECT unapi.acp( cp.id, 'xml', 'copy', array_remove($4,'acn'), $5, $6, $7, $8, FALSE),
- evergreen.rank_cp(cp) AS rank_avail
- FROM asset.copy cp
- JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5), $6) aoud ON (cp.circ_lib = aoud.id)
- WHERE cp.call_number = acn.id
- AND cp.deleted IS FALSE
- ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode
- LIMIT ($7 -> 'acp')::INT
- OFFSET ($8 -> 'acp')::INT
- )x)
- )
- ELSE
- XMLELEMENT( name copies,
- (SELECT XMLAGG(acp ORDER BY rank_avail) FROM (
- SELECT unapi.acp( cp.id, 'xml', 'copy', array_remove($4,'acn'), $5, $6, $7, $8, FALSE),
- evergreen.rank_cp(cp) AS rank_avail
- FROM asset.copy cp
- JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5) ) aoud ON (cp.circ_lib = aoud.id)
- WHERE cp.call_number = acn.id
- AND cp.deleted IS FALSE
- ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode
- LIMIT ($7 -> 'acp')::INT
- OFFSET ($8 -> 'acp')::INT
- )x)
- )
- END
- ELSE NULL
- END,
- XMLELEMENT(
- name uris,
- (SELECT XMLAGG(auri) FROM (SELECT unapi.auri(uri,'xml','uri', array_remove($4,'acn'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE call_number = acn.id)x)
- ),
- unapi.acnp( acn.prefix, 'marcxml', 'prefix', array_remove($4,'acn'), $5, $6, $7, $8, FALSE),
- unapi.acns( acn.suffix, 'marcxml', 'suffix', array_remove($4,'acn'), $5, $6, $7, $8, FALSE),
- CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( acn.record, 'marcxml', 'record', array_remove($4,'acn'), $5, $6, $7, $8, FALSE) ELSE NULL END
- ) AS x
- FROM asset.call_number acn
- JOIN actor.org_unit o ON (o.id = acn.owning_lib)
- WHERE acn.id = $1
- AND acn.deleted IS FALSE
- GROUP BY acn.id, o.shortname, o.opac_visible, deleted, label, label_sortkey, label_class, owning_lib, record, acn.prefix, acn.suffix;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.auri ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name uri,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@auri/' || uri.id AS id,
- use_restriction,
- href,
- label
- ),
- CASE
- WHEN ('acn' = ANY ($4)) THEN
- XMLELEMENT( name copies,
- (SELECT XMLAGG(acn) FROM (SELECT unapi.acn( call_number, 'xml', 'copy', array_remove($4,'auri'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE uri = uri.id)x)
- )
- ELSE NULL
- END
- ) AS x
- FROM asset.uri uri
- WHERE uri.id = $1
- GROUP BY uri.id, use_restriction, href, label;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.circ (obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT DEFAULT '-', depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name circ,
- XMLATTRIBUTES(
- CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- 'tag:open-ils.org:U2@circ/' || id AS id,
- xact_start,
- due_date
- ),
- CASE WHEN ('aou' = ANY ($4)) THEN unapi.aou( circ_lib, $2, 'circ_lib', array_remove($4,'circ'), $5, $6, $7, $8, FALSE) ELSE NULL END,
- CASE WHEN ('acp' = ANY ($4)) THEN unapi.acp( circ_lib, $2, 'target_copy', array_remove($4,'circ'), $5, $6, $7, $8, FALSE) ELSE NULL END
- )
- FROM action.circulation
- WHERE id = $1;
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.mmr_holdings_xml (
- mid BIGINT,
- ouid INT,
- org TEXT,
- depth INT DEFAULT NULL,
- includes TEXT[] DEFAULT NULL::TEXT[],
- slimit HSTORE DEFAULT NULL,
- soffset HSTORE DEFAULT NULL,
- include_xmlns BOOL DEFAULT TRUE,
- pref_lib INT DEFAULT NULL
-)
-RETURNS XML AS $F$
- SELECT XMLELEMENT(
- name holdings,
- XMLATTRIBUTES(
- CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
- CASE WHEN ('mmr' = ANY ($5)) THEN 'tag:open-ils.org:U2@mmr/' || $1 || '/' || $3 ELSE NULL END AS id,
- (SELECT metarecord_has_holdable_copy FROM asset.metarecord_has_holdable_copy($1)) AS has_holdable
- ),
- XMLELEMENT(
- name counts,
- (SELECT XMLAGG(XMLELEMENT::XML) FROM (
- SELECT XMLELEMENT(
- name count,
- XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
- )::text
- FROM asset.opac_ou_metarecord_copy_count($2, $1)
- UNION
- SELECT XMLELEMENT(
- name count,
- XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
- )::text
- FROM asset.staff_ou_metarecord_copy_count($2, $1)
- UNION
- SELECT XMLELEMENT(
- name count,
- XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
- )::text
- FROM asset.opac_ou_metarecord_copy_count($9, $1)
- ORDER BY 1
- )x)
- ),
- -- XXX monograph_parts and foreign_copies are skipped in MRs ... put them back some day?
- XMLELEMENT(
- name volumes,
- (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
- -- Physical copies
- SELECT unapi.acn(y.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey
- FROM evergreen.ranked_volumes((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $4, $6, $7, $9, $5) AS y
- UNION ALL
- -- Located URIs
- SELECT unapi.acn(uris.id,'xml','volume',array_remove( array_remove($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey
- FROM evergreen.located_uris((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $9) AS uris
- )x)
- ),
- CASE WHEN ('ssub' = ANY ($5)) THEN
- XMLELEMENT(
- name subscriptions,
- (SELECT XMLAGG(ssub) FROM (
- SELECT unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
- FROM serial.subscription
- WHERE record_entry IN (SELECT source FROM metabib.metarecord_source_map WHERE metarecord = $1)
- )x)
- )
- ELSE NULL END
- );
-$F$ LANGUAGE SQL STABLE;
-
-CREATE OR REPLACE FUNCTION unapi.mmr (
- obj_id BIGINT,
- format TEXT,
- ename TEXT,
- includes TEXT[],
- org TEXT,
- depth INT DEFAULT NULL,
- slimit HSTORE DEFAULT NULL,
- soffset HSTORE DEFAULT NULL,
- include_xmlns BOOL DEFAULT TRUE,
- pref_lib INT DEFAULT NULL
-)
-RETURNS XML AS $F$
-DECLARE
- mmrec metabib.metarecord%ROWTYPE;
- leadrec biblio.record_entry%ROWTYPE;
- subrec biblio.record_entry%ROWTYPE;
- layout unapi.bre_output_layout%ROWTYPE;
- xfrm config.xml_transform%ROWTYPE;
- ouid INT;
- xml_buf TEXT; -- growing XML document
- tmp_xml TEXT; -- single-use XML string
- xml_frag TEXT; -- single-use XML fragment
- top_el TEXT;
- output XML;
- hxml XML;
- axml XML;
- subxml XML; -- subordinate records elements
- sub_xpath TEXT;
- parts TEXT[];
-BEGIN
-
- -- xpath for extracting bre.marc values from subordinate records
- -- so they may be appended to the MARC of the master record prior
- -- to XSLT processing.
- -- subjects, isbn, issn, upc -- anything else?
- sub_xpath :=
- '//*[starts-with(@tag, "6") or @tag="020" or @tag="022" or @tag="024"]';
-
- IF org = '-' OR org IS NULL THEN
- SELECT shortname INTO org FROM evergreen.org_top();
- END IF;
-
- SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
-
- IF ouid IS NULL THEN
- RETURN NULL::XML;
- END IF;
-
- SELECT INTO mmrec * FROM metabib.metarecord WHERE id = obj_id;
- IF NOT FOUND THEN
- RETURN NULL::XML;
- END IF;
-
- -- TODO: aggregate holdings from constituent records
- IF format = 'holdings_xml' THEN -- the special case
- output := unapi.mmr_holdings_xml(
- obj_id, ouid, org, depth,
- array_remove(includes,'holdings_xml'),
- slimit, soffset, include_xmlns, pref_lib);
- RETURN output;
- END IF;
-
- SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
-
- IF layout.name IS NULL THEN
- RETURN NULL::XML;
- END IF;
-
- SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
-
- SELECT INTO leadrec * FROM biblio.record_entry WHERE id = mmrec.master_record;
-
- -- Grab distinct MVF for all records if requested
- IF ('mra' = ANY (includes)) THEN
- axml := unapi.mmr_mra(obj_id,NULL,NULL,NULL,org,depth,NULL,NULL,TRUE,pref_lib);
- ELSE
- axml := NULL::XML;
- END IF;
-
- xml_buf = leadrec.marc;
-
- hxml := NULL::XML;
- IF ('holdings_xml' = ANY (includes)) THEN
- hxml := unapi.mmr_holdings_xml(
- obj_id, ouid, org, depth,
- array_remove(includes,'holdings_xml'),
- slimit, soffset, include_xmlns, pref_lib);
- END IF;
-
- subxml := NULL::XML;
- parts := '{}'::TEXT[];
- FOR subrec IN SELECT bre.* FROM biblio.record_entry bre
- JOIN metabib.metarecord_source_map mmsm ON (mmsm.source = bre.id)
- JOIN metabib.metarecord mmr ON (mmr.id = mmsm.metarecord)
- WHERE mmr.id = obj_id AND NOT bre.deleted
- ORDER BY CASE WHEN bre.id = mmr.master_record THEN 0 ELSE bre.id END
- LIMIT COALESCE((slimit->'bre')::INT, 5) LOOP
-
- IF subrec.id = leadrec.id THEN CONTINUE; END IF;
- -- Append choice data from the the non-lead records to the
- -- the lead record document
-
- parts := parts || xpath(sub_xpath, subrec.marc::XML)::TEXT[];
- END LOOP;
-
- SELECT ARRAY_TO_STRING( ARRAY_AGG( DISTINCT p ), '' )::XML INTO subxml FROM UNNEST(parts) p;
-
- -- append data from the subordinate records to the
- -- main record document before applying the XSLT
-
- IF subxml IS NOT NULL THEN
- xml_buf := REGEXP_REPLACE(xml_buf,
- '</record>(.*?)$', subxml || '</record>' || E'\\1');
- END IF;
-
- IF format = 'marcxml' THEN
- -- If we're not using the prefixed namespace in
- -- this record, then remove all declarations of it
- IF xml_buf !~ E'<marc:' THEN
- xml_buf := REGEXP_REPLACE(xml_buf,
- ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
- END IF;
- ELSE
- xml_buf := oils_xslt_process(xml_buf, xfrm.xslt)::XML;
- END IF;
-
- -- update top_el to reflect the change in xml_buf, which may
- -- now be a different type of document (e.g. record -> mods)
- top_el := REGEXP_REPLACE(xml_buf, E'^.*?<((?:\\S+:)?' ||
- layout.holdings_element || ').*$', E'\\1');
-
- IF axml IS NOT NULL THEN
- xml_buf := REGEXP_REPLACE(xml_buf,
- '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
- END IF;
-
- IF hxml IS NOT NULL THEN
- xml_buf := REGEXP_REPLACE(xml_buf,
- '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
- END IF;
-
- IF ('mmr.unapi' = ANY (includes)) THEN
- output := REGEXP_REPLACE(
- xml_buf,
- '</' || top_el || '>(.*?)',
- XMLELEMENT(
- name abbr,
- XMLATTRIBUTES(
- 'http://www.w3.org/1999/xhtml' AS xmlns,
- 'unapi-id' AS class,
- 'tag:open-ils.org:U2@mmr/' || obj_id || '/' || org AS title
- )
- )::TEXT || '</' || top_el || E'>\\1'
- );
- ELSE
- output := xml_buf;
- END IF;
-
- -- remove ignorable whitesace
- output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
- RETURN output;
-END;
-$F$ LANGUAGE PLPGSQL STABLE;
-
-CREATE OR REPLACE FUNCTION authority.extract_headings(marc TEXT, restrict INT[] DEFAULT NULL) RETURNS SETOF authority.heading AS $func$
-DECLARE
- idx authority.heading_field%ROWTYPE;
- xfrm config.xml_transform%ROWTYPE;
- prev_xfrm TEXT;
- transformed_xml TEXT;
- heading_node TEXT;
- heading_node_list TEXT[];
- component_node TEXT;
- component_node_list TEXT[];
- raw_text TEXT;
- normalized_text TEXT;
- normalizer RECORD;
- curr_text TEXT;
- joiner TEXT;
- type_value TEXT;
- base_thesaurus TEXT := NULL;
- output_row authority.heading;
-BEGIN
-
- -- Loop over the indexing entries
- FOR idx IN SELECT * FROM authority.heading_field WHERE restrict IS NULL OR id = ANY (restrict) ORDER BY format LOOP
-
- output_row.field := idx.id;
- output_row.type := idx.heading_type;
- output_row.purpose := idx.heading_purpose;
-
- joiner := COALESCE(idx.joiner, ' ');
-
- SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format;
-
- -- See if we can skip the XSLT ... it's expensive
- IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
- -- Can't skip the transform
- IF xfrm.xslt <> '---' THEN
- transformed_xml := oils_xslt_process(marc, xfrm.xslt);
- ELSE
- transformed_xml := marc;
- END IF;
-
- prev_xfrm := xfrm.name;
- END IF;
-
- IF idx.thesaurus_xpath IS NOT NULL THEN
- base_thesaurus := ARRAY_TO_STRING(oils_xpath(idx.thesaurus_xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), '');
- END IF;
-
- heading_node_list := oils_xpath( idx.heading_xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
-
- FOR heading_node IN SELECT x FROM unnest(heading_node_list) AS x LOOP
-
- CONTINUE WHEN heading_node !~ E'^\\s*<';
-
- output_row.variant_type := NULL;
- output_row.related_type := NULL;
- output_row.thesaurus := NULL;
- output_row.heading := NULL;
-
- IF idx.heading_purpose = 'variant' AND idx.type_xpath IS NOT NULL THEN
- type_value := ARRAY_TO_STRING(oils_xpath(idx.type_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), '');
- BEGIN
- output_row.variant_type := type_value;
- EXCEPTION WHEN invalid_text_representation THEN
- RAISE NOTICE 'Do not recognize variant heading type %', type_value;
- END;
- END IF;
- IF idx.heading_purpose = 'related' AND idx.type_xpath IS NOT NULL THEN
- type_value := ARRAY_TO_STRING(oils_xpath(idx.type_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), '');
- BEGIN
- output_row.related_type := type_value;
- EXCEPTION WHEN invalid_text_representation THEN
- RAISE NOTICE 'Do not recognize related heading type %', type_value;
- END;
- END IF;
-
- IF idx.thesaurus_override_xpath IS NOT NULL THEN
- output_row.thesaurus := ARRAY_TO_STRING(oils_xpath(idx.thesaurus_override_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]), '');
- END IF;
- IF output_row.thesaurus IS NULL THEN
- output_row.thesaurus := base_thesaurus;
- END IF;
-
- raw_text := NULL;
-
- -- now iterate over components of heading
- component_node_list := oils_xpath( idx.component_xpath, heading_node, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
- FOR component_node IN SELECT x FROM unnest(component_node_list) AS x LOOP
- -- XXX much of this should be moved into oils_xpath_string...
- curr_text := ARRAY_TO_STRING(array_remove(array_remove(
- oils_xpath( '//text()', -- get the content of all the nodes within the main selected node
- REGEXP_REPLACE( component_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space
- ), ' '), ''), -- throw away morally empty (bankrupt?) strings
- joiner
- );
-
- CONTINUE WHEN curr_text IS NULL OR curr_text = '';
-
- IF raw_text IS NOT NULL THEN
- raw_text := raw_text || joiner;
- END IF;
-
- raw_text := COALESCE(raw_text,'') || curr_text;
- END LOOP;
-
- IF raw_text IS NOT NULL THEN
- output_row.heading := raw_text;
- normalized_text := raw_text;
-
- FOR normalizer IN
- SELECT n.func AS func,
- n.param_count AS param_count,
- m.params AS params
- FROM config.index_normalizer n
- JOIN authority.heading_field_norm_map m ON (m.norm = n.id)
- WHERE m.field = idx.id
- ORDER BY m.pos LOOP
-
- EXECUTE 'SELECT ' || normalizer.func || '(' ||
- quote_literal( normalized_text ) ||
- CASE
- WHEN normalizer.param_count > 0
- THEN ',' || REPLACE(REPLACE(BTRIM(normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
- ELSE ''
- END ||
- ')' INTO normalized_text;
-
- END LOOP;
-
- output_row.normalized_heading := normalized_text;
-
- RETURN NEXT output_row;
- END IF;
- END LOOP;
-
- END LOOP;
-END;
-$func$ LANGUAGE PLPGSQL;
-
-CREATE OR REPLACE FUNCTION authority.extract_headings(rid BIGINT, restrict INT[] DEFAULT NULL) RETURNS SETOF authority.heading AS $func$
-DECLARE
- auth authority.record_entry%ROWTYPE;
- output_row authority.heading;
-BEGIN
- -- Get the record
- SELECT INTO auth * FROM authority.record_entry WHERE id = rid;
-
- RETURN QUERY SELECT * FROM authority.extract_headings(auth.marc, restrict);
-END;
-$func$ LANGUAGE PLPGSQL;
-
-CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry (
- rid BIGINT,
- default_joiner TEXT,
- field_types TEXT[],
- only_fields INT[]
-) RETURNS SETOF metabib.field_entry_template AS $func$
-DECLARE
- bib biblio.record_entry%ROWTYPE;
- idx config.metabib_field%ROWTYPE;
- xfrm config.xml_transform%ROWTYPE;
- prev_xfrm TEXT;
- transformed_xml TEXT;
- xml_node TEXT;
- xml_node_list TEXT[];
- facet_text TEXT;
- display_text TEXT;
- browse_text TEXT;
- sort_value TEXT;
- raw_text TEXT;
- curr_text TEXT;
- joiner TEXT := default_joiner; -- XXX will index defs supply a joiner?
- authority_text TEXT;
- authority_link BIGINT;
- output_row metabib.field_entry_template%ROWTYPE;
- process_idx BOOL;
-BEGIN
-
- -- Start out with no field-use bools set
- output_row.browse_field = FALSE;
- output_row.facet_field = FALSE;
- output_row.display_field = FALSE;
- output_row.search_field = FALSE;
-
- -- Get the record
- SELECT INTO bib * FROM biblio.record_entry WHERE id = rid;
-
- -- Loop over the indexing entries
- FOR idx IN SELECT * FROM config.metabib_field WHERE id = ANY (only_fields) ORDER BY format LOOP
- CONTINUE WHEN idx.xpath IS NULL OR idx.xpath = ''; -- pure virtual field
-
- process_idx := FALSE;
- IF idx.display_field AND 'display' = ANY (field_types) THEN process_idx = TRUE; END IF;
- IF idx.browse_field AND 'browse' = ANY (field_types) THEN process_idx = TRUE; END IF;
- IF idx.search_field AND 'search' = ANY (field_types) THEN process_idx = TRUE; END IF;
- IF idx.facet_field AND 'facet' = ANY (field_types) THEN process_idx = TRUE; END IF;
- CONTINUE WHEN process_idx = FALSE; -- disabled for all types
-
- joiner := COALESCE(idx.joiner, default_joiner);
-
- SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format;
-
- -- See if we can skip the XSLT ... it's expensive
- IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
- -- Can't skip the transform
- IF xfrm.xslt <> '---' THEN
- transformed_xml := oils_xslt_process(bib.marc,xfrm.xslt);
- ELSE
- transformed_xml := bib.marc;
- END IF;
-
- prev_xfrm := xfrm.name;
- END IF;
-
- xml_node_list := oils_xpath( idx.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
-
- raw_text := NULL;
- FOR xml_node IN SELECT x FROM unnest(xml_node_list) AS x LOOP
- CONTINUE WHEN xml_node !~ E'^\\s*<';
-
- -- XXX much of this should be moved into oils_xpath_string...
- curr_text := ARRAY_TO_STRING(array_remove(array_remove(
- oils_xpath( '//text()', -- get the content of all the nodes within the main selected node
- REGEXP_REPLACE( xml_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space
- ), ' '), ''), -- throw away morally empty (bankrupt?) strings
- joiner
- );
-
- CONTINUE WHEN curr_text IS NULL OR curr_text = '';
-
- IF raw_text IS NOT NULL THEN
- raw_text := raw_text || joiner;
- END IF;
-
- raw_text := COALESCE(raw_text,'') || curr_text;
-
- -- autosuggest/metabib.browse_entry
- IF idx.browse_field THEN
-
- IF idx.browse_xpath IS NOT NULL AND idx.browse_xpath <> '' THEN
- browse_text := oils_xpath_string( idx.browse_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
- ELSE
- browse_text := curr_text;
- END IF;
-
- IF idx.browse_sort_xpath IS NOT NULL AND
- idx.browse_sort_xpath <> '' THEN
-
- sort_value := oils_xpath_string(
- idx.browse_sort_xpath, xml_node, joiner,
- ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]
- );
- ELSE
- sort_value := browse_text;
- END IF;
-
- output_row.field_class = idx.field_class;
- output_row.field = idx.id;
- output_row.source = rid;
- output_row.value = BTRIM(REGEXP_REPLACE(browse_text, E'\\s+', ' ', 'g'));
- output_row.sort_value :=
- public.naco_normalize(sort_value);
-
- output_row.authority := NULL;
-
- IF idx.authority_xpath IS NOT NULL AND idx.authority_xpath <> '' THEN
- authority_text := oils_xpath_string(
- idx.authority_xpath, xml_node, joiner,
- ARRAY[
- ARRAY[xfrm.prefix, xfrm.namespace_uri],
- ARRAY['xlink','http://www.w3.org/1999/xlink']
- ]
- );
-
- IF authority_text ~ '^\d+$' THEN
- authority_link := authority_text::BIGINT;
- PERFORM * FROM authority.record_entry WHERE id = authority_link;
- IF FOUND THEN
- output_row.authority := authority_link;
- END IF;
- END IF;
-
- END IF;
-
- output_row.browse_field = TRUE;
- -- Returning browse rows with search_field = true for search+browse
- -- configs allows us to retain granularity of being able to search
- -- browse fields with "starts with" type operators (for example, for
- -- titles of songs in music albums)
- IF idx.search_field THEN
- output_row.search_field = TRUE;
- END IF;
- RETURN NEXT output_row;
- output_row.browse_field = FALSE;
- output_row.search_field = FALSE;
- output_row.sort_value := NULL;
- END IF;
-
- -- insert raw node text for faceting
- IF idx.facet_field THEN
-
- IF idx.facet_xpath IS NOT NULL AND idx.facet_xpath <> '' THEN
- facet_text := oils_xpath_string( idx.facet_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
- ELSE
- facet_text := curr_text;
- END IF;
-
- output_row.field_class = idx.field_class;
- output_row.field = -1 * idx.id;
- output_row.source = rid;
- output_row.value = BTRIM(REGEXP_REPLACE(facet_text, E'\\s+', ' ', 'g'));
-
- output_row.facet_field = TRUE;
- RETURN NEXT output_row;
- output_row.facet_field = FALSE;
- END IF;
-
- -- insert raw node text for display
- IF idx.display_field THEN
-
- IF idx.display_xpath IS NOT NULL AND idx.display_xpath <> '' THEN
- display_text := oils_xpath_string( idx.display_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
- ELSE
- display_text := curr_text;
- END IF;
-
- output_row.field_class = idx.field_class;
- output_row.field = -1 * idx.id;
- output_row.source = rid;
- output_row.value = BTRIM(REGEXP_REPLACE(display_text, E'\\s+', ' ', 'g'));
-
- output_row.display_field = TRUE;
- RETURN NEXT output_row;
- output_row.display_field = FALSE;
- END IF;
-
- END LOOP;
-
- CONTINUE WHEN raw_text IS NULL OR raw_text = '';
-
- -- insert combined node text for searching
- IF idx.search_field THEN
- output_row.field_class = idx.field_class;
- output_row.field = idx.id;
- output_row.source = rid;
- output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
-
- output_row.search_field = TRUE;
- RETURN NEXT output_row;
- output_row.search_field = FALSE;
- END IF;
-
- END LOOP;
-
-END;
-$func$ LANGUAGE PLPGSQL;
-
--- We no longer need the custom function
-DROP FUNCTION evergreen.array_remove_item_by_value(ANYARRAY, ANYELEMENT);
-
-COMMIT;
-