]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/sql/Pg/upgrade/0507.schema.unapi-rewrite.sql
LP#1759238: stamping upgrade script
[Evergreen.git] / Open-ILS / src / sql / Pg / upgrade / 0507.schema.unapi-rewrite.sql
1 DROP SCHEMA IF EXISTS unapi CASCADE;
2
3 BEGIN;
4
5 INSERT INTO config.upgrade_log (version) VALUES ('0507'); --miker
6
7 CREATE SCHEMA unapi;
8
9 CREATE OR REPLACE FUNCTION array_remove_item_by_value(inp ANYARRAY, el ANYELEMENT) RETURNS anyarray AS $$ SELECT ARRAY_ACCUM(x.e) FROM UNNEST( $1 ) x(e) WHERE x.e <> $2; $$ LANGUAGE SQL;
10
11 CREATE TABLE unapi.bre_output_layout (
12     name                TEXT    PRIMARY KEY,
13     transform           TEXT    REFERENCES config.xml_transform (name) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
14     mime_type           TEXT    NOT NULL,
15     feed_top            TEXT    NOT NULL,
16     holdings_element    TEXT,
17     title_element       TEXT,
18     description_element TEXT,
19     creator_element     TEXT,
20     update_ts_element   TEXT
21 );
22
23 INSERT INTO unapi.bre_output_layout
24     (name,           transform, mime_type,              holdings_element, feed_top,         title_element, description_element, creator_element, update_ts_element)
25         VALUES
26     ('holdings_xml', NULL,      'application/xml',      NULL,             'hxml',           NULL,          NULL,                NULL,            NULL),
27     ('marcxml',      'marcxml', 'application/marc+xml', 'record',         'collection',     NULL,          NULL,                NULL,            NULL),
28     ('mods32',       'mods32',  'application/mods+xml', 'mods',           'modsCollection', NULL,          NULL,                NULL,            NULL)
29 ;
30
31 -- Dummy functions, so we can create the real ones out of order
32 CREATE OR REPLACE FUNCTION unapi.aou    ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
33 CREATE OR REPLACE FUNCTION unapi.acnp   ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
34 CREATE OR REPLACE FUNCTION unapi.acns   ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
35 CREATE OR REPLACE FUNCTION unapi.acn    ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
36 CREATE OR REPLACE FUNCTION unapi.ssub   ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
37 CREATE OR REPLACE FUNCTION unapi.sdist  ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
38 CREATE OR REPLACE FUNCTION unapi.sstr   ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
39 CREATE OR REPLACE FUNCTION unapi.sitem  ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
40 CREATE OR REPLACE FUNCTION unapi.sunit  ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
41 CREATE OR REPLACE FUNCTION unapi.sisum  ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
42 CREATE OR REPLACE FUNCTION unapi.sbsum  ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
43 CREATE OR REPLACE FUNCTION unapi.sssum  ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
44 CREATE OR REPLACE FUNCTION unapi.siss   ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
45 CREATE OR REPLACE FUNCTION unapi.auri   ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
46 CREATE OR REPLACE FUNCTION unapi.acp    ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
47 CREATE OR REPLACE FUNCTION unapi.acpn   ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
48 CREATE OR REPLACE FUNCTION unapi.acl    ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
49 CREATE OR REPLACE FUNCTION unapi.ccs    ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
50 CREATE OR REPLACE FUNCTION unapi.ascecm ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
51 CREATE OR REPLACE FUNCTION unapi.bre    ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
52 CREATE OR REPLACE FUNCTION unapi.bmp    ( obj_id BIGINT, format TEXT, ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
53
54 CREATE OR REPLACE FUNCTION unapi.holdings_xml ( bid BIGINT, ouid INT, org TEXT, depth INT DEFAULT NULL, includes TEXT[] DEFAULT NULL::TEXT[], slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE) RETURNS XML AS $F$ SELECT NULL::XML $F$ LANGUAGE SQL;
55 CREATE OR REPLACE FUNCTION unapi.biblio_record_entry_feed ( id_list BIGINT[], format TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT 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;
56
57 CREATE OR REPLACE FUNCTION unapi.memoize (classname TEXT, obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
58 DECLARE
59     key     TEXT;
60     output  XML;
61 BEGIN
62     key :=
63         'id'        || COALESCE(obj_id::TEXT,'') ||
64         'format'    || COALESCE(format::TEXT,'') ||
65         'ename'     || COALESCE(ename::TEXT,'') ||
66         'includes'  || COALESCE(includes::TEXT,'{}'::TEXT[]::TEXT) ||
67         'org'       || COALESCE(org::TEXT,'') ||
68         'depth'     || COALESCE(depth::TEXT,'') ||
69         'slimit'    || COALESCE(slimit::TEXT,'') ||
70         'soffset'   || COALESCE(soffset::TEXT,'') ||
71         'include_xmlns'   || COALESCE(include_xmlns::TEXT,'');
72     -- RAISE NOTICE 'memoize key: %', key;
73
74     key := MD5(key);
75     -- RAISE NOTICE 'memoize hash: %', key;
76
77     -- XXX cache logic ... memcached? table?
78
79     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;
80     RETURN output;
81 END;
82 $F$ LANGUAGE PLPGSQL;
83
84 CREATE OR REPLACE FUNCTION unapi.biblio_record_entry_feed ( id_list BIGINT[], format TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT 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$
85 DECLARE
86     layout          unapi.bre_output_layout%ROWTYPE;
87     transform       config.xml_transform%ROWTYPE;
88     item_format     TEXT;
89     tmp_xml         TEXT;
90     xmlns_uri       TEXT := 'http://open-ils.org/spec/feed-xml/v1';
91     ouid            INT;
92     element_list    TEXT[];
93 BEGIN
94
95     SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
96     SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
97
98     IF layout.name IS NULL THEN
99         RETURN NULL::XML;
100     END IF;
101
102     SELECT * INTO transform FROM config.xml_transform WHERE name = layout.transform;
103     xmlns_uri := COALESCE(transform.namespace_uri,xmlns_uri);
104
105     -- Gather the bib xml
106     SELECT XMLAGG( unapi.bre(i, format, '', includes, org, depth, slimit, soffset, include_xmlns)) INTO tmp_xml FROM UNNEST( id_list ) i;
107
108     IF layout.title_element IS NOT NULL THEN
109         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.title_element ||', CASE WHEN $4 THEN XMLATTRIBUTES( $1 AS xmlns) ELSE NULL END, $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, title, include_xmlns;
110     END IF;
111
112     IF layout.description_element IS NOT NULL THEN
113         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.description_element ||', CASE WHEN $4 THEN XMLATTRIBUTES( $1 AS xmlns) ELSE NULL END, $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, description, include_xmlns;
114     END IF;
115
116     IF layout.creator_element IS NOT NULL THEN
117         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.creator_element ||', CASE WHEN $4 THEN XMLATTRIBUTES( $1 AS xmlns) ELSE NULL END, $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, creator, include_xmlns;
118     END IF;
119
120     IF layout.update_ts_element IS NOT NULL THEN
121         EXECUTE 'SELECT XMLCONCAT( XMLELEMENT( name '|| layout.update_ts_element ||', CASE WHEN $4 THEN XMLATTRIBUTES( $1 AS xmlns) ELSE NULL END, $3), $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, update_ts, include_xmlns;
122     END IF;
123
124     IF unapi_url IS NOT NULL THEN
125         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;
126     END IF;
127
128     IF header_xml IS NOT NULL THEN tmp_xml := XMLCONCAT(header_xml,tmp_xml::XML); END IF;
129
130     element_list := regexp_split_to_array(layout.feed_top,E'\\.');
131     FOR i IN REVERSE ARRAY_UPPER(element_list, 1) .. 1 LOOP
132         EXECUTE 'SELECT XMLELEMENT( name '|| quote_ident(element_list[i]) ||', CASE WHEN $4 THEN XMLATTRIBUTES( $1 AS xmlns) ELSE NULL END, $2)' INTO tmp_xml USING xmlns_uri, tmp_xml::XML, include_xmlns;
133     END LOOP;
134
135     RETURN tmp_xml::XML;
136 END;
137 $F$ LANGUAGE PLPGSQL;
138
139 CREATE OR REPLACE FUNCTION unapi.bre ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
140 DECLARE
141     me      biblio.record_entry%ROWTYPE;
142     layout  unapi.bre_output_layout%ROWTYPE;
143     xfrm    config.xml_transform%ROWTYPE;
144     ouid    INT;
145     tmp_xml TEXT;
146     top_el  TEXT;
147     output  XML;
148     hxml    XML;
149 BEGIN
150
151     SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
152
153     IF ouid IS NULL THEN
154         RETURN NULL::XML;
155     END IF;
156
157     IF format = 'holdings_xml' THEN -- the special case
158         output := unapi.holdings_xml( obj_id, ouid, org, depth, includes, slimit, soffset, include_xmlns);
159         RETURN output;
160     END IF;
161
162     SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
163
164     IF layout.name IS NULL THEN
165         RETURN NULL::XML;
166     END IF;
167
168     SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
169
170     SELECT * INTO me FROM biblio.record_entry WHERE id = obj_id;
171
172     -- grab hodlings if we need them
173     IF ('holdings_xml' = ANY (includes)) THEN 
174         hxml := unapi.holdings_xml(obj_id, ouid, org, depth, array_remove_item_by_value(includes,'holdings_xml'), slimit, soffset, include_xmlns);
175     ELSE
176         hxml := NULL::XML;
177     END IF;
178
179
180     -- generate our item node
181
182
183     IF format = 'marcxml' THEN
184         tmp_xml := me.marc;
185         IF tmp_xml !~ E'<marc:' THEN -- If we're not using the prefixed namespace in this record, then remove all declarations of it
186            tmp_xml := REGEXP_REPLACE(tmp_xml, ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
187         END IF; 
188     ELSE
189         tmp_xml := oils_xslt_process(me.marc, xfrm.xslt)::XML;
190     END IF;
191
192     top_el := REGEXP_REPLACE(tmp_xml, E'^.*?<((?:\\S+:)?' || layout.holdings_element || ').*$', E'\\1');
193
194     IF hxml IS NOT NULL THEN -- XXX how do we configure the holdings position?
195         tmp_xml := REGEXP_REPLACE(tmp_xml, '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
196     END IF;
197
198     IF ('bre.unapi' = ANY (includes)) THEN 
199         output := REGEXP_REPLACE(
200             tmp_xml,
201             '</' || top_el || '>(.*?)',
202             XMLELEMENT(
203                 name abbr,
204                 XMLATTRIBUTES(
205                     'http://www.w3.org/1999/xhtml' AS xmlns,
206                     'unapi-id' AS class,
207                     'tag:open-ils.org:U2@bre/' || obj_id || '/' || org AS title
208                 )
209             )::TEXT || '</' || top_el || E'>\\1'
210         );
211     ELSE
212         output := tmp_xml;
213     END IF;
214
215     RETURN output;
216 END;
217 $F$ LANGUAGE PLPGSQL;
218
219 CREATE OR REPLACE FUNCTION unapi.holdings_xml (bid BIGINT, ouid INT, org TEXT, depth INT DEFAULT NULL, includes TEXT[] DEFAULT NULL::TEXT[], slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE) RETURNS XML AS $F$
220      SELECT  XMLELEMENT(
221                  name holdings,
222                  XMLATTRIBUTES(
223                     CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
224                     CASE WHEN ('bre' = ANY ('{acn,auri}'::TEXT[] || $5)) THEN 'tag:open-ils.org:U2@bre/' || $1 || '/' || $3 ELSE NULL END AS id
225                  ),
226                  XMLELEMENT(
227                      name counts,
228                      (SELECT  XMLAGG(XMLELEMENT::XML) FROM (
229                          SELECT  XMLELEMENT(
230                                      name count,
231                                      XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
232                                  )::text
233                            FROM  asset.opac_ou_record_copy_count($2,  $1)
234                                      UNION
235                          SELECT  XMLELEMENT(
236                                      name count,
237                                      XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
238                                  )::text
239                            FROM  asset.staff_ou_record_copy_count($2, $1)
240                                      ORDER BY 1
241                      )x)
242                  ),
243                  CASE 
244                      WHEN ('bmp' = ANY ($5)) THEN
245                         XMLELEMENT( name monograph_parts,
246                             XMLAGG((SELECT unapi.bmp( id, 'xml', 'monograph_part', array_remove_item_by_value( array_remove_item_by_value($5,'bre'), 'holdings_xml'), $3, $4, $6, $7, FALSE) FROM biblio.monograph_part WHERE record = $1))
247                         )
248                      ELSE NULL
249                  END,
250                  CASE WHEN ('acn' = ANY ('{acn,auri}'::TEXT[] || $5)) THEN 
251                      XMLELEMENT(
252                          name volumes,
253                          (SELECT XMLAGG(acn) FROM (
254                             SELECT  unapi.acn(acn.id,'xml','volume',array_remove_item_by_value(array_remove_item_by_value('{acn,auri}'::TEXT[] || $5,'holdings_xml'),'bre'), $3, $4, $6, $7, FALSE)
255                               FROM  asset.call_number acn
256                               WHERE acn.record = $1
257                                     AND EXISTS (
258                                         SELECT  1
259                                           FROM  asset.copy acp
260                                                 JOIN actor.org_unit_descendants(
261                                                     $2,
262                                                     (COALESCE(
263                                                         $4,
264                                                         (SELECT aout.depth
265                                                           FROM  actor.org_unit_type aout
266                                                                 JOIN actor.org_unit aou ON (aou.ou_type = aout.id AND aou.id = $2)
267                                                         )
268                                                     ))
269                                                 ) aoud ON (acp.circ_lib = aoud.id)
270                                           LIMIT 1
271                                     )
272                               ORDER BY label_sortkey
273                               LIMIT $6
274                               OFFSET $7
275                          )x)
276                      )
277                  ELSE NULL END,
278                  CASE WHEN ('ssub' = ANY ('{acn,auri}'::TEXT[] || $5)) THEN 
279                      XMLELEMENT(
280                          name subscriptions,
281                          (SELECT XMLAGG(ssub) FROM (
282                             SELECT  unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
283                               FROM  serial.subscription
284                               WHERE record_entry = $1
285                         )x)
286                      )
287                  ELSE NULL END
288              );
289 $F$ LANGUAGE SQL;
290
291 CREATE OR REPLACE FUNCTION unapi.ssub ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
292         SELECT  XMLELEMENT(
293                     name subscription,
294                     XMLATTRIBUTES(
295                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
296                         'tag:open-ils.org:U2@ssub/' || id AS id,
297                         start_date AS start, end_date AS end, expected_date_offset
298                     ),
299                     unapi.aou( owning_lib, $2, 'owning_lib', array_remove_item_by_value($4,'ssub'), $5, $6, $7, $8),
300                     XMLELEMENT( name distributions,
301                         CASE 
302                             WHEN ('sdist' = ANY ($4)) THEN
303                                 XMLAGG((SELECT unapi.sdist( id, 'xml', 'distribution', array_remove_item_by_value($4,'ssub'), $5, $6, $7, $8, FALSE) FROM serial.distribution WHERE subscription = ssub.id))
304                             ELSE NULL
305                         END
306                     )
307                 )
308           FROM  serial.subscription ssub
309           WHERE id = $1
310           GROUP BY id, start_date, end_date, expected_date_offset, owning_lib;
311 $F$ LANGUAGE SQL;
312
313 CREATE OR REPLACE FUNCTION unapi.sdist ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
314         SELECT  XMLELEMENT(
315                     name distribution,
316                     XMLATTRIBUTES(
317                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
318                         'tag:open-ils.org:U2@sdist/' || id AS id,
319                         'tag:open-ils.org:U2@acn/' || receive_call_number AS receive_call_number,
320                         'tag:open-ils.org:U2@acn/' || bind_call_number AS bind_call_number,
321                         unit_label_prefix, label, unit_label_suffix, summary_method
322                     ),
323                     unapi.aou( holding_lib, $2, 'holding_lib', array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8),
324                     CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE) ELSE NULL END,
325                     XMLELEMENT( name streams,
326                         CASE 
327                             WHEN ('sstr' = ANY ($4)) THEN
328                                 XMLAGG((SELECT unapi.sstr( id, 'xml', 'stream', array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE) FROM serial.stream WHERE distribution = sdist.id))
329                             ELSE NULL
330                         END
331                     ),
332                     XMLELEMENT( name summaries,
333                         CASE 
334                             WHEN ('ssum' = ANY ($4)) THEN
335                                 XMLAGG((SELECT unapi.sbsum( id, 'xml', 'serial_summary', array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE) FROM serial.basic_summary WHERE distribution = sdist.id))
336                             ELSE NULL
337                         END,
338                         CASE 
339                             WHEN ('ssum' = ANY ($4)) THEN
340                                 XMLAGG((SELECT unapi.sisum( id, 'xml', 'serial_summary', array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE) FROM serial.index_summary WHERE distribution = sdist.id))
341                             ELSE NULL
342                         END,
343                         CASE 
344                             WHEN ('ssum' = ANY ($4)) THEN
345                                 XMLAGG((SELECT unapi.sssum( id, 'xml', 'serial_summary', array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8, FALSE) FROM serial.supplement_summary WHERE distribution = sdist.id))
346                             ELSE NULL
347                         END
348                     )
349                 )
350           FROM  serial.distribution sdist
351           WHERE id = $1
352           GROUP BY id, label, unit_label_prefix, unit_label_suffix, holding_lib, summary_method, subscription, receive_call_number, bind_call_number;
353 $F$ LANGUAGE SQL;
354
355 CREATE OR REPLACE FUNCTION unapi.sstr ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
356     SELECT  XMLELEMENT(
357                 name stream,
358                 XMLATTRIBUTES(
359                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
360                     'tag:open-ils.org:U2@sstr/' || id AS id,
361                     routing_label
362                 ),
363                 CASE WHEN distribution IS NOT NULL AND ('sdist' = ANY ($4)) THEN unapi.sssum( distribution, 'xml', 'distribtion', array_remove_item_by_value($4,'sstr'), $5, $6, $7, $8, FALSE) ELSE NULL END,
364                 XMLELEMENT( name items,
365                     CASE 
366                         WHEN ('sitem' = ANY ($4)) THEN
367                             XMLAGG((SELECT unapi.sitem( id, 'xml', 'serial_item', array_remove_item_by_value($4,'sstr'), $5, $6, $7, $8, FALSE) FROM serial.item WHERE stream = sstr.id))
368                         ELSE NULL
369                     END
370                 )
371             )
372       FROM  serial.stream sstr
373       WHERE id = $1
374       GROUP BY id, routing_label, distribution;
375 $F$ LANGUAGE SQL;
376
377 CREATE OR REPLACE FUNCTION unapi.siss ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
378     SELECT  XMLELEMENT(
379                 name issuance,
380                 XMLATTRIBUTES(
381                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
382                     'tag:open-ils.org:U2@siss/' || id AS id,
383                     create_date, edit_date, label, date_published,
384                     holding_code, holding_type, holding_link_id
385                 ),
386                 CASE WHEN subscription IS NOT NULL AND ('ssub' = ANY ($4)) THEN unapi.ssub( subscription, 'xml', 'subscription', array_remove_item_by_value($4,'siss'), $5, $6, $7, $8, FALSE) ELSE NULL END,
387                 XMLELEMENT( name items,
388                     CASE 
389                         WHEN ('sitem' = ANY ($4)) THEN
390                             XMLAGG((SELECT unapi.sitem( id, 'xml', 'serial_item', array_remove_item_by_value($4,'siss'), $5, $6, $7, $8, FALSE) FROM serial.item WHERE issuance = sstr.id))
391                         ELSE NULL
392                     END
393                 )
394             )
395       FROM  serial.issuance sstr
396       WHERE id = $1
397       GROUP BY id, create_date, edit_date, label, date_published, holding_code, holding_type, holding_link_id, subscription;
398 $F$ LANGUAGE SQL;
399
400 CREATE OR REPLACE FUNCTION unapi.sitem ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
401         SELECT  XMLELEMENT(
402                     name serial_item,
403                     XMLATTRIBUTES(
404                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
405                         'tag:open-ils.org:U2@sitem/' || id AS id,
406                         'tag:open-ils.org:U2@siss/' || issuance AS issuance,
407                         date_expected, date_received
408                     ),
409                     CASE WHEN issuance IS NOT NULL AND ('siss' = ANY ($4)) THEN unapi.siss( issuance, $2, 'issuance', array_remove_item_by_value($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
410                     CASE WHEN stream IS NOT NULL AND ('sstr' = ANY ($4)) THEN unapi.sstr( stream, $2, 'stream', array_remove_item_by_value($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
411                     CASE WHEN unit IS NOT NULL AND ('sunit' = ANY ($4)) THEN unapi.sunit( stream, $2, 'serial_unit', array_remove_item_by_value($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END,
412                     CASE WHEN uri IS NOT NULL AND ('auri' = ANY ($4)) THEN unapi.auri( uri, $2, 'uri', array_remove_item_by_value($4,'sitem'), $5, $6, $7, $8, FALSE) ELSE NULL END
413 --                    XMLELEMENT( name notes,
414 --                        CASE 
415 --                            WHEN ('acpn' = ANY ($4)) THEN
416 --                                XMLAGG((SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8) FROM asset.copy_note WHERE owning_copy = cp.id AND pub))
417 --                            ELSE NULL
418 --                        END
419 --                    )
420                 )
421           FROM  serial.item sitem
422           WHERE id = $1;
423 $F$ LANGUAGE SQL;
424
425
426 CREATE OR REPLACE FUNCTION unapi.sssum ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
427     SELECT  XMLELEMENT(
428                 name serial_summary,
429                 XMLATTRIBUTES(
430                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
431                     'tag:open-ils.org:U2@sbsum/' || id AS id,
432                     'sssum' AS type, generated_coverage, textual_holdings, show_generated
433                 ),
434                 CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove_item_by_value($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
435             )
436       FROM  serial.supplement_summary ssum
437       WHERE id = $1
438       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
439 $F$ LANGUAGE SQL;
440
441 CREATE OR REPLACE FUNCTION unapi.sbsum ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
442     SELECT  XMLELEMENT(
443                 name serial_summary,
444                 XMLATTRIBUTES(
445                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
446                     'tag:open-ils.org:U2@sbsum/' || id AS id,
447                     'sbsum' AS type, generated_coverage, textual_holdings, show_generated
448                 ),
449                 CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove_item_by_value($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
450             )
451       FROM  serial.basic_summary ssum
452       WHERE id = $1
453       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
454 $F$ LANGUAGE SQL;
455
456 CREATE OR REPLACE FUNCTION unapi.sisum ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
457     SELECT  XMLELEMENT(
458                 name serial_summary,
459                 XMLATTRIBUTES(
460                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
461                     'tag:open-ils.org:U2@sbsum/' || id AS id,
462                     'sisum' AS type, generated_coverage, textual_holdings, show_generated
463                 ),
464                 CASE WHEN ('sdist' = ANY ($4)) THEN unapi.sdist( distribution, 'xml', 'distribtion', array_remove_item_by_value($4,'ssum'), $5, $6, $7, $8, FALSE) ELSE NULL END
465             )
466       FROM  serial.index_summary ssum
467       WHERE id = $1
468       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
469 $F$ LANGUAGE SQL;
470
471
472 CREATE OR REPLACE FUNCTION unapi.aou ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
473 DECLARE
474     output XML;
475 BEGIN
476     IF ename = 'circlib' THEN
477         SELECT  XMLELEMENT(
478                     name circlib,
479                     XMLATTRIBUTES(
480                         'http://open-ils.org/spec/actors/v1' AS xmlns,
481                         id AS ident
482                     ),
483                     name
484                 ) INTO output
485           FROM  actor.org_unit aou
486           WHERE id = obj_id;
487     ELSE
488         EXECUTE $$SELECT  XMLELEMENT(
489                     name $$ || ename || $$,
490                     XMLATTRIBUTES(
491                         'http://open-ils.org/spec/actors/v1' AS xmlns,
492                         'tag:open-ils.org:U2@aou/' || id AS id,
493                         shortname, name, opac_visible
494                     )
495                 )
496           FROM  actor.org_unit aou
497          WHERE id = $1 $$ INTO output USING obj_id;
498     END IF;
499
500     RETURN output;
501
502 END;
503 $F$ LANGUAGE PLPGSQL;
504
505 CREATE OR REPLACE FUNCTION unapi.acl ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
506     SELECT  XMLELEMENT(
507                 name location,
508                 XMLATTRIBUTES(
509                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
510                     id AS ident
511                 ),
512                 name
513             )
514       FROM  asset.copy_location
515       WHERE id = $1;
516 $F$ LANGUAGE SQL;
517
518 CREATE OR REPLACE FUNCTION unapi.ccs ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
519     SELECT  XMLELEMENT(
520                 name status,
521                 XMLATTRIBUTES(
522                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
523                     id AS ident
524                 ),
525                 name
526             )
527       FROM  config.copy_status
528       WHERE id = $1;
529 $F$ LANGUAGE SQL;
530
531 CREATE OR REPLACE FUNCTION unapi.acpn ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
532         SELECT  XMLELEMENT(
533                     name copy_note,
534                     XMLATTRIBUTES(
535                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
536                         create_date AS date,
537                         title
538                     ),
539                     value
540                 )
541           FROM  asset.copy_note
542           WHERE id = $1;
543 $F$ LANGUAGE SQL;
544
545 CREATE OR REPLACE FUNCTION unapi.ascecm ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
546         SELECT  XMLELEMENT(
547                     name statcat,
548                     XMLATTRIBUTES(
549                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
550                         sc.name,
551                         sc.opac_visible
552                     ),
553                     asce.value
554                 )
555           FROM  asset.stat_cat_entry asce
556                 JOIN asset.stat_cat sc ON (sc.id = asce.stat_cat)
557           WHERE asce.id = $1;
558 $F$ LANGUAGE SQL;
559
560 CREATE OR REPLACE FUNCTION unapi.bmp ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
561         SELECT  XMLELEMENT(
562                     name monograph_part,
563                     XMLATTRIBUTES(
564                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
565                         'tag:open-ils.org:U2@bmp/' || id AS id,
566                         id AS ident,
567                         label,
568                         label_sortkey,
569                         'tag:open-ils.org:U2@bre/' || record AS record
570                     ),
571                     CASE 
572                         WHEN ('acp' = ANY ($4)) THEN
573                             XMLELEMENT( name copies,
574                                 (SELECT XMLAGG(acp) FROM (
575                                     SELECT  unapi.acp( cp.id, 'xml', 'copy', array_remove_item_by_value($4,'bmp'), $5, $6, $7, $8, FALSE)
576                                       FROM  asset.copy cp
577                                             JOIN asset.copy_part_map cpm ON (cpm.target_copy = cp.id)
578                                       WHERE cpm.part = $1
579                                       ORDER BY COALESCE(cp.copy_number,0), cp.barcode
580                                       LIMIT $7
581                                       OFFSET $8
582                                 )x)
583                             )
584                         ELSE NULL
585                     END,
586                     CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( record, 'marcxml', 'record', array_remove_item_by_value($4,'bmp'), $5, $6, $7, $8, FALSE) ELSE NULL END
587                 )
588           FROM  biblio.monograph_part
589           WHERE id = $1
590           GROUP BY id, label, label_sortkey, record;
591 $F$ LANGUAGE SQL;
592
593 CREATE OR REPLACE FUNCTION unapi.acp ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
594         SELECT  XMLELEMENT(
595                     name copy,
596                     XMLATTRIBUTES(
597                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
598                         'tag:open-ils.org:U2@acp/' || id AS id,
599                         create_date, edit_date, copy_number, circulate, deposit,
600                         ref, holdable, deleted, deposit_amount, price, barcode,
601                         circ_modifier, circ_as_type, opac_visible
602                     ),
603                     unapi.ccs( status, $2, 'status', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE),
604                     unapi.acl( location, $2, 'location', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE),
605                     unapi.aou( circ_lib, $2, 'circ_lib', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8),
606                     unapi.aou( circ_lib, $2, 'circlib', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8),
607                     CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END,
608                     XMLELEMENT( name copy_notes,
609                         CASE 
610                             WHEN ('acpn' = ANY ($4)) THEN
611                                 XMLAGG((SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE) FROM asset.copy_note WHERE owning_copy = cp.id AND pub))
612                             ELSE NULL
613                         END
614                     ),
615                     XMLELEMENT( name statcats,
616                         CASE 
617                             WHEN ('ascecm' = ANY ($4)) THEN
618                                 XMLAGG((SELECT unapi.ascecm( stat_cat_entry, 'xml', 'statcat', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE) FROM asset.stat_cat_entry_copy_map WHERE owning_copy = cp.id))
619                             ELSE NULL
620                         END
621                     ),
622                     CASE 
623                         WHEN ('bmp' = ANY ($4)) THEN
624                             XMLELEMENT( name monograph_parts,
625                                 XMLAGG((SELECT unapi.bmp( part, 'xml', 'monograph_part', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE) FROM asset.copy_part_map WHERE target_copy = cp.id))
626                             )
627                         ELSE NULL
628                     END
629                 )
630           FROM  asset.copy cp
631           WHERE id = $1
632           GROUP BY id, status, location, circ_lib, call_number, create_date, edit_date, copy_number, circulate, deposit, ref, holdable, deleted, deposit_amount, price, barcode, circ_modifier, circ_as_type, opac_visible;
633 $F$ LANGUAGE SQL;
634
635 CREATE OR REPLACE FUNCTION unapi.sunit ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
636         SELECT  XMLELEMENT(
637                     name serial_unit,
638                     XMLATTRIBUTES(
639                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
640                         'tag:open-ils.org:U2@acp/' || id AS id,
641                         create_date, edit_date, copy_number, circulate, deposit,
642                         ref, holdable, deleted, deposit_amount, price, barcode,
643                         circ_modifier, circ_as_type, opac_visible, status_changed_time,
644                         floating, mint_condition, detailed_contents, sort_key, summary_contents, cost 
645                     ),
646                     unapi.ccs( status, $2, 'status', array_remove_item_by_value(array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE),
647                     unapi.acl( location, $2, 'location', array_remove_item_by_value(array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE),
648                     unapi.aou( circ_lib, $2, 'circ_lib', array_remove_item_by_value(array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8),
649                     unapi.aou( circ_lib, $2, 'circlib', array_remove_item_by_value(array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8),
650                     CASE WHEN ('acn' = ANY ($4)) THEN unapi.acn( call_number, $2, 'call_number', array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE) ELSE NULL END,
651                     XMLELEMENT( name copy_notes,
652                         CASE 
653                             WHEN ('acpn' = ANY ($4)) THEN
654                                 XMLAGG((SELECT unapi.acpn( id, 'xml', 'copy_note', array_remove_item_by_value(array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE) FROM asset.copy_note WHERE owning_copy = cp.id AND pub))
655                             ELSE NULL
656                         END
657                     ),
658                     XMLELEMENT( name statcats,
659                         CASE 
660                             WHEN ('ascecm' = ANY ($4)) THEN
661                                 XMLAGG((SELECT unapi.acpn( stat_cat_entry, 'xml', 'statcat', array_remove_item_by_value(array_remove_item_by_value($4,'acp'),'sunit'), $5, $6, $7, $8, FALSE) FROM asset.stat_cat_entry_copy_map WHERE owning_copy = cp.id))
662                             ELSE NULL
663                         END
664                     )
665                 )
666           FROM  serial.unit cp
667           WHERE id = $1
668           GROUP BY  id, status, location, circ_lib, call_number, create_date, edit_date, copy_number, circulate, floating, mint_condition,
669                     deposit, ref, holdable, deleted, deposit_amount, price, barcode, circ_modifier, circ_as_type, opac_visible, status_changed_time, detailed_contents, sort_key, summary_contents, cost;
670 $F$ LANGUAGE SQL;
671
672 CREATE OR REPLACE FUNCTION unapi.acn ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
673         SELECT  XMLELEMENT(
674                     name volume,
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@acn/' || acn.id AS id,
678                         o.shortname AS lib,
679                         o.opac_visible AS opac_visible,
680                         deleted, label, label_sortkey, label_class, record
681                     ),
682                     unapi.aou( owning_lib, $2, 'owning_lib', array_remove_item_by_value($4,'acn'), $5, $6, $7, $8),
683                     XMLELEMENT( name copies,
684                         CASE 
685                             WHEN ('acp' = ANY ($4)) THEN
686                                 (SELECT XMLAGG(acp) FROM (
687                                     SELECT  unapi.acp( cp.id, 'xml', 'copy', array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE)
688                                       FROM  asset.copy cp
689                                             JOIN actor.org_unit_descendants(
690                                                 (SELECT id FROM actor.org_unit WHERE shortname = $5),
691                                                 (COALESCE($6,(SELECT aout.depth FROM actor.org_unit_type aout JOIN actor.org_unit aou ON (aou.ou_type = aout.id AND aou.shortname = $5))))
692                                             ) aoud ON (cp.circ_lib = aoud.id)
693                                       WHERE cp.call_number = acn.id
694                                       ORDER BY COALESCE(cp.copy_number,0), cp.barcode
695                                       LIMIT $7
696                                       OFFSET $8
697                                 )x)
698                             ELSE NULL
699                         END
700                     ),
701                     XMLELEMENT(
702                         name uris,
703                         (SELECT XMLAGG(auri) FROM (SELECT unapi.auri(uri,'xml','uri', array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE call_number = acn.id)x)
704                     ),
705                     CASE WHEN ('acnp' = ANY ($4)) THEN unapi.acnp( acn.prefix, 'marcxml', 'prefix', array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE) ELSE NULL END,
706                     CASE WHEN ('acns' = ANY ($4)) THEN unapi.acns( acn.suffix, 'marcxml', 'suffix', array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE) ELSE NULL END,
707                     CASE WHEN ('bre' = ANY ($4)) THEN unapi.bre( acn.record, 'marcxml', 'record', array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE) ELSE NULL END
708                 ) AS x
709           FROM  asset.call_number acn
710                 JOIN actor.org_unit o ON (o.id = acn.owning_lib)
711           WHERE acn.id = $1
712           GROUP BY acn.id, o.shortname, o.opac_visible, deleted, label, label_sortkey, label_class, owning_lib, record, acn.prefix, acn.suffix;
713 $F$ LANGUAGE SQL;
714
715 CREATE OR REPLACE FUNCTION unapi.acnp ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
716         SELECT  XMLELEMENT(
717                     name call_number_prefix,
718                     XMLATTRIBUTES(
719                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
720                         id AS ident,
721                         label,
722                         label_sortkey
723                     ),
724                     unapi.aou( owning_lib, $2, 'owning_lib', array_remove_item_by_value($4,'acnp'), $5, $6, $7, $8)
725                 )
726           FROM  asset.call_number_prefix
727           WHERE id = $1;
728 $F$ LANGUAGE SQL;
729
730 CREATE OR REPLACE FUNCTION unapi.acns ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
731         SELECT  XMLELEMENT(
732                     name call_number_suffix,
733                     XMLATTRIBUTES(
734                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
735                         id AS ident,
736                         label,
737                         label_sortkey
738                     ),
739                     unapi.aou( owning_lib, $2, 'owning_lib', array_remove_item_by_value($4,'acns'), $5, $6, $7, $8)
740                 )
741           FROM  asset.call_number_suffix
742           WHERE id = $1;
743 $F$ LANGUAGE SQL;
744
745 CREATE OR REPLACE FUNCTION unapi.auri ( obj_id BIGINT, format TEXT,  ename TEXT, includes TEXT[], org TEXT, depth INT DEFAULT NULL, slimit INT DEFAULT NULL, soffset INT DEFAULT NULL, include_xmlns BOOL DEFAULT TRUE ) RETURNS XML AS $F$
746         SELECT  XMLELEMENT(
747                     name volume,
748                     XMLATTRIBUTES(
749                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
750                         'tag:open-ils.org:U2@auri/' || uri.id AS id,
751                         use_restriction,
752                         href,
753                         label
754                     ),
755                     XMLELEMENT( name copies,
756                         CASE 
757                             WHEN ('acn' = ANY ($4)) THEN
758                                 (SELECT XMLAGG(acn) FROM (SELECT unapi.acn( call_number, 'xml', 'copy', array_remove_item_by_value($4,'auri'), $5, $6, $7, $8, FALSE) FROM asset.uri_call_number_map WHERE uri = uri.id)x)
759                             ELSE NULL
760                         END
761                     )
762                 ) AS x
763           FROM  asset.uri uri
764           WHERE uri.id = $1
765           GROUP BY uri.id, use_restriction, href, label;
766 $F$ LANGUAGE SQL;
767
768 /*
769
770  -- Some test queries
771
772 SELECT unapi.memoize( 'bre', 1,'mods32','','{holdings_xml,acp}'::TEXT[], 'SYS1');
773 SELECT unapi.memoize( 'bre', 1,'marcxml','','{holdings_xml,acp}'::TEXT[], 'SYS1');
774 SELECT unapi.memoize( 'bre', 1,'holdings_xml','','{holdings_xml,acp}'::TEXT[], 'SYS1');
775
776 SELECT unapi.biblio_record_entry_feed('{1}'::BIGINT[],'mods32','{holdings_xml,acp}'::TEXT[],'SYS1',NULL,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>');
777
778 SELECT unapi.biblio_record_entry_feed('{7209,7394}'::BIGINT[],'marcxml','{}'::TEXT[],'SYS1',NULL,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>');
779 EXPLAIN ANALYZE SELECT unapi.biblio_record_entry_feed('{7209,7394}'::BIGINT[],'marcxml','{}'::TEXT[],'SYS1',NULL,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>');
780 EXPLAIN ANALYZE SELECT unapi.biblio_record_entry_feed('{7209,7394}'::BIGINT[],'marcxml','{holdings_xml}'::TEXT[],'SYS1',NULL,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>');
781 EXPLAIN ANALYZE SELECT unapi.biblio_record_entry_feed('{7209,7394}'::BIGINT[],'mods32','{holdings_xml}'::TEXT[],'SYS1',NULL,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>');
782
783 SELECT unapi.biblio_record_entry_feed('{216}'::BIGINT[],'marcxml','{}'::TEXT[], 'BR1');
784 EXPLAIN ANALYZE SELECT unapi.bre(216,'marcxml','record','{holdings_xml,bre.unapi}'::TEXT[], 'BR1');
785 EXPLAIN ANALYZE SELECT unapi.bre(216,'holdings_xml','record','{}'::TEXT[], 'BR1');
786 EXPLAIN ANALYZE SELECT unapi.holdings_xml(216,4,'BR1',2,'{bre}'::TEXT[]);
787 EXPLAIN ANALYZE SELECT unapi.bre(216,'mods32','record','{}'::TEXT[], 'BR1');
788
789 */
790
791 COMMIT;
792