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