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