]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/sql/Pg/012.schema.vandelay.sql
Vandelay item extraction and field removal; setting true AND false values for boolean...
[Evergreen.git] / Open-ILS / src / sql / Pg / 012.schema.vandelay.sql
1 DROP SCHEMA vandelay CASCADE;
2
3 BEGIN;
4
5 CREATE SCHEMA vandelay;
6
7 CREATE TABLE vandelay.queue (
8         id                              BIGSERIAL       PRIMARY KEY,
9         owner                   INT                     NOT NULL REFERENCES actor.usr (id) DEFERRABLE INITIALLY DEFERRED,
10         name                    TEXT            NOT NULL,
11         complete                BOOL            NOT NULL DEFAULT FALSE,
12         queue_type              TEXT            NOT NULL DEFAULT 'bib' CHECK (queue_type IN ('bib','authority')),
13         CONSTRAINT vand_queue_name_once_per_owner_const UNIQUE (owner,name,queue_type)
14 );
15
16 CREATE TABLE vandelay.queued_record (
17     id                  BIGSERIAL                   PRIMARY KEY,
18     create_time TIMESTAMP WITH TIME ZONE    NOT NULL DEFAULT NOW(),
19     import_time TIMESTAMP WITH TIME ZONE,
20         purpose         TEXT                                            NOT NULL DEFAULT 'import' CHECK (purpose IN ('import','overlay')),
21     marc                TEXT                        NOT NULL
22 );
23
24
25
26 /* Bib stuff at the top */
27 ----------------------------------------------------
28
29 CREATE TABLE vandelay.bib_attr_definition (
30         id                      SERIAL  PRIMARY KEY,
31         code            TEXT    UNIQUE NOT NULL,
32         description     TEXT,
33         xpath           TEXT    NOT NULL,
34         remove          TEXT    NOT NULL DEFAULT '',
35         ident           BOOL    NOT NULL DEFAULT FALSE
36 );
37
38 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath ) VALUES ('title','Title of work','//*[@tag="245"]/*[contains("abcmnopr",@code)]');
39 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath ) VALUES ('author','Author of work','//*[@tag="100" or @tag="110" or @tag="113"]/*[contains("ad",@code)]');
40 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath ) VALUES ('language','Lanuage of work','//*[@tag="240"]/*[@code="l"][1]');
41 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath ) VALUES ('pagination','Pagination','//*[@tag="300"]/*[@code="a"][1]');
42 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath, ident, remove ) VALUES ('isbn','ISBN','//*[@tag="020"]/*[@code="a"]', TRUE, $r$(?:-|\s.+$)$r$);
43 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath, ident, remove ) VALUES ('issn','ISSN','//*[@tag="022"]/*[@code="a"]', TRUE, $r$(?:-|\s.+$)$r$);
44 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath ) VALUES ('price','Price','//*[@tag="020" or @tag="022"]/*[@code="c"][1]');
45 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath, ident ) VALUES ('rec_identifier','Accession Number','//*[@tag="001"]', TRUE);
46 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath, ident ) VALUES ('eg_tcn','TCN Value','//*[@tag="901"]/*[@code="a"]', TRUE);
47 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath ) VALUES ('eg_tcn_source','TCN Source','//*[@tag="901"]/*[@code="b"]', TRUE);
48 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath, ident ) VALUES ('eg_identifier','Internal ID','//*[@tag="901"]/*[@code="c"]', TRUE);
49 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath ) VALUES ('publisher','Publisher','//*[@tag="260"]/*[@code="b"][1]');
50 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath, remove ) VALUES ('pubdate','Publication Date','//*[@tag="260"]/*[@code="c"][1]',$r$\D$r$);
51 INSERT INTO vandelay.bib_attr_definition ( code, description, xpath ) VALUES ('edition','Edition','//*[@tag="250"]/*[@code="a"][1]');
52
53
54 CREATE TABLE vandelay.bib_queue (
55         queue_type          TEXT        NOT NULL DEFAULT 'bib' CHECK (queue_type = 'bib'),
56         item_attr_def   TEXT    REFERENCES vandelay.import_item_attr_definition (id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
57         CONSTRAINT vand_bib_queue_name_once_per_owner_const UNIQUE (owner,name,queue_type)
58 ) INHERITS (vandelay.queue);
59 ALTER TABLE vandelay.bib_queue ADD PRIMARY KEY (id);
60
61 CREATE TABLE vandelay.queued_bib_record (
62         queue           INT             NOT NULL REFERENCES vandelay.bib_queue (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
63         bib_source      INT             REFERENCES config.bib_source (id) DEFERRABLE INITIALLY DEFERRED,
64         imported_as     INT             REFERENCES biblio.record_entry (id) DEFERRABLE INITIALLY DEFERRED
65 ) INHERITS (vandelay.queued_record);
66 ALTER TABLE vandelay.queued_bib_record ADD PRIMARY KEY (id);
67
68 CREATE TABLE vandelay.queued_bib_record_attr (
69         id                      BIGSERIAL       PRIMARY KEY,
70         record          BIGINT          NOT NULL REFERENCES vandelay.queued_bib_record (id) DEFERRABLE INITIALLY DEFERRED,
71         field           INT                     NOT NULL REFERENCES vandelay.bib_attr_definition (id) DEFERRABLE INITIALLY DEFERRED,
72         attr_value      TEXT            NOT NULL
73 );
74
75 CREATE TABLE vandelay.bib_match (
76         id                              BIGSERIAL       PRIMARY KEY,
77         field_type              TEXT            NOT NULL CHECK (field_type in ('isbn','tcn_value','id')),
78         matched_attr    INT                     REFERENCES vandelay.queued_bib_record_attr (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
79         queued_record   BIGINT          REFERENCES vandelay.queued_bib_record (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
80         eg_record               BIGINT          REFERENCES biblio.record_entry (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED
81 );
82
83 -- Each TEXT field (other than 'name') should hold an XPath predicate for pulling the data needed
84 -- DROP TABLE vandelay.import_item_attr_definition CASCADE;
85 CREATE TABLE vandelay.import_item_attr_definition (
86     id              BIGSERIAL   PRIMARY KEY,
87     owner           INT         NOT NULL REFERENCES actor.org_unit (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
88     name            TEXT        NOT NULL,
89     tag             TEXT        NOT NULL,
90     keep            BOOL        NOT NULL DEFAULT FALSE,
91     owning_lib      TEXT,
92     circ_lib        TEXT,
93     call_number     TEXT,
94     copy_number     TEXT,
95     status          TEXT,
96     location        TEXT,
97     circulate       TEXT,
98     deposit         TEXT,
99     deposit_amount  TEXT,
100     ref             TEXT,
101     holdable        TEXT,
102     price           TEXT,
103     barcode         TEXT,
104     circ_modifier   TEXT,
105     circ_as_type    TEXT,
106     alert_message   TEXT,
107     opac_visible    TEXT,
108     pub_note_title  TEXT,
109     pub_note        TEXT,
110     priv_note_title TEXT,
111     priv_note       TEXT,
112         CONSTRAINT vand_import_item_attr_def_idx UNIQUE (owner,name)
113 );
114
115 INSERT INTO vandelay.import_item_attr_definition (
116     owner, name, tag, owning_lib, circ_lib, location,
117     call_number, circ_modifier, barcode, price, copy_number,
118     circulate, ref, holdable, opac_visible, status
119 ) VALUES (
120     1,
121     'Evergreen 852 export format',
122     '852',
123     '[@code = "b"][1]',
124     '[@code = "b"][2]',
125     'c',
126     'j',
127     'g',
128     'p',
129     'y',
130     't',
131     '[@code = "x" and text() = "ncirculating"]',
132     '[@code = "x" and text() = "reference"]',
133     '[@code = "x" and text() = "holdable"]',
134     '[@code = "x" and text() = "visible"]',
135     'z'
136 );
137
138 INSERT INTO vandelay.import_item_attr_definition (
139     owner,
140     name,
141     tag,
142     owning_lib,
143     location,
144     call_number,
145     circ_modifier,
146     barcode,
147     price,
148     status
149 ) VALUES (
150     1,
151     'Unicorn Import format -- 999',
152     '999',
153     'm',
154     'l',
155     'a',
156     't',
157     'i',
158     'p',
159     'k'
160 );
161
162 -- DROP TABLE vandelay.import_item CASCADE;
163 CREATE TABLE vandelay.import_item (
164     id              BIGSERIAL   PRIMARY KEY,
165     definition      BIGINT      NOT NULL REFERENCES vandelay.import_item_attr_definition (id),
166     owning_lib      INT,
167     circ_lib        INT,
168     call_number     TEXT,
169     copy_number     INT,
170     status          INT,
171     location        INT,
172     circulate       BOOL,
173     deposit         BOOL,
174     deposit_amount  NUMERIC(8,2),
175     ref             BOOL,
176     holdable        BOOL,
177     price           NUMERIC(8,2),
178     barcode         TEXT,
179     circ_modifier   TEXT,
180     circ_as_type    TEXT,
181     alert_message   TEXT,
182     pub_note        TEXT,
183     priv_note       TEXT,
184     opac_visible    BOOL
185 );
186  
187 CREATE TABLE vandelay.import_bib_trash_fields (
188     id              BIGSERIAL   PRIMARY KEY,
189     owner           INT         NOT NULL REFERENCES actor.org_unit (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
190     field           TEXT        NOT NULL,
191         CONSTRAINT vand_import_bib_trash_fields_idx UNIQUE (owner,field)
192 );
193
194 CREATE OR REPLACE FUNCTION vandelay.strip_field ( xml TEXT, field TEXT ) RETURNS TEXT AS $_$
195
196     use MARC::Record;
197     use MARC::File::XML;
198
199     my $xml = shift;
200     my $field_spec = shift;
201
202     my @fields 
203
204     my $r = MARC::Record->new_from_xml( $xml );
205     $r->delete_field( $_ ) for ( $r->field( $field_spec ) );
206
207     $xml = $r->as_xml_record;
208     $xml =~ s/^<\?.+?\?>$//mo;
209     $xml =~ s/\n//sgo;
210     $xml =~ s/>\s+</></sgo;
211
212     return $xml;
213
214 $_$ LANGUAGE PLPERLU;
215
216
217 CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$
218 DECLARE
219
220     owning_lib      TEXT;
221     circ_lib        TEXT;
222     call_number     TEXT;
223     copy_number     TEXT;
224     status          TEXT;
225     location        TEXT;
226     circulate       TEXT;
227     deposit         TEXT;
228     deposit_amount  TEXT;
229     ref             TEXT;
230     holdable        TEXT;
231     price           TEXT;
232     barcode         TEXT;
233     circ_modifier   TEXT;
234     circ_as_type    TEXT;
235     alert_message   TEXT;
236     opac_visible    TEXT;
237     pub_note        TEXT;
238     priv_note       TEXT;
239
240     attr_def        RECORD;
241     tmp_attr_set    RECORD;
242     attr_set        vandelay.import_item%ROWTYPE;
243
244     xpath           TEXT;
245
246 BEGIN
247
248     SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id;
249
250     IF FOUND THEN
251
252         attr_set.definition := attr_def.id; 
253     
254         -- Build the combined XPath
255     
256         owning_lib :=
257             CASE
258                 WHEN attr_def.owning_lib IS NULL THEN 'null()'
259                 WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.owning_lib || '"]'
260                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.owning_lib
261             END;
262     
263         circ_lib :=
264             CASE
265                 WHEN attr_def.circ_lib IS NULL THEN 'null()'
266                 WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_lib || '"]'
267                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_lib
268             END;
269     
270         call_number :=
271             CASE
272                 WHEN attr_def.call_number IS NULL THEN 'null()'
273                 WHEN LENGTH( attr_def.call_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.call_number || '"]'
274                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.call_number
275             END;
276     
277         copy_number :=
278             CASE
279                 WHEN attr_def.copy_number IS NULL THEN 'null()'
280                 WHEN LENGTH( attr_def.copy_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.copy_number || '"]'
281                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.copy_number
282             END;
283     
284         status :=
285             CASE
286                 WHEN attr_def.status IS NULL THEN 'null()'
287                 WHEN LENGTH( attr_def.status ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.status || '"]'
288                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.status
289             END;
290     
291         location :=
292             CASE
293                 WHEN attr_def.location IS NULL THEN 'null()'
294                 WHEN LENGTH( attr_def.location ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.location || '"]'
295                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.location
296             END;
297     
298         circulate :=
299             CASE
300                 WHEN attr_def.circulate IS NULL THEN 'null()'
301                 WHEN LENGTH( attr_def.circulate ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circulate || '"]'
302                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circulate
303             END;
304     
305         deposit :=
306             CASE
307                 WHEN attr_def.deposit IS NULL THEN 'null()'
308                 WHEN LENGTH( attr_def.deposit ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit || '"]'
309                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit
310             END;
311     
312         deposit_amount :=
313             CASE
314                 WHEN attr_def.deposit_amount IS NULL THEN 'null()'
315                 WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit_amount || '"]'
316                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit_amount
317             END;
318     
319         ref :=
320             CASE
321                 WHEN attr_def.ref IS NULL THEN 'null()'
322                 WHEN LENGTH( attr_def.ref ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.ref || '"]'
323                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.ref
324             END;
325     
326         holdable :=
327             CASE
328                 WHEN attr_def.holdable IS NULL THEN 'null()'
329                 WHEN LENGTH( attr_def.holdable ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.holdable || '"]'
330                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.holdable
331             END;
332     
333         price :=
334             CASE
335                 WHEN attr_def.price IS NULL THEN 'null()'
336                 WHEN LENGTH( attr_def.price ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.price || '"]'
337                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.price
338             END;
339     
340         barcode :=
341             CASE
342                 WHEN attr_def.barcode IS NULL THEN 'null()'
343                 WHEN LENGTH( attr_def.barcode ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.barcode || '"]'
344                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.barcode
345             END;
346     
347         circ_modifier :=
348             CASE
349                 WHEN attr_def.circ_modifier IS NULL THEN 'null()'
350                 WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_modifier || '"]'
351                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_modifier
352             END;
353     
354         circ_as_type :=
355             CASE
356                 WHEN attr_def.circ_as_type IS NULL THEN 'null()'
357                 WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_as_type || '"]'
358                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_as_type
359             END;
360     
361         alert_message :=
362             CASE
363                 WHEN attr_def.alert_message IS NULL THEN 'null()'
364                 WHEN LENGTH( attr_def.alert_message ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.alert_message || '"]'
365                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.alert_message
366             END;
367     
368         opac_visible :=
369             CASE
370                 WHEN attr_def.opac_visible IS NULL THEN 'null()'
371                 WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.opac_visible || '"]'
372                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.opac_visible
373             END;
374
375         pub_note :=
376             CASE
377                 WHEN attr_def.pub_note IS NULL THEN 'null()'
378                 WHEN LENGTH( attr_def.pub_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.pub_note || '"]'
379                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.pub_note
380             END;
381         priv_note :=
382             CASE
383                 WHEN attr_def.priv_note IS NULL THEN 'null()'
384                 WHEN LENGTH( attr_def.priv_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.priv_note || '"]'
385                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.priv_note
386             END;
387     
388     
389         xpath := 
390             owning_lib      || '|' || 
391             circ_lib        || '|' || 
392             call_number     || '|' || 
393             copy_number     || '|' || 
394             status          || '|' || 
395             location        || '|' || 
396             circulate       || '|' || 
397             deposit         || '|' || 
398             deposit_amount  || '|' || 
399             ref             || '|' || 
400             holdable        || '|' || 
401             price           || '|' || 
402             barcode         || '|' || 
403             circ_modifier   || '|' || 
404             circ_as_type    || '|' || 
405             alert_message   || '|' || 
406             pub_note        || '|' || 
407             priv_note       || '|' || 
408             opac_visible;
409
410         -- RAISE NOTICE 'XPath: %', xpath;
411         
412         FOR tmp_attr_set IN
413                 SELECT  *
414                   FROM  xpath_table( 'id', 'marc', 'vandelay.queued_bib_record', xpath, 'id = ' || import_id )
415                             AS t( id BIGINT, ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT,
416                                   dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT,
417                                   circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, opac_vis TEXT )
418         LOOP
419     
420             tmp_attr_set.pr = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g');
421             tmp_attr_set.dep_amount = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g');
422
423             tmp_attr_set.pr := NULLIF( tmp_attr_set.pr, '' );
424             tmp_attr_set.dep_amount := NULLIF( tmp_attr_set.dep_amount, '' );
425     
426             SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT
427             SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT
428             SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT
429     
430             SELECT  id INTO attr_set.location
431               FROM  asset.copy_location
432               WHERE LOWER(name) = LOWER(tmp_attr_set.cl)
433                     AND owning_lib = COALESCE(attr_set.owning_lib, attr_set.circ_lib); -- INT
434     
435             attr_set.circulate      :=
436                 LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1')
437                 OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL
438
439             attr_set.deposit        :=
440                 LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1')
441                 OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL
442
443             attr_set.holdable       :=
444                 LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1')
445                 OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL
446
447             attr_set.opac_visible   :=
448                 LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1')
449                 OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL
450
451             attr_set.ref            :=
452                 LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1')
453                 OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL
454     
455             attr_set.copy_number    := tmp_attr_set.cnum::INT; -- INT,
456             attr_set.deposit_amount := tmp_attr_set.dep_amount::NUMERIC(6,2); -- NUMERIC(6,2),
457             attr_set.price          := tmp_attr_set.pr::NUMERIC(8,2); -- NUMERIC(8,2),
458     
459             attr_set.call_number    := tmp_attr_set.cn; -- TEXT
460             attr_set.barcode        := tmp_attr_set.bc; -- TEXT,
461             attr_set.circ_modifier  := tmp_attr_set.circ_mod; -- TEXT,
462             attr_set.circ_as_type   := tmp_attr_set.circ_as; -- TEXT,
463             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
464             attr_set.pub_note       := tmp_attr_set.note; -- TEXT,
465             attr_set.priv_note      := tmp_attr_set.pnote; -- TEXT,
466             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
467     
468             RETURN NEXT attr_set;
469     
470         END LOOP;
471     
472     END IF;
473
474 END;
475 $$ LANGUAGE PLPGSQL;
476
477
478 CREATE OR REPLACE FUNCTION vandelay.ingest_bib_marc ( ) RETURNS TRIGGER AS $$
479 DECLARE
480     value   TEXT;
481     atype   TEXT;
482     adef    RECORD;
483 BEGIN
484     FOR adef IN SELECT * FROM vandelay.bib_attr_definition LOOP
485
486         SELECT extract_marc_field('vandelay.queued_bib_record', id, adef.xpath, adef.remove) INTO value FROM vandelay.queued_bib_record WHERE id = NEW.id;
487         IF (value IS NOT NULL AND value <> '') THEN
488             INSERT INTO vandelay.queued_bib_record_attr (record, field, attr_value) VALUES (NEW.id, adef.id, value);
489         END IF;
490
491     END LOOP;
492
493     RETURN NULL;
494 END;
495 $$ LANGUAGE PLPGSQL;
496
497 CREATE OR REPLACE FUNCTION vandelay.match_bib_record ( ) RETURNS TRIGGER AS $func$
498 DECLARE
499     attr    RECORD;
500     eg_rec  RECORD;
501 BEGIN
502     FOR attr IN SELECT a.* FROM vandelay.queued_bib_record_attr a JOIN vandelay.bib_attr_definition d ON (d.id = a.field) WHERE record = NEW.id AND d.ident IS TRUE LOOP
503
504                 -- All numbers? check for an id match
505                 IF (attr.attr_value ~ $r$^\d+$$r$) THEN
506                 FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE id = attr.attr_value::BIGINT AND deleted IS FALSE LOOP
507                         INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('id', attr.id, NEW.id, eg_rec.id);
508                         END LOOP;
509                 END IF;
510
511                 -- Looks like an ISBN? check for an isbn match
512                 IF (attr.attr_value ~* $r$^[0-9x]+$$r$ AND character_length(attr.attr_value) IN (10,13)) THEN
513                 FOR eg_rec IN EXECUTE $$SELECT * FROM metabib.full_rec fr WHERE fr.value LIKE LOWER('$$ || attr.attr_value || $$%') AND fr.tag = '020' AND fr.subfield = 'a'$$ LOOP
514                                 PERFORM id FROM biblio.record_entry WHERE id = eg_rec.record AND deleted IS FALSE;
515                                 IF FOUND THEN
516                                 INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('isbn', attr.id, NEW.id, eg_rec.record);
517                                 END IF;
518                         END LOOP;
519
520                         -- subcheck for isbn-as-tcn
521                     FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE tcn_value = 'i' || attr.attr_value AND deleted IS FALSE LOOP
522                             INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('tcn_value', attr.id, NEW.id, eg_rec.id);
523                 END LOOP;
524                 END IF;
525
526                 -- check for an OCLC tcn_value match
527                 IF (attr.attr_value ~ $r$^o\d+$$r$) THEN
528                     FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE tcn_value = regexp_replace(attr.attr_value,'^o','ocm') AND deleted IS FALSE LOOP
529                             INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('tcn_value', attr.id, NEW.id, eg_rec.id);
530                 END LOOP;
531                 END IF;
532
533                 -- check for a direct tcn_value match
534         FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE tcn_value = attr.attr_value AND deleted IS FALSE LOOP
535             INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('tcn_value', attr.id, NEW.id, eg_rec.id);
536         END LOOP;
537
538     END LOOP;
539
540     RETURN NULL;
541 END;
542 $func$ LANGUAGE PLPGSQL;
543
544 CREATE OR REPLACE FUNCTION vandelay.cleanup_bib_marc ( ) RETURNS TRIGGER AS $$
545 BEGIN
546     DELETE FROM vandelay.queued_bib_record_attr WHERE lineitem = OLD.id;
547     IF TG_OP = 'UPDATE' THEN
548         RETURN NEW;
549     END IF;
550     RETURN OLD;
551 END;
552 $$ LANGUAGE PLPGSQL;
553
554 CREATE TRIGGER cleanup_bib_trigger
555     BEFORE UPDATE OR DELETE ON vandelay.queued_bib_record
556     FOR EACH ROW EXECUTE PROCEDURE vandelay.cleanup_bib_marc();
557
558 CREATE TRIGGER ingest_bib_trigger
559     AFTER INSERT OR UPDATE ON vandelay.queued_bib_record
560     FOR EACH ROW EXECUTE PROCEDURE vandelay.ingest_bib_marc();
561
562 CREATE TRIGGER zz_match_bibs_trigger
563     AFTER INSERT OR UPDATE ON vandelay.queued_bib_record
564     FOR EACH ROW EXECUTE PROCEDURE vandelay.match_bib_record();
565
566
567 /* Authority stuff down here */
568 ---------------------------------------
569 CREATE TABLE vandelay.authority_attr_definition (
570         id                      SERIAL  PRIMARY KEY,
571         code            TEXT    UNIQUE NOT NULL,
572         description     TEXT,
573         xpath           TEXT    NOT NULL,
574         remove          TEXT    NOT NULL DEFAULT '',
575         ident           BOOL    NOT NULL DEFAULT FALSE
576 );
577 INSERT INTO vandelay.authority_attr_definition ( code, description, xpath, ident ) VALUES ('rec_identifier','Identifier','//*[@tag="001"]', TRUE);
578
579 CREATE TABLE vandelay.authority_queue (
580         queue_type      TEXT            NOT NULL DEFAULT 'authority' CHECK (queue_type = 'authority'),
581         CONSTRAINT vand_authority_queue_name_once_per_owner_const UNIQUE (owner,name,queue_type)
582 ) INHERITS (vandelay.queue);
583 ALTER TABLE vandelay.authority_queue ADD PRIMARY KEY (id);
584
585 CREATE TABLE vandelay.queued_authority_record (
586         queue           INT     NOT NULL REFERENCES vandelay.authority_queue (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
587         imported_as     INT     REFERENCES authority.record_entry (id) DEFERRABLE INITIALLY DEFERRED
588 ) INHERITS (vandelay.queued_record);
589 ALTER TABLE vandelay.queued_authority_record ADD PRIMARY KEY (id);
590
591 CREATE TABLE vandelay.queued_authority_record_attr (
592         id                      BIGSERIAL       PRIMARY KEY,
593         record          BIGINT          NOT NULL REFERENCES vandelay.queued_authority_record (id) DEFERRABLE INITIALLY DEFERRED,
594         field           INT                     NOT NULL REFERENCES vandelay.authority_attr_definition (id) DEFERRABLE INITIALLY DEFERRED,
595         attr_value      TEXT            NOT NULL
596 );
597
598 CREATE TABLE vandelay.authority_match (
599         id                              BIGSERIAL       PRIMARY KEY,
600         matched_attr    INT                     REFERENCES vandelay.queued_authority_record_attr (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
601         queued_record   BIGINT          REFERENCES vandelay.queued_authority_record (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
602         eg_record               BIGINT          REFERENCES authority.record_entry (id) DEFERRABLE INITIALLY DEFERRED
603 );
604
605 CREATE OR REPLACE FUNCTION vandelay.ingest_authority_marc ( ) RETURNS TRIGGER AS $$
606 DECLARE
607     value   TEXT;
608     atype   TEXT;
609     adef    RECORD;
610 BEGIN
611     FOR adef IN SELECT * FROM vandelay.authority_attr_definition LOOP
612
613         SELECT extract_marc_field('vandelay.queued_authority_record', id, adef.xpath, adef.remove) INTO value FROM vandelay.queued_authority_record WHERE id = NEW.id;
614         IF (value IS NOT NULL AND value <> '') THEN
615             INSERT INTO vandelay.queued_authority_record_attr (record, field, attr_value) VALUES (NEW.id, adef.id, value);
616         END IF;
617
618     END LOOP;
619
620     RETURN NULL;
621 END;
622 $$ LANGUAGE PLPGSQL;
623
624 CREATE OR REPLACE FUNCTION vandelay.cleanup_authority_marc ( ) RETURNS TRIGGER AS $$
625 BEGIN
626     DELETE FROM vandelay.queued_authority_record_attr WHERE lineitem = OLD.id;
627     IF TG_OP = 'UPDATE' THEN
628         RETURN NEW;
629     END IF;
630     RETURN OLD;
631 END;
632 $$ LANGUAGE PLPGSQL;
633
634 CREATE TRIGGER cleanup_authority_trigger
635     BEFORE UPDATE OR DELETE ON vandelay.queued_authority_record
636     FOR EACH ROW EXECUTE PROCEDURE vandelay.cleanup_authority_marc();
637
638 CREATE TRIGGER ingest_authority_trigger
639     AFTER INSERT OR UPDATE ON vandelay.queued_authority_record
640     FOR EACH ROW EXECUTE PROCEDURE vandelay.ingest_authority_marc();
641
642 COMMIT;
643