]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/990.schema.unapi.sql
add SVF data to in-db unAPI
[working/Evergreen.git] / Open-ILS / src / sql / Pg / 990.schema.unapi.sql
1 DROP SCHEMA IF EXISTS unapi CASCADE;
2
3 BEGIN;
4 CREATE SCHEMA unapi;
5
6 CREATE OR REPLACE FUNCTION evergreen.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     RETURN output;
226 END;
227 $F$ LANGUAGE PLPGSQL;
228
229 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$
230      SELECT  XMLELEMENT(
231                  name holdings,
232                  XMLATTRIBUTES(
233                     CASE WHEN $8 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
234                     CASE WHEN ('bre' = ANY ('{acn,auri}'::TEXT[] || $5)) THEN 'tag:open-ils.org:U2@bre/' || $1 || '/' || $3 ELSE NULL END AS id
235                  ),
236                  XMLELEMENT(
237                      name counts,
238                      (SELECT  XMLAGG(XMLELEMENT::XML) FROM (
239                          SELECT  XMLELEMENT(
240                                      name count,
241                                      XMLATTRIBUTES('public' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
242                                  )::text
243                            FROM  asset.opac_ou_record_copy_count($2,  $1)
244                                      UNION
245                          SELECT  XMLELEMENT(
246                                      name count,
247                                      XMLATTRIBUTES('staff' as type, depth, org_unit, coalesce(transcendant,0) as transcendant, available, visible as count, unshadow)
248                                  )::text
249                            FROM  asset.staff_ou_record_copy_count($2, $1)
250                                      ORDER BY 1
251                      )x)
252                  ),
253                  CASE 
254                      WHEN ('bmp' = ANY ($5)) THEN
255                         XMLELEMENT( name monograph_parts,
256                             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))
257                         )
258                      ELSE NULL
259                  END,
260                  CASE WHEN ('acn' = ANY ('{acn,auri}'::TEXT[] || $5)) THEN 
261                      XMLELEMENT(
262                          name volumes,
263                          (SELECT XMLAGG(acn) FROM (
264                             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)
265                               FROM  asset.call_number acn
266                               WHERE acn.record = $1
267                                     AND EXISTS (
268                                         SELECT  1
269                                           FROM  asset.copy acp
270                                                 JOIN actor.org_unit_descendants(
271                                                     $2,
272                                                     (COALESCE(
273                                                         $4,
274                                                         (SELECT aout.depth
275                                                           FROM  actor.org_unit_type aout
276                                                                 JOIN actor.org_unit aou ON (aou.ou_type = aout.id AND aou.id = $2)
277                                                         )
278                                                     ))
279                                                 ) aoud ON (acp.circ_lib = aoud.id)
280                                           LIMIT 1
281                                     )
282                               ORDER BY label_sortkey
283                               LIMIT $6
284                               OFFSET $7
285                          )x)
286                      )
287                  ELSE NULL END,
288                  CASE WHEN ('ssub' = ANY ('{acn,auri}'::TEXT[] || $5)) THEN 
289                      XMLELEMENT(
290                          name subscriptions,
291                          (SELECT XMLAGG(ssub) FROM (
292                             SELECT  unapi.ssub(id,'xml','subscription','{}'::TEXT[], $3, $4, $6, $7, FALSE)
293                               FROM  serial.subscription
294                               WHERE record_entry = $1
295                         )x)
296                      )
297                  ELSE NULL END,
298                  CASE WHEN ('acp' = ANY ($5)) THEN 
299                      XMLELEMENT(
300                          name foreign_copies,
301                          (SELECT XMLAGG(acp) FROM (
302                             SELECT  unapi.acp(p.target_copy,'xml','copy','{}'::TEXT[], $3, $4, $6, $7, FALSE)
303                               FROM  biblio.peer_bib_copy_map p
304                                     JOIN asset.copy c ON (p.target_copy = c.id)
305                               WHERE NOT c.deleted AND peer_record = $1
306                         )x)
307                      )
308                  ELSE NULL END
309              );
310 $F$ LANGUAGE SQL;
311
312 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$
313         SELECT  XMLELEMENT(
314                     name subscription,
315                     XMLATTRIBUTES(
316                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
317                         'tag:open-ils.org:U2@ssub/' || id AS id,
318                         start_date AS start, end_date AS end, expected_date_offset
319                     ),
320                     unapi.aou( owning_lib, $2, 'owning_lib', evergreen.array_remove_item_by_value($4,'ssub'), $5, $6, $7, $8),
321                     XMLELEMENT( name distributions,
322                         CASE 
323                             WHEN ('sdist' = ANY ($4)) THEN
324                                 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))
325                             ELSE NULL
326                         END
327                     )
328                 )
329           FROM  serial.subscription ssub
330           WHERE id = $1
331           GROUP BY id, start_date, end_date, expected_date_offset, owning_lib;
332 $F$ LANGUAGE SQL;
333
334 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$
335         SELECT  XMLELEMENT(
336                     name distribution,
337                     XMLATTRIBUTES(
338                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
339                         'tag:open-ils.org:U2@sdist/' || id AS id,
340                         'tag:open-ils.org:U2@acn/' || receive_call_number AS receive_call_number,
341                         'tag:open-ils.org:U2@acn/' || bind_call_number AS bind_call_number,
342                         unit_label_prefix, label, unit_label_suffix, summary_method
343                     ),
344                     unapi.aou( holding_lib, $2, 'holding_lib', evergreen.array_remove_item_by_value($4,'sdist'), $5, $6, $7, $8),
345                     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,
346                     XMLELEMENT( name streams,
347                         CASE 
348                             WHEN ('sstr' = ANY ($4)) THEN
349                                 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))
350                             ELSE NULL
351                         END
352                     ),
353                     XMLELEMENT( name summaries,
354                         CASE 
355                             WHEN ('ssum' = ANY ($4)) THEN
356                                 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))
357                             ELSE NULL
358                         END,
359                         CASE 
360                             WHEN ('ssum' = ANY ($4)) THEN
361                                 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))
362                             ELSE NULL
363                         END,
364                         CASE 
365                             WHEN ('ssum' = ANY ($4)) THEN
366                                 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))
367                             ELSE NULL
368                         END
369                     )
370                 )
371           FROM  serial.distribution sdist
372           WHERE id = $1
373           GROUP BY id, label, unit_label_prefix, unit_label_suffix, holding_lib, summary_method, subscription, receive_call_number, bind_call_number;
374 $F$ LANGUAGE SQL;
375
376 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$
377     SELECT  XMLELEMENT(
378                 name stream,
379                 XMLATTRIBUTES(
380                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
381                     'tag:open-ils.org:U2@sstr/' || id AS id,
382                     routing_label
383                 ),
384                 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,
385                 XMLELEMENT( name items,
386                     CASE 
387                         WHEN ('sitem' = ANY ($4)) THEN
388                             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))
389                         ELSE NULL
390                     END
391                 )
392             )
393       FROM  serial.stream sstr
394       WHERE id = $1
395       GROUP BY id, routing_label, distribution;
396 $F$ LANGUAGE SQL;
397
398 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$
399     SELECT  XMLELEMENT(
400                 name issuance,
401                 XMLATTRIBUTES(
402                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
403                     'tag:open-ils.org:U2@siss/' || id AS id,
404                     create_date, edit_date, label, date_published,
405                     holding_code, holding_type, holding_link_id
406                 ),
407                 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,
408                 XMLELEMENT( name items,
409                     CASE 
410                         WHEN ('sitem' = ANY ($4)) THEN
411                             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))
412                         ELSE NULL
413                     END
414                 )
415             )
416       FROM  serial.issuance sstr
417       WHERE id = $1
418       GROUP BY id, create_date, edit_date, label, date_published, holding_code, holding_type, holding_link_id, subscription;
419 $F$ LANGUAGE SQL;
420
421 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$
422         SELECT  XMLELEMENT(
423                     name serial_item,
424                     XMLATTRIBUTES(
425                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
426                         'tag:open-ils.org:U2@sitem/' || id AS id,
427                         'tag:open-ils.org:U2@siss/' || issuance AS issuance,
428                         date_expected, date_received
429                     ),
430                     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,
431                     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,
432                     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,
433                     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
434 --                    XMLELEMENT( name notes,
435 --                        CASE 
436 --                            WHEN ('acpn' = ANY ($4)) THEN
437 --                                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))
438 --                            ELSE NULL
439 --                        END
440 --                    )
441                 )
442           FROM  serial.item sitem
443           WHERE id = $1;
444 $F$ LANGUAGE SQL;
445
446
447 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$
448     SELECT  XMLELEMENT(
449                 name serial_summary,
450                 XMLATTRIBUTES(
451                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
452                     'tag:open-ils.org:U2@sbsum/' || id AS id,
453                     'sssum' AS type, generated_coverage, textual_holdings, show_generated
454                 ),
455                 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
456             )
457       FROM  serial.supplement_summary ssum
458       WHERE id = $1
459       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
460 $F$ LANGUAGE SQL;
461
462 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$
463     SELECT  XMLELEMENT(
464                 name serial_summary,
465                 XMLATTRIBUTES(
466                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
467                     'tag:open-ils.org:U2@sbsum/' || id AS id,
468                     'sbsum' AS type, generated_coverage, textual_holdings, show_generated
469                 ),
470                 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
471             )
472       FROM  serial.basic_summary ssum
473       WHERE id = $1
474       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
475 $F$ LANGUAGE SQL;
476
477 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$
478     SELECT  XMLELEMENT(
479                 name serial_summary,
480                 XMLATTRIBUTES(
481                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
482                     'tag:open-ils.org:U2@sbsum/' || id AS id,
483                     'sisum' AS type, generated_coverage, textual_holdings, show_generated
484                 ),
485                 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
486             )
487       FROM  serial.index_summary ssum
488       WHERE id = $1
489       GROUP BY id, generated_coverage, textual_holdings, distribution, show_generated;
490 $F$ LANGUAGE SQL;
491
492
493 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$
494 DECLARE
495     output XML;
496 BEGIN
497     IF ename = 'circlib' THEN
498         SELECT  XMLELEMENT(
499                     name circlib,
500                     XMLATTRIBUTES(
501                         'http://open-ils.org/spec/actors/v1' AS xmlns,
502                         id AS ident
503                     ),
504                     name
505                 ) INTO output
506           FROM  actor.org_unit aou
507           WHERE id = obj_id;
508     ELSE
509         EXECUTE $$SELECT  XMLELEMENT(
510                     name $$ || ename || $$,
511                     XMLATTRIBUTES(
512                         'http://open-ils.org/spec/actors/v1' AS xmlns,
513                         'tag:open-ils.org:U2@aou/' || id AS id,
514                         shortname, name, opac_visible
515                     )
516                 )
517           FROM  actor.org_unit aou
518          WHERE id = $1 $$ INTO output USING obj_id;
519     END IF;
520
521     RETURN output;
522
523 END;
524 $F$ LANGUAGE PLPGSQL;
525
526 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$
527     SELECT  XMLELEMENT(
528                 name location,
529                 XMLATTRIBUTES(
530                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
531                     id AS ident
532                 ),
533                 name
534             )
535       FROM  asset.copy_location
536       WHERE id = $1;
537 $F$ LANGUAGE SQL;
538
539 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$
540     SELECT  XMLELEMENT(
541                 name status,
542                 XMLATTRIBUTES(
543                     CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
544                     id AS ident
545                 ),
546                 name
547             )
548       FROM  config.copy_status
549       WHERE id = $1;
550 $F$ LANGUAGE SQL;
551
552 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$
553         SELECT  XMLELEMENT(
554                     name copy_note,
555                     XMLATTRIBUTES(
556                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
557                         create_date AS date,
558                         title
559                     ),
560                     value
561                 )
562           FROM  asset.copy_note
563           WHERE id = $1;
564 $F$ LANGUAGE SQL;
565
566 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$
567         SELECT  XMLELEMENT(
568                     name statcat,
569                     XMLATTRIBUTES(
570                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
571                         sc.name,
572                         sc.opac_visible
573                     ),
574                     asce.value
575                 )
576           FROM  asset.stat_cat_entry asce
577                 JOIN asset.stat_cat sc ON (sc.id = asce.stat_cat)
578           WHERE asce.id = $1;
579 $F$ LANGUAGE SQL;
580
581 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$
582         SELECT  XMLELEMENT(
583                     name monograph_part,
584                     XMLATTRIBUTES(
585                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
586                         'tag:open-ils.org:U2@bmp/' || id AS id,
587                         id AS ident,
588                         label,
589                         label_sortkey,
590                         'tag:open-ils.org:U2@bre/' || record AS record
591                     ),
592                     CASE 
593                         WHEN ('acp' = ANY ($4)) THEN
594                             XMLELEMENT( name copies,
595                                 (SELECT XMLAGG(acp) FROM (
596                                     SELECT  unapi.acp( cp.id, 'xml', 'copy', evergreen.array_remove_item_by_value($4,'bmp'), $5, $6, $7, $8, FALSE)
597                                       FROM  asset.copy cp
598                                             JOIN asset.copy_part_map cpm ON (cpm.target_copy = cp.id)
599                                       WHERE cpm.part = $1
600                                       ORDER BY COALESCE(cp.copy_number,0), cp.barcode
601                                       LIMIT $7
602                                       OFFSET $8
603                                 )x)
604                             )
605                         ELSE NULL
606                     END,
607                     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
608                 )
609           FROM  biblio.monograph_part
610           WHERE id = $1
611           GROUP BY id, label, label_sortkey, record;
612 $F$ LANGUAGE SQL;
613
614 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$
615         SELECT  XMLELEMENT(
616                     name copy,
617                     XMLATTRIBUTES(
618                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
619                         'tag:open-ils.org:U2@acp/' || id AS id,
620                         create_date, edit_date, copy_number, circulate, deposit,
621                         ref, holdable, deleted, deposit_amount, price, barcode,
622                         circ_modifier, circ_as_type, opac_visible
623                     ),
624                     unapi.ccs( status, $2, 'status', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE),
625                     unapi.acl( location, $2, 'location', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8, FALSE),
626                     unapi.aou( circ_lib, $2, 'circ_lib', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8),
627                     unapi.aou( circ_lib, $2, 'circlib', evergreen.array_remove_item_by_value($4,'acp'), $5, $6, $7, $8),
628                     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,
629                     XMLELEMENT( name copy_notes,
630                         CASE 
631                             WHEN ('acpn' = ANY ($4)) THEN
632                                 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))
633                             ELSE NULL
634                         END
635                     ),
636                     XMLELEMENT( name statcats,
637                         CASE 
638                             WHEN ('ascecm' = ANY ($4)) THEN
639                                 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))
640                             ELSE NULL
641                         END
642                     ),
643                     XMLELEMENT( name foreign_records,
644                         CASE
645                             WHEN ('bre' = ANY ($4)) THEN
646                                 XMLAGG((SELECT unapi.bre(peer_record,'marcxml','record','{}'::TEXT[], $5, $6, $7, $8, FALSE) FROM biblio.peer_bib_copy_map WHERE target_copy = cp.id))
647                             ELSE NULL
648                         END
649
650                     ),
651                     CASE 
652                         WHEN ('bmp' = ANY ($4)) THEN
653                             XMLELEMENT( name monograph_parts,
654                                 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))
655                             )
656                         ELSE NULL
657                     END
658                 )
659           FROM  asset.copy cp
660           WHERE id = $1
661           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;
662 $F$ LANGUAGE SQL;
663
664 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$
665         SELECT  XMLELEMENT(
666                     name serial_unit,
667                     XMLATTRIBUTES(
668                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
669                         'tag:open-ils.org:U2@acp/' || id AS id,
670                         create_date, edit_date, copy_number, circulate, deposit,
671                         ref, holdable, deleted, deposit_amount, price, barcode,
672                         circ_modifier, circ_as_type, opac_visible, status_changed_time,
673                         floating, mint_condition, detailed_contents, sort_key, summary_contents, cost 
674                     ),
675                     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),
676                     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),
677                     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),
678                     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),
679                     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,
680                     XMLELEMENT( name copy_notes,
681                         CASE 
682                             WHEN ('acpn' = ANY ($4)) THEN
683                                 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))
684                             ELSE NULL
685                         END
686                     ),
687                     XMLELEMENT( name statcats,
688                         CASE 
689                             WHEN ('ascecm' = ANY ($4)) THEN
690                                 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))
691                             ELSE NULL
692                         END
693                     )
694                 )
695           FROM  serial.unit cp
696           WHERE id = $1
697           GROUP BY  id, status, location, circ_lib, call_number, create_date, edit_date, copy_number, circulate, floating, mint_condition,
698                     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;
699 $F$ LANGUAGE SQL;
700
701 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$
702         SELECT  XMLELEMENT(
703                     name volume,
704                     XMLATTRIBUTES(
705                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
706                         'tag:open-ils.org:U2@acn/' || acn.id AS id,
707                         o.shortname AS lib,
708                         o.opac_visible AS opac_visible,
709                         deleted, label, label_sortkey, label_class, record
710                     ),
711                     unapi.aou( owning_lib, $2, 'owning_lib', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8),
712                     XMLELEMENT( name copies,
713                         CASE 
714                             WHEN ('acp' = ANY ($4)) THEN
715                                 (SELECT XMLAGG(acp) FROM (
716                                     SELECT  unapi.acp( cp.id, 'xml', 'copy', evergreen.array_remove_item_by_value($4,'acn'), $5, $6, $7, $8, FALSE)
717                                       FROM  asset.copy cp
718                                             JOIN actor.org_unit_descendants(
719                                                 (SELECT id FROM actor.org_unit WHERE shortname = $5),
720                                                 (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))))
721                                             ) aoud ON (cp.circ_lib = aoud.id)
722                                       WHERE cp.call_number = acn.id
723                                       ORDER BY COALESCE(cp.copy_number,0), cp.barcode
724                                       LIMIT $7
725                                       OFFSET $8
726                                 )x)
727                             ELSE NULL
728                         END
729                     ),
730                     XMLELEMENT(
731                         name uris,
732                         (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)
733                     ),
734                     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,
735                     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,
736                     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
737                 ) AS x
738           FROM  asset.call_number acn
739                 JOIN actor.org_unit o ON (o.id = acn.owning_lib)
740           WHERE acn.id = $1
741           GROUP BY acn.id, o.shortname, o.opac_visible, deleted, label, label_sortkey, label_class, owning_lib, record, acn.prefix, acn.suffix;
742 $F$ LANGUAGE SQL;
743
744 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$
745         SELECT  XMLELEMENT(
746                     name call_number_prefix,
747                     XMLATTRIBUTES(
748                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
749                         id AS ident,
750                         label,
751                         label_sortkey
752                     ),
753                     unapi.aou( owning_lib, $2, 'owning_lib', evergreen.array_remove_item_by_value($4,'acnp'), $5, $6, $7, $8)
754                 )
755           FROM  asset.call_number_prefix
756           WHERE id = $1;
757 $F$ LANGUAGE SQL;
758
759 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$
760         SELECT  XMLELEMENT(
761                     name call_number_suffix,
762                     XMLATTRIBUTES(
763                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
764                         id AS ident,
765                         label,
766                         label_sortkey
767                     ),
768                     unapi.aou( owning_lib, $2, 'owning_lib', evergreen.array_remove_item_by_value($4,'acns'), $5, $6, $7, $8)
769                 )
770           FROM  asset.call_number_suffix
771           WHERE id = $1;
772 $F$ LANGUAGE SQL;
773
774 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$
775         SELECT  XMLELEMENT(
776                     name volume,
777                     XMLATTRIBUTES(
778                         CASE WHEN $9 THEN 'http://open-ils.org/spec/holdings/v1' ELSE NULL END AS xmlns,
779                         'tag:open-ils.org:U2@auri/' || uri.id AS id,
780                         use_restriction,
781                         href,
782                         label
783                     ),
784                     XMLELEMENT( name copies,
785                         CASE 
786                             WHEN ('acn' = ANY ($4)) THEN
787                                 (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)
788                             ELSE NULL
789                         END
790                     )
791                 ) AS x
792           FROM  asset.uri uri
793           WHERE uri.id = $1
794           GROUP BY uri.id, use_restriction, href, label;
795 $F$ LANGUAGE SQL;
796
797 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$
798         SELECT  XMLELEMENT(
799                     name attributes,
800                     XMLATTRIBUTES(
801                         CASE WHEN $9 THEN 'http://open-ils.org/spec/indexing/v1' ELSE NULL END AS xmlns,
802                         'tag:open-ils.org:U2@mra/' || mra.id AS id,
803                         'tag:open-ils.org:U2@bre/' || mra.id AS record
804                     ),
805                     (SELECT XMLAGG(foo.y)
806                       FROM (SELECT XMLELEMENT(
807                                 name field,
808                                 XMLATTRIBUTES(
809                                     key AS name,
810                                     cvm.value AS "coded-value",
811                                     rad.filter,
812                                     rad.sorter
813                                 ),
814                                 x.value
815                             )
816                            FROM EACH(mra.attrs) AS x
817                                 JOIN config.record_attr_definition rad ON (x.key = rad.name)
818                                 LEFT JOIN config.coded_value_map cvm ON (cvm.ctype = x.key AND code = x.value)
819                         )foo(y)
820                     )
821                 )
822           FROM  metabib.record_attr mra
823           WHERE mra.id = $1;
824 $F$ LANGUAGE SQL;
825
826 /*
827
828  -- Some test queries
829
830 SELECT unapi.memoize( 'bre', 1,'mods32','','{holdings_xml,acp}'::TEXT[], 'SYS1');
831 SELECT unapi.memoize( 'bre', 1,'marcxml','','{holdings_xml,acp}'::TEXT[], 'SYS1');
832 SELECT unapi.memoize( 'bre', 1,'holdings_xml','','{holdings_xml,acp}'::TEXT[], 'SYS1');
833
834 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>');
835
836 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>');
837 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>');
838 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>');
839 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>');
840
841 SELECT unapi.biblio_record_entry_feed('{216}'::BIGINT[],'marcxml','{}'::TEXT[], 'BR1');
842 EXPLAIN ANALYZE SELECT unapi.bre(216,'marcxml','record','{holdings_xml,bre.unapi}'::TEXT[], 'BR1');
843 EXPLAIN ANALYZE SELECT unapi.bre(216,'holdings_xml','record','{}'::TEXT[], 'BR1');
844 EXPLAIN ANALYZE SELECT unapi.holdings_xml(216,4,'BR1',2,'{bre}'::TEXT[]);
845 EXPLAIN ANALYZE SELECT unapi.bre(216,'mods32','record','{}'::TEXT[], 'BR1');
846
847 */
848
849 COMMIT;
850