]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/sql/Pg/990.schema.unapi.sql
rank_ou() honors pref-lib in non-global context
[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_ACCUM(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 ) RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank BIGINT) AS $$
75     SELECT ua.id, ua.name, ua.label_sortkey, MIN(ua.rank) AS rank FROM (
76         SELECT acn.id, aou.name, acn.label_sortkey,
77             evergreen.rank_ou(aou.id, $2, $6), evergreen.rank_cp_status(acp.status),
78             RANK() OVER w
79         FROM asset.call_number acn
80             JOIN asset.copy acp ON (acn.id = acp.call_number)
81             JOIN actor.org_unit_descendants( $2, COALESCE(
82                 $3, (
83                     SELECT depth
84                     FROM actor.org_unit_type aout
85                         INNER JOIN actor.org_unit ou ON ou_type = aout.id
86                     WHERE ou.id = $2
87                 ), $6)
88             ) AS aou ON (acp.circ_lib = aou.id)
89         WHERE acn.record = $1
90             AND acn.deleted IS FALSE
91             AND acp.deleted IS FALSE
92         GROUP BY acn.id, acp.status, aou.name, acn.label_sortkey, aou.id
93         WINDOW w AS (
94             ORDER BY evergreen.rank_ou(aou.id, $2, $6), evergreen.rank_cp_status(acp.status)
95         )
96     ) AS ua
97     GROUP BY ua.id, ua.name, ua.label_sortkey
98     ORDER BY rank, ua.name, ua.label_sortkey
99     LIMIT ($4 -> 'acn')::INT
100     OFFSET ($5 -> 'acn')::INT;
101 $$
102 LANGUAGE SQL STABLE;
103
104 CREATE OR REPLACE FUNCTION evergreen.located_uris (
105     bibid BIGINT, 
106     ouid INT,
107     pref_lib INT DEFAULT NULL
108 ) RETURNS TABLE (id BIGINT, name TEXT, label_sortkey TEXT, rank INT) AS $$
109     SELECT acn.id, aou.name, acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou
110       FROM asset.call_number acn
111            INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number 
112            INNER JOIN asset.uri auri ON auri.id = auricnm.uri
113            INNER JOIN actor.org_unit_ancestors( COALESCE($3, $2) ) aou ON (acn.owning_lib = aou.id)
114       WHERE acn.record = $1
115           AND acn.deleted IS FALSE
116           AND auri.active IS TRUE
117     UNION
118     SELECT acn.id, aou.name, acn.label_sortkey, evergreen.rank_ou(aou.id, $2, $3) AS pref_ou
119       FROM asset.call_number acn
120            INNER JOIN asset.uri_call_number_map auricnm ON acn.id = auricnm.call_number 
121            INNER JOIN asset.uri auri ON auri.id = auricnm.uri
122            INNER JOIN actor.org_unit_ancestors( $2 ) aou ON (acn.owning_lib = aou.id)
123       WHERE acn.record = $1
124           AND acn.deleted IS FALSE
125           AND auri.active IS TRUE;
126 $$
127 LANGUAGE SQL STABLE;
128
129 CREATE TABLE unapi.bre_output_layout (
130     name                TEXT    PRIMARY KEY,
131     transform           TEXT    REFERENCES config.xml_transform (name) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
132     mime_type           TEXT    NOT NULL,
133     feed_top            TEXT    NOT NULL,
134     holdings_element    TEXT,
135     title_element       TEXT,
136     description_element TEXT,
137     creator_element     TEXT,
138     update_ts_element   TEXT
139 );
140
141 INSERT INTO unapi.bre_output_layout
142     (name,           transform, mime_type,              holdings_element, feed_top,         title_element, description_element, creator_element, update_ts_element)
143         VALUES
144     ('holdings_xml', NULL,      'application/xml',      NULL,             'hxml',           NULL,          NULL,                NULL,            NULL),
145     ('marcxml',      'marcxml', 'application/marc+xml', 'record',         'collection',     NULL,          NULL,                NULL,            NULL),
146     ('mods32',       'mods32',  'application/mods+xml', 'mods',           'modsCollection', NULL,          NULL,                NULL,            NULL)
147 ;
148
149 -- Dummy functions, so we can create the real ones out of order
150 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;
151 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;
152 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;
153 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;
154 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;
155 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;
156 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;
157 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;
158 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;
159 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;
160 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;
161 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;
162 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;
163 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;
164 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;
165 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;
166 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;
167 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;
168 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;
169 CREATE OR REPLACE FUNCTION unapi.bre (
170     obj_id BIGINT,
171     format TEXT,
172     ename TEXT,
173     includes TEXT[],
174     org TEXT,
175     depth INT DEFAULT NULL,
176     slimit HSTORE DEFAULT NULL,
177     soffset HSTORE DEFAULT NULL,
178     include_xmlns BOOL DEFAULT TRUE,
179     pref_lib INT DEFAULT NULL
180 )
181 RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL STABLE;
182 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;
183 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;
184 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;
185
186 CREATE OR REPLACE FUNCTION unapi.holdings_xml (
187     bid BIGINT,
188     ouid INT,
189     org TEXT,
190     depth INT DEFAULT NULL,
191     includes TEXT[] DEFAULT NULL::TEXT[],
192     slimit HSTORE DEFAULT NULL,
193     soffset HSTORE DEFAULT NULL,
194     include_xmlns BOOL DEFAULT TRUE,
195     pref_lib INT DEFAULT NULL
196 )
197 RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL STABLE;
198
199 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;
200
201 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$
202 DECLARE
203     key     TEXT;
204     output  XML;
205 BEGIN
206     key :=
207         'id'        || COALESCE(obj_id::TEXT,'') ||
208         'format'    || COALESCE(format::TEXT,'') ||
209         'ename'     || COALESCE(ename::TEXT,'') ||
210         'includes'  || COALESCE(includes::TEXT,'{}'::TEXT[]::TEXT) ||
211         'org'       || COALESCE(org::TEXT,'') ||
212         'depth'     || COALESCE(depth::TEXT,'') ||
213         'slimit'    || COALESCE(slimit::TEXT,'') ||
214         'soffset'   || COALESCE(soffset::TEXT,'') ||
215         'include_xmlns'   || COALESCE(include_xmlns::TEXT,'');
216     -- RAISE NOTICE 'memoize key: %', key;
217
218     key := MD5(key);
219     -- RAISE NOTICE 'memoize hash: %', key;
220
221     -- XXX cache logic ... memcached? table?
222
223     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;
224     RETURN output;
225 END;
226 $F$ LANGUAGE PLPGSQL STABLE;
227
228 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$
229 DECLARE
230     layout          unapi.bre_output_layout%ROWTYPE;
231     transform       config.xml_transform%ROWTYPE;
232     item_format     TEXT;
233     tmp_xml         TEXT;
234     xmlns_uri       TEXT := 'http://open-ils.org/spec/feed-xml/v1';
235     ouid            INT;
236     element_list    TEXT[];
237 BEGIN
238
239     IF org = '-' OR org IS NULL THEN
240         SELECT shortname INTO org FROM evergreen.org_top();
241     END IF;
242
243     SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
244     SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
245
246     IF layout.name IS NULL THEN
247         RETURN NULL::XML;
248     END IF;
249
250     SELECT * INTO transform FROM config.xml_transform WHERE name = layout.transform;
251     xmlns_uri := COALESCE(transform.namespace_uri,xmlns_uri);
252
253     -- Gather the bib xml
254     SELECT XMLAGG( unapi.bre(i, format, '', includes, org, depth, slimit, soffset, include_xmlns)) INTO tmp_xml FROM UNNEST( id_list ) i;
255
256     IF layout.title_element IS NOT NULL THEN
257         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.title_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, title;
258     END IF;
259
260     IF layout.description_element IS NOT NULL THEN
261         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.description_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, description;
262     END IF;
263
264     IF layout.creator_element IS NOT NULL THEN
265         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.creator_element ||', XMLATTRIBUTES( $1 AS xmlns), $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, creator;
266     END IF;
267
268     IF layout.update_ts_element IS NOT NULL THEN
269         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;
270     END IF;
271
272     IF unapi_url IS NOT NULL THEN
273         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;
274     END IF;
275
276     IF header_xml IS NOT NULL THEN tmp_xml := XMLCONCAT(header_xml,tmp_xml::XML); END IF;
277
278     element_list := regexp_split_to_array(layout.feed_top,E'\\.');
279     FOR i IN REVERSE ARRAY_UPPER(element_list, 1) .. 1 LOOP
280         EXECUTE 'SELECT XMLELEMENT( name '|| quote_ident(element_list[i]) ||', XMLATTRIBUTES( $1 AS xmlns), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML;
281     END LOOP;
282
283     RETURN tmp_xml::XML;
284 END;
285 $F$ LANGUAGE PLPGSQL STABLE;
286
287 CREATE OR REPLACE FUNCTION unapi.bre (
288     obj_id BIGINT,
289     format TEXT,
290     ename TEXT,
291     includes TEXT[],
292     org TEXT,
293     depth INT DEFAULT NULL,
294     slimit HSTORE DEFAULT NULL,
295     soffset HSTORE DEFAULT NULL,
296     include_xmlns BOOL DEFAULT TRUE,
297     pref_lib INT DEFAULT NULL
298 )
299 RETURNS XML AS $F$
300 DECLARE
301     me      biblio.record_entry%ROWTYPE;
302     layout  unapi.bre_output_layout%ROWTYPE;
303     xfrm    config.xml_transform%ROWTYPE;
304     ouid    INT;
305     tmp_xml TEXT;
306     top_el  TEXT;
307     output  XML;
308     hxml    XML;
309     axml    XML;
310 BEGIN
311
312     IF org = '-' OR org IS NULL THEN
313         SELECT shortname INTO org FROM evergreen.org_top();
314     END IF;
315
316     SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
317
318     IF ouid IS NULL THEN
319         RETURN NULL::XML;
320     END IF;
321
322     IF format = 'holdings_xml' THEN -- the special case
323         output := unapi.holdings_xml( obj_id, ouid, org, depth, includes, slimit, soffset, include_xmlns);
324         RETURN output;
325     END IF;
326
327     SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
328
329     IF layout.name IS NULL THEN
330         RETURN NULL::XML;
331     END IF;
332
333     SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
334
335     SELECT * INTO me FROM biblio.record_entry WHERE id = obj_id;
336
337     -- grab SVF if we need them
338     IF ('mra' = ANY (includes)) THEN 
339         axml := unapi.mra(obj_id,NULL,NULL,NULL,NULL);
340     ELSE
341         axml := NULL::XML;
342     END IF;
343
344     -- grab holdings if we need them
345     IF ('holdings_xml' = ANY (includes)) THEN 
346         hxml := unapi.holdings_xml(obj_id, ouid, org, depth, evergreen.array_remove_item_by_value(includes,'holdings_xml'), slimit, soffset, include_xmlns, pref_lib);
347     ELSE
348         hxml := NULL::XML;
349     END IF;
350
351
352     -- generate our item node
353
354
355     IF format = 'marcxml' THEN
356         tmp_xml := me.marc;
357         IF tmp_xml !~ E'<marc:' THEN -- If we're not using the prefixed namespace in this record, then remove all declarations of it
358            tmp_xml := REGEXP_REPLACE(tmp_xml, ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
359         END IF; 
360     ELSE
361         tmp_xml := oils_xslt_process(me.marc, xfrm.xslt)::XML;
362     END IF;
363
364     top_el := REGEXP_REPLACE(tmp_xml, E'^.*?<((?:\\S+:)?' || layout.holdings_element || ').*$', E'\\1');
365
366     IF axml IS NOT NULL THEN 
367         tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
368     END IF;
369
370     IF hxml IS NOT NULL THEN -- XXX how do we configure the holdings position?
371         tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
372     END IF;
373
374     IF ('bre.unapi' = ANY (includes)) THEN 
375         output := REGEXP_REPLACE(
376             tmp_xml,
377             '</' || top_el || '>(.*?)',
378             XMLELEMENT(
379                 name abbr,
380                 XMLATTRIBUTES(
381                     'http://www.w3.org/1999/xhtml' AS xmlns,
382                     'unapi-id' AS class,
383                     'tag:open-ils.org:U2@bre/' || obj_id || '/' || org AS title
384                 )
385             )::TEXT || '</' || top_el || E'>\\1'
386         );
387     ELSE
388         output := tmp_xml;
389     END IF;
390
391     output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
392     RETURN output;
393 END;
394 $F$ LANGUAGE PLPGSQL STABLE;
395
396 CREATE OR REPLACE FUNCTION unapi.holdings_xml (
397     bid BIGINT,
398     ouid INT,
399     org TEXT,
400     depth INT DEFAULT NULL,
401     includes TEXT[] DEFAULT NULL::TEXT[],
402     slimit HSTORE DEFAULT NULL,
403     soffset HSTORE DEFAULT NULL,
404     include_xmlns BOOL DEFAULT TRUE,
405     pref_lib INT DEFAULT NULL
406 )
407 RETURNS XML AS $F$
408      SELECT  XMLELEMENT(
409                  name holdings,
410                  XMLATTRIBUTES(
411                     CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
412                     CASE WHEN ('bre' = ANY ($5)) THEN 'tag:open-ils.org:U2@bre/' || $1 || '/' || $3 ELSE NULL END AS id,
413                     (SELECT record_has_holdable_copy FROM asset.record_has_holdable_copy($1)) AS has_holdable
414                  ),
415                  XMLELEMENT(
416                      name counts,
417                      (SELECT  XMLAGG(XMLELEMENT::XML) FROM (
418                          SELECT  XMLELEMENT(
419                                      name count,
420                                      XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
421                                  )::text
422                            FROM  asset.opac_ou_record_copy_count($2,  $1)
423                                      UNION
424                          SELECT  XMLELEMENT(
425                                      name count,
426                                      XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
427                                  )::text
428                            FROM  asset.staff_ou_record_copy_count($2, $1)
429                                      UNION
430                          SELECT  XMLELEMENT(
431                                      name count,
432                                      XMLATTRIBUTES('pref_lib' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
433                                  )::text
434                            FROM  asset.opac_ou_record_copy_count($9,  $1)
435                                      ORDER BY 1
436                      )x)
437                  ),
438                  CASE 
439                      WHEN ('bmp' = ANY ($5)) THEN
440                         XMLELEMENT(
441                             name monograph_parts,
442                             (SELECT XMLAGG(bmp) FROM (
443                                 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)
444                                   FROM  biblio.monograph_part
445                                   WHERE record = $1
446                             )x)
447                         )
448                      ELSE NULL
449                  END,
450                  XMLELEMENT(
451                      name volumes,
452                      (SELECT XMLAGG(acn ORDER BY rank, name, label_sortkey) FROM (
453                         -- Physical copies
454                         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
455                         FROM evergreen.ranked_volumes($1, $2, $4, $6, $7, $9) AS y
456                         UNION ALL
457                         -- Located URIs
458                         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), 0, name, label_sortkey
459                         FROM evergreen.located_uris($1, $2, $9) AS uris
460                      )x)
461                  ),
462                  CASE WHEN ('ssub' = ANY ($5)) THEN 
463                      XMLELEMENT(
464                          name subscriptions,
465                          (SELECT XMLAGG(ssub) FROM (
466                             SELECT  unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
467                               FROM  serial.subscription
468                               WHERE record_entry = $1
469                         )x)
470                      )
471                  ELSE NULL END,
472                  CASE WHEN ('acp' = ANY ($5)) THEN 
473                      XMLELEMENT(
474                          name foreign_copies,
475                          (SELECT XMLAGG(acp) FROM (
476                             SELECT  unapi.acp(p.target_copy,'xml','copy',evergreen.array_remove_item_by_value($5,'acp'), $3, $4, $6, $7, FALSE)
477                               FROM  biblio.peer_bib_copy_map p
478                                     JOIN asset.copy c ON (p.target_copy = c.id)
479                               WHERE NOT c.deleted AND p.peer_record = $1
480                             LIMIT ($6 -> 'acp')::INT
481                             OFFSET ($7 -> 'acp')::INT
482                         )x)
483                      )
484                  ELSE NULL END
485              );
486 $F$ LANGUAGE SQL STABLE;
487
488 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$
489         SELECT  XMLELEMENT(
490                     name subscription,
491                     XMLATTRIBUTES(
492                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
493                         'tag:open-ils.org:U2@ssub/' || id AS id,
494                         'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib,
495                         start_date AS start, end_date AS end, expected_date_offset
496                     ),
497                     CASE 
498                         WHEN ('sdist' = ANY ($4)) THEN
499                             XMLELEMENT( name distributions,
500                                 (SELECT XMLAGG(sdist) FROM (
501                                     SELECT  unapi.sdist( id, 'xml', 'distribution', evergreen.array_remove_item_by_value($4,'ssub'), $5, $6, $7, $8, FALSE)
502                                       FROM  serial.distribution
503                                       WHERE subscription = ssub.id
504                                 )x)
505                             )
506                         ELSE NULL
507                     END
508                 )
509           FROM  serial.subscription ssub
510           WHERE id = $1
511           GROUP BY id, start_date, end_date, expected_date_offset, owning_lib;
512 $F$ LANGUAGE SQL STABLE;
513
514 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$
515         SELECT  XMLELEMENT(
516                     name distribution,
517                     XMLATTRIBUTES(
518                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
519                         'tag:open-ils.org:U2@sdist/' || id AS id,
520                                 'tag:open-ils.org:U2@acn/' || receive_call_number AS receive_call_number,
521                                     'tag:open-ils.org:U2@acn/' || bind_call_number AS bind_call_number,
522                         unit_label_prefix, label, unit_label_suffix, summary_method
523                     ),
524                     unapi.aou( holding_lib, $2, 'holding_lib', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8),
525                     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,
526                     CASE 
527                         WHEN ('sstr' = ANY ($4)) THEN
528                             XMLELEMENT( name streams,
529                                 (SELECT XMLAGG(sstr) FROM (
530                                     SELECT  unapi.sstr( id, 'xml', 'stream', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE)
531                                       FROM  serial.stream
532                                       WHERE distribution = sdist.id
533                                 )x)
534                             )
535                         ELSE NULL
536                     END,
537                     XMLELEMENT( name summaries,
538                         CASE 
539                             WHEN ('sbsum' = ANY ($4)) THEN
540                                 (SELECT XMLAGG(sbsum) FROM (
541                                     SELECT  unapi.sbsum( id, 'xml', 'serial_summary', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE)
542                                       FROM  serial.basic_summary
543                                       WHERE distribution = sdist.id
544                                 )x)
545                             ELSE NULL
546                         END,
547                         CASE 
548                             WHEN ('sisum' = ANY ($4)) THEN
549                                 (SELECT XMLAGG(sisum) FROM (
550                                     SELECT  unapi.sisum( id, 'xml', 'serial_summary', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE)
551                                       FROM  serial.index_summary
552                                       WHERE distribution = sdist.id
553                                 )x)
554                             ELSE NULL
555                         END,
556                         CASE 
557                             WHEN ('sssum' = ANY ($4)) THEN
558                                 (SELECT XMLAGG(sssum) FROM (
559                                     SELECT  unapi.sssum( id, 'xml', 'serial_summary', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE)
560                                       FROM  serial.supplement_summary
561                                       WHERE distribution = sdist.id
562                                 )x)
563                             ELSE NULL
564                         END
565                     )
566                 )
567           FROM  serial.distribution sdist
568           WHERE id = $1
569           GROUP BY id, label, unit_label_prefix, unit_label_suffix, holding_lib, summary_method, subscription, receive_call_number, bind_call_number;
570 $F$ LANGUAGE SQL STABLE;
571
572 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$
573     SELECT  XMLELEMENT(
574                 name stream,
575                 XMLATTRIBUTES(
576                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
577                     'tag:open-ils.org:U2@sstr/' || id AS id,
578                     routing_label
579                 ),
580                 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,
581                 CASE 
582                     WHEN ('sitem' = ANY ($4)) THEN
583                         XMLELEMENT( name items,
584                             (SELECT XMLAGG(sitem) FROM (
585                                 SELECT  unapi.sitem( id, 'xml', 'serial_item', evergreen.array_remove_item_by_value($4,'sstr'), $5, $6, $7, $8, FALSE)
586                                   FROM  serial.item
587                                   WHERE stream = sstr.id
588                             )x)
589                         )
590                     ELSE NULL
591                 END
592             )
593       FROM  serial.stream sstr
594       WHERE id = $1
595       GROUP BY id, routing_label, distribution;
596 $F$ LANGUAGE SQL STABLE;
597
598 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$
599     SELECT  XMLELEMENT(
600                 name issuance,
601                 XMLATTRIBUTES(
602                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
603                     'tag:open-ils.org:U2@siss/' || id AS id,
604                     create_date, edit_date, label, date_published,
605                     holding_code, holding_type, holding_link_id
606                 ),
607                 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,
608                 CASE 
609                     WHEN ('sitem' = ANY ($4)) THEN
610                         XMLELEMENT( name items,
611                             (SELECT XMLAGG(sitem) FROM (
612                                 SELECT  unapi.sitem( id, 'xml', 'serial_item', evergreen.array_remove_item_by_value($4,'siss'), $5, $6, $7, $8, FALSE)
613                                   FROM  serial.item
614                                   WHERE issuance = sstr.id
615                             )x)
616                         )
617                     ELSE NULL
618                 END
619             )
620       FROM  serial.issuance sstr
621       WHERE id = $1
622       GROUP BY id, create_date, edit_date, label, date_published, holding_code, holding_type, holding_link_id, subscription;
623 $F$ LANGUAGE SQL STABLE;
624
625 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$
626         SELECT  XMLELEMENT(
627                     name serial_item,
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@sitem/' || id AS id,
631                         'tag:open-ils.org:U2@siss/' || issuance AS issuance,
632                         date_expected, date_received
633                     ),
634                     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,
635                     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,
636                     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,
637                     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
638 --                    XMLELEMENT( name notes,
639 --                        CASE 
640 --                            WHEN ('acpn' = ANY ($4)) THEN
641 --                                (SELECT XMLAGG(acpn) FROM (
642 --                                    SELECT  unapi.acpn( id, 'xml', 'copy_note', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8)
643 --                                      FROM  asset.copy_note
644 --                                      WHERE owning_copy = cp.id AND pub
645 --                                )x)
646 --                            ELSE NULL
647 --                        END
648 --                    )
649                 )
650           FROM  serial.item sitem
651           WHERE id = $1;
652 $F$ LANGUAGE SQL STABLE;
653
654
655 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$
656     SELECT  XMLELEMENT(
657                 name serial_summary,
658                 XMLATTRIBUTES(
659                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
660                     'tag:open-ils.org:U2@sbsum/' || id AS id,
661                     'sssum' AS type, generated_coverage, textual_holdings, show_generated
662                 ),
663                 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
664             )
665       FROM  serial.supplement_summary ssum
666       WHERE id = $1
667       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
668 $F$ LANGUAGE SQL STABLE;
669
670 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$
671     SELECT  XMLELEMENT(
672                 name serial_summary,
673                 XMLATTRIBUTES(
674                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
675                     'tag:open-ils.org:U2@sbsum/' || id AS id,
676                     'sbsum' AS type, generated_coverage, textual_holdings, show_generated
677                 ),
678                 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
679             )
680       FROM  serial.basic_summary ssum
681       WHERE id = $1
682       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
683 $F$ LANGUAGE SQL STABLE;
684
685 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$
686     SELECT  XMLELEMENT(
687                 name serial_summary,
688                 XMLATTRIBUTES(
689                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
690                     'tag:open-ils.org:U2@sbsum/' || id AS id,
691                     'sisum' AS type, generated_coverage, textual_holdings, show_generated
692                 ),
693                 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
694             )
695       FROM  serial.index_summary ssum
696       WHERE id = $1
697       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
698 $F$ LANGUAGE SQL STABLE;
699
700
701 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$
702 DECLARE
703     output XML;
704 BEGIN
705     IF ename = 'circlib' THEN
706         SELECT  XMLELEMENT(
707                     name circlib,
708                     XMLATTRIBUTES(
709                         'http://open-ils.org/spec/actors/v1' AS xmlns,
710                         id AS ident
711                     ),
712                     name
713                 ) INTO output
714           FROM  actor.org_unit aou
715           WHERE id = obj_id;
716     ELSE
717         EXECUTE $$SELECT  XMLELEMENT(
718                     name $$ || ename || $$,
719                     XMLATTRIBUTES(
720                         'http://open-ils.org/spec/actors/v1' AS xmlns,
721                         'tag:open-ils.org:U2@aou/' || id AS id,
722                         shortname, name, opac_visible
723                     )
724                 )
725           FROM  actor.org_unit aou
726          WHERE id = $1 $$ INTO output USING obj_id;
727     END IF;
728
729     RETURN output;
730
731 END;
732 $F$ LANGUAGE PLPGSQL STABLE;
733
734 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$
735     SELECT  XMLELEMENT(
736                 name location,
737                 XMLATTRIBUTES(
738                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
739                     id AS ident,
740                     holdable,
741                     opac_visible,
742                     label_prefix AS prefix,
743                     label_suffix AS suffix
744                 ),
745                 name
746             )
747       FROM  asset.copy_location
748       WHERE id = $1;
749 $F$ LANGUAGE SQL STABLE;
750
751 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$
752     SELECT  XMLELEMENT(
753                 name status,
754                 XMLATTRIBUTES(
755                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
756                     id AS ident,
757                     holdable,
758                     opac_visible
759                 ),
760                 name
761             )
762       FROM  config.copy_status
763       WHERE id = $1;
764 $F$ LANGUAGE SQL STABLE;
765
766 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$
767         SELECT  XMLELEMENT(
768                     name copy_note,
769                     XMLATTRIBUTES(
770                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
771                         create_date AS date,
772                         title
773                     ),
774                     value
775                 )
776           FROM  asset.copy_note
777           WHERE id = $1;
778 $F$ LANGUAGE SQL STABLE;
779
780 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$
781         SELECT  XMLELEMENT(
782                     name statcat,
783                     XMLATTRIBUTES(
784                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
785                         sc.name,
786                         sc.opac_visible
787                     ),
788                     asce.value
789                 )
790           FROM  asset.stat_cat_entry asce
791                 JOIN asset.stat_cat sc ON (sc.id = asce.stat_cat)
792           WHERE asce.id = $1;
793 $F$ LANGUAGE SQL STABLE;
794
795 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$
796         SELECT  XMLELEMENT(
797                     name monograph_part,
798                     XMLATTRIBUTES(
799                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
800                         'tag:open-ils.org:U2@bmp/' || id AS id,
801                         id AS ident,
802                         label,
803                         label_sortkey,
804                         'tag:open-ils.org:U2@bre/' || record AS record
805                     ),
806                     CASE 
807                         WHEN ('acp' = ANY ($4)) THEN
808                             XMLELEMENT( name copies,
809                                 (SELECT XMLAGG(acp) FROM (
810                                     SELECT  unapi.acp( cp.id, 'xml', 'copy', evergreen.array_remove_item_by_value($4,'bmp'), $5, $6, $7, $8, FALSE)
811                                       FROM  asset.copy cp
812                                             JOIN asset.copy_part_map cpm ON (cpm.target_copy = cp.id)
813                                       WHERE cpm.part = $1
814                                           AND cp.deleted IS FALSE
815                                       ORDER BY COALESCE(cp.copy_number,0), cp.barcode
816                                       LIMIT ($7 -> 'acp')::INT
817                                       OFFSET ($8 -> 'acp')::INT
818
819                                 )x)
820                             )
821                         ELSE NULL
822                     END,
823                     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
824                 )
825           FROM  biblio.monograph_part
826           WHERE id = $1
827           GROUP BY id, label, label_sortkey, record;
828 $F$ LANGUAGE SQL STABLE;
829
830 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$
831         SELECT  XMLELEMENT(
832                     name copy,
833                     XMLATTRIBUTES(
834                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
835                         'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id,
836                         create_date, edit_date, copy_number, circulate, deposit,
837                         ref, holdable, deleted, deposit_amount, price, barcode,
838                         circ_modifier, circ_as_type, opac_visible, age_protect
839                     ),
840                     unapi.ccs( status, $2, 'status', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE),
841                     unapi.acl( location, $2, 'location', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE),
842                     unapi.aou( circ_lib, $2, 'circ_lib', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8),
843                     unapi.aou( circ_lib, $2, 'circlib', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8),
844                     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,
845                     CASE 
846                         WHEN ('acpn' = ANY ($4)) THEN
847                             XMLELEMENT( name copy_notes,
848                                 (SELECT XMLAGG(acpn) FROM (
849                                     SELECT  unapi.acpn( id, 'xml', 'copy_note', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
850                                       FROM  asset.copy_note
851                                       WHERE owning_copy = cp.id AND pub
852                                 )x)
853                             )
854                         ELSE NULL
855                     END,
856                     CASE 
857                         WHEN ('ascecm' = ANY ($4)) THEN
858                             XMLELEMENT( name statcats,
859                                 (SELECT XMLAGG(ascecm) FROM (
860                                     SELECT  unapi.ascecm( stat_cat_entry, 'xml', 'statcat', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
861                                       FROM  asset.stat_cat_entry_copy_map
862                                       WHERE owning_copy = cp.id
863                                 )x)
864                             )
865                         ELSE NULL
866                     END,
867                     CASE
868                         WHEN ('bre' = ANY ($4)) THEN
869                             XMLELEMENT( name foreign_records,
870                                 (SELECT XMLAGG(bre) FROM (
871                                     SELECT  unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE)
872                                       FROM  biblio.peer_bib_copy_map
873                                       WHERE target_copy = cp.id
874                                 )x)
875
876                             )
877                         ELSE NULL
878                     END,
879                     CASE 
880                         WHEN ('bmp' = ANY ($4)) THEN
881                             XMLELEMENT( name monograph_parts,
882                                 (SELECT XMLAGG(bmp) FROM (
883                                     SELECT  unapi.bmp( part, 'xml', 'monograph_part', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
884                                       FROM  asset.copy_part_map
885                                       WHERE target_copy = cp.id
886                                 )x)
887                             )
888                         ELSE NULL
889                     END,
890                     CASE 
891                         WHEN ('circ' = ANY ($4)) THEN
892                             XMLELEMENT( name current_circulation,
893                                 (SELECT XMLAGG(circ) FROM (
894                                     SELECT  unapi.circ( id, 'xml', 'circ', evergreen.array_remove_item_by_value($4,'circ'), $5, $6, $7, $8, FALSE)
895                                       FROM  action.circulation
896                                       WHERE target_copy = cp.id
897                                             AND checkin_time IS NULL
898                                 )x)
899                             )
900                         ELSE NULL
901                     END
902                 )
903           FROM  asset.copy cp
904           WHERE id = $1
905               AND cp.deleted IS FALSE
906           GROUP BY id, status, location, circ_lib, call_number, create_date,
907               edit_date, copy_number, circulate, deposit, ref, holdable,
908               deleted, deposit_amount, price, barcode, circ_modifier,
909               circ_as_type, opac_visible, age_protect;
910 $F$ LANGUAGE SQL STABLE;
911
912 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$
913         SELECT  XMLELEMENT(
914                     name serial_unit,
915                     XMLATTRIBUTES(
916                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
917                         'tag:open-ils.org:U2@acp/' || id AS id, id AS copy_id,
918                         create_date, edit_date, copy_number, circulate, deposit,
919                         ref, holdable, deleted, deposit_amount, price, barcode,
920                         circ_modifier, circ_as_type, opac_visible, age_protect,
921                         status_changed_time, floating, mint_condition,
922                         detailed_contents, sort_key, summary_contents, cost 
923                     ),
924                     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),
925                     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),
926                     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),
927                     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),
928                     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,
929                     XMLELEMENT( name copy_notes,
930                         CASE 
931                             WHEN ('acpn' = ANY ($4)) THEN
932                                 (SELECT XMLAGG(acpn) FROM (
933                                     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)
934                                       FROM  asset.copy_note
935                                       WHERE owning_copy = cp.id AND pub
936                                 )x)
937                             ELSE NULL
938                         END
939                     ),
940                     XMLELEMENT( name statcats,
941                         CASE 
942                             WHEN ('ascecm' = ANY ($4)) THEN
943                                 (SELECT XMLAGG(ascecm) FROM (
944                                     SELECT  unapi.ascecm( stat_cat_entry, 'xml', 'statcat', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
945                                       FROM  asset.stat_cat_entry_copy_map
946                                       WHERE owning_copy = cp.id
947                                 )x)
948                             ELSE NULL
949                         END
950                     ),
951                     XMLELEMENT( name foreign_records,
952                         CASE
953                             WHEN ('bre' = ANY ($4)) THEN
954                                 (SELECT XMLAGG(bre) FROM (
955                                     SELECT  unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE)
956                                       FROM  biblio.peer_bib_copy_map
957                                       WHERE target_copy = cp.id
958                                 )x)
959                             ELSE NULL
960                         END
961                     ),
962                     CASE 
963                         WHEN ('bmp' = ANY ($4)) THEN
964                             XMLELEMENT( name monograph_parts,
965                                 (SELECT XMLAGG(bmp) FROM (
966                                     SELECT  unapi.bmp( part, 'xml', 'monograph_part', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE)
967                                       FROM  asset.copy_part_map
968                                       WHERE target_copy = cp.id
969                                 )x)
970                             )
971                         ELSE NULL
972                     END,
973                     CASE 
974                         WHEN ('circ' = ANY ($4)) THEN
975                             XMLELEMENT( name current_circulation,
976                                 (SELECT XMLAGG(circ) FROM (
977                                     SELECT  unapi.circ( id, 'xml', 'circ', evergreen.array_remove_item_by_value($4,'circ'), $5, $6, $7, $8, FALSE)
978                                       FROM  action.circulation
979                                       WHERE target_copy = cp.id
980                                             AND checkin_time IS NULL
981                                 )x)
982                             )
983                         ELSE NULL
984                     END
985                 )
986           FROM  serial.unit cp
987           WHERE id = $1
988               AND cp.deleted IS FALSE
989           GROUP BY id, status, location, circ_lib, call_number, create_date,
990               edit_date, copy_number, circulate, floating, mint_condition,
991               deposit, ref, holdable, deleted, deposit_amount, price,
992               barcode, circ_modifier, circ_as_type, opac_visible,
993               status_changed_time, detailed_contents, sort_key,
994               summary_contents, cost, age_protect;
995 $F$ LANGUAGE SQL STABLE;
996
997 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$
998         SELECT  XMLELEMENT(
999                     name volume,
1000                     XMLATTRIBUTES(
1001                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1002                         'tag:open-ils.org:U2@acn/' || acn.id AS id,
1003                         acn.id AS vol_id, o.shortname AS lib,
1004                         o.opac_visible AS opac_visible,
1005                         deleted, label, label_sortkey, label_class, record
1006                     ),
1007                     unapi.aou( owning_lib, $2, 'owning_lib', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8),
1008                     CASE 
1009                         WHEN ('acp' = ANY ($4)) THEN
1010                             CASE WHEN $6 IS NOT NULL THEN
1011                                 XMLELEMENT( name copies,
1012                                     (SELECT XMLAGG(acp ORDER BY rank_avail) FROM (
1013                                         SELECT  unapi.acp( cp.id, 'xml', 'copy', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE),
1014                                             evergreen.rank_cp_status(cp.status) AS rank_avail
1015                                           FROM  asset.copy cp
1016                                                 JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5), $6) aoud ON (cp.circ_lib = aoud.id)
1017                                           WHERE cp.call_number = acn.id
1018                                               AND cp.deleted IS FALSE
1019                                           ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode
1020                                           LIMIT ($7 -> 'acp')::INT
1021                                           OFFSET ($8 -> 'acp')::INT
1022                                     )x)
1023                                 )
1024                             ELSE
1025                                 XMLELEMENT( name copies,
1026                                     (SELECT XMLAGG(acp ORDER BY rank_avail) FROM (
1027                                         SELECT  unapi.acp( cp.id, 'xml', 'copy', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE),
1028                                             evergreen.rank_cp_status(cp.status) AS rank_avail
1029                                           FROM  asset.copy cp
1030                                                 JOIN actor.org_unit_descendants( (SELECT id FROM actor.org_unit WHERE shortname = $5) ) aoud ON (cp.circ_lib = aoud.id)
1031                                           WHERE cp.call_number = acn.id
1032                                               AND cp.deleted IS FALSE
1033                                           ORDER BY rank_avail, COALESCE(cp.copy_number,0), cp.barcode
1034                                           LIMIT ($7 -> 'acp')::INT
1035                                           OFFSET ($8 -> 'acp')::INT
1036                                     )x)
1037                                 )
1038                             END
1039                         ELSE NULL
1040                     END,
1041                     XMLELEMENT(
1042                         name uris,
1043                         (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)
1044                     ),
1045                     unapi.acnp( acn.prefix, 'marcxml', 'prefix', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE),
1046                     unapi.acns( acn.suffix, 'marcxml', 'suffix', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE),
1047                     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
1048                 ) AS x
1049           FROM  asset.call_number acn
1050                 JOIN actor.org_unit o ON (o.id = acn.owning_lib)
1051           WHERE acn.id = $1
1052               AND acn.deleted IS FALSE
1053           GROUP BY acn.id, o.shortname, o.opac_visible, deleted, label, label_sortkey, label_class, owning_lib, record, acn.prefix, acn.suffix;
1054 $F$ LANGUAGE SQL STABLE;
1055
1056 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$
1057         SELECT  XMLELEMENT(
1058                     name call_number_prefix,
1059                     XMLATTRIBUTES(
1060                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1061                         id AS ident,
1062                         label,
1063                         'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib,
1064                         label_sortkey
1065                     )
1066                 )
1067           FROM  asset.call_number_prefix
1068           WHERE id = $1;
1069 $F$ LANGUAGE SQL STABLE;
1070
1071 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$
1072         SELECT  XMLELEMENT(
1073                     name call_number_suffix,
1074                     XMLATTRIBUTES(
1075                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1076                         id AS ident,
1077                         label,
1078                         'tag:open-ils.org:U2@aou/' || owning_lib AS owning_lib,
1079                         label_sortkey
1080                     )
1081                 )
1082           FROM  asset.call_number_suffix
1083           WHERE id = $1;
1084 $F$ LANGUAGE SQL STABLE;
1085
1086 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$
1087         SELECT  XMLELEMENT(
1088                     name uri,
1089                     XMLATTRIBUTES(
1090                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1091                         'tag:open-ils.org:U2@auri/' || uri.id AS id,
1092                         use_restriction,
1093                         href,
1094                         label
1095                     ),
1096                     CASE 
1097                         WHEN ('acn' = ANY ($4)) THEN
1098                             XMLELEMENT( name copies,
1099                                 (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)
1100                             )
1101                         ELSE NULL
1102                     END
1103                 ) AS x
1104           FROM  asset.uri uri
1105           WHERE uri.id = $1
1106           GROUP BY uri.id, use_restriction, href, label;
1107 $F$ LANGUAGE SQL STABLE;
1108
1109 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$
1110         SELECT  XMLELEMENT(
1111                     name attributes,
1112                     XMLATTRIBUTES(
1113                         CASE WHEN $9 THEN 'http://open-ils.org/spec/indexing/v1' ELSE NULL END AS xmlns,
1114                         'tag:open-ils.org:U2@mra/' || mra.id AS id,
1115                         'tag:open-ils.org:U2@bre/' || mra.id AS record
1116                     ),
1117                     (SELECT XMLAGG(foo.y)
1118                       FROM (SELECT XMLELEMENT(
1119                                 name field,
1120                                 XMLATTRIBUTES(
1121                                     key AS name,
1122                                     cvm.value AS "coded-value",
1123                                     rad.filter,
1124                                     rad.sorter
1125                                 ),
1126                                 x.value
1127                             )
1128                            FROM EACH(mra.attrs) AS x
1129                                 JOIN config.record_attr_definition rad ON (x.key = rad.name)
1130                                 LEFT JOIN config.coded_value_map cvm ON (cvm.ctype = x.key AND code = x.value)
1131                         )foo(y)
1132                     )
1133                 )
1134           FROM  metabib.record_attr mra
1135           WHERE mra.id = $1;
1136 $F$ LANGUAGE SQL STABLE;
1137
1138 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$
1139     SELECT XMLELEMENT(
1140         name circ,
1141         XMLATTRIBUTES(
1142             CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
1143             'tag:open-ils.org:U2@circ/' || id AS id,
1144             xact_start,
1145             due_date
1146         ),
1147         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,
1148         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
1149     )
1150     FROM action.circulation
1151     WHERE id = $1;
1152 $F$ LANGUAGE SQL STABLE;
1153
1154 /*
1155
1156  -- Some test queries
1157
1158 SELECT unapi.memoize( 'bre', 1,'mods32','','{holdings_xml,acp}'::TEXT[], 'SYS1');
1159 SELECT unapi.memoize( 'bre', 1,'marcxml','','{holdings_xml,acp}'::TEXT[], 'SYS1');
1160 SELECT unapi.memoize( 'bre', 1,'holdings_xml','','{holdings_xml,acp}'::TEXT[], 'SYS1');
1161
1162 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>');
1163
1164 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>');
1165 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>');
1166 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>');
1167 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>');
1168
1169 SELECT unapi.biblio_record_entry_feed('{216}'::BIGINT[],'marcxml','{}'::TEXT[], 'BR1');
1170 EXPLAIN ANALYZE SELECT unapi.bre(216,'marcxml','record','{holdings_xml,bre.unapi}'::TEXT[], 'BR1');
1171 EXPLAIN ANALYZE SELECT unapi.bre(216,'holdings_xml','record','{}'::TEXT[], 'BR1');
1172 EXPLAIN ANALYZE SELECT unapi.holdings_xml(216,4,'BR1',2,'{bre}'::TEXT[]);
1173 EXPLAIN ANALYZE SELECT unapi.bre(216,'mods32','record','{}'::TEXT[], 'BR1');
1174
1175 -- Limit to 5 call numbers, 5 copies, with a preferred library of 4 (BR1), in SYS2 at a depth of 0
1176 EXPLAIN ANALYZE SELECT unapi.bre(36,'marcxml','record','{holdings_xml,mra,acp,acnp,acns,bmp}','SYS2',0,'acn=>5,acp=>5',NULL,TRUE,4);
1177
1178 */
1179
1180 COMMIT;