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