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