]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/sql/Pg/012.schema.vandelay.sql
added some missing param commas
[working/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   BIGINT 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 DEFERRABLE INITIALLY DEFERRED,
103     definition      BIGINT      NOT NULL REFERENCES vandelay.import_item_attr_definition (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
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.add_field ( incumbent_xml TEXT, incoming_xml TEXT, field TEXT ) RETURNS TEXT AS $_$
133
134     use MARC::Record;
135     use MARC::File::XML;
136
137     my $incumbent_xml = shift;
138     my $incoming_xml = shift;
139     my $field_spec = shift;
140     $field_spec =~ s/\s+//g;
141
142     my $incumbent_r = MARC::Record->new_from_xml( $incumbent_xml );
143     my $incoming_r = MARC::Record->new_from_xml( $incoming_xml );
144
145     return $incumbent_xml unless ($incumbent_r && $incoming_r);
146
147     my @field_list = split(',', $field_spec);
148
149     my %fields;
150     for my $f (@field_list) {
151         if ($f =~ /^(.{3})(.*)$/) {
152             $fields{$1} = [ split('', $2) ];
153         }
154     }
155
156     for my $f ( keys %fields) {
157         if ( @{$fields{$f}} ) {
158             for my $from_field ($incoming_r->field( $f )) {
159                 for my $to_field ($incumbent_r->field( $f )) {
160                     my @new_sf = map { ($_ => $from_field->subfield($_)) } @{$fields{$f}};
161                     $to_field->add_subfields( @new_sf );
162                 }
163             }
164         } else {
165             my @new_fields = map { $_->clone } $incoming_r->field( $f );
166             $incumbent_r->insert_fields_ordered( @new_fields );
167         }
168     }
169
170     $incumbent_xml = $incumbent_r->as_xml_record;
171     $incumbent_xml =~ s/^<\?.+?\?>$//mo;
172     $incumbent_xml =~ s/\n//sgo;
173     $incumbent_xml =~ s/>\s+</></sgo;
174
175     return $incumbent_xml;
176
177 $_$ LANGUAGE PLPERLU;
178
179 CREATE OR REPLACE FUNCTION vandelay.strip_field ( xml TEXT, field TEXT ) RETURNS TEXT AS $_$
180
181     use MARC::Record;
182     use MARC::File::XML;
183
184     my $xml = shift;
185     my $r = MARC::Record->new_from_xml( $xml );
186
187     return $xml unless ($r);
188
189     my $field_spec = shift;
190     $field_spec =~ s/\s+//g;
191
192     my @field_list = split(',', $field_spec);
193
194     my %fields;
195     for my $f (@field_list) {
196         if ($f =~ /^(.{3})(.*)$/) {
197             $fields{$1} = [ split('', $2) ];
198         }
199     }
200
201     for my $f ( keys %fields) {
202         if ( @{$fields{$f}} ) {
203             $_->delete_subfield(code => $fields{$f}) for ($r->field( $f ));
204         } else {
205             $r->delete_field( $_ ) for ( $r->field( $f ) );
206         }
207     }
208
209     $xml = $r->as_xml_record;
210     $xml =~ s/^<\?.+?\?>$//mo;
211     $xml =~ s/\n//sgo;
212     $xml =~ s/>\s+</></sgo;
213
214     return $xml;
215
216 $_$ LANGUAGE PLPERLU;
217
218 CREATE OR REPLACE FUNCTION vandelay.replace_field ( incumbent_xml TEXT, incoming_xml TEXT, field TEXT ) RETURNS TEXT AS $_$
219     SELECT vandelay.add_field( vandelay.strip_field( $1, $3), $2, $3 );
220 $_$ LANGUAGE SQL;
221
222 CREATE OR REPLACE FUNCTION vandelay.preserve_field ( incumbent_xml TEXT, incoming_xml TEXT, field TEXT ) RETURNS TEXT AS $_$
223     SELECT vandelay.add_field( vandelay.strip_field( $2, $3), $1, $3 );
224 $_$ LANGUAGE SQL;
225
226 CREATE OR REPLACE FUNCTION vandelay.ingest_items ( import_id BIGINT, attr_def_id BIGINT ) RETURNS SETOF vandelay.import_item AS $$
227 DECLARE
228
229     owning_lib      TEXT;
230     circ_lib        TEXT;
231     call_number     TEXT;
232     copy_number     TEXT;
233     status          TEXT;
234     location        TEXT;
235     circulate       TEXT;
236     deposit         TEXT;
237     deposit_amount  TEXT;
238     ref             TEXT;
239     holdable        TEXT;
240     price           TEXT;
241     barcode         TEXT;
242     circ_modifier   TEXT;
243     circ_as_type    TEXT;
244     alert_message   TEXT;
245     opac_visible    TEXT;
246     pub_note        TEXT;
247     priv_note       TEXT;
248
249     attr_def        RECORD;
250     tmp_attr_set    RECORD;
251     attr_set        vandelay.import_item%ROWTYPE;
252
253     xpath           TEXT;
254
255 BEGIN
256
257     SELECT * INTO attr_def FROM vandelay.import_item_attr_definition WHERE id = attr_def_id;
258
259     IF FOUND THEN
260
261         attr_set.definition := attr_def.id; 
262     
263         -- Build the combined XPath
264     
265         owning_lib :=
266             CASE
267                 WHEN attr_def.owning_lib IS NULL THEN 'null()'
268                 WHEN LENGTH( attr_def.owning_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.owning_lib || '"]'
269                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.owning_lib
270             END;
271     
272         circ_lib :=
273             CASE
274                 WHEN attr_def.circ_lib IS NULL THEN 'null()'
275                 WHEN LENGTH( attr_def.circ_lib ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_lib || '"]'
276                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_lib
277             END;
278     
279         call_number :=
280             CASE
281                 WHEN attr_def.call_number IS NULL THEN 'null()'
282                 WHEN LENGTH( attr_def.call_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.call_number || '"]'
283                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.call_number
284             END;
285     
286         copy_number :=
287             CASE
288                 WHEN attr_def.copy_number IS NULL THEN 'null()'
289                 WHEN LENGTH( attr_def.copy_number ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.copy_number || '"]'
290                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.copy_number
291             END;
292     
293         status :=
294             CASE
295                 WHEN attr_def.status IS NULL THEN 'null()'
296                 WHEN LENGTH( attr_def.status ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.status || '"]'
297                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.status
298             END;
299     
300         location :=
301             CASE
302                 WHEN attr_def.location IS NULL THEN 'null()'
303                 WHEN LENGTH( attr_def.location ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.location || '"]'
304                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.location
305             END;
306     
307         circulate :=
308             CASE
309                 WHEN attr_def.circulate IS NULL THEN 'null()'
310                 WHEN LENGTH( attr_def.circulate ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circulate || '"]'
311                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circulate
312             END;
313     
314         deposit :=
315             CASE
316                 WHEN attr_def.deposit IS NULL THEN 'null()'
317                 WHEN LENGTH( attr_def.deposit ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit || '"]'
318                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit
319             END;
320     
321         deposit_amount :=
322             CASE
323                 WHEN attr_def.deposit_amount IS NULL THEN 'null()'
324                 WHEN LENGTH( attr_def.deposit_amount ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.deposit_amount || '"]'
325                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.deposit_amount
326             END;
327     
328         ref :=
329             CASE
330                 WHEN attr_def.ref IS NULL THEN 'null()'
331                 WHEN LENGTH( attr_def.ref ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.ref || '"]'
332                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.ref
333             END;
334     
335         holdable :=
336             CASE
337                 WHEN attr_def.holdable IS NULL THEN 'null()'
338                 WHEN LENGTH( attr_def.holdable ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.holdable || '"]'
339                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.holdable
340             END;
341     
342         price :=
343             CASE
344                 WHEN attr_def.price IS NULL THEN 'null()'
345                 WHEN LENGTH( attr_def.price ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.price || '"]'
346                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.price
347             END;
348     
349         barcode :=
350             CASE
351                 WHEN attr_def.barcode IS NULL THEN 'null()'
352                 WHEN LENGTH( attr_def.barcode ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.barcode || '"]'
353                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.barcode
354             END;
355     
356         circ_modifier :=
357             CASE
358                 WHEN attr_def.circ_modifier IS NULL THEN 'null()'
359                 WHEN LENGTH( attr_def.circ_modifier ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_modifier || '"]'
360                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_modifier
361             END;
362     
363         circ_as_type :=
364             CASE
365                 WHEN attr_def.circ_as_type IS NULL THEN 'null()'
366                 WHEN LENGTH( attr_def.circ_as_type ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.circ_as_type || '"]'
367                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.circ_as_type
368             END;
369     
370         alert_message :=
371             CASE
372                 WHEN attr_def.alert_message IS NULL THEN 'null()'
373                 WHEN LENGTH( attr_def.alert_message ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.alert_message || '"]'
374                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.alert_message
375             END;
376     
377         opac_visible :=
378             CASE
379                 WHEN attr_def.opac_visible IS NULL THEN 'null()'
380                 WHEN LENGTH( attr_def.opac_visible ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.opac_visible || '"]'
381                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.opac_visible
382             END;
383
384         pub_note :=
385             CASE
386                 WHEN attr_def.pub_note IS NULL THEN 'null()'
387                 WHEN LENGTH( attr_def.pub_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.pub_note || '"]'
388                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.pub_note
389             END;
390         priv_note :=
391             CASE
392                 WHEN attr_def.priv_note IS NULL THEN 'null()'
393                 WHEN LENGTH( attr_def.priv_note ) = 1 THEN '//*[@tag="' || attr_def.tag || '"]/*[@code="' || attr_def.priv_note || '"]'
394                 ELSE '//*[@tag="' || attr_def.tag || '"]/*' || attr_def.priv_note
395             END;
396     
397     
398         xpath := 
399             owning_lib      || '|' || 
400             circ_lib        || '|' || 
401             call_number     || '|' || 
402             copy_number     || '|' || 
403             status          || '|' || 
404             location        || '|' || 
405             circulate       || '|' || 
406             deposit         || '|' || 
407             deposit_amount  || '|' || 
408             ref             || '|' || 
409             holdable        || '|' || 
410             price           || '|' || 
411             barcode         || '|' || 
412             circ_modifier   || '|' || 
413             circ_as_type    || '|' || 
414             alert_message   || '|' || 
415             pub_note        || '|' || 
416             priv_note       || '|' || 
417             opac_visible;
418
419         -- RAISE NOTICE 'XPath: %', xpath;
420         
421         FOR tmp_attr_set IN
422                 SELECT  *
423                   FROM  oils_xpath_table( 'id', 'marc', 'vandelay.queued_bib_record', xpath, 'id = ' || import_id )
424                             AS t( id INT, ol TEXT, clib TEXT, cn TEXT, cnum TEXT, cs TEXT, cl TEXT, circ TEXT,
425                                   dep TEXT, dep_amount TEXT, r TEXT, hold TEXT, pr TEXT, bc TEXT, circ_mod TEXT,
426                                   circ_as TEXT, amessage TEXT, note TEXT, pnote TEXT, opac_vis TEXT )
427         LOOP
428     
429             tmp_attr_set.pr = REGEXP_REPLACE(tmp_attr_set.pr, E'[^0-9\\.]', '', 'g');
430             tmp_attr_set.dep_amount = REGEXP_REPLACE(tmp_attr_set.dep_amount, E'[^0-9\\.]', '', 'g');
431
432             tmp_attr_set.pr := NULLIF( tmp_attr_set.pr, '' );
433             tmp_attr_set.dep_amount := NULLIF( tmp_attr_set.dep_amount, '' );
434     
435             SELECT id INTO attr_set.owning_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.ol); -- INT
436             SELECT id INTO attr_set.circ_lib FROM actor.org_unit WHERE shortname = UPPER(tmp_attr_set.clib); -- INT
437             SELECT id INTO attr_set.status FROM config.copy_status WHERE LOWER(name) = LOWER(tmp_attr_set.cs); -- INT
438     
439             SELECT  id INTO attr_set.location
440               FROM  asset.copy_location
441               WHERE LOWER(name) = LOWER(tmp_attr_set.cl)
442                     AND asset.copy_location.owning_lib = COALESCE(attr_set.owning_lib, attr_set.circ_lib); -- INT
443     
444             attr_set.circulate      :=
445                 LOWER( SUBSTRING( tmp_attr_set.circ, 1, 1)) IN ('t','y','1')
446                 OR LOWER(tmp_attr_set.circ) = 'circulating'; -- BOOL
447
448             attr_set.deposit        :=
449                 LOWER( SUBSTRING( tmp_attr_set.dep, 1, 1 ) ) IN ('t','y','1')
450                 OR LOWER(tmp_attr_set.dep) = 'deposit'; -- BOOL
451
452             attr_set.holdable       :=
453                 LOWER( SUBSTRING( tmp_attr_set.hold, 1, 1 ) ) IN ('t','y','1')
454                 OR LOWER(tmp_attr_set.hold) = 'holdable'; -- BOOL
455
456             attr_set.opac_visible   :=
457                 LOWER( SUBSTRING( tmp_attr_set.opac_vis, 1, 1 ) ) IN ('t','y','1')
458                 OR LOWER(tmp_attr_set.opac_vis) = 'visible'; -- BOOL
459
460             attr_set.ref            :=
461                 LOWER( SUBSTRING( tmp_attr_set.r, 1, 1 ) ) IN ('t','y','1')
462                 OR LOWER(tmp_attr_set.r) = 'reference'; -- BOOL
463     
464             attr_set.copy_number    := tmp_attr_set.cnum::INT; -- INT,
465             attr_set.deposit_amount := tmp_attr_set.dep_amount::NUMERIC(6,2); -- NUMERIC(6,2),
466             attr_set.price          := tmp_attr_set.pr::NUMERIC(8,2); -- NUMERIC(8,2),
467     
468             attr_set.call_number    := tmp_attr_set.cn; -- TEXT
469             attr_set.barcode        := tmp_attr_set.bc; -- TEXT,
470             attr_set.circ_modifier  := tmp_attr_set.circ_mod; -- TEXT,
471             attr_set.circ_as_type   := tmp_attr_set.circ_as; -- TEXT,
472             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
473             attr_set.pub_note       := tmp_attr_set.note; -- TEXT,
474             attr_set.priv_note      := tmp_attr_set.pnote; -- TEXT,
475             attr_set.alert_message  := tmp_attr_set.amessage; -- TEXT,
476     
477             RETURN NEXT attr_set;
478     
479         END LOOP;
480     
481     END IF;
482
483 END;
484 $$ LANGUAGE PLPGSQL;
485
486
487 CREATE OR REPLACE FUNCTION vandelay.ingest_bib_marc ( ) RETURNS TRIGGER AS $$
488 DECLARE
489     value   TEXT;
490     atype   TEXT;
491     adef    RECORD;
492 BEGIN
493     FOR adef IN SELECT * FROM vandelay.bib_attr_definition LOOP
494
495         SELECT extract_marc_field('vandelay.queued_bib_record', id, adef.xpath, adef.remove) INTO value FROM vandelay.queued_bib_record WHERE id = NEW.id;
496         IF (value IS NOT NULL AND value <> '') THEN
497             INSERT INTO vandelay.queued_bib_record_attr (record, field, attr_value) VALUES (NEW.id, adef.id, value);
498         END IF;
499
500     END LOOP;
501
502     RETURN NULL;
503 END;
504 $$ LANGUAGE PLPGSQL;
505
506 CREATE OR REPLACE FUNCTION vandelay.ingest_bib_items ( ) RETURNS TRIGGER AS $func$
507 DECLARE
508     attr_def    BIGINT;
509     item_data   vandelay.import_item%ROWTYPE;
510 BEGIN
511
512     SELECT item_attr_def INTO attr_def FROM vandelay.bib_queue WHERE id = NEW.queue;
513
514     FOR item_data IN SELECT * FROM vandelay.ingest_items( NEW.id::BIGINT, attr_def ) LOOP
515         INSERT INTO vandelay.import_item (
516             record,
517             definition,
518             owning_lib,
519             circ_lib,
520             call_number,
521             copy_number,
522             status,
523             location,
524             circulate,
525             deposit,
526             deposit_amount,
527             ref,
528             holdable,
529             price,
530             barcode,
531             circ_modifier,
532             circ_as_type,
533             alert_message,
534             pub_note,
535             priv_note,
536             opac_visible
537         ) VALUES (
538             NEW.id,
539             item_data.definition,
540             item_data.owning_lib,
541             item_data.circ_lib,
542             item_data.call_number,
543             item_data.copy_number,
544             item_data.status,
545             item_data.location,
546             item_data.circulate,
547             item_data.deposit,
548             item_data.deposit_amount,
549             item_data.ref,
550             item_data.holdable,
551             item_data.price,
552             item_data.barcode,
553             item_data.circ_modifier,
554             item_data.circ_as_type,
555             item_data.alert_message,
556             item_data.pub_note,
557             item_data.priv_note,
558             item_data.opac_visible
559         );
560     END LOOP;
561
562     RETURN NULL;
563 END;
564 $func$ LANGUAGE PLPGSQL;
565
566 CREATE OR REPLACE FUNCTION vandelay.match_bib_record ( ) RETURNS TRIGGER AS $func$
567 DECLARE
568     attr    RECORD;
569     eg_rec  RECORD;
570 BEGIN
571     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
572
573                 -- All numbers? check for an id match
574                 IF (attr.attr_value ~ $r$^\d+$$r$) THEN
575                 FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE id = attr.attr_value::BIGINT AND deleted IS FALSE LOOP
576                         INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('id', attr.id, NEW.id, eg_rec.id);
577                         END LOOP;
578                 END IF;
579
580                 -- Looks like an ISBN? check for an isbn match
581                 IF (attr.attr_value ~* $r$^[0-9x]+$$r$ AND character_length(attr.attr_value) IN (10,13)) THEN
582                 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
583                                 PERFORM id FROM biblio.record_entry WHERE id = eg_rec.record AND deleted IS FALSE;
584                                 IF FOUND THEN
585                                 INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('isbn', attr.id, NEW.id, eg_rec.record);
586                                 END IF;
587                         END LOOP;
588
589                         -- subcheck for isbn-as-tcn
590                     FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE tcn_value = 'i' || attr.attr_value AND deleted IS FALSE LOOP
591                             INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('tcn_value', attr.id, NEW.id, eg_rec.id);
592                 END LOOP;
593                 END IF;
594
595                 -- check for an OCLC tcn_value match
596                 IF (attr.attr_value ~ $r$^o\d+$$r$) THEN
597                     FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE tcn_value = regexp_replace(attr.attr_value,'^o','ocm') AND deleted IS FALSE LOOP
598                             INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('tcn_value', attr.id, NEW.id, eg_rec.id);
599                 END LOOP;
600                 END IF;
601
602                 -- check for a direct tcn_value match
603         FOR eg_rec IN SELECT * FROM biblio.record_entry WHERE tcn_value = attr.attr_value AND deleted IS FALSE LOOP
604             INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('tcn_value', attr.id, NEW.id, eg_rec.id);
605         END LOOP;
606
607                 -- check for a direct item barcode match
608         FOR eg_rec IN
609                 SELECT  DISTINCT b.*
610                   FROM  biblio.record_entry b
611                         JOIN asset.call_number cn ON (cn.record = b.id)
612                         JOIN asset.copy cp ON (cp.call_number = cn.id)
613                   WHERE cp.barcode = attr.attr_value AND cp.deleted IS FALSE
614         LOOP
615             INSERT INTO vandelay.bib_match (field_type, matched_attr, queued_record, eg_record) VALUES ('id', attr.id, NEW.id, eg_rec.id);
616         END LOOP;
617
618     END LOOP;
619
620     RETURN NULL;
621 END;
622 $func$ LANGUAGE PLPGSQL;
623
624 CREATE OR REPLACE FUNCTION vandelay.cleanup_bib_marc ( ) RETURNS TRIGGER AS $$
625 BEGIN
626     DELETE FROM vandelay.queued_bib_record_attr WHERE record = OLD.id;
627     DELETE FROM vandelay.import_item WHERE record = OLD.id;
628
629     IF TG_OP = 'UPDATE' THEN
630         RETURN NEW;
631     END IF;
632     RETURN OLD;
633 END;
634 $$ LANGUAGE PLPGSQL;
635
636 CREATE TRIGGER cleanup_bib_trigger
637     BEFORE UPDATE OR DELETE ON vandelay.queued_bib_record
638     FOR EACH ROW EXECUTE PROCEDURE vandelay.cleanup_bib_marc();
639
640 CREATE TRIGGER ingest_bib_trigger
641     AFTER INSERT OR UPDATE ON vandelay.queued_bib_record
642     FOR EACH ROW EXECUTE PROCEDURE vandelay.ingest_bib_marc();
643
644 CREATE TRIGGER ingest_item_trigger
645     AFTER INSERT OR UPDATE ON vandelay.queued_bib_record
646     FOR EACH ROW EXECUTE PROCEDURE vandelay.ingest_bib_items();
647
648 CREATE TRIGGER zz_match_bibs_trigger
649     AFTER INSERT OR UPDATE ON vandelay.queued_bib_record
650     FOR EACH ROW EXECUTE PROCEDURE vandelay.match_bib_record();
651
652
653 /* Authority stuff down here */
654 ---------------------------------------
655 CREATE TABLE vandelay.authority_attr_definition (
656         id                      SERIAL  PRIMARY KEY,
657         code            TEXT    UNIQUE NOT NULL,
658         description     TEXT,
659         xpath           TEXT    NOT NULL,
660         remove          TEXT    NOT NULL DEFAULT '',
661         ident           BOOL    NOT NULL DEFAULT FALSE
662 );
663
664 CREATE TABLE vandelay.authority_queue (
665         queue_type      TEXT            NOT NULL DEFAULT 'authority' CHECK (queue_type = 'authority'),
666         CONSTRAINT vand_authority_queue_name_once_per_owner_const UNIQUE (owner,name,queue_type)
667 ) INHERITS (vandelay.queue);
668 ALTER TABLE vandelay.authority_queue ADD PRIMARY KEY (id);
669
670 CREATE TABLE vandelay.queued_authority_record (
671         queue           INT     NOT NULL REFERENCES vandelay.authority_queue (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
672         imported_as     INT     REFERENCES authority.record_entry (id) DEFERRABLE INITIALLY DEFERRED
673 ) INHERITS (vandelay.queued_record);
674 ALTER TABLE vandelay.queued_authority_record ADD PRIMARY KEY (id);
675
676 CREATE TABLE vandelay.queued_authority_record_attr (
677         id                      BIGSERIAL       PRIMARY KEY,
678         record          BIGINT          NOT NULL REFERENCES vandelay.queued_authority_record (id) DEFERRABLE INITIALLY DEFERRED,
679         field           INT                     NOT NULL REFERENCES vandelay.authority_attr_definition (id) DEFERRABLE INITIALLY DEFERRED,
680         attr_value      TEXT            NOT NULL
681 );
682
683 CREATE TABLE vandelay.authority_match (
684         id                              BIGSERIAL       PRIMARY KEY,
685         matched_attr    INT                     REFERENCES vandelay.queued_authority_record_attr (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
686         queued_record   BIGINT          REFERENCES vandelay.queued_authority_record (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
687         eg_record               BIGINT          REFERENCES authority.record_entry (id) DEFERRABLE INITIALLY DEFERRED
688 );
689
690 CREATE OR REPLACE FUNCTION vandelay.ingest_authority_marc ( ) RETURNS TRIGGER AS $$
691 DECLARE
692     value   TEXT;
693     atype   TEXT;
694     adef    RECORD;
695 BEGIN
696     FOR adef IN SELECT * FROM vandelay.authority_attr_definition LOOP
697
698         SELECT extract_marc_field('vandelay.queued_authority_record', id, adef.xpath, adef.remove) INTO value FROM vandelay.queued_authority_record WHERE id = NEW.id;
699         IF (value IS NOT NULL AND value <> '') THEN
700             INSERT INTO vandelay.queued_authority_record_attr (record, field, attr_value) VALUES (NEW.id, adef.id, value);
701         END IF;
702
703     END LOOP;
704
705     RETURN NULL;
706 END;
707 $$ LANGUAGE PLPGSQL;
708
709 CREATE OR REPLACE FUNCTION vandelay.cleanup_authority_marc ( ) RETURNS TRIGGER AS $$
710 BEGIN
711     DELETE FROM vandelay.queued_authority_record_attr WHERE record = OLD.id;
712     IF TG_OP = 'UPDATE' THEN
713         RETURN NEW;
714     END IF;
715     RETURN OLD;
716 END;
717 $$ LANGUAGE PLPGSQL;
718
719 CREATE TRIGGER cleanup_authority_trigger
720     BEFORE UPDATE OR DELETE ON vandelay.queued_authority_record
721     FOR EACH ROW EXECUTE PROCEDURE vandelay.cleanup_authority_marc();
722
723 CREATE TRIGGER ingest_authority_trigger
724     AFTER INSERT OR UPDATE ON vandelay.queued_authority_record
725     FOR EACH ROW EXECUTE PROCEDURE vandelay.ingest_authority_marc();
726
727 -- Vandelay (for importing and exporting records) 012.schema.vandelay.sql 
728 --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)]');
729 --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)]');
730 --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]');
731 --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]');
732 --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$);
733 --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$);
734 --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]');
735 --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);
736 --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);
737 --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);
738 --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);
739 --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]');
740 --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$);
741 --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]');
742 --
743 --INSERT INTO vandelay.import_item_attr_definition (
744 --    owner, name, tag, owning_lib, circ_lib, location,
745 --    call_number, circ_modifier, barcode, price, copy_number,
746 --    circulate, ref, holdable, opac_visible, status
747 --) VALUES (
748 --    1,
749 --    'Evergreen 852 export format',
750 --    '852',
751 --    '[@code = "b"][1]',
752 --    '[@code = "b"][2]',
753 --    'c',
754 --    'j',
755 --    'g',
756 --    'p',
757 --    'y',
758 --    't',
759 --    '[@code = "x" and text() = "circulating"]',
760 --    '[@code = "x" and text() = "reference"]',
761 --    '[@code = "x" and text() = "holdable"]',
762 --    '[@code = "x" and text() = "visible"]',
763 --    'z'
764 --);
765 --
766 --INSERT INTO vandelay.import_item_attr_definition (
767 --    owner,
768 --    name,
769 --    tag,
770 --    owning_lib,
771 --    location,
772 --    call_number,
773 --    circ_modifier,
774 --    barcode,
775 --    price,
776 --    status
777 --) VALUES (
778 --    1,
779 --    'Unicorn Import format -- 999',
780 --    '999',
781 --    'm',
782 --    'l',
783 --    'a',
784 --    't',
785 --    'i',
786 --    'p',
787 --    'k'
788 --);
789 --
790 --INSERT INTO vandelay.authority_attr_definition ( code, description, xpath, ident ) VALUES ('rec_identifier','Identifier','//*[@tag="001"]', TRUE);
791
792 COMMIT;
793