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