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