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