]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/990.schema.unapi.sql
34737d5977bcc6f8c4275cf888a61f37612a2e5e
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 990.schema.unapi.sql
1 DROP SCHEMA IF EXISTS unapi CASCADE;
2
3 BEGIN;
4 CREATE SCHEMA unapi;
5
6 CREATE OR REPLACE FUNCTION evergreen.org_top()
7 RETURNS SETOF actor.org_unit AS $$
8     SELECT * FROM actor.org_unit WHERE parent_ou IS NULL LIMIT 1;
9 $$ LANGUAGE SQL STABLE
10 ROWS 1;
11
12 CREATE OR REPLACE FUNCTION evergreen.array_remove_item_by_value(inp ANYARRAY, el ANYELEMENT)
13 RETURNS anyarray AS $$
14     SELECT ARRAY_AGG(x.e) FROM UNNEST( $1 ) x(e) WHERE x.e <> $2;
15 $$ LANGUAGE SQL STABLE;
16
17 CREATE OR REPLACE FUNCTION evergreen.rank_ou(lib INT, search_lib INT, pref_lib INT DEFAULT NULL)
18 RETURNS INTEGER AS $$
19     SELECT COALESCE(
20
21         -- lib matches search_lib
22         (SELECT CASE WHEN $1 = $2 THEN -20000 END),
23
24         -- lib matches pref_lib
25         (SELECT CASE WHEN $1 = $3 THEN -10000 END),
26
27
28         -- pref_lib is a child of search_lib and lib is a child of pref lib.  
29         -- For example, searching CONS, pref lib is SYS1, 
30         -- copies at BR1 and BR2 sort to the front.
31         (SELECT distance - 5000
32             FROM actor.org_unit_descendants_distance($3) 
33             WHERE id = $1 AND $3 IN (
34                 SELECT id FROM actor.org_unit_descendants($2))),
35
36         -- lib is a child of search_lib
37         (SELECT distance FROM actor.org_unit_descendants_distance($2) WHERE id = $1),
38
39         -- all others pay cash
40         1000
41     );
42 $$ LANGUAGE SQL STABLE;
43
44 CREATE OR REPLACE FUNCTION evergreen.rank_cp_status(status INT)
45 RETURNS INTEGER AS $$
46     WITH totally_available AS (
47         SELECT id, 0 AS avail_rank
48         FROM config.copy_status
49         WHERE opac_visible IS TRUE
50             AND copy_active IS TRUE
51             AND id != 1 -- "Checked out"
52     ), almost_available AS (
53         SELECT id, 10 AS avail_rank
54         FROM config.copy_status
55         WHERE holdable IS TRUE
56             AND opac_visible IS TRUE
57             AND copy_active IS FALSE
58             OR id = 1 -- "Checked out"
59     )
60     SELECT COALESCE(
61         (SELECT avail_rank FROM totally_available WHERE $1 IN (id)),
62         (SELECT avail_rank FROM almost_available WHERE $1 IN (id)),
63         100
64     );
65 $$ LANGUAGE SQL STABLE;
66
67 CREATE OR REPLACE FUNCTION evergreen.ranked_volumes(
68     bibid BIGINT[], 
69     ouid INT,
70     depth INT DEFAULT NULL,
71     slimit HSTORE DEFAULT NULL,
72     soffset HSTORE DEFAULT NULL,
73     pref_lib INT DEFAULT NULL,
74     includes TEXT[] DEFAULT NULL::TEXT[]
75 ) RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank BIGINT) AS $$
76     SELECT ua.id, ua.name, ua.label_sortkey, MIN(ua.rank) AS rank FROM (
77         SELECT acn.id, aou.name, acn.label_sortkey,
78             evergreen.rank_ou(aou.id, $2, $6), evergreen.rank_cp_status(acp.status),
79             RANK() OVER w
80         FROM asset.call_number acn
81             JOIN asset.copy acp ON (acn.id = acp.call_number)
82             JOIN actor.org_unit_descendants( $2, COALESCE(
83                 $3, (
84                     SELECT depth
85                     FROM actor.org_unit_type aout
86                         INNER JOIN actor.org_unit ou ON ou_type = aout.id
87                     WHERE ou.id = $2
88                 ), $6)
89             ) AS aou ON (acp.circ_lib = aou.id)
90         WHERE acn.record = ANY ($1)
91             AND acn.deleted IS FALSE
92             AND acp.deleted IS FALSE
93             AND CASE WHEN ('exclude_invisible_acn' = ANY($7)) THEN 
94                 EXISTS (
95                     SELECT 1 
96                     FROM asset.opac_visible_copies 
97                     WHERE copy_id = acp.id AND record = acn.record
98                 ) ELSE TRUE END
99         GROUP BY acn.id, acp.status, aou.name, acn.label_sortkey, aou.id
100         WINDOW w AS (
101             ORDER BY evergreen.rank_ou(aou.id, $2, $6), evergreen.rank_cp_status(acp.status)
102         )
103     ) AS ua
104     GROUP BY ua.id, ua.name, ua.label_sortkey
105     ORDER BY rank, ua.name, ua.label_sortkey
106     LIMIT ($4 -> 'acn')::INT
107     OFFSET ($5 -> 'acn')::INT;
108 $$
109 LANGUAGE SQL STABLE;
110
111 CREATE OR REPLACE FUNCTION evergreen.ranked_volumes
112     ( bibid BIGINT, ouid INT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, pref_lib INT DEFAULT NULL, includes TEXT[] DEFAULT NULL::TEXT[] )
113     RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank BIGINT)
114     AS $$ SELECT * FROM evergreen.ranked_volumes(ARRAY[$1],$2,$3,$4,$5,$6,$7) $$ LANGUAGE SQL STABLE;
115
116
117 CREATE OR REPLACE FUNCTION evergreen.located_uris (
118     bibid BIGINT[], 
119     ouid INT,
120     pref_lib INT DEFAULT NULL
121 ) RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank INT) AS $$
122     WITH all_orgs AS (SELECT COALESCE( enabled, FALSE ) AS flag FROM config.global_flag WHERE name = 'opac.located_uri.act_as_copy')
123     SELECT DISTINCT ON (id) * FROM (
124     SELECT acn.id, COALESCE(aou.name,aoud.name), acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou
125       FROM asset.call_number acn
126            INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number
127            INNER JOIN asset.uri auri ON auri.id = auricnm.uri
128            LEFT JOIN actor.org_unit_ancestors( COALESCE($3, $2) ) aou ON (acn.owning_lib = aou.id)
129            LEFT JOIN actor.org_unit_descendants( COALESCE($3, $2) ) aoud ON (acn.owning_lib = aoud.id),
130            all_orgs
131       WHERE acn.record = ANY ($1)
132           AND acn.deleted IS FALSE
133           AND auri.active IS TRUE
134           AND ((NOT all_orgs.flag AND aou.id IS NOT NULL) OR COALESCE(aou.id,aoud.id) IS NOT NULL)
135     UNION
136     SELECT acn.id, COALESCE(aou.name,aoud.name) AS name, acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou
137       FROM asset.call_number acn
138            INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number
139            INNER JOIN asset.uri auri ON auri.id = auricnm.uri
140            LEFT JOIN actor.org_unit_ancestors( $2 ) aou ON (acn.owning_lib = aou.id)
141            LEFT JOIN actor.org_unit_descendants( $2 ) aoud ON (acn.owning_lib = aoud.id),
142            all_orgs
143       WHERE acn.record = ANY ($1)
144           AND acn.deleted IS FALSE
145           AND auri.active IS TRUE
146           AND ((NOT all_orgs.flag AND aou.id IS NOT NULL) OR COALESCE(aou.id,aoud.id) IS NOT NULL))x
147     ORDER BY id, pref_ou DESC;
148 $$
149 LANGUAGE SQL STABLE;
150
151 CREATE OR REPLACE FUNCTION evergreen.located_uris ( bibid BIGINT, ouid INT, pref_lib INT DEFAULT NULL)
152     RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank INT)
153     AS $$ SELECT * FROM evergreen.located_uris(ARRAY[$1],$2,$3) $$ LANGUAGE SQL STABLE;
154
155 CREATE TABLE unapi.bre_output_layout (
156     name                TEXT    PRIMARY KEY,
157     transform           TEXT    REFERENCES config.xml_transform (name) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
158     mime_type           TEXT    NOT NULL,
159     feed_top            TEXT    NOT NULL,
160     holdings_element    TEXT,
161     title_element       TEXT,
162     description_element TEXT,
163     creator_element     TEXT,
164     update_ts_element   TEXT
165 );
166
167 INSERT INTO unapi.bre_output_layout
168     (name,           transform, mime_type,              holdings_element, feed_top,         title_element, description_element, creator_element, update_ts_element)
169         VALUES
170     ('holdings_xml', NULL,      'application/xml',      NULL,             'hxml',           NULL,          NULL,                NULL,            NULL),
171     ('marcxml',      'marcxml', 'application/marc+xml', 'record',         'collection',     NULL,          NULL,                NULL,            NULL),
172     ('mods32',       'mods32',  'application/mods+xml', 'mods',           'modsCollection', NULL,          NULL,                NULL,            NULL)
173 ;
174
175 -- Dummy functions, so we can create the real ones out of order
176 CREATE OR REPLACE FUNCTION unapi.aou    ( 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 NULL::XML $F$ LANGUAGE SQL STABLE;
177 CREATE OR REPLACE FUNCTION unapi.acnp   ( 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 NULL::XML $F$ LANGUAGE SQL STABLE;
178 CREATE OR REPLACE FUNCTION unapi.acns   ( 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 NULL::XML $F$ LANGUAGE SQL STABLE;
179 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 NULL::XML $F$ LANGUAGE SQL STABLE;
180 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 NULL::XML $F$ LANGUAGE SQL STABLE;
181 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 NULL::XML $F$ LANGUAGE SQL STABLE;
182 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 NULL::XML $F$ LANGUAGE SQL STABLE;
183 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 NULL::XML $F$ LANGUAGE SQL STABLE;
184 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 NULL::XML $F$ LANGUAGE SQL STABLE;
185 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 NULL::XML $F$ LANGUAGE SQL STABLE;
186 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 NULL::XML $F$ LANGUAGE SQL STABLE;
187 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 NULL::XML $F$ LANGUAGE SQL STABLE;
188 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 NULL::XML $F$ LANGUAGE SQL STABLE;
189 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 NULL::XML $F$ LANGUAGE SQL STABLE;
190 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 NULL::XML $F$ LANGUAGE SQL STABLE;
191 CREATE OR REPLACE FUNCTION unapi.acpn   ( 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 NULL::XML $F$ LANGUAGE SQL STABLE;
192 CREATE OR REPLACE FUNCTION unapi.acl    ( 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 NULL::XML $F$ LANGUAGE SQL STABLE;
193 CREATE OR REPLACE FUNCTION unapi.ccs    ( 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 NULL::XML $F$ LANGUAGE SQL STABLE;
194 CREATE OR REPLACE FUNCTION unapi.ascecm ( 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 NULL::XML $F$ LANGUAGE SQL STABLE;
195 CREATE OR REPLACE FUNCTION unapi.bre (
196     obj_id BIGINT,
197     format TEXT,
198     ename TEXT,
199     includes TEXT[],
200     org TEXT,
201     depth INT DEFAULT NULL,
202     slimit HSTORE DEFAULT NULL,
203     soffset HSTORE DEFAULT NULL,
204     include_xmlns BOOL DEFAULT TRUE,
205     pref_lib INT DEFAULT NULL
206 )
207 RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL STABLE;
208 CREATE OR REPLACE FUNCTION unapi.mmr (
209     obj_id BIGINT,
210     format TEXT,
211     ename TEXT,
212     includes TEXT[],
213     org TEXT,
214     depth INT DEFAULT NULL,
215     slimit HSTORE DEFAULT NULL,
216     soffset HSTORE DEFAULT NULL,
217     include_xmlns BOOL DEFAULT TRUE,
218     pref_lib INT DEFAULT NULL
219 )
220 RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL STABLE;
221 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 NULL::XML $F$ LANGUAGE SQL STABLE;
222 CREATE OR REPLACE FUNCTION unapi.mra    ( 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 NULL::XML $F$ LANGUAGE SQL STABLE;
223 CREATE OR REPLACE FUNCTION unapi.mmr_mra    ( 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$ SELECT NULL::XML $F$ LANGUAGE SQL STABLE;
224 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 NULL::XML $F$ LANGUAGE SQL STABLE;
225
226 CREATE OR REPLACE FUNCTION unapi.holdings_xml (
227     bid BIGINT,
228     ouid INT,
229     org TEXT,
230     depth INT DEFAULT NULL,
231     includes TEXT[] DEFAULT NULL::TEXT[],
232     slimit HSTORE DEFAULT NULL,
233     soffset HSTORE DEFAULT NULL,
234     include_xmlns BOOL DEFAULT TRUE,
235     pref_lib INT DEFAULT NULL
236 )
237 RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL STABLE;
238
239 CREATE OR REPLACE FUNCTION unapi.mmr_holdings_xml (
240     mid BIGINT,
241     ouid INT,
242     org TEXT,
243     depth INT DEFAULT NULL,
244     includes TEXT[] DEFAULT NULL::TEXT[],
245     slimit HSTORE DEFAULT NULL,
246     soffset HSTORE DEFAULT NULL,
247     include_xmlns BOOL DEFAULT TRUE,
248     pref_lib INT DEFAULT NULL
249 )
250 RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL STABLE;
251
252 CREATE OR REPLACE FUNCTION unapi.biblio_record_entry_feed ( id_list BIGINT[], format TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE, title TEXT DEFAULT NULL, description TEXT DEFAULT NULL, creator TEXT DEFAULT NULL, update_ts TEXT DEFAULT NULL, unapi_url TEXT DEFAULT NULL, header_xml XML DEFAULT NULL ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL STABLE;
253
254 CREATE OR REPLACE FUNCTION unapi.memoize (classname TEXT, 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$
255 DECLARE
256     key     TEXT;
257     output  XML;
258 BEGIN
259     key :=
260         'id'        || COALESCE(obj_id::TEXT,'') ||
261         'format'    || COALESCE(format::TEXT,'') ||
262         'ename'     || COALESCE(ename::TEXT,'') ||
263         'includes'  || COALESCE(includes::TEXT,'{}'::TEXT[]::TEXT) ||
264         'org'       || COALESCE(org::TEXT,'') ||
265         'depth'     || COALESCE(depth::TEXT,'') ||
266         'slimit'    || COALESCE(slimit::TEXT,'') ||
267         'soffset'   || COALESCE(soffset::TEXT,'') ||
268         'include_xmlns'   || COALESCE(include_xmlns::TEXT,'');
269     -- RAISE NOTICE 'memoize key: %', key;
270
271     key := MD5(key);
272     -- RAISE NOTICE 'memoize hash: %', key;
273
274     -- XXX cache logic ... memcached? table?
275
276     EXECUTE $$SELECT unapi.$$ || classname || $$( $1, $2, $3, $4, $5, $6, $7, $8, $9);$$ INTO output USING obj_id, format, ename, includes, org, depth, slimit, soffset, include_xmlns;
277     RETURN output;
278 END;
279 $F$ LANGUAGE PLPGSQL STABLE;
280
281 CREATE OR REPLACE FUNCTION unapi.biblio_record_entry_feed ( id_list BIGINT[], format TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit HSTORE DEFAULT NULL, soffset HSTORE DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE, title TEXT DEFAULT NULL, description TEXT DEFAULT NULL, creator TEXT DEFAULT NULL, update_ts TEXT DEFAULT NULL, unapi_url TEXT DEFAULT NULL, header_xml XML DEFAULT NULL ) RETURNS XML AS $F$
282 DECLARE
283     layout          unapi.bre_output_layout%ROWTYPE;
284     transform       config.xml_transform%ROWTYPE;
285     item_format     TEXT;
286     tmp_xml         TEXT;
287     xmlns_uri       TEXT := 'http://open-ils.org/spec/feed-xml/v1';
288     ouid            INT;
289     element_list    TEXT[];
290 BEGIN
291
292     IF org = '-' OR org IS NULL THEN
293         SELECT shortname INTO org FROM evergreen.org_top();
294     END IF;
295
296     SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
297     SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
298
299     IF layout.name IS NULL THEN
300         RETURN NULL::XML;
301     END IF;
302
303     SELECT * INTO transform FROM config.xml_transform WHERE name = layout.transform;
304     xmlns_uri := COALESCE(transform.namespace_uri,xmlns_uri);
305
306     -- Gather the bib xml
307     SELECT XMLAGG( unapi.bre(i, format, '', includes, org, depth, slimit, soffset, include_xmlns)) INTO tmp_xml FROM UNNEST( id_list ) i;
308
309     IF layout.title_element IS NOT NULL THEN
310         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.title_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, title;
311     END IF;
312
313     IF layout.description_element IS NOT NULL THEN
314         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.description_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, description;
315     END IF;
316
317     IF layout.creator_element IS NOT NULL THEN
318         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.creator_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, creator;
319     END IF;
320
321     IF layout.update_ts_element IS NOT NULL THEN
322         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.update_ts_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, update_ts;
323     END IF;
324
325     IF unapi_url IS NOT NULL THEN
326         EXECUTE $$SELECT XMLCONCAT( XMLELEMENT( name link, XMLATTRIBUTES( 'http://www.w3.org/1999/xhtml' AS xmlns, 'unapi-server' AS rel, $1 AS href, 'unapi' AS title)), $2)$$ INTO tmp_xml USING unapi_url, tmp_xml::XML;
327     END IF;
328
329     IF header_xml IS NOT NULL THEN tmp_xml := XMLCONCAT(header_xml,tmp_xml::XML); END IF;
330
331     element_list := regexp_split_to_array(layout.feed_top,E'\\.');
332     FOR i IN REVERSE ARRAY_UPPER(element_list, 1) .. 1 LOOP
333         EXECUTE 'SELECT XMLELEMENT( name '|| quote_ident(element_list[i]) ||', XMLATTRIBUTES( $1 AS xmlns), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML;
334     END LOOP;
335
336     RETURN tmp_xml::XML;
337 END;
338 $F$ LANGUAGE PLPGSQL STABLE;
339
340 CREATE OR REPLACE FUNCTION unapi.bre (
341     obj_id BIGINT,
342     format TEXT,
343     ename TEXT,
344     includes TEXT[],
345     org TEXT,
346     depth INT DEFAULT NULL,
347     slimit HSTORE DEFAULT NULL,
348     soffset HSTORE DEFAULT NULL,
349     include_xmlns BOOL DEFAULT TRUE,
350     pref_lib INT DEFAULT NULL
351 )
352 RETURNS XML AS $F$
353 DECLARE
354     me      biblio.record_entry%ROWTYPE;
355     layout  unapi.bre_output_layout%ROWTYPE;
356     xfrm    config.xml_transform%ROWTYPE;
357     ouid    INT;
358     tmp_xml TEXT;
359     top_el  TEXT;
360     output  XML;
361     hxml    XML;
362     axml    XML;
363 BEGIN
364
365     IF org = '-' OR org IS NULL THEN
366         SELECT shortname INTO org FROM evergreen.org_top();
367     END IF;
368
369     SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
370
371     IF ouid IS NULL THEN
372         RETURN NULL::XML;
373     END IF;
374
375     IF format = 'holdings_xml' THEN -- the special case
376         output := unapi.holdings_xml( obj_id, ouid, org, depth, includes, slimit, soffset, include_xmlns);
377         RETURN output;
378     END IF;
379
380     SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
381
382     IF layout.name IS NULL THEN
383         RETURN NULL::XML;
384     END IF;
385
386     SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
387
388     SELECT * INTO me FROM biblio.record_entry WHERE id = obj_id;
389
390     -- grab SVF if we need them
391     IF ('mra' = ANY (includes)) THEN 
392         axml := unapi.mra(obj_id,NULL,NULL,NULL,NULL);
393     ELSE
394         axml := NULL::XML;
395     END IF;
396
397     -- grab holdings if we need them
398     IF ('holdings_xml' = ANY (includes)) THEN 
399         hxml := unapi.holdings_xml(obj_id, ouid, org, depth, evergreen.array_remove_item_by_value(includes,'holdings_xml'), slimit, soffset, include_xmlns, pref_lib);
400     ELSE
401         hxml := NULL::XML;
402     END IF;
403
404
405     -- generate our item node
406
407
408     IF format = 'marcxml' THEN
409         tmp_xml := me.marc;
410         IF tmp_xml !~ E'<marc:' THEN -- If we're not using the prefixed namespace in this record, then remove all declarations of it
411            tmp_xml := REGEXP_REPLACE(tmp_xml, ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
412         END IF; 
413     ELSE
414         tmp_xml := oils_xslt_process(me.marc, xfrm.xslt)::XML;
415     END IF;
416
417     top_el := REGEXP_REPLACE(tmp_xml, E'^.*?<((?:\\S+:)?' || layout.holdings_element || ').*$', E'\\1');
418
419     IF axml IS NOT NULL THEN 
420         tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
421     END IF;
422
423     IF hxml IS NOT NULL THEN -- XXX how do we configure the holdings position?
424         tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
425     END IF;
426
427     IF ('bre.unapi' = ANY (includes)) THEN 
428         output := REGEXP_REPLACE(
429             tmp_xml,
430             '</' || top_el || '>(.*?)',
431             XMLELEMENT(
432                 name abbr,
433                 XMLATTRIBUTES(
434                     'http://www.w3.org/1999/xhtml' AS xmlns,
435                     'unapi-id' AS class,
436                     'tag:open-ils.org:U2@bre/' || obj_id || '/' || org AS title
437                 )
438             )::TEXT || '</' || top_el || E'>\\1'
439         );
440     ELSE
441         output := tmp_xml;
442     END IF;
443
444     output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
445     RETURN output;
446 END;
447 $F$ LANGUAGE PLPGSQL STABLE;
448
449 CREATE OR REPLACE FUNCTION unapi.holdings_xml (
450     bid BIGINT,
451     ouid INT,
452     org TEXT,
453     depth INT DEFAULT NULL,
454     includes TEXT[] DEFAULT NULL::TEXT[],
455     slimit HSTORE DEFAULT NULL,
456     soffset HSTORE DEFAULT NULL,
457     include_xmlns BOOL DEFAULT TRUE,
458     pref_lib INT DEFAULT NULL
459 )
460 RETURNS XML AS $F$
461      SELECT  XMLELEMENT(
462                  name holdings,
463                  XMLATTRIBUTES(
464                     CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
465                     CASE WHEN ('bre' = ANY ($5)) THEN 'tag:open-ils.org:U2@bre/' || $1 || '/' || $3 ELSE NULL END AS id,
466                     (SELECT record_has_holdable_copy FROM asset.record_has_holdable_copy($1)) AS has_holdable
467                  ),
468                  XMLELEMENT(
469                      name counts,
470                      (SELECT  XMLAGG(XMLELEMENT::XML) FROM (
471                          SELECT  XMLELEMENT(
472                                      name count,
473                                      XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
474                                  )::text
475                            FROM  asset.opac_ou_record_copy_count($2,  $1)
476                                      UNION
477                          SELECT  XMLELEMENT(
478                                      name count,
479                                      XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
480                                  )::text
481                            FROM  asset.staff_ou_record_copy_count($2, $1)
482                                      UNION
483                          SELECT  XMLELEMENT(
484                                      name count,
485                                      XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
486                                  )::text
487                            FROM  asset.opac_ou_record_copy_count($9,  $1)
488                                      ORDER BY 1
489                      )x)
490                  ),
491                  CASE 
492                      WHEN ('bmp' = ANY ($5)) THEN
493                         XMLELEMENT(
494                             name monograph_parts,
495                             (SELECT XMLAGG(bmp) FROM (
496                                 SELECT  unapi.bmp( id, 'xml', 'monograph_part', evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'bre'), 'holdings_xml'), $3, $4, $6, $7, FALSE)
497                                   FROM  biblio.monograph_part
498                                   WHERE record = $1
499                             )x)
500                         )
501                      ELSE NULL
502                  END,
503                  XMLELEMENT(
504                      name volumes,
505                      (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
506                         -- Physical copies
507                         SELECT  unapi.acn(y.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey
508                         FROM evergreen.ranked_volumes($1, $2, $4, $6, $7, $9, $5) AS y
509                         UNION ALL
510                         -- Located URIs
511                         SELECT unapi.acn(uris.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey
512                         FROM evergreen.located_uris($1, $2, $9) AS uris
513                      )x)
514                  ),
515                  CASE WHEN ('ssub' = ANY ($5)) THEN 
516                      XMLELEMENT(
517                          name subscriptions,
518                          (SELECT XMLAGG(ssub) FROM (
519                             SELECT  unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
520                               FROM  serial.subscription
521                               WHERE record_entry = $1
522                         )x)
523                      )
524                  ELSE NULL END,
525                  CASE WHEN ('acp' = ANY ($5)) THEN 
526                      XMLELEMENT(
527                          name foreign_copies,
528                          (SELECT XMLAGG(acp) FROM (
529                             SELECT  unapi.acp(p.target_copy,'xml','copy',evergreen.array_remove_item_by_value($5,'acp'), $3, $4, $6, $7, FALSE)
530                               FROM  biblio.peer_bib_copy_map p
531                                     JOIN asset.copy c ON (p.target_copy = c.id)
532                               WHERE NOT c.deleted AND p.peer_record = $1
533                             LIMIT ($6 -> 'acp')::INT
534                             OFFSET ($7 -> 'acp')::INT
535                         )x)
536                      )
537                  ELSE NULL END
538              );
539 $F$ LANGUAGE SQL STABLE;
540
541 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$
542         SELECT  XMLELEMENT(
543                     name subscription,
544                     XMLATTRIBUTES(
545                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
546                         'tag:open-ils.org:U2@ssub/' || id AS id,
547                         'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib,
548                         start_date AS start, end_date AS end, expected_date_offset
549                     ),
550                     CASE 
551                         WHEN ('sdist' = ANY ($4)) THEN
552                             XMLELEMENT( name distributions,
553                                 (SELECT XMLAGG(sdist) FROM (
554                                     SELECT  unapi.sdist( id, 'xml', 'distribution', evergreen.array_remove_item_by_value($4,'ssub'), $5, $6, $7, $8, FALSE)
555                                       FROM  serial.distribution
556                                       WHERE subscription = ssub.id
557                                 )x)
558                             )
559                         ELSE NULL
560                     END
561                 )
562           FROM  serial.subscription ssub
563           WHERE id = $1
564           GROUP BY id, start_date, end_date, expected_date_offset, owning_lib;
565 $F$ LANGUAGE SQL STABLE;
566
567 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$
568         SELECT  XMLELEMENT(
569                     name distribution,
570                     XMLATTRIBUTES(
571                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
572                         'tag:open-ils.org:U2@sdist/' || id AS id,
573                                 'tag:open-ils.org:U2@acn/' || receive_call_number AS receive_call_number,
574                                     'tag:open-ils.org:U2@acn/' || bind_call_number AS bind_call_number,
575                         unit_label_prefix, label, unit_label_suffix, summary_method
576                     ),
577                     unapi.aou( holding_lib, $2, 'holding_lib', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8),
578                     CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE) ELSE NULL END,
579                     CASE 
580                         WHEN ('sstr' = ANY ($4)) THEN
581                             XMLELEMENT( name streams,
582                                 (SELECT XMLAGG(sstr) FROM (
583                                     SELECT  unapi.sstr( id, 'xml', 'stream', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE)
584                                       FROM  serial.stream
585                                       WHERE distribution = sdist.id
586                                 )x)
587                             )
588                         ELSE NULL
589                     END,
590                     XMLELEMENT( name summaries,
591                         CASE 
592                             WHEN ('sbsum' = ANY ($4)) THEN
593                                 (SELECT XMLAGG(sbsum) FROM (
594                                     SELECT  unapi.sbsum( id, 'xml', 'serial_summary', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE)
595                                       FROM  serial.basic_summary
596                                       WHERE distribution = sdist.id
597                                 )x)
598                             ELSE NULL
599                         END,
600                         CASE 
601                             WHEN ('sisum' = ANY ($4)) THEN
602                                 (SELECT XMLAGG(sisum) FROM (
603                                     SELECT  unapi.sisum( id, 'xml', 'serial_summary', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE)
604                                       FROM  serial.index_summary
605                                       WHERE distribution = sdist.id
606                                 )x)
607                             ELSE NULL
608                         END,
609                         CASE 
610                             WHEN ('sssum' = ANY ($4)) THEN
611                                 (SELECT XMLAGG(sssum) FROM (
612                                     SELECT  unapi.sssum( id, 'xml', 'serial_summary', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE)
613                                       FROM  serial.supplement_summary
614                                       WHERE distribution = sdist.id
615                                 )x)
616                             ELSE NULL
617                         END
618                     )
619                 )
620           FROM  serial.distribution sdist
621           WHERE id = $1
622           GROUP BY id, label, unit_label_prefix, unit_label_suffix, holding_lib, summary_method, subscription, receive_call_number, bind_call_number;
623 $F$ LANGUAGE SQL STABLE;
624
625 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$
626     SELECT  XMLELEMENT(
627                 name stream,
628                 XMLATTRIBUTES(
629                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
630                     'tag:open-ils.org:U2@sstr/' || id AS id,
631                     routing_label
632                 ),
633                 CASE WHEN distribution IS NOT NULL AND ('sdist' = ANY ($4)) THEN unapi.sssum( distribution, 'xml', 'distribtion', evergreen.array_remove_item_by_value($4,'sstr'), $5, $6, $7, $8, FALSE) ELSE NULL END,
634                 CASE 
635                     WHEN ('sitem' = ANY ($4)) THEN
636                         XMLELEMENT( name items,
637                             (SELECT XMLAGG(sitem) FROM (
638                                 SELECT  unapi.sitem( id, 'xml', 'serial_item', evergreen.array_remove_item_by_value($4,'sstr'), $5, $6, $7, $8, FALSE)
639                                   FROM  serial.item
640                                   WHERE stream = sstr.id
641                             )x)
642                         )
643                     ELSE NULL
644                 END
645             )
646       FROM  serial.stream sstr
647       WHERE id = $1
648       GROUP BY id, routing_label, distribution;
649 $F$ LANGUAGE SQL STABLE;
650
651 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$
652     SELECT  XMLELEMENT(
653                 name issuance,
654                 XMLATTRIBUTES(
655                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
656                     'tag:open-ils.org:U2@siss/' || id AS id,
657                     create_date, edit_date, label, date_published,
658                     holding_code, holding_type, holding_link_id
659                 ),
660                 CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', evergreen.array_remove_item_by_value($4,'siss'), $5, $6, $7, $8, FALSE) ELSE NULL END,
661                 CASE 
662                     WHEN ('sitem' = ANY ($4)) THEN
663                         XMLELEMENT( name items,
664                             (SELECT XMLAGG(sitem) FROM (
665                                 SELECT  unapi.sitem( id, 'xml', 'serial_item', evergreen.array_remove_item_by_value($4,'siss'), $5, $6, $7, $8, FALSE)
666                                   FROM  serial.item
667                                   WHERE issuance = sstr.id
668                             )x)
669                         )
670                     ELSE NULL
671                 END
672             )
673       FROM  serial.issuance sstr
674       WHERE id = $1
675       GROUP BY id, create_date, edit_date, label, date_published, holding_code, holding_type, holding_link_id, subscription;
676 $F$ LANGUAGE SQL STABLE;
677
678 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$
679         SELECT  XMLELEMENT(
680                     name serial_item,
681                     XMLATTRIBUTES(
682                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
683                         'tag:open-ils.org:U2@sitem/' || id AS id,
684                         'tag:open-ils.org:U2@siss/' || issuance AS issuance,
685                         date_expected, date_received
686                     ),
687                     CASE WHEN issuance IS NOT NULL AND ('siss' = ANY ($4)) THEN unapi.siss( issuance, $2, 'issuance', evergreen.array_remove_item_by_value($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
688                     CASE WHEN stream IS NOT NULL AND ('sstr' = ANY ($4)) THEN unapi.sstr( stream, $2, 'stream', evergreen.array_remove_item_by_value($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
689                     CASE WHEN unit IS NOT NULL AND ('sunit' = ANY ($4)) THEN unapi.sunit( unit, $2, 'serial_unit', evergreen.array_remove_item_by_value($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
690                     CASE WHEN uri IS NOT NULL AND ('auri' = ANY ($4)) THEN unapi.auri( uri, $2, 'uri', evergreen.array_remove_item_by_value($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END
691 --                    XMLELEMENT( name notes,
692 --                        CASE 
693 --                            WHEN ('acpn' = ANY ($4)) THEN
694 --                                (SELECT XMLAGG(acpn) FROM (
695 --                                    SELECT  unapi.acpn( id, 'xml', 'copy_note', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8)
696 --                                      FROM  asset.copy_note
697 --                                      WHERE owning_copy = cp.id AND pub
698 --                                )x)
699 --                            ELSE NULL
700 --                        END
701 --                    )
702                 )
703           FROM  serial.item sitem
704           WHERE id = $1;
705 $F$ LANGUAGE SQL STABLE;
706
707
708 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$
709     SELECT  XMLELEMENT(
710                 name serial_summary,
711                 XMLATTRIBUTES(
712                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
713                     'tag:open-ils.org:U2@sbsum/' || id AS id,
714                     'sssum' AS type, generated_coverage, textual_holdings, show_generated
715                 ),
716                 CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', evergreen.array_remove_item_by_value($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
717             )
718       FROM  serial.supplement_summary ssum
719       WHERE id = $1
720       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
721 $F$ LANGUAGE SQL STABLE;
722
723 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$
724     SELECT  XMLELEMENT(
725                 name serial_summary,
726                 XMLATTRIBUTES(
727                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
728                     'tag:open-ils.org:U2@sbsum/' || id AS id,
729                     'sbsum' AS type, generated_coverage, textual_holdings, show_generated
730                 ),
731                 CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', evergreen.array_remove_item_by_value($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
732             )
733       FROM  serial.basic_summary ssum
734       WHERE id = $1
735       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
736 $F$ LANGUAGE SQL STABLE;
737
738 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$
739     SELECT  XMLELEMENT(
740                 name serial_summary,
741                 XMLATTRIBUTES(
742                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
743                     'tag:open-ils.org:U2@sbsum/' || id AS id,
744                     'sisum' AS type, generated_coverage, textual_holdings, show_generated
745                 ),
746                 CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', evergreen.array_remove_item_by_value($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
747             )
748       FROM  serial.index_summary ssum
749       WHERE id = $1
750       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
751 $F$ LANGUAGE SQL STABLE;
752
753
754 CREATE OR REPLACE FUNCTION unapi.aou ( 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$
755 DECLARE
756     output XML;
757 BEGIN
758     IF ename = 'circlib' THEN
759         SELECT  XMLELEMENT(
760                     name circlib,
761                     XMLATTRIBUTES(
762                         'http://open-ils.org/spec/actors/v1' AS xmlns,
763                         id AS ident
764                     ),
765                     name
766                 ) INTO output
767           FROM  actor.org_unit aou
768           WHERE id = obj_id;
769     ELSE
770         EXECUTE $$SELECT  XMLELEMENT(
771                     name $$ || ename || $$,
772                     XMLATTRIBUTES(
773                         'http://open-ils.org/spec/actors/v1' AS xmlns,
774                         'tag:open-ils.org:U2@aou/' || id AS id,
775                         shortname, name, opac_visible
776                     )
777                 )
778           FROM  actor.org_unit aou
779          WHERE id = $1 $$ INTO output USING obj_id;
780     END IF;
781
782     RETURN output;
783
784 END;
785 $F$ LANGUAGE PLPGSQL STABLE;
786
787 CREATE OR REPLACE FUNCTION unapi.acl ( 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$
788     SELECT  XMLELEMENT(
789                 name location,
790                 XMLATTRIBUTES(
791                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
792                     id AS ident,
793                     holdable,
794                     opac_visible,
795                     label_prefix AS prefix,
796                     label_suffix AS suffix
797                 ),
798                 name
799             )
800       FROM  asset.copy_location
801       WHERE id = $1;
802 $F$ LANGUAGE SQL STABLE;
803
804 CREATE OR REPLACE FUNCTION unapi.ccs ( 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$
805     SELECT  XMLELEMENT(
806                 name status,
807                 XMLATTRIBUTES(
808                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
809                     id AS ident,
810                     holdable,
811                     opac_visible
812                 ),
813                 name
814             )
815       FROM  config.copy_status
816       WHERE id = $1;
817 $F$ LANGUAGE SQL STABLE;
818
819 CREATE OR REPLACE FUNCTION unapi.acpn ( 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$
820         SELECT  XMLELEMENT(
821                     name copy_note,
822                     XMLATTRIBUTES(
823                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
824                         create_date AS date,
825                         title
826                     ),
827                     value
828                 )
829           FROM  asset.copy_note
830           WHERE id = $1;
831 $F$ LANGUAGE SQL STABLE;
832
833 CREATE OR REPLACE FUNCTION unapi.ascecm ( 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$
834         SELECT  XMLELEMENT(
835                     name statcat,
836                     XMLATTRIBUTES(
837                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
838                         sc.name,
839                         sc.opac_visible
840                     ),
841                     asce.value
842                 )
843           FROM  asset.stat_cat_entry asce
844                 JOIN asset.stat_cat sc ON (sc.id = asce.stat_cat)
845           WHERE asce.id = $1;
846 $F$ LANGUAGE SQL STABLE;
847
848 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$
849         SELECT  XMLELEMENT(
850                     name monograph_part,
851                     XMLATTRIBUTES(
852                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
853                         'tag:open-ils.org:U2@bmp/' || id AS id,
854                         id AS ident,
855                         label,
856                         label_sortkey,
857                         'tag:open-ils.org:U2@bre/' || record AS record
858                     ),
859                     CASE 
860                         WHEN ('acp' = ANY ($4)) THEN
861                             XMLELEMENT( name copies,
862                                 (SELECT XMLAGG(acp) FROM (
863                                     SELECT  unapi.acp( cp.id, 'xml', 'copy', evergreen.array_remove_item_by_value($4,'bmp'), $5, $6, $7, $8, FALSE)
864                                       FROM  asset.copy cp
865                                             JOIN asset.copy_part_map cpm ON (cpm.target_copy = cp.id)
866                                       WHERE cpm.part = $1
867                                           AND cp.deleted IS FALSE
868                                       ORDER BY COALESCE(cp.copy_number,0), cp.barcode
869                                       LIMIT ($7 -> 'acp')::INT
870                                       OFFSET ($8 -> 'acp')::INT
871
872                                 )x)
873                             )
874                         ELSE NULL
875                     END,
876                     CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( record, 'marcxml', 'record', evergreen.array_remove_item_by_value($4,'bmp'), $5, $6, $7, $8, FALSE) ELSE NULL END
877                 )
878           FROM  biblio.monograph_part
879           WHERE id = $1
880           GROUP BY id, label, label_sortkey, record;
881 $F$ LANGUAGE SQL STABLE;
882
883 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$
884         SELECT  XMLELEMENT(
885                     name copy,
886                     XMLATTRIBUTES(
887                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
888                         'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id,
889                         create_date, edit_date, copy_number, circulate, deposit,
890                         ref, holdable, deleted, deposit_amount, price, barcode,
891                         circ_modifier, circ_as_type, opac_visible, age_protect
892                     ),
893                     unapi.ccs( status, $2, 'status', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE),
894                     unapi.acl( location, $2, 'location', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE),
895                     unapi.aou( circ_lib, $2, 'circ_lib', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8),
896                     unapi.aou( circ_lib, $2, 'circlib', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8),
897                     CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END,
898                     CASE 
899                         WHEN ('acpn' = ANY ($4)) THEN
900                             XMLELEMENT( name copy_notes,
901                                 (SELECT XMLAGG(acpn) FROM (
902                                     SELECT  unapi.acpn( id, 'xml', 'copy_note', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
903                                       FROM  asset.copy_note
904                                       WHERE owning_copy = cp.id AND pub
905                                 )x)
906                             )
907                         ELSE NULL
908                     END,
909                     CASE 
910                         WHEN ('ascecm' = ANY ($4)) THEN
911                             XMLELEMENT( name statcats,
912                                 (SELECT XMLAGG(ascecm) FROM (
913                                     SELECT  unapi.ascecm( stat_cat_entry, 'xml', 'statcat', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
914                                       FROM  asset.stat_cat_entry_copy_map
915                                       WHERE owning_copy = cp.id
916                                 )x)
917                             )
918                         ELSE NULL
919                     END,
920                     CASE
921                         WHEN ('bre' = ANY ($4)) THEN
922                             XMLELEMENT( name foreign_records,
923                                 (SELECT XMLAGG(bre) FROM (
924                                     SELECT  unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE)
925                                       FROM  biblio.peer_bib_copy_map
926                                       WHERE target_copy = cp.id
927                                 )x)
928
929                             )
930                         ELSE NULL
931                     END,
932                     CASE 
933                         WHEN ('bmp' = ANY ($4)) THEN
934                             XMLELEMENT( name monograph_parts,
935                                 (SELECT XMLAGG(bmp) FROM (
936                                     SELECT  unapi.bmp( part, 'xml', 'monograph_part', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
937                                       FROM  asset.copy_part_map
938                                       WHERE target_copy = cp.id
939                                 )x)
940                             )
941                         ELSE NULL
942                     END,
943                     CASE 
944                         WHEN ('circ' = ANY ($4)) THEN
945                             XMLELEMENT( name current_circulation,
946                                 (SELECT XMLAGG(circ) FROM (
947                                     SELECT  unapi.circ( id, 'xml', 'circ', evergreen.array_remove_item_by_value($4,'circ'), $5, $6, $7, $8, FALSE)
948                                       FROM  action.circulation
949                                       WHERE target_copy = cp.id
950                                             AND checkin_time IS NULL
951                                 )x)
952                             )
953                         ELSE NULL
954                     END
955                 )
956           FROM  asset.copy cp
957           WHERE id = $1
958               AND cp.deleted IS FALSE
959           GROUP BY id, status, location, circ_lib, call_number, create_date,
960               edit_date, copy_number, circulate, deposit, ref, holdable,
961               deleted, deposit_amount, price, barcode, circ_modifier,
962               circ_as_type, opac_visible, age_protect;
963 $F$ LANGUAGE SQL STABLE;
964
965 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$
966         SELECT  XMLELEMENT(
967                     name serial_unit,
968                     XMLATTRIBUTES(
969                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
970                         'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id,
971                         create_date, edit_date, copy_number, circulate, deposit,
972                         ref, holdable, deleted, deposit_amount, price, barcode,
973                         circ_modifier, circ_as_type, opac_visible, age_protect,
974                         status_changed_time, floating, mint_condition,
975                         detailed_contents, sort_key, summary_contents, cost 
976                     ),
977                     unapi.ccs( status, $2, 'status', evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE),
978                     unapi.acl( location, $2, 'location', evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE),
979                     unapi.aou( circ_lib, $2, 'circ_lib', evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8),
980                     unapi.aou( circ_lib, $2, 'circlib', evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8),
981                     CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END,
982                     XMLELEMENT( name copy_notes,
983                         CASE 
984                             WHEN ('acpn' = ANY ($4)) THEN
985                                 (SELECT XMLAGG(acpn) FROM (
986                                     SELECT  unapi.acpn( id, 'xml', 'copy_note', evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE)
987                                       FROM  asset.copy_note
988                                       WHERE owning_copy = cp.id AND pub
989                                 )x)
990                             ELSE NULL
991                         END
992                     ),
993                     XMLELEMENT( name statcats,
994                         CASE 
995                             WHEN ('ascecm' = ANY ($4)) THEN
996                                 (SELECT XMLAGG(ascecm) FROM (
997                                     SELECT  unapi.ascecm( stat_cat_entry, 'xml', 'statcat', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
998                                       FROM  asset.stat_cat_entry_copy_map
999                                       WHERE owning_copy = cp.id
1000                                 )x)
1001                             ELSE NULL
1002                         END
1003                     ),
1004                     XMLELEMENT( name foreign_records,
1005                         CASE
1006                             WHEN ('bre' = ANY ($4)) THEN
1007                                 (SELECT XMLAGG(bre) FROM (
1008                                     SELECT  unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE)
1009                                       FROM  biblio.peer_bib_copy_map
1010                                       WHERE target_copy = cp.id
1011                                 )x)
1012                             ELSE NULL
1013                         END
1014                     ),
1015                     CASE 
1016                         WHEN ('bmp' = ANY ($4)) THEN
1017                             XMLELEMENT( name monograph_parts,
1018                                 (SELECT XMLAGG(bmp) FROM (
1019                                     SELECT  unapi.bmp( part, 'xml', 'monograph_part', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
1020                                       FROM  asset.copy_part_map
1021                                       WHERE target_copy = cp.id
1022                                 )x)
1023                             )
1024                         ELSE NULL
1025                     END,
1026                     CASE 
1027                         WHEN ('circ' = ANY ($4)) THEN
1028                             XMLELEMENT( name current_circulation,
1029                                 (SELECT XMLAGG(circ) FROM (
1030                                     SELECT  unapi.circ( id, 'xml', 'circ', evergreen.array_remove_item_by_value($4,'circ'), $5, $6, $7, $8, FALSE)
1031                                       FROM  action.circulation
1032                                       WHERE target_copy = cp.id
1033                                             AND checkin_time IS NULL
1034                                 )x)
1035                             )
1036                         ELSE NULL
1037                     END
1038                 )
1039           FROM  serial.unit cp
1040           WHERE id = $1
1041               AND cp.deleted IS FALSE
1042           GROUP BY id, status, location, circ_lib, call_number, create_date,
1043               edit_date, copy_number, circulate, floating, mint_condition,
1044               deposit, ref, holdable, deleted, deposit_amount, price,
1045               barcode, circ_modifier, circ_as_type, opac_visible,
1046               status_changed_time, detailed_contents, sort_key,
1047               summary_contents, cost, age_protect;
1048 $F$ LANGUAGE SQL STABLE;
1049
1050 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$
1051         SELECT  XMLELEMENT(
1052                     name volume,
1053                     XMLATTRIBUTES(
1054                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1055                         'tag:open-ils.org:U2@acn/' || acn.id AS id,
1056                         acn.id AS vol_id, o.shortname AS lib,
1057                         o.opac_visible AS opac_visible,
1058                         deleted, label, label_sortkey, label_class, record
1059                     ),
1060                     unapi.aou( owning_lib, $2, 'owning_lib', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8),
1061                     CASE 
1062                         WHEN ('acp' = ANY ($4)) THEN
1063                             CASE WHEN $6 IS NOT NULL THEN
1064                                 XMLELEMENT( name copies,
1065                                     (SELECT XMLAGG(acp ORDER BY rank_avail) FROM (
1066                                         SELECT  unapi.acp( cp.id, 'xml', 'copy', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE),
1067                                             evergreen.rank_cp_status(cp.status) AS rank_avail
1068                                           FROM  asset.copy cp
1069                                                 JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5), $6) aoud ON (cp.circ_lib = aoud.id)
1070                                           WHERE cp.call_number = acn.id
1071                                               AND cp.deleted IS FALSE
1072                                           ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode
1073                                           LIMIT ($7 -> 'acp')::INT
1074                                           OFFSET ($8 -> 'acp')::INT
1075                                     )x)
1076                                 )
1077                             ELSE
1078                                 XMLELEMENT( name copies,
1079                                     (SELECT XMLAGG(acp ORDER BY rank_avail) FROM (
1080                                         SELECT  unapi.acp( cp.id, 'xml', 'copy', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE),
1081                                             evergreen.rank_cp_status(cp.status) AS rank_avail
1082                                           FROM  asset.copy cp
1083                                                 JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5) ) aoud ON (cp.circ_lib = aoud.id)
1084                                           WHERE cp.call_number = acn.id
1085                                               AND cp.deleted IS FALSE
1086                                           ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode
1087                                           LIMIT ($7 -> 'acp')::INT
1088                                           OFFSET ($8 -> 'acp')::INT
1089                                     )x)
1090                                 )
1091                             END
1092                         ELSE NULL
1093                     END,
1094                     XMLELEMENT(
1095                         name uris,
1096                         (SELECT XMLAGG(auri) FROM (SELECT unapi.auri(uri,'xml','uri', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE call_number = acn.id)x)
1097                     ),
1098                     unapi.acnp( acn.prefix, 'marcxml', 'prefix', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE),
1099                     unapi.acns( acn.suffix, 'marcxml', 'suffix', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE),
1100                     CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( acn.record, 'marcxml', 'record', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE) ELSE NULL END
1101                 ) AS x
1102           FROM  asset.call_number acn
1103                 JOIN actor.org_unit o ON (o.id = acn.owning_lib)
1104           WHERE acn.id = $1
1105               AND acn.deleted IS FALSE
1106           GROUP BY acn.id, o.shortname, o.opac_visible, deleted, label, label_sortkey, label_class, owning_lib, record, acn.prefix, acn.suffix;
1107 $F$ LANGUAGE SQL STABLE;
1108
1109 CREATE OR REPLACE FUNCTION unapi.acnp ( 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$
1110         SELECT  XMLELEMENT(
1111                     name call_number_prefix,
1112                     XMLATTRIBUTES(
1113                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1114                         id AS ident,
1115                         label,
1116                         'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib,
1117                         label_sortkey
1118                     )
1119                 )
1120           FROM  asset.call_number_prefix
1121           WHERE id = $1;
1122 $F$ LANGUAGE SQL STABLE;
1123
1124 CREATE OR REPLACE FUNCTION unapi.acns ( 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$
1125         SELECT  XMLELEMENT(
1126                     name call_number_suffix,
1127                     XMLATTRIBUTES(
1128                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1129                         id AS ident,
1130                         label,
1131                         'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib,
1132                         label_sortkey
1133                     )
1134                 )
1135           FROM  asset.call_number_suffix
1136           WHERE id = $1;
1137 $F$ LANGUAGE SQL STABLE;
1138
1139 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$
1140         SELECT  XMLELEMENT(
1141                     name uri,
1142                     XMLATTRIBUTES(
1143                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1144                         'tag:open-ils.org:U2@auri/' || uri.id AS id,
1145                         use_restriction,
1146                         href,
1147                         label
1148                     ),
1149                     CASE 
1150                         WHEN ('acn' = ANY ($4)) THEN
1151                             XMLELEMENT( name copies,
1152                                 (SELECT XMLAGG(acn) FROM (SELECT unapi.acn( call_number, 'xml', 'copy', evergreen.array_remove_item_by_value($4,'auri'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE uri = uri.id)x)
1153                             )
1154                         ELSE NULL
1155                     END
1156                 ) AS x
1157           FROM  asset.uri uri
1158           WHERE uri.id = $1
1159           GROUP BY uri.id, use_restriction, href, label;
1160 $F$ LANGUAGE SQL STABLE;
1161
1162 CREATE OR REPLACE FUNCTION unapi.mra (
1163     obj_id BIGINT,
1164     format TEXT,
1165     ename TEXT,
1166     includes TEXT[],
1167     org TEXT,
1168     depth INT DEFAULT NULL,
1169     slimit HSTORE DEFAULT NULL,
1170     soffset HSTORE DEFAULT NULL,
1171     include_xmlns BOOL DEFAULT TRUE
1172 ) RETURNS XML AS $F$
1173     SELECT  XMLELEMENT(
1174         name attributes,
1175         XMLATTRIBUTES(
1176             CASE WHEN $9 THEN 'http://open-ils.org/spec/indexing/v1' ELSE NULL END AS xmlns,
1177             'tag:open-ils.org:U2@mra/' || $1 AS id, 
1178             'tag:open-ils.org:U2@bre/' || $1 AS record 
1179         ),  
1180         (SELECT XMLAGG(foo.y)
1181           FROM (
1182             SELECT  XMLELEMENT(
1183                         name field,
1184                         XMLATTRIBUTES(
1185                             mra.attr AS name,
1186                             cvm.value AS "coded-value",
1187                             cvm.id AS "cvmid",
1188                             rad.composite,
1189                             rad.multi,
1190                             rad.filter,
1191                             rad.sorter
1192                         ),
1193                         mra.value
1194                     )
1195               FROM  metabib.record_attr_flat mra
1196                     JOIN config.record_attr_definition rad ON (mra.attr = rad.name)
1197                     LEFT JOIN config.coded_value_map cvm ON (cvm.ctype = mra.attr AND code = mra.value)
1198               WHERE mra.id = $1
1199             )foo(y)
1200         )   
1201     )   
1202 $F$ LANGUAGE SQL STABLE;
1203
1204 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$
1205     SELECT XMLELEMENT(
1206         name circ,
1207         XMLATTRIBUTES(
1208             CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1209             'tag:open-ils.org:U2@circ/' || id AS id,
1210             xact_start,
1211             due_date
1212         ),
1213         CASE WHEN ('aou' = ANY ($4)) THEN unapi.aou( circ_lib, $2, 'circ_lib', evergreen.array_remove_item_by_value($4,'circ'), $5, $6, $7, $8, FALSE) ELSE NULL END,
1214         CASE WHEN ('acp' = ANY ($4)) THEN unapi.acp( circ_lib, $2, 'target_copy', evergreen.array_remove_item_by_value($4,'circ'), $5, $6, $7, $8, FALSE) ELSE NULL END
1215     )
1216     FROM action.circulation
1217     WHERE id = $1;
1218 $F$ LANGUAGE SQL STABLE;
1219
1220 CREATE OR REPLACE FUNCTION unapi.mmr_mra (
1221     obj_id BIGINT,
1222     format TEXT,
1223     ename TEXT,
1224     includes TEXT[],
1225     org TEXT,
1226     depth INT DEFAULT NULL,
1227     slimit HSTORE DEFAULT NULL,
1228     soffset HSTORE DEFAULT NULL,
1229     include_xmlns BOOL DEFAULT TRUE,
1230     pref_lib INT DEFAULT NULL
1231 ) RETURNS XML AS $F$
1232     SELECT  XMLELEMENT(
1233         name attributes,
1234         XMLATTRIBUTES(
1235             CASE WHEN $9 THEN 'http://open-ils.org/spec/indexing/v1' ELSE NULL END AS xmlns,
1236             'tag:open-ils.org:U2@mmr/' || $1 AS metarecord
1237         ),
1238         (SELECT XMLAGG(foo.y)
1239           FROM (
1240             SELECT  DISTINCT ON (COALESCE(cvm.id,uvm.id))
1241                     COALESCE(cvm.id,uvm.id),
1242                     XMLELEMENT(
1243                         name field,
1244                         XMLATTRIBUTES(
1245                             mra.attr AS name,
1246                             cvm.value AS "coded-value",
1247                             cvm.id AS "cvmid",
1248                             rad.composite,
1249                             rad.multi,
1250                             rad.filter,
1251                             rad.sorter
1252                         ),
1253                         mra.value
1254                     )
1255               FROM  metabib.record_attr_flat mra
1256                     JOIN config.record_attr_definition rad ON (mra.attr = rad.name)
1257                     LEFT JOIN config.coded_value_map cvm ON (cvm.ctype = mra.attr AND code = mra.value)
1258                     LEFT JOIN metabib.uncontrolled_record_attr_value uvm ON (uvm.attr = mra.attr AND uvm.value = mra.value)
1259               WHERE mra.id IN (
1260                     WITH aou AS (SELECT COALESCE(id, (evergreen.org_top()).id) AS id 
1261                         FROM actor.org_unit WHERE shortname = $5 LIMIT 1)
1262                     SELECT source 
1263                     FROM metabib.metarecord_source_map, aou
1264                     WHERE metarecord = $1 AND (
1265                         EXISTS (
1266                             SELECT 1 FROM asset.opac_visible_copies 
1267                             WHERE record = source AND circ_lib IN (
1268                                 SELECT id FROM actor.org_unit_descendants(aou.id, $6)) 
1269                             LIMIT 1
1270                         )
1271                         OR EXISTS (SELECT 1 FROM located_uris(source, aou.id, $10) LIMIT 1)
1272                     )
1273                 )
1274               ORDER BY 1
1275             )foo(id,y)
1276         )
1277     )
1278 $F$ LANGUAGE SQL STABLE;
1279
1280 CREATE OR REPLACE FUNCTION unapi.mmr_holdings_xml (
1281     mid BIGINT,
1282     ouid INT,
1283     org TEXT,
1284     depth INT DEFAULT NULL,
1285     includes TEXT[] DEFAULT NULL::TEXT[],
1286     slimit HSTORE DEFAULT NULL,
1287     soffset HSTORE DEFAULT NULL,
1288     include_xmlns BOOL DEFAULT TRUE,
1289     pref_lib INT DEFAULT NULL
1290 )
1291 RETURNS XML AS $F$
1292      SELECT  XMLELEMENT(
1293                  name holdings,
1294                  XMLATTRIBUTES(
1295                     CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1296                     CASE WHEN ('mmr' = ANY ($5)) THEN 'tag:open-ils.org:U2@mmr/' || $1 || '/' || $3 ELSE NULL END AS id,
1297                     (SELECT metarecord_has_holdable_copy FROM asset.metarecord_has_holdable_copy($1)) AS has_holdable
1298                  ),
1299                  XMLELEMENT(
1300                      name counts,
1301                      (SELECT  XMLAGG(XMLELEMENT::XML) FROM (
1302                          SELECT  XMLELEMENT(
1303                                      name count,
1304                                      XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
1305                                  )::text
1306                            FROM  asset.opac_ou_metarecord_copy_count($2,  $1)
1307                                      UNION
1308                          SELECT  XMLELEMENT(
1309                                      name count,
1310                                      XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
1311                                  )::text
1312                            FROM  asset.staff_ou_metarecord_copy_count($2, $1)
1313                                      UNION
1314                          SELECT  XMLELEMENT(
1315                                      name count,
1316                                      XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
1317                                  )::text
1318                            FROM  asset.opac_ou_metarecord_copy_count($9,  $1)
1319                                      ORDER BY 1
1320                      )x)
1321                  ),
1322                  -- XXX monograph_parts and foreign_copies are skipped in MRs ... put them back some day?
1323                  XMLELEMENT(
1324                      name volumes,
1325                      (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
1326                         -- Physical copies
1327                         SELECT  unapi.acn(y.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), y.rank, name, label_sortkey
1328                         FROM evergreen.ranked_volumes((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $4, $6, $7, $9, $5) AS y
1329                         UNION ALL
1330                         -- Located URIs
1331                         SELECT unapi.acn(uris.id,'xml','volume',evergreen.array_remove_item_by_value( evergreen.array_remove_item_by_value($5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE), uris.rank, name, label_sortkey
1332                         FROM evergreen.located_uris((SELECT ARRAY_AGG(source) FROM metabib.metarecord_source_map WHERE metarecord = $1), $2, $9) AS uris
1333                      )x)
1334                  ),
1335                  CASE WHEN ('ssub' = ANY ($5)) THEN
1336                      XMLELEMENT(
1337                          name subscriptions,
1338                          (SELECT XMLAGG(ssub) FROM (
1339                             SELECT  unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
1340                               FROM  serial.subscription
1341                               WHERE record_entry IN (SELECT source FROM metabib.metarecord_source_map WHERE metarecord = $1)
1342                         )x)
1343                      )
1344                  ELSE NULL END
1345              );
1346 $F$ LANGUAGE SQL STABLE;
1347
1348 CREATE OR REPLACE FUNCTION unapi.mmr (
1349     obj_id BIGINT,
1350     format TEXT,
1351     ename TEXT,
1352     includes TEXT[],
1353     org TEXT,
1354     depth INT DEFAULT NULL,
1355     slimit HSTORE DEFAULT NULL,
1356     soffset HSTORE DEFAULT NULL,
1357     include_xmlns BOOL DEFAULT TRUE,
1358     pref_lib INT DEFAULT NULL
1359 )
1360 RETURNS XML AS $F$
1361 DECLARE
1362     mmrec   metabib.metarecord%ROWTYPE;
1363     leadrec biblio.record_entry%ROWTYPE;
1364     subrec biblio.record_entry%ROWTYPE;
1365     layout  unapi.bre_output_layout%ROWTYPE;
1366     xfrm    config.xml_transform%ROWTYPE;
1367     ouid    INT;
1368     xml_buf TEXT; -- growing XML document
1369     tmp_xml TEXT; -- single-use XML string
1370     xml_frag TEXT; -- single-use XML fragment
1371     top_el  TEXT;
1372     output  XML;
1373     hxml    XML;
1374     axml    XML;
1375     subxml  XML; -- subordinate records elements
1376     sub_xpath TEXT; 
1377     parts   TEXT[]; 
1378 BEGIN
1379
1380     -- xpath for extracting bre.marc values from subordinate records 
1381     -- so they may be appended to the MARC of the master record prior
1382     -- to XSLT processing.
1383     -- subjects, isbn, issn, upc -- anything else?
1384     sub_xpath := 
1385       '//*[starts-with(@tag, "6") or @tag="020" or @tag="022" or @tag="024"]';
1386
1387     IF org = '-' OR org IS NULL THEN
1388         SELECT shortname INTO org FROM evergreen.org_top();
1389     END IF;
1390
1391     SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
1392
1393     IF ouid IS NULL THEN
1394         RETURN NULL::XML;
1395     END IF;
1396
1397     SELECT INTO mmrec * FROM metabib.metarecord WHERE id = obj_id;
1398     IF NOT FOUND THEN
1399         RETURN NULL::XML;
1400     END IF;
1401
1402     -- TODO: aggregate holdings from constituent records
1403     IF format = 'holdings_xml' THEN -- the special case
1404         output := unapi.mmr_holdings_xml(
1405             obj_id, ouid, org, depth,
1406             evergreen.array_remove_item_by_value(includes,'holdings_xml'),
1407             slimit, soffset, include_xmlns, pref_lib);
1408         RETURN output;
1409     END IF;
1410
1411     SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
1412
1413     IF layout.name IS NULL THEN
1414         RETURN NULL::XML;
1415     END IF;
1416
1417     SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
1418
1419     SELECT INTO leadrec * FROM biblio.record_entry WHERE id = mmrec.master_record;
1420
1421     -- Grab distinct MVF for all records if requested
1422     IF ('mra' = ANY (includes)) THEN 
1423         axml := unapi.mmr_mra(obj_id,NULL,NULL,NULL,org,depth,NULL,NULL,TRUE,pref_lib);
1424     ELSE
1425         axml := NULL::XML;
1426     END IF;
1427
1428     xml_buf = leadrec.marc;
1429
1430     hxml := NULL::XML;
1431     IF ('holdings_xml' = ANY (includes)) THEN
1432         hxml := unapi.mmr_holdings_xml(
1433                     obj_id, ouid, org, depth,
1434                     evergreen.array_remove_item_by_value(includes,'holdings_xml'),
1435                     slimit, soffset, include_xmlns, pref_lib);
1436     END IF;
1437
1438     subxml := NULL::XML;
1439     parts := '{}'::TEXT[];
1440     FOR subrec IN SELECT bre.* FROM biblio.record_entry bre
1441          JOIN metabib.metarecord_source_map mmsm ON (mmsm.source = bre.id)
1442          JOIN metabib.metarecord mmr ON (mmr.id = mmsm.metarecord)
1443          WHERE mmr.id = obj_id
1444          ORDER BY CASE WHEN bre.id = mmr.master_record THEN 0 ELSE bre.id END
1445          LIMIT COALESCE((slimit->'bre')::INT, 5) LOOP
1446
1447         IF subrec.id = leadrec.id THEN CONTINUE; END IF;
1448         -- Append choice data from the the non-lead records to the 
1449         -- the lead record document
1450
1451         parts := parts || xpath(sub_xpath, subrec.marc::XML)::TEXT[];
1452     END LOOP;
1453
1454     SELECT ARRAY_TO_STRING( ARRAY_AGG( DISTINCT p ), '' )::XML INTO subxml FROM UNNEST(parts) p;
1455
1456     -- append data from the subordinate records to the 
1457     -- main record document before applying the XSLT
1458
1459     IF subxml IS NOT NULL THEN 
1460         xml_buf := REGEXP_REPLACE(xml_buf, 
1461             '</record>(.*?)$', subxml || '</record>' || E'\\1');
1462     END IF;
1463
1464     IF format = 'marcxml' THEN
1465          -- If we're not using the prefixed namespace in 
1466          -- this record, then remove all declarations of it
1467         IF xml_buf !~ E'<marc:' THEN
1468            xml_buf := REGEXP_REPLACE(xml_buf, 
1469             ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
1470         END IF; 
1471     ELSE
1472         xml_buf := oils_xslt_process(xml_buf, xfrm.xslt)::XML;
1473     END IF;
1474
1475     -- update top_el to reflect the change in xml_buf, which may
1476     -- now be a different type of document (e.g. record -> mods)
1477     top_el := REGEXP_REPLACE(xml_buf, E'^.*?<((?:\\S+:)?' || 
1478         layout.holdings_element || ').*$', E'\\1');
1479
1480     IF axml IS NOT NULL THEN 
1481         xml_buf := REGEXP_REPLACE(xml_buf, 
1482             '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
1483     END IF;
1484
1485     IF hxml IS NOT NULL THEN
1486         xml_buf := REGEXP_REPLACE(xml_buf, 
1487             '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
1488     END IF;
1489
1490     IF ('mmr.unapi' = ANY (includes)) THEN 
1491         output := REGEXP_REPLACE(
1492             xml_buf,
1493             '</' || top_el || '>(.*?)',
1494             XMLELEMENT(
1495                 name abbr,
1496                 XMLATTRIBUTES(
1497                     'http://www.w3.org/1999/xhtml' AS xmlns,
1498                     'unapi-id' AS class,
1499                     'tag:open-ils.org:U2@mmr/' || obj_id || '/' || org AS title
1500                 )
1501             )::TEXT || '</' || top_el || E'>\\1'
1502         );
1503     ELSE
1504         output := xml_buf;
1505     END IF;
1506
1507     -- remove ignorable whitesace
1508     output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
1509     RETURN output;
1510 END;
1511 $F$ LANGUAGE PLPGSQL STABLE;
1512
1513
1514 /*
1515
1516  -- Some test queries
1517
1518 SELECT unapi.memoize( 'bre', 1,'mods32','','{holdings_xml,acp}'::TEXT[], 'SYS1');
1519 SELECT unapi.memoize( 'bre', 1,'marcxml','','{holdings_xml,acp}'::TEXT[], 'SYS1');
1520 SELECT unapi.memoize( 'bre', 1,'holdings_xml','','{holdings_xml,acp}'::TEXT[], 'SYS1');
1521
1522 SELECT unapi.biblio_record_entry_feed('{1}'::BIGINT[],'mods32','{holdings_xml,acp}'::TEXT[],'SYS1',NULL,'acn=>1',NULL, NULL,NULL,NULL,NULL,'http://c64/opac/extras/unapi', '<totalResults xmlns="http://a9.com/-/spec/opensearch/1.1/">2</totalResults><startIndex xmlns="http://a9.com/-/spec/opensearch/1.1/">1</startIndex><itemsPerPage xmlns="http://a9.com/-/spec/opensearch/1.1/">10</itemsPerPage>');
1523
1524 SELECT unapi.biblio_record_entry_feed('{7209,7394}'::BIGINT[],'marcxml','{}'::TEXT[],'SYS1',NULL,'acn=>1',NULL, NULL,NULL,NULL,NULL,'http://fulfillment2.esilibrary.com/opac/extras/unapi', '<totalResults xmlns="http://a9.com/-/spec/opensearch/1.1/">2</totalResults><startIndex xmlns="http://a9.com/-/spec/opensearch/1.1/">1</startIndex><itemsPerPage xmlns="http://a9.com/-/spec/opensearch/1.1/">10</itemsPerPage>');
1525 EXPLAIN ANALYZE SELECT unapi.biblio_record_entry_feed('{7209,7394}'::BIGINT[],'marcxml','{}'::TEXT[],'SYS1',NULL,'acn=>1',NULL, NULL,NULL,NULL,NULL,'http://fulfillment2.esilibrary.com/opac/extras/unapi', '<totalResults xmlns="http://a9.com/-/spec/opensearch/1.1/">2</totalResults><startIndex xmlns="http://a9.com/-/spec/opensearch/1.1/">1</startIndex><itemsPerPage xmlns="http://a9.com/-/spec/opensearch/1.1/">10</itemsPerPage>');
1526 EXPLAIN ANALYZE SELECT unapi.biblio_record_entry_feed('{7209,7394}'::BIGINT[],'marcxml','{holdings_xml}'::TEXT[],'SYS1',NULL,'acn=>1',NULL, NULL,NULL,NULL,NULL,'http://fulfillment2.esilibrary.com/opac/extras/unapi', '<totalResults xmlns="http://a9.com/-/spec/opensearch/1.1/">2</totalResults><startIndex xmlns="http://a9.com/-/spec/opensearch/1.1/">1</startIndex><itemsPerPage xmlns="http://a9.com/-/spec/opensearch/1.1/">10</itemsPerPage>');
1527 EXPLAIN ANALYZE SELECT unapi.biblio_record_entry_feed('{7209,7394}'::BIGINT[],'mods32','{holdings_xml}'::TEXT[],'SYS1',NULL,'acn=>1',NULL, NULL,NULL,NULL,NULL,'http://fulfillment2.esilibrary.com/opac/extras/unapi', '<totalResults xmlns="http://a9.com/-/spec/opensearch/1.1/">2</totalResults><startIndex xmlns="http://a9.com/-/spec/opensearch/1.1/">1</startIndex><itemsPerPage xmlns="http://a9.com/-/spec/opensearch/1.1/">10</itemsPerPage>');
1528
1529 SELECT unapi.biblio_record_entry_feed('{216}'::BIGINT[],'marcxml','{}'::TEXT[], 'BR1');
1530 EXPLAIN ANALYZE SELECT unapi.bre(216,'marcxml','record','{holdings_xml,bre.unapi}'::TEXT[], 'BR1');
1531 EXPLAIN ANALYZE SELECT unapi.bre(216,'holdings_xml','record','{}'::TEXT[], 'BR1');
1532 EXPLAIN ANALYZE SELECT unapi.holdings_xml(216,4,'BR1',2,'{bre}'::TEXT[]);
1533 EXPLAIN ANALYZE SELECT unapi.bre(216,'mods32','record','{}'::TEXT[], 'BR1');
1534
1535 -- Limit to 5 call numbers, 5 copies, with a preferred library of 4 (BR1), in SYS2 at a depth of 0
1536 EXPLAIN ANALYZE SELECT unapi.bre(36,'marcxml','record','{holdings_xml,mra,acp,acnp,acns,bmp}','SYS2',0,'acn=>5,acp=>5',NULL,TRUE,4);
1537
1538 */
1539
1540 COMMIT;
1541