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