[open-ils-commits] [GIT] Evergreen ILS branch master updated. b930174c8c3cf75309993e9f90d9fb8d816e4d23

Evergreen Git git at git.evergreen-ils.org
Fri Sep 1 17:17:56 EDT 2017


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  b930174c8c3cf75309993e9f90d9fb8d816e4d23 (commit)
       via  0161aef74694648a57307915157469246947e9d1 (commit)
       via  4d96474c8f085392c2c5dc21d0ba40a5a8e7c814 (commit)
       via  d74649d498fd83f1651a1b39f474d530e822eba3 (commit)
       via  c095a3adb3649c575bcfcb846040c16b79757661 (commit)
       via  0403f71a2e5458c73ed4ad9ce26e15608fbd3990 (commit)
       via  eee9c17df8e49ed5661b1cb56918a85bc041863f (commit)
       via  6e86943b5ae02217330ec71ef30ecf68abe0f9ff (commit)
       via  436345ea4808152bdeee1f737a4073f15b73f2df (commit)
       via  2ce54127d256e0087abcf2be8a1e0258b22ffee8 (commit)
       via  4d9df04f07e77f91f7c2d4830ff16b8d67f633e5 (commit)
       via  c7598ec8d3d4cf442ed2c3cb153b00ec4cf58ce4 (commit)
       via  1ffccff52c4a003c7d56c5e67477d173b6d3256f (commit)
       via  2b9e0ff2b769f58cdda42022fda0c7e2fd45131a (commit)
       via  a473001c669604d9085d3bda6484b320d3bcd754 (commit)
       via  071ca406ba4806b9be9abf3565b685e6c17efbc1 (commit)
       via  4196a3a4c181debd68be410dc18897bfdc4841e2 (commit)
       via  0773c439935f172ed571186d45f41bef1a1b8e0e (commit)
       via  11507993c4befcbdbe8d2c46c2f9e5ab40920c31 (commit)
       via  054027e6340baf5d2f7e58287ed6e1253cab4382 (commit)
       via  9d57def5f515dc7aa9ef11a02f016e6fe8a33b17 (commit)
       via  0f98fc18012ac949e1b299a7339bbea9639648bf (commit)
       via  537efb752bb1508f885edba22e65af26716ec303 (commit)
      from  3a14a5078160139d6e724dba0f6c295e6ba1f86c (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b930174c8c3cf75309993e9f90d9fb8d816e4d23
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Sep 1 17:17:16 2017 -0400

    Stamping upgrade scripts for Display Fields and Vandelay regression
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index ff27a68..06c7836 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -92,7 +92,7 @@ CREATE TRIGGER no_overlapping_deps
     BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1072', :eg_version); -- gmcharlt/kmlussier
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('1075', :eg_version); -- gmcharlt/miker
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/1073.schema.metabib-display-field.sql
similarity index 99%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
rename to Open-ILS/src/sql/Pg/upgrade/1073.schema.metabib-display-field.sql
index 2e452b9..a0c4e6c 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/1073.schema.metabib-display-field.sql
@@ -1,6 +1,8 @@
 
 BEGIN;
 
+SELECT evergreen.upgrade_deps_block_check('1073', :eg_version);
+
 ALTER TABLE config.metabib_field 
     ADD COLUMN display_xpath TEXT, 
     ADD COLUMN display_field BOOL NOT NULL DEFAULT FALSE;
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/1074.data.metabib-display-field.sql
similarity index 94%
rename from Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
rename to Open-ILS/src/sql/Pg/upgrade/1074.data.metabib-display-field.sql
index 33fdac4..138686c 100644
--- a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/1074.data.metabib-display-field.sql
@@ -1,6 +1,8 @@
 
 BEGIN;
 
+SELECT evergreen.upgrade_deps_block_check('1074', :eg_version);
+
 INSERT INTO config.internal_flag (name, enabled) 
     VALUES ('ingest.skip_display_indexing', FALSE);
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.fix_vii_fake_fkey.sql b/Open-ILS/src/sql/Pg/upgrade/1075.schema.fix_vii_fake_fkey.sql
similarity index 89%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.schema.fix_vii_fake_fkey.sql
rename to Open-ILS/src/sql/Pg/upgrade/1075.schema.fix_vii_fake_fkey.sql
index 8c2b1e4..346b8bf 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.fix_vii_fake_fkey.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/1075.schema.fix_vii_fake_fkey.sql
@@ -1,5 +1,7 @@
 BEGIN;
 
+SELECT evergreen.upgrade_deps_block_check('1075', :eg_version);
+
 CREATE OR REPLACE FUNCTION evergreen.vandelay_import_item_imported_as_inh_fkey() RETURNS TRIGGER AS $f$
 BEGIN   
         IF NEW.imported_as IS NULL THEN

commit 0161aef74694648a57307915157469246947e9d1
Author: Galen Charlton <gmc at equinoxinitiative.org>
Date:   Fri Sep 1 17:26:32 2017 -0400

    LP#1152753: upgrade script
    
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.fix_vii_fake_fkey.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.fix_vii_fake_fkey.sql
new file mode 100644
index 0000000..8c2b1e4
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.fix_vii_fake_fkey.sql
@@ -0,0 +1,19 @@
+BEGIN;
+
+CREATE OR REPLACE FUNCTION evergreen.vandelay_import_item_imported_as_inh_fkey() RETURNS TRIGGER AS $f$
+BEGIN   
+        IF NEW.imported_as IS NULL THEN
+                RETURN NEW;
+        END IF;
+        PERFORM 1 FROM asset.copy WHERE id = NEW.imported_as;
+        IF NOT FOUND THEN
+                RAISE foreign_key_violation USING MESSAGE = FORMAT(
+                        $$Referenced asset.copy id not found, imported_as:%s$$, NEW.imported_as
+                );
+        END IF;
+        RETURN NEW;
+END;
+$f$ LANGUAGE PLPGSQL VOLATILE COST 50;
+
+
+COMMIT;

commit 4d96474c8f085392c2c5dc21d0ba40a5a8e7c814
Author: Galen Charlton <gmc at equinoxinitiative.org>
Date:   Fri Sep 1 17:22:42 2017 -0400

    LP#1152753: fix fake FK trigger on vandelay.import_item
    
    Fixes a regression caught by live_t/0824.item_import_defaults.pg
    
    Signed-off-by: Galen Charlton <gmc at equinoxinitiative.org>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/800.fkeys.sql b/Open-ILS/src/sql/Pg/800.fkeys.sql
index 8ae7d26..1ee6ead 100644
--- a/Open-ILS/src/sql/Pg/800.fkeys.sql
+++ b/Open-ILS/src/sql/Pg/800.fkeys.sql
@@ -110,6 +110,9 @@ ALTER TABLE serial.unit ADD CONSTRAINT serial_unit_editor_fkey FOREIGN KEY (edit
 
 CREATE OR REPLACE FUNCTION evergreen.vandelay_import_item_imported_as_inh_fkey() RETURNS TRIGGER AS $f$
 BEGIN
+        IF NEW.imported_as IS NULL THEN
+                RETURN NEW;
+        END IF;
         PERFORM 1 FROM asset.copy WHERE id = NEW.imported_as;
         IF NOT FOUND THEN
                 RAISE foreign_key_violation USING MESSAGE = FORMAT(

commit d74649d498fd83f1651a1b39f474d530e822eba3
Author: Bill Erickson <berickxx at gmail.com>
Date:   Fri Aug 25 12:58:00 2017 -0400

    LP#1251394 Display fields release notes
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/docs/RELEASE_NOTES_NEXT/Administration/display-fields.adoc b/docs/RELEASE_NOTES_NEXT/Administration/display-fields.adoc
new file mode 100644
index 0000000..dbeeb9d
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/Administration/display-fields.adoc
@@ -0,0 +1,55 @@
+Configurable Bib Record Display Fields
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Admin -> Server Admin -> 'MARC Search/Facet Fields' have 2 new configuration 
+fields: 'Display Field?' and 'Display XPATH'.
+
+When 'Display Field' is set to true, data from the field will be extracted
+from each record and added to a new table of display data for each bib 
+record.  
+
+If a value is present in the 'Display XPATH' field, this XPATH will be
+applied to the extracted data *after* the base XPATH (from the 'XPath' 
+field) is applied to each field.
+
+This data acts as a replacement for the various and sundry ways bib record 
+data is currently extracted, including inline XPATH in the TPAC, reporter 
+views, real-time 'MVR' compilation from MODS, etc. and will be available
+to the user interface, notification templates, etc. for rendering bib 
+records.  
+
+The browser client gets a new service 'egBibDisplay' which is capable
+of translating the display field data from various formats into 
+data more suitable for JavaScript usage.
+
+The database gets 3 new VIEWs for representing display data in various
+formats:
+
+ * metabib.flat_display_entry
+  ** List of all display fields linked to their configuration.
+ * metabib.compressed_display_entry
+  ** Same as metabib.flat_display_entry except there's one row
+     per display field type, which 'mulit' rows compressed into
+     JSON arrays.  Non-multi fields are represented as JSON 
+     strings/numbers.
+ * metabib.wide_display_entry
+  ** Tabular view of display field data, one column per well-known
+     field.  Values are represented JSON, consistent with 
+     metabib.flat_display_entry.  The view DOE NOT CONTAIN locally
+     configured dispaly fields, as each field must be encoded in
+     the view and IDL definition.  This is essentially a replacement 
+     for reporter.simple_record.
+
+Reingesting
++++++++++++
+
+After making changes to display field configuration, it's possible to 
+reingest only display field data in the database using the following:
+
+[source,sql]
+---------------------------------------------------------------------
+SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE, 
+  (SELECT ARRAY_AGG(id)::INT[] FROM config.metabib_field WHERE display_field))
+  FROM biblio.record_entry WHERE NOT deleted AND id > 0;
+---------------------------------------------------------------------
+

commit c095a3adb3649c575bcfcb846040c16b79757661
Author: Bill Erickson <berickxx at gmail.com>
Date:   Fri Aug 25 12:40:20 2017 -0400

    LP#1251394 Author display field xpath
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
index e633751..33fdac4 100644
--- a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
@@ -14,6 +14,11 @@ INSERT INTO config.metabib_field ( id, field_class, name, label,
      'mods32', $$//mods32:mods/mods32:name[mods32:role/mods32:roleTerm[text()='creator']]$$, 
      TRUE, $$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
 
+-- 'author' field
+UPDATE config.metabib_field SET display_xpath = 
+    $$//*[local-name()='namePart']$$ -- /* to fool vim */
+    WHERE id = 8;
+
 INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('title', 6, FALSE),
     ('author', 8, FALSE),

commit 0403f71a2e5458c73ed4ad9ce26e15608fbd3990
Author: Bill Erickson <berickxx at gmail.com>
Date:   Fri Aug 25 12:28:10 2017 -0400

    LP#1251394 More representative field cleanup
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 92a8e71..4e4e969 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -2810,12 +2810,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field reporter:label="B Weight" name="b_weight" reporter:datatype="float" />
 			<field reporter:label="C Weight" name="c_weight" reporter:datatype="float" />
 			<field reporter:label="D Weight" name="d_weight" reporter:datatype="float" />
-			<field reporter:label="Representative Field" name="representative_field" reporter:datatype="link" />
 			<field reporter:label="Fields" name="fields" reporter:datatype="link" oils_persist:virtual="true"/>
 		</fields>
 		<links>
 			<link field="fields" reltype="has_many" key="name" map="" class="cmf"/>
-			<link field="representative_field" reltype="has_a" key="id" map="" class="cmf"/>
 		</links>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>

commit eee9c17df8e49ed5661b1cb56918a85bc041863f
Author: Bill Erickson <berickxx at gmail.com>
Date:   Fri Aug 25 12:15:28 2017 -0400

    LP#1251394 Display field CDBI thinko repair
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
index c6d7fdd..12f4f45 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
@@ -31,7 +31,7 @@ package config::metabib_field;
 use base qw/config/;
 __PACKAGE__->table('config_metabib_field');
 __PACKAGE__->columns(Primary => 'id');
-__PACKAGE__->columns(Essential => qw/field_class name xpath weight format search_field facet_field metabib_field/);
+__PACKAGE__->columns(Essential => qw/field_class name xpath weight format search_field facet_field display_xpath display_field/);
 #-------------------------------------------------------------------------------
 
 package config::identification_type;

commit 6e86943b5ae02217330ec71ef30ecf68abe0f9ff
Author: Bill Erickson <berickxx at gmail.com>
Date:   Fri Aug 25 11:50:27 2017 -0400

    LP#1251394 egBibDisplay service examples
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/web/js/ui/default/staff/cat/services/record.js b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
index 8dbbef2..7aa25e1 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/services/record.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
@@ -232,6 +232,47 @@ angular.module('egCoreMod')
  * the prescribed fields from the IDL (and database view), while the
  * 'mfde' hash-based objects contain all configured display fields,
  * including local/custom fields.
+ *
+ * Example:
+ *
+ *  --
+ *  // Display well-known fields
+ *
+ *  $scope.record = copy.call_number().record();
+ *
+ *  // translate wide display entry values inline
+ *  egBibDisplay.mwdeJSONToJS($scope.record.wide_display_entry());
+ *
+ *  <div>Title:</div>
+ *  <div>{{record.wide_display_entry().title()}}</div>
+ *
+ *  ---
+ *  //  Display any field using known keys
+ *
+ *  $scope.all_display_fields = 
+ *      egBibDisplay.mfdeToHash(record.flat_display_entries());
+ *
+ *  <div>Title:</div>
+ *  <div>{{all_display_fields.title}}</div>
+ *
+ *  ---
+ *  // Display all fields dynamically, using confgured labels
+ *
+ *  $scope.all_display_fields_with_meta = 
+ *      egBibDisplay.mfdeToMetaHash(record.flat_display_entries());
+ *
+ *  <div ng-repeat="(key, content) in all_display_fields_with_meta">
+ *    <div>Field Label</div><div>{{content.label}}</div>
+ *    <div ng-if="content.multi == 't'">
+ *      <div ng-repeat="val in content.value">
+ *        <div>Field Value</div><div>{{val}}</div>
+ *      </div>
+ *    </div>
+ *    <div ng-if="content.multi == 'f'">
+ *      <div>Field Value</div><div>{{content.value}}</div>
+ *    </div>
+ *  </div>
+ *
  */
 .factory('egBibDisplay', ['$q', 'egCore', function($q, egCore) {
     var service = {};

commit 436345ea4808152bdeee1f737a4073f15b73f2df
Author: Bill Erickson <berickxx at gmail.com>
Date:   Fri Aug 25 10:50:44 2017 -0400

    LP#1251394 Display field schema sync'ing
    
    Copy flat/compressed/wide display entry views into base schema.
    Synchronize a few remaining seed data bits.
    
    Replace references to 'topic_subject' in wide display views with the new
    'creators' field.
    
    Remove ZZZZ.UNDO testing SQL file.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 4d944a8..92a8e71 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -3807,7 +3807,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field name="title" reporter:label="Title" reporter:datatype="text"/>
 			<field name="author" reporter:label="Author" reporter:datatype="text"/>
 			<field name="subject" reporter:label="Subject" reporter:datatype="text"/>
-			<field name="topic_subject" reporter:label="Topic Subject" reporter:datatype="text"/>
+			<field name="creators" reporter:label="Creators" reporter:datatype="text"/>
 			<field name="isbn" reporter:label="ISBN" reporter:datatype="text"/>
 			<!-- TODO add all well-known fields -->
 		</fields>
diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index e8f3f24..ff27a68 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -48,9 +48,11 @@ INSERT INTO config.internal_flag (name) VALUES ('ingest.assume_inserts_only');
 INSERT INTO config.internal_flag (name) VALUES ('ingest.skip_browse_indexing');
 INSERT INTO config.internal_flag (name) VALUES ('ingest.skip_search_indexing');
 INSERT INTO config.internal_flag (name) VALUES ('ingest.skip_facet_indexing');
+INSERT INTO config.internal_flag (name) VALUES ('ingest.skip_display_indexing');
 INSERT INTO config.internal_flag (name) VALUES ('serial.rematerialize_on_same_holding_code');
 INSERT INTO config.internal_flag (name) VALUES ('ingest.metarecord_mapping.preserve_on_delete');
 
+
 CREATE TABLE config.global_flag (
     label   TEXT    NOT NULL
 ) INHERITS (config.internal_flag);
@@ -226,6 +228,12 @@ $$;
 
 CREATE UNIQUE INDEX config_metabib_field_class_name_idx ON config.metabib_field (field_class, name);
 
+CREATE TABLE config.display_field_map (
+    name    TEXT   PRIMARY KEY,
+    field   INTEGER REFERENCES config.metabib_field (id),
+    multi   BOOLEAN DEFAULT FALSE
+);
+
 CREATE TABLE config.ts_config_list (
 	id			TEXT PRIMARY KEY,
 	name		TEXT NOT NULL
diff --git a/Open-ILS/src/sql/Pg/030.schema.metabib.sql b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
index 0240622..f55905d 100644
--- a/Open-ILS/src/sql/Pg/030.schema.metabib.sql
+++ b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
@@ -195,6 +195,63 @@ CREATE INDEX metabib_display_entry_field_idx
 CREATE INDEX metabib_display_entry_source_idx 
     ON metabib.display_entry (source);
 
+CREATE VIEW metabib.flat_display_entry AS
+    /* One row per display entry fleshed with field info */
+    SELECT
+        mde.source,
+        cdfm.name,
+        cdfm.multi,
+        cmf.label,
+        cmf.id AS field,
+        mde.value
+    FROM metabib.display_entry mde
+    JOIN config.metabib_field cmf ON (cmf.id = mde.field)
+    JOIN config.display_field_map cdfm ON (cdfm.field = mde.field)
+;
+
+CREATE VIEW metabib.compressed_display_entry AS
+/* Like flat_display_entry except values are compressed into 
+   one row per display_field_map and JSON-ified.  */
+    SELECT 
+        source,
+        name,
+        multi,
+        label,
+        field,
+        CASE WHEN multi THEN
+            TO_JSON(ARRAY_AGG(value))
+        ELSE
+            TO_JSON(MIN(value))
+        END AS value
+    FROM metabib.flat_display_entry
+    GROUP BY 1, 2, 3, 4, 5
+;
+
+CREATE VIEW metabib.wide_display_entry AS
+/* Table-like view of well-known display fields.   
+   This VIEW expands as well-known display fields are added. */
+    SELECT 
+        bre.id AS source,
+        COALESCE(mcde_title.value, 'null') AS title,
+        COALESCE(mcde_author.value, 'null') AS author,
+        COALESCE(mcde_subject.value, 'null') AS subject,
+        COALESCE(mcde_creators.value, 'null') AS creators,
+        COALESCE(mcde_isbn.value, 'null') AS isbn
+    -- ensure one row per bre regardless of the presence of display entries
+    FROM biblio.record_entry bre 
+    LEFT JOIN metabib.compressed_display_entry mcde_title 
+        ON (bre.id = mcde_title.source AND mcde_title.name = 'title')
+    LEFT JOIN metabib.compressed_display_entry mcde_author 
+        ON (bre.id = mcde_author.source AND mcde_author.name = 'author')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject 
+        ON (bre.id = mcde_subject.source AND mcde_subject.name = 'subject')
+    LEFT JOIN metabib.compressed_display_entry mcde_creators 
+        ON (bre.id = mcde_creators.source AND mcde_creators.name = 'creators')
+    LEFT JOIN metabib.compressed_display_entry mcde_isbn 
+        ON (bre.id = mcde_isbn.source AND mcde_isbn.name = 'isbn')
+;
+
+
 CREATE TABLE metabib.browse_entry (
     id BIGSERIAL PRIMARY KEY,
     value TEXT,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index b679ff6..2e452b9 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -60,7 +60,7 @@ CREATE VIEW metabib.wide_display_entry AS
         COALESCE(mcde_title.value, 'null') AS title,
         COALESCE(mcde_author.value, 'null') AS author,
         COALESCE(mcde_subject.value, 'null') AS subject,
-        COALESCE(mcde_topic_subject.value, 'null') AS topic_subject,
+        COALESCE(mcde_creators.value, 'null') AS creators,
         COALESCE(mcde_isbn.value, 'null') AS isbn
     -- ensure one row per bre regardless of any display fields
     FROM biblio.record_entry bre 
@@ -70,8 +70,8 @@ CREATE VIEW metabib.wide_display_entry AS
         ON (bre.id = mcde_author.source AND mcde_author.name = 'author')
     LEFT JOIN metabib.compressed_display_entry mcde_subject 
         ON (bre.id = mcde_subject.source AND mcde_subject.name = 'subject')
-    LEFT JOIN metabib.compressed_display_entry mcde_topic_subject 
-        ON (bre.id = mcde_topic_subject.source AND mcde_topic_subject.name = 'topic_subject')
+    LEFT JOIN metabib.compressed_display_entry mcde_creators 
+        ON (bre.id = mcde_creators.source AND mcde_creators.name = 'creators')
     LEFT JOIN metabib.compressed_display_entry mcde_isbn 
         ON (bre.id = mcde_isbn.source AND mcde_isbn.name = 'isbn')
 ;
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
index c1258e7..e633751 100644
--- a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
@@ -11,7 +11,8 @@ UPDATE config.metabib_field SET display_field = TRUE WHERE id IN (6, 8, 16, 18);
 INSERT INTO config.metabib_field ( id, field_class, name, label,
     format, xpath, display_field, display_xpath ) VALUES
     (37, 'author', 'creator', oils_i18n_gettext(8, 'All Creators', 'cmf', 'label'),
-     'mods32', $$//mods32:mods/mods32:name[mods32:role/mods32:roleTerm[text()='creator']]$$, TRUE, $$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
+     'mods32', $$//mods32:mods/mods32:name[mods32:role/mods32:roleTerm[text()='creator']]$$, 
+     TRUE, $$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
 
 INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('title', 6, FALSE),
@@ -24,5 +25,7 @@ INSERT INTO config.display_field_map (name, field, multi) VALUES
 COMMIT;
 
 -- REINGEST DISPLAY ENTRIES
-SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE, '{6,8,16,18,37}'::INT[]) FROM biblio.record_entry WHERE NOT deleted AND id > 0;
+SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE, 
+    (SELECT ARRAY_AGG(id)::INT[] FROM config.metabib_field WHERE display_field))
+    FROM biblio.record_entry WHERE NOT deleted AND id > 0;
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql
deleted file mode 100644
index 5997b97..0000000
--- a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql
+++ /dev/null
@@ -1,308 +0,0 @@
--- XXX REVERT FILE -- DELETE THIS BEFORE MERGING XXX --
-
-DELETE FROM metabib.display_entry;
-DELETE FROM config.display_field_map;
-DELETE FROM config.metabib_field WHERE display_field; -- ASSUMES ALL NEW FIELDS
-
-DELETE FROM config.internal_flag WHERE name = 'ingest.skip_display_indexing';
-
-BEGIN;
-
-DROP FUNCTION metabib.reingest_metabib_field_entries(BIGINT, BOOL, BOOL, BOOL, BOOL);
-
-CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
-DECLARE
-    fclass          RECORD;
-    ind_data        metabib.field_entry_template%ROWTYPE;
-    mbe_row         metabib.browse_entry%ROWTYPE;
-    mbe_id          BIGINT;
-    b_skip_facet    BOOL;
-    b_skip_browse   BOOL;
-    b_skip_search   BOOL;
-    value_prepped   TEXT;
-BEGIN
-
-    SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
-    SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
-    SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
-
-    PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
-    IF NOT FOUND THEN
-        IF NOT b_skip_search THEN
-            FOR fclass IN SELECT * FROM config.metabib_class LOOP
-                -- RAISE NOTICE 'Emptying out %', fclass.name;
-                EXECUTE $$DELETE FROM metabib.$$ || fclass.name || $$_field_entry WHERE source = $$ || bib_id;
-            END LOOP;
-        END IF;
-        IF NOT b_skip_facet THEN
-            DELETE FROM metabib.facet_entry WHERE source = bib_id;
-        END IF;
-        IF NOT b_skip_browse THEN
-            DELETE FROM metabib.browse_entry_def_map WHERE source = bib_id;
-        END IF;
-    END IF;
-
-    FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
-
-	-- don't store what has been normalized away
-        CONTINUE WHEN ind_data.value IS NULL;
-
-        IF ind_data.field < 0 THEN
-            ind_data.field = -1 * ind_data.field;
-        END IF;
-
-        IF ind_data.facet_field AND NOT b_skip_facet THEN
-            INSERT INTO metabib.facet_entry (field, source, value)
-                VALUES (ind_data.field, ind_data.source, ind_data.value);
-        END IF;
-
-        IF ind_data.browse_field AND NOT b_skip_browse THEN
-            -- A caveat about this SELECT: this should take care of replacing
-            -- old mbe rows when data changes, but not if normalization (by
-            -- which I mean specifically the output of
-            -- evergreen.oils_tsearch2()) changes.  It may or may not be
-            -- expensive to add a comparison of index_vector to index_vector
-            -- to the WHERE clause below.
-
-            CONTINUE WHEN ind_data.sort_value IS NULL;
-
-            value_prepped := metabib.browse_normalize(ind_data.value, ind_data.field);
-            SELECT INTO mbe_row * FROM metabib.browse_entry
-                WHERE value = value_prepped AND sort_value = ind_data.sort_value;
-
-            IF FOUND THEN
-                mbe_id := mbe_row.id;
-            ELSE
-                INSERT INTO metabib.browse_entry
-                    ( value, sort_value ) VALUES
-                    ( value_prepped, ind_data.sort_value );
-
-                mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS);
-            END IF;
-
-            INSERT INTO metabib.browse_entry_def_map (entry, def, source, authority)
-                VALUES (mbe_id, ind_data.field, ind_data.source, ind_data.authority);
-        END IF;
-
-        IF ind_data.search_field AND NOT b_skip_search THEN
-            -- Avoid inserting duplicate rows
-            EXECUTE 'SELECT 1 FROM metabib.' || ind_data.field_class ||
-                '_field_entry WHERE field = $1 AND source = $2 AND value = $3'
-                INTO mbe_id USING ind_data.field, ind_data.source, ind_data.value;
-                -- RAISE NOTICE 'Search for an already matching row returned %', mbe_id;
-            IF mbe_id IS NULL THEN
-                EXECUTE $$
-                INSERT INTO metabib.$$ || ind_data.field_class || $$_field_entry (field, source, value)
-                    VALUES ($$ ||
-                        quote_literal(ind_data.field) || $$, $$ ||
-                        quote_literal(ind_data.source) || $$, $$ ||
-                        quote_literal(ind_data.value) ||
-                    $$);$$;
-            END IF;
-        END IF;
-
-    END LOOP;
-
-    IF NOT b_skip_search THEN
-        PERFORM metabib.update_combined_index_vectors(bib_id);
-    END IF;
-
-    RETURN;
-END;
-$func$ LANGUAGE PLPGSQL;
-
-
-CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) RETURNS SETOF metabib.field_entry_template AS $func$
-DECLARE
-    bib     biblio.record_entry%ROWTYPE;
-    idx     config.metabib_field%ROWTYPE;
-    xfrm        config.xml_transform%ROWTYPE;
-    prev_xfrm   TEXT;
-    transformed_xml TEXT;
-    xml_node    TEXT;
-    xml_node_list   TEXT[];
-    facet_text  TEXT;
-    browse_text TEXT;
-    sort_value  TEXT;
-    raw_text    TEXT;
-    curr_text   TEXT;
-    joiner      TEXT := default_joiner; -- XXX will index defs supply a joiner?
-    authority_text TEXT;
-    authority_link BIGINT;
-    output_row  metabib.field_entry_template%ROWTYPE;
-BEGIN
-
-    -- Start out with no field-use bools set
-    output_row.browse_field = FALSE;
-    output_row.facet_field = FALSE;
-    output_row.search_field = FALSE;
-
-    -- Get the record
-    SELECT INTO bib * FROM biblio.record_entry WHERE id = rid;
-
-    -- Loop over the indexing entries
-    FOR idx IN SELECT * FROM config.metabib_field ORDER BY format LOOP
-
-        joiner := COALESCE(idx.joiner, default_joiner);
-
-        SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format;
-
-        -- See if we can skip the XSLT ... it's expensive
-        IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
-            -- Can't skip the transform
-            IF xfrm.xslt <> '---' THEN
-                transformed_xml := oils_xslt_process(bib.marc,xfrm.xslt);
-            ELSE
-                transformed_xml := bib.marc;
-            END IF;
-
-            prev_xfrm := xfrm.name;
-        END IF;
-
-        xml_node_list := oils_xpath( idx.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
-
-        raw_text := NULL;
-        FOR xml_node IN SELECT x FROM unnest(xml_node_list) AS x LOOP
-            CONTINUE WHEN xml_node !~ E'^\\s*<';
-
-            -- XXX much of this should be moved into oils_xpath_string...
-            curr_text := ARRAY_TO_STRING(evergreen.array_remove_item_by_value(evergreen.array_remove_item_by_value(
-                oils_xpath( '//text()', -- get the content of all the nodes within the main selected node
-                    REGEXP_REPLACE( xml_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space
-                ), ' '), ''),  -- throw away morally empty (bankrupt?) strings
-                joiner
-            );
-
-            CONTINUE WHEN curr_text IS NULL OR curr_text = '';
-
-            IF raw_text IS NOT NULL THEN
-                raw_text := raw_text || joiner;
-            END IF;
-
-            raw_text := COALESCE(raw_text,'') || curr_text;
-
-            -- autosuggest/metabib.browse_entry
-            IF idx.browse_field THEN
-
-                IF idx.browse_xpath IS NOT NULL AND idx.browse_xpath <> '' THEN
-                    browse_text := oils_xpath_string( idx.browse_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
-                ELSE
-                    browse_text := curr_text;
-                END IF;
-
-                IF idx.browse_sort_xpath IS NOT NULL AND
-                    idx.browse_sort_xpath <> '' THEN
-
-                    sort_value := oils_xpath_string(
-                        idx.browse_sort_xpath, xml_node, joiner,
-                        ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]
-                    );
-                ELSE
-                    sort_value := browse_text;
-                END IF;
-
-                output_row.field_class = idx.field_class;
-                output_row.field = idx.id;
-                output_row.source = rid;
-                output_row.value = BTRIM(REGEXP_REPLACE(browse_text, E'\\s+', ' ', 'g'));
-                output_row.sort_value :=
-                    public.naco_normalize(sort_value);
-
-                output_row.authority := NULL;
-
-                IF idx.authority_xpath IS NOT NULL AND idx.authority_xpath <> '' THEN
-                    authority_text := oils_xpath_string(
-                        idx.authority_xpath, xml_node, joiner,
-                        ARRAY[
-                            ARRAY[xfrm.prefix, xfrm.namespace_uri],
-                            ARRAY['xlink','http://www.w3.org/1999/xlink']
-                        ]
-                    );
-
-                    IF authority_text ~ '^\d+$' THEN
-                        authority_link := authority_text::BIGINT;
-                        PERFORM * FROM authority.record_entry WHERE id = authority_link;
-                        IF FOUND THEN
-                            output_row.authority := authority_link;
-                        END IF;
-                    END IF;
-
-                END IF;
-
-                output_row.browse_field = TRUE;
-                -- Returning browse rows with search_field = true for search+browse
-                -- configs allows us to retain granularity of being able to search
-                -- browse fields with "starts with" type operators (for example, for
-                -- titles of songs in music albums)
-                IF idx.search_field THEN
-                    output_row.search_field = TRUE;
-                END IF;
-                RETURN NEXT output_row;
-                output_row.browse_field = FALSE;
-                output_row.search_field = FALSE;
-                output_row.sort_value := NULL;
-            END IF;
-
-            -- insert raw node text for faceting
-            IF idx.facet_field THEN
-
-                IF idx.facet_xpath IS NOT NULL AND idx.facet_xpath <> '' THEN
-                    facet_text := oils_xpath_string( idx.facet_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
-                ELSE
-                    facet_text := curr_text;
-                END IF;
-
-                output_row.field_class = idx.field_class;
-                output_row.field = -1 * idx.id;
-                output_row.source = rid;
-                output_row.value = BTRIM(REGEXP_REPLACE(facet_text, E'\\s+', ' ', 'g'));
-
-                output_row.facet_field = TRUE;
-                RETURN NEXT output_row;
-                output_row.facet_field = FALSE;
-            END IF;
-
-        END LOOP;
-
-        CONTINUE WHEN raw_text IS NULL OR raw_text = '';
-
-        -- insert combined node text for searching
-        IF idx.search_field THEN
-            output_row.field_class = idx.field_class;
-            output_row.field = idx.id;
-            output_row.source = rid;
-            output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
-
-            output_row.search_field = TRUE;
-            RETURN NEXT output_row;
-            output_row.search_field = FALSE;
-        END IF;
-
-    END LOOP;
-
-END;
-
-$func$ LANGUAGE PLPGSQL;
-
-
-ALTER TYPE metabib.field_entry_template DROP ATTRIBUTE display_field;
-DROP TRIGGER display_field_force_nfc_tgr ON metabib.display_entry;
-DROP FUNCTION evergreen.display_field_force_nfc();
-DROP TRIGGER display_field_normalize_tgr ON metabib.display_entry;
-DROP FUNCTION metabib.display_field_normalize_trigger();
-DROP INDEX metabib.metabib_display_entry_source_idx;
-DROP INDEX metabib.metabib_display_entry_field_idx;
-DROP VIEW metabib.wide_display_entry;
-DROP VIEW metabib.compressed_display_entry;
-DROP VIEW metabib.flat_display_entry;
-DROP TABLE config.display_field_map;
-DROP TABLE metabib.display_entry;
-
-ALTER TABLE config.metabib_field 
-    DROP COLUMN display_xpath,
-    DROP COLUMN display_field;
-
-COMMIT;
-
-
-

commit 2ce54127d256e0087abcf2be8a1e0258b22ffee8
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Aug 18 17:18:29 2017 -0400

    LP#1251394: Seed data changes
    
    Removing the topic_subject map, since it ends up with single terms rather than
    the more useful "--"-separated full subjects.  Also added an "all creators"
    mapping so that if the default "author" is empty for a record, the display
    logic can do its best to find an appropriate value.
    
    Gone, again, is the representative_field structure from the baseline (and from
    my upgrade changes).
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index 2468948..e8f3f24 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -224,26 +224,6 @@ a "class" of either title, subject, author, keyword, series
 or identifier.
 $$;
 
-CREATE OR REPLACE FUNCTION
-    config.metabib_representative_field_is_valid(INTEGER, TEXT) RETURNS BOOLEAN AS $$
-    SELECT EXISTS (SELECT 1 FROM config.metabib_field WHERE id = $1 AND field_class = $2);
-$$ LANGUAGE SQL STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION config.metabib_representative_field_is_valid(INTEGER, TEXT) IS $$
-Ensure the field_class value on the selected representative field matches
-the class name.
-$$;
-
-ALTER TABLE config.metabib_class
-    ADD COLUMN representative_field
-        INTEGER REFERENCES config.metabib_field(id),
-    ADD CONSTRAINT rep_field_unique UNIQUE(representative_field),
-    ADD CONSTRAINT rep_field_is_valid CHECK (
-	        representative_field IS NULL OR
-	        config.metabib_representative_field_is_valid(representative_field, name)
-	)
-;
-
 CREATE UNIQUE INDEX config_metabib_field_class_name_idx ON config.metabib_field (field_class, name);
 
 CREATE TABLE config.ts_config_list (
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index 99ea346..1d2f9d1 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -125,15 +125,13 @@ INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath,
     (4, 'title', 'alternative', oils_i18n_gettext(4, 'Alternate Title', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:titleInfo[mods32:title and starts-with(@type,'alternative')]$$, '//@xlink:href', $$*[local-name() != "nonSort"]$$ );
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, authority_xpath, browse_sort_xpath ) VALUES 
     (5, 'title', 'uniform', oils_i18n_gettext(5, 'Uniform Title', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:titleInfo[mods32:title and (@type='uniform-nfi')]$$, '//@xlink:href', $$*[local-name() != "nonSort"]$$ );
-INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, authority_xpath, browse_field ) VALUES
-    (6, 'title', 'proper', oils_i18n_gettext(6, 'Title Proper', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:titleNonfiling[mods32:title and not (@type)]$$, '//@xlink:href', FALSE );
-UPDATE config.metabib_class SET representative_field = 6 WHERE name = 'title';
+INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, authority_xpath, browse_field, display_field ) VALUES
+    (6, 'title', 'proper', oils_i18n_gettext(6, 'Title Proper', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:titleNonfiling[mods32:title and not (@type)]$$, '//@xlink:href', FALSE,TRUE );
 
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, facet_xpath, facet_field , authority_xpath, browse_xpath) VALUES 
     (7, 'author', 'corporate', oils_i18n_gettext(7, 'Corporate Author', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:name[@type='corporate' and (mods32:role/mods32:roleTerm[text()='creator'] or mods32:role/mods32:roleTerm[text()='aut'] or mods32:role/mods32:roleTerm[text()='cre'])]$$, $$//*[local-name()='namePart']$$, TRUE, '//@xlink:href',$$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
-INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, facet_xpath, facet_field, authority_xpath, browse_xpath ) VALUES 
-    (8, 'author', 'personal', oils_i18n_gettext(8, 'Personal Author', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:name[@type='personal' and mods32:role/mods32:roleTerm[text()='creator']]$$, $$//*[local-name()='namePart']$$, TRUE, '//@xlink:href',$$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
-UPDATE config.metabib_class SET representative_field = 8 WHERE name = 'author';
+INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, facet_xpath, facet_field, authority_xpath, browse_xpath, display_field, display_xpath ) VALUES 
+    (8, 'author', 'personal', oils_i18n_gettext(8, 'Personal Author', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:name[@type='personal' and mods32:role/mods32:roleTerm[text()='creator']]$$, $$//*[local-name()='namePart']$$, TRUE, '//@xlink:href',$$//*[local-name()='namePart']$$,TRUE,$$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, facet_xpath, facet_field, authority_xpath, browse_xpath ) VALUES 
     (9, 'author', 'conference', oils_i18n_gettext(9, 'Conference Author', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:name[@type='conference' and mods32:role/mods32:roleTerm[text()='creator']]$$, $$//*[local-name()='namePart']$$, TRUE, '//@xlink:href',$$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, facet_xpath, facet_field, authority_xpath, browse_xpath ) VALUES 
@@ -152,7 +150,7 @@ INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath,
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, display_field ) VALUES 
     (15, 'keyword', 'keyword', oils_i18n_gettext(15, 'General Keywords', 'cmf', 'label'), 'mods32', $$//mods32:mods/*[not(local-name()='originInfo')]$$, FALSE, FALSE ); -- /* to fool vim */;
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, display_field ) VALUES
-    (16, 'subject', 'complete', oils_i18n_gettext(16, 'All Subjects', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:subject$$, FALSE, FALSE );
+    (16, 'subject', 'complete', oils_i18n_gettext(16, 'All Subjects', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:subject$$, FALSE, TRUE );
 
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field ) VALUES
     (17, 'identifier', 'accession', oils_i18n_gettext(17, 'Accession Number', 'cmf', 'label'), 'marcxml', $$//marc:controlfield[@tag='001']$$, FALSE );
@@ -190,7 +188,7 @@ INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath,
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, facet_field, facet_xpath, joiner ) VALUES
     (33, 'identifier', 'genre', oils_i18n_gettext(33, 'Genre', 'cmf', 'label'), 'marcxml', $$//marc:datafield[@tag='655']$$, FALSE, TRUE, $$//*[local-name()='subfield' and contains('abvxyz', at code)]$$, ' -- ' ); -- /* to fool vim */;
 
-UPDATE config.metabib_field SET joiner = ' -- ' WHERE field_class = 'subject' AND name NOT IN ('name', 'complete');
+UPDATE config.metabib_field SET joiner = ' -- ' WHERE field_class = 'subject' AND name NOT IN ('name');
 
 INSERT INTO config.metabib_field ( id, field_class, name, label, 
      format, xpath, search_field, browse_field, authority_xpath, joiner ) VALUES
@@ -207,6 +205,12 @@ INSERT INTO config.metabib_field ( id, field_class, name, label,
     (36, 'subject', 'temporal_browse', oils_i18n_gettext(36, 'Temporal Term Browse', 'cmf', 'label'), 
      'mods32', $$//mods32:mods/mods32:subject[local-name(./*[1]) = "temporal"]$$, FALSE, TRUE, '//@xlink:href', ' -- ' ); -- /* to fool vim */;
 
+INSERT INTO config.metabib_field ( id, field_class, name, label,
+    format, xpath, display_field, display_xpath ) VALUES 
+    (37, 'author', 'creator', oils_i18n_gettext(8, 'All Creators', 'cmf', 'label'),
+     'mods32', $$//mods32:mods/mods32:name[mods32:role/mods32:roleTerm[text()='creator']]$$, TRUE, $$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
+
+
 INSERT INTO config.metabib_field_index_norm_map (field,norm)
     SELECT  m.id,
             i.id
@@ -217,6 +221,14 @@ INSERT INTO config.metabib_field_index_norm_map (field,norm)
 
 SELECT SETVAL('config.metabib_field_id_seq', GREATEST(1000, (SELECT MAX(id) FROM config.metabib_field)));
 
+INSERT INTO config.display_field_map (name, field, multi) VALUES
+    ('title', 6, FALSE),
+    ('author', 8, FALSE),
+    ('creators', 37, TRUE),
+    ('subject', 16, TRUE),
+    ('isbn', 18, TRUE)
+;
+
 INSERT INTO config.metabib_search_alias (alias,field_class) VALUES ('kw','keyword');
 INSERT INTO config.metabib_search_alias (alias,field_class) VALUES ('eg.keyword','keyword');
 INSERT INTO config.metabib_search_alias (alias,field_class) VALUES ('dc.publisher','keyword');
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index 1dd3753..b679ff6 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -1,26 +1,6 @@
 
 BEGIN;
 
-CREATE OR REPLACE FUNCTION
-    config.metabib_representative_field_is_valid(INTEGER, TEXT) RETURNS BOOLEAN AS $$
-    SELECT EXISTS (SELECT 1 FROM config.metabib_field WHERE id = $1 AND field_class = $2);
-$$ LANGUAGE SQL STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION config.metabib_representative_field_is_valid(INTEGER, TEXT) IS $$
-Ensure the field_class value on the selected representative field matches
-the class name.
-$$;
-
-ALTER TABLE config.metabib_class
-    ADD COLUMN representative_field
-        INTEGER REFERENCES config.metabib_field(id),
-    ADD CONSTRAINT rep_field_unique UNIQUE(representative_field),
-    ADD CONSTRAINT rep_field_is_valid CHECK (
-            representative_field IS NULL OR
-            config.metabib_representative_field_is_valid(representative_field, name)
-    )
-;
-
 ALTER TABLE config.metabib_field 
     ADD COLUMN display_xpath TEXT, 
     ADD COLUMN display_field BOOL NOT NULL DEFAULT FALSE;
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
index 08832be..c1258e7 100644
--- a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
@@ -6,21 +6,23 @@ INSERT INTO config.internal_flag (name, enabled)
 
 -- Adds seed data to replace (for now) values from the 'mvr' class
 
-UPDATE config.metabib_field SET display_field = TRUE WHERE id IN (6, 8, 14, 16, 18);
+UPDATE config.metabib_field SET display_field = TRUE WHERE id IN (6, 8, 16, 18);
+
+INSERT INTO config.metabib_field ( id, field_class, name, label,
+    format, xpath, display_field, display_xpath ) VALUES
+    (37, 'author', 'creator', oils_i18n_gettext(8, 'All Creators', 'cmf', 'label'),
+     'mods32', $$//mods32:mods/mods32:name[mods32:role/mods32:roleTerm[text()='creator']]$$, TRUE, $$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
 
 INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('title', 6, FALSE),
     ('author', 8, FALSE),
+    ('creators', 37, TRUE),
     ('subject', 16, TRUE),
-    ('topic_subject', 14, TRUE),
     ('isbn', 18, TRUE)
 ;
 
-UPDATE config.metabib_class SET representative_field = 6 WHERE name = 'title';
-UPDATE config.metabib_class SET representative_field = 8 WHERE name = 'author';
-
 COMMIT;
 
 -- REINGEST DISPLAY ENTRIES
-SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE, '{6,8,14,16,18}'::INT[]) FROM biblio.record_entry WHERE NOT deleted AND id > 0;
+SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE, '{6,8,16,18,37}'::INT[]) FROM biblio.record_entry WHERE NOT deleted AND id > 0;
 

commit 4d9df04f07e77f91f7c2d4830ff16b8d67f633e5
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Aug 18 16:34:04 2017 -0400

    LP#1251394: Minor fixes
    
     * Fix function names in drop statements for upgrade
     * Adjust array concat syntax in plpgsql
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/030.schema.metabib.sql b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
index eea6a25..0240622 100644
--- a/Open-ILS/src/sql/Pg/030.schema.metabib.sql
+++ b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
@@ -914,10 +914,10 @@ BEGIN
     SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
     SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
 
-    IF NOT b_skip_facet THEN field_types := field_types || 'facet'; END IF;
-    IF NOT b_skip_display THEN field_types := field_types || 'display'; END IF;
-    IF NOT b_skip_browse THEN field_types := field_types || 'browse'; END IF;
-    IF NOT b_skip_search THEN field_types := field_types || 'search'; END IF;
+    IF NOT b_skip_facet THEN field_types := field_types || '{facet}'; END IF;
+    IF NOT b_skip_display THEN field_types := field_types || '{display}'; END IF;
+    IF NOT b_skip_browse THEN field_types := field_types || '{browse}'; END IF;
+    IF NOT b_skip_search THEN field_types := field_types || '{search}'; END IF;
 
     PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
     IF NOT FOUND THEN
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index 5493d65..1dd3753 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -151,8 +151,8 @@ CREATE TRIGGER display_field_force_nfc_tgr
 ALTER TYPE metabib.field_entry_template ADD ATTRIBUTE display_field BOOL;
 
 DROP FUNCTION metabib.reingest_metabib_field_entries(BIGINT, BOOL, BOOL, BOOL);
-DROP FUNCTION metabib.extract_metabib_field_entries(BIGINT);
-DROP FUNCTION metabib.extract_metabib_field_entries(BIGINT, TEXT);
+DROP FUNCTION biblio.extract_metabib_field_entry(BIGINT);
+DROP FUNCTION biblio.extract_metabib_field_entry(BIGINT, TEXT);
 
 CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry (
     rid BIGINT,
@@ -391,10 +391,10 @@ BEGIN
     SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
     SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
 
-    IF NOT b_skip_facet THEN field_types := field_types || 'facet'; END IF;
-    IF NOT b_skip_display THEN field_types := field_types || 'display'; END IF;
-    IF NOT b_skip_browse THEN field_types := field_types || 'browse'; END IF;
-    IF NOT b_skip_search THEN field_types := field_types || 'search'; END IF;
+    IF NOT b_skip_facet THEN field_types := field_types || '{facet}'; END IF;
+    IF NOT b_skip_display THEN field_types := field_types || '{display}'; END IF;
+    IF NOT b_skip_browse THEN field_types := field_types || '{browse}'; END IF;
+    IF NOT b_skip_search THEN field_types := field_types || '{search}'; END IF;
 
     PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
     IF NOT FOUND THEN

commit c7598ec8d3d4cf442ed2c3cb153b00ec4cf58ce4
Author: Mike Rylander <mrylander at gmail.com>
Date:   Fri Aug 18 15:32:34 2017 -0400

    LP#1251394: Reingest streamlining, schema realigning, rebasing
    
    I've rebased this to master and undertake some work to allow streamlined
    reingest of specific index definitions.  The API remains essentially backwards
    compatable, but is reingest_metabib_field_entries() is extended to accept a
    list of index definition IDs to which it should restrict its work.  If that
    optional parameter is not passed, all index definitions are processed.
    
    This has the benefit of skipping XML transformation for index definitions
    which won't produce output useful to the requested reingest process, which
    should provide a significant speed boost for some situations.
    
    The upgrade schema has now been realigned with some missing bits from the
    baseline, but the baseline may still be lacking some from the upgrade.
    
    The data upgrade script has been made to use the existing index definitions
    where they match the needs of the new ones, and to use the new reindexing
    options.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/030.schema.metabib.sql b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
index c9935ba..eea6a25 100644
--- a/Open-ILS/src/sql/Pg/030.schema.metabib.sql
+++ b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
@@ -624,7 +624,12 @@ CREATE TYPE metabib.field_entry_template AS (
     sort_value          TEXT
 );
 
-CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) RETURNS SETOF metabib.field_entry_template AS $func$
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry (
+    rid BIGINT,
+    default_joiner TEXT,
+    field_types TEXT[],
+    only_fields INT[]
+) RETURNS SETOF metabib.field_entry_template AS $func$
 DECLARE
     bib     biblio.record_entry%ROWTYPE;
     idx     config.metabib_field%ROWTYPE;
@@ -643,6 +648,7 @@ DECLARE
     authority_text TEXT;
     authority_link BIGINT;
     output_row  metabib.field_entry_template%ROWTYPE;
+    process_idx BOOL;
 BEGIN
 
     -- Start out with no field-use bools set
@@ -655,7 +661,14 @@ BEGIN
     SELECT INTO bib * FROM biblio.record_entry WHERE id = rid;
 
     -- Loop over the indexing entries
-    FOR idx IN SELECT * FROM config.metabib_field ORDER BY format LOOP
+    FOR idx IN SELECT * FROM config.metabib_field WHERE id = ANY (only_fields) ORDER BY format LOOP
+
+        process_idx := FALSE;
+        IF idx.display_field AND 'display' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.browse_field AND 'browse' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.search_field AND 'search' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.facet_field AND 'facet' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        CONTINUE WHEN process_idx = FALSE;
 
         joiner := COALESCE(idx.joiner, default_joiner);
 
@@ -871,9 +884,13 @@ END;
 $func$ LANGUAGE PLPGSQL;
 
 CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( 
-    bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, 
-    skip_display BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, 
-    skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
+    bib_id BIGINT,
+    skip_facet BOOL DEFAULT FALSE, 
+    skip_display BOOL DEFAULT FALSE,
+    skip_browse BOOL DEFAULT FALSE, 
+    skip_search BOOL DEFAULT FALSE,
+    only_fields INT[] DEFAULT '{}'::INT[]
+) RETURNS VOID AS $func$
 DECLARE
     fclass          RECORD;
     ind_data        metabib.field_entry_template%ROWTYPE;
@@ -884,13 +901,24 @@ DECLARE
     b_skip_browse   BOOL;
     b_skip_search   BOOL;
     value_prepped   TEXT;
+    field_list      INT[] := only_fields;
+    field_types     TEXT[] := '{}'::TEXT[];
 BEGIN
 
+    IF field_list = '{}'::INT[] THEN
+        SELECT ARRAY_AGG(id) INTO field_list FROM config.metabib_field;
+    END IF;
+
     SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
     SELECT COALESCE(NULLIF(skip_display, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_display_indexing' AND enabled)) INTO b_skip_display;
     SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
     SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
 
+    IF NOT b_skip_facet THEN field_types := field_types || 'facet'; END IF;
+    IF NOT b_skip_display THEN field_types := field_types || 'display'; END IF;
+    IF NOT b_skip_browse THEN field_types := field_types || 'browse'; END IF;
+    IF NOT b_skip_search THEN field_types := field_types || 'search'; END IF;
+
     PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
     IF NOT FOUND THEN
         IF NOT b_skip_search THEN
@@ -910,7 +938,7 @@ BEGIN
         END IF;
     END IF;
 
-    FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
+    FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id, ' ', field_types, field_list ) LOOP
 
 	-- don't store what has been normalized away
         CONTINUE WHEN ind_data.value IS NULL;
@@ -985,11 +1013,6 @@ BEGIN
 END;
 $func$ LANGUAGE PLPGSQL;
 
--- default to a space joiner
-CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( BIGINT ) RETURNS SETOF metabib.field_entry_template AS $func$
-	SELECT * FROM biblio.extract_metabib_field_entry($1, ' ');
-$func$ LANGUAGE SQL;
-
 CREATE OR REPLACE FUNCTION authority.flatten_marc ( rid BIGINT ) RETURNS SETOF authority.full_rec AS $func$
 DECLARE
 	auth	authority.record_entry%ROWTYPE;
@@ -1710,17 +1733,8 @@ BEGIN
     PERFORM metabib.reingest_metabib_field_entries(NEW.id);
 
     -- Located URI magic
-    IF TG_OP = 'INSERT' THEN
-        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
-        IF NOT FOUND THEN
-            PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor );
-        END IF;
-    ELSE
-        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
-        IF NOT FOUND THEN
-            PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor );
-        END IF;
-    END IF;
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
+    IF NOT FOUND THEN PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor ); END IF;
 
     -- (re)map metarecord-bib linking
     IF TG_OP = 'INSERT' THEN -- if not deleted and performing an insert, check for the flag
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index 467ef60..5493d65 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -1,6 +1,26 @@
 
 BEGIN;
 
+CREATE OR REPLACE FUNCTION
+    config.metabib_representative_field_is_valid(INTEGER, TEXT) RETURNS BOOLEAN AS $$
+    SELECT EXISTS (SELECT 1 FROM config.metabib_field WHERE id = $1 AND field_class = $2);
+$$ LANGUAGE SQL STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION config.metabib_representative_field_is_valid(INTEGER, TEXT) IS $$
+Ensure the field_class value on the selected representative field matches
+the class name.
+$$;
+
+ALTER TABLE config.metabib_class
+    ADD COLUMN representative_field
+        INTEGER REFERENCES config.metabib_field(id),
+    ADD CONSTRAINT rep_field_unique UNIQUE(representative_field),
+    ADD CONSTRAINT rep_field_is_valid CHECK (
+            representative_field IS NULL OR
+            config.metabib_representative_field_is_valid(representative_field, name)
+    )
+;
+
 ALTER TABLE config.metabib_field 
     ADD COLUMN display_xpath TEXT, 
     ADD COLUMN display_field BOOL NOT NULL DEFAULT FALSE;
@@ -130,7 +150,16 @@ CREATE TRIGGER display_field_force_nfc_tgr
 
 ALTER TYPE metabib.field_entry_template ADD ATTRIBUTE display_field BOOL;
 
-CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) RETURNS SETOF metabib.field_entry_template AS $func$
+DROP FUNCTION metabib.reingest_metabib_field_entries(BIGINT, BOOL, BOOL, BOOL);
+DROP FUNCTION metabib.extract_metabib_field_entries(BIGINT);
+DROP FUNCTION metabib.extract_metabib_field_entries(BIGINT, TEXT);
+
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry (
+    rid BIGINT,
+    default_joiner TEXT,
+    field_types TEXT[],
+    only_fields INT[]
+) RETURNS SETOF metabib.field_entry_template AS $func$
 DECLARE
     bib     biblio.record_entry%ROWTYPE;
     idx     config.metabib_field%ROWTYPE;
@@ -149,6 +178,7 @@ DECLARE
     authority_text TEXT;
     authority_link BIGINT;
     output_row  metabib.field_entry_template%ROWTYPE;
+    process_idx BOOL;
 BEGIN
 
     -- Start out with no field-use bools set
@@ -161,7 +191,14 @@ BEGIN
     SELECT INTO bib * FROM biblio.record_entry WHERE id = rid;
 
     -- Loop over the indexing entries
-    FOR idx IN SELECT * FROM config.metabib_field ORDER BY format LOOP
+    FOR idx IN SELECT * FROM config.metabib_field WHERE id = ANY (only_fields) ORDER BY format LOOP
+
+        process_idx := FALSE;
+        IF idx.display_field AND 'display' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.browse_field AND 'browse' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.search_field AND 'search' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        IF idx.facet_field AND 'facet' = ANY (field_types) THEN process_idx = TRUE; END IF;
+        CONTINUE WHEN process_idx = FALSE;
 
         joiner := COALESCE(idx.joiner, default_joiner);
 
@@ -323,12 +360,14 @@ END;
 
 $func$ LANGUAGE PLPGSQL;
 
-DROP FUNCTION metabib.reingest_metabib_field_entries(BIGINT, BOOL, BOOL, BOOL);
-
 CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( 
-    bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, 
-    skip_display BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, 
-    skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
+    bib_id BIGINT,
+    skip_facet BOOL DEFAULT FALSE, 
+    skip_display BOOL DEFAULT FALSE,
+    skip_browse BOOL DEFAULT FALSE, 
+    skip_search BOOL DEFAULT FALSE,
+    only_fields INT[] DEFAULT '{}'::INT[]
+) RETURNS VOID AS $func$
 DECLARE
     fclass          RECORD;
     ind_data        metabib.field_entry_template%ROWTYPE;
@@ -339,13 +378,24 @@ DECLARE
     b_skip_browse   BOOL;
     b_skip_search   BOOL;
     value_prepped   TEXT;
+    field_list      INT[] := only_fields;
+    field_types     TEXT[] := '{}'::TEXT[];
 BEGIN
 
+    IF field_list = '{}'::INT[] THEN
+        SELECT ARRAY_AGG(id) INTO field_list FROM config.metabib_field;
+    END IF;
+
     SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
     SELECT COALESCE(NULLIF(skip_display, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_display_indexing' AND enabled)) INTO b_skip_display;
     SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
     SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
 
+    IF NOT b_skip_facet THEN field_types := field_types || 'facet'; END IF;
+    IF NOT b_skip_display THEN field_types := field_types || 'display'; END IF;
+    IF NOT b_skip_browse THEN field_types := field_types || 'browse'; END IF;
+    IF NOT b_skip_search THEN field_types := field_types || 'search'; END IF;
+
     PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
     IF NOT FOUND THEN
         IF NOT b_skip_search THEN
@@ -365,7 +415,7 @@ BEGIN
         END IF;
     END IF;
 
-    FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
+    FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id, ' ', field_types, field_list ) LOOP
 
 	-- don't store what has been normalized away
         CONTINUE WHEN ind_data.value IS NULL;
@@ -440,7 +490,83 @@ BEGIN
 END;
 $func$ LANGUAGE PLPGSQL;
 
-COMMIT;
+-- AFTER UPDATE OR INSERT trigger for biblio.record_entry
+CREATE OR REPLACE FUNCTION biblio.indexing_ingest_or_delete () RETURNS TRIGGER AS $func$
+DECLARE
+    tmp_bool BOOL;
+BEGIN
+
+    IF NEW.deleted THEN -- If this bib is deleted
+
+        PERFORM * FROM config.internal_flag WHERE
+            name = 'ingest.metarecord_mapping.preserve_on_delete' AND enabled;
+
+        tmp_bool := FOUND; -- Just in case this is changed by some other statement
+
+        PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint, TRUE, tmp_bool );
+
+        IF NOT tmp_bool THEN
+            -- One needs to keep these around to support searches
+            -- with the #deleted modifier, so one should turn on the named
+            -- internal flag for that functionality.
+            DELETE FROM metabib.record_attr_vector_list WHERE source = NEW.id;
+        END IF;
+
+        DELETE FROM authority.bib_linking WHERE bib = NEW.id; -- Avoid updating fields in bibs that are no longer visible
+        DELETE FROM biblio.peer_bib_copy_map WHERE peer_record = NEW.id; -- Separate any multi-homed items
+        DELETE FROM metabib.browse_entry_def_map WHERE source = NEW.id; -- Don't auto-suggest deleted bibs
+        RETURN NEW; -- and we're done
+    END IF;
+
+    IF TG_OP = 'UPDATE' THEN -- re-ingest?
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.reingest.force_on_same_marc' AND enabled;
 
+        IF NOT FOUND AND OLD.marc = NEW.marc THEN -- don't do anything if the MARC didn't change
+            RETURN NEW;
+        END IF;
+    END IF;
+
+    -- Record authority linking
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_authority_linking' AND enabled;
+    IF NOT FOUND THEN
+        PERFORM biblio.map_authority_linking( NEW.id, NEW.marc );
+    END IF;
+
+    -- Flatten and insert the mfr data
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_full_rec' AND enabled;
+    IF NOT FOUND THEN
+        PERFORM metabib.reingest_metabib_full_rec(NEW.id);
+
+        -- Now we pull out attribute data, which is dependent on the mfr for all but XPath-based fields
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_metabib_rec_descriptor' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM metabib.reingest_record_attributes(NEW.id, NULL, NEW.marc, TG_OP = 'INSERT' OR OLD.deleted);
+        END IF;
+    END IF;
+
+    -- Gather and insert the field entry data
+    PERFORM metabib.reingest_metabib_field_entries(NEW.id);
 
+    -- Located URI magic
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.disable_located_uri' AND enabled;
+    IF NOT FOUND THEN PERFORM biblio.extract_located_uris( NEW.id, NEW.marc, NEW.editor ); END IF;
+
+    -- (re)map metarecord-bib linking
+    IF TG_OP = 'INSERT' THEN -- if not deleted and performing an insert, check for the flag
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_insert' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint );
+        END IF;
+    ELSE -- we're doing an update, and we're not deleted, remap
+        PERFORM * FROM config.internal_flag WHERE name = 'ingest.metarecord_mapping.skip_on_update' AND enabled;
+        IF NOT FOUND THEN
+            PERFORM metabib.remap_metarecord_for_bib( NEW.id, NEW.fingerprint );
+        END IF;
+    END IF;
+
+    RETURN NEW;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+COMMIT;
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
index 09de901..08832be 100644
--- a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
@@ -6,46 +6,21 @@ INSERT INTO config.internal_flag (name, enabled)
 
 -- Adds seed data to replace (for now) values from the 'mvr' class
 
-INSERT INTO config.metabib_field (id, field_class, name, format,
-    display_field, search_field, browse_field, label, xpath) 
-VALUES
-    (37, 'title', 'display|title', 'mods32', TRUE, FALSE, FALSE,
-        oils_i18n_gettext(37, 'Title', 'cmf', 'label'),
-        '//mods32:mods/mods32:titleNonfiling[mods32:title and not (@type)]'),
-    (38, 'author', 'display|author', 'mods32', TRUE, FALSE, FALSE,
-        oils_i18n_gettext(38, 'Author', 'cmf', 'label'),
-        $$//mods32:mods/mods32:name[@type='personal' and mods32:role/mods32:roleTerm[text()='creator']]$$),
-    (39, 'subject', 'display|subject', 'mods32', TRUE, FALSE, FALSE,
-        oils_i18n_gettext(39, 'Subject', 'cmf', 'label'),
-        '//mods32:mods/mods32:subject'),
-    (40, 'subject', 'display|topic_subject', 'mods32', TRUE, FALSE, FALSE,
-        oils_i18n_gettext(40, 'Subject', 'cmf', 'label'),
-        '//mods32:mods/mods32:subject/mods32:topic'),
-    (41, 'identifier', 'display|isbn', 'marcxml', TRUE, FALSE, FALSE,
-        oils_i18n_gettext(41, 'ISBN', 'cmf', 'label'),
-        $$//marc:datafield[@tag='020']/marc:subfield[@code='a' or @code='z']$$)
-
-;
+UPDATE config.metabib_field SET display_field = TRUE WHERE id IN (6, 8, 14, 16, 18);
 
 INSERT INTO config.display_field_map (name, field, multi) VALUES
-    ('title', 37, FALSE),
-    ('author', 38, FALSE),
-    ('subject', 39, TRUE),
-    ('topic_subject', 40, TRUE),
-    ('isbn', 41, TRUE)
+    ('title', 6, FALSE),
+    ('author', 8, FALSE),
+    ('subject', 16, TRUE),
+    ('topic_subject', 14, TRUE),
+    ('isbn', 18, TRUE)
 ;
 
+UPDATE config.metabib_class SET representative_field = 6 WHERE name = 'title';
+UPDATE config.metabib_class SET representative_field = 8 WHERE name = 'author';
+
 COMMIT;
 
 -- REINGEST DISPLAY ENTRIES
-
-BEGIN;
-UPDATE config.internal_flag SET enabled = TRUE WHERE name IN (
-'ingest.assume_inserts_only','ingest.disable_authority_auto_update','ingest.disable_authority_linking','ingest.disable_located_uri','ingest.disable_metabib_field_entry','ingest.disable_metabib_full_rec','ingest.disable_metabib_rec_descriptor','ingest.metarecord_mapping.preserve_on_delete','ingest.metarecord_mapping.skip_on_insert','ingest.metarecord_mapping.skip_on_update','ingest.reingest.force_on_same_marc','ingest.skip_browse_indexing','ingest.skip_facet_indexing','ingest.skip_search_indexing');
-
-UPDATE biblio.record_entry SET marc = marc;
-
-UPDATE config.internal_flag SET enabled = FALSE WHERE name IN (
-'ingest.assume_inserts_only','ingest.disable_authority_auto_update','ingest.disable_authority_linking','ingest.disable_located_uri','ingest.disable_metabib_field_entry','ingest.disable_metabib_full_rec','ingest.disable_metabib_rec_descriptor','ingest.metarecord_mapping.preserve_on_delete','ingest.metarecord_mapping.skip_on_insert','ingest.metarecord_mapping.skip_on_update','ingest.reingest.force_on_same_marc','ingest.skip_browse_indexing','ingest.skip_facet_indexing','ingest.skip_search_indexing');
-COMMIT;
+SELECT metabib.reingest_metabib_field_entries(id, TRUE, FALSE, TRUE, TRUE, '{6,8,14,16,18}'::INT[]) FROM biblio.record_entry WHERE NOT deleted AND id > 0;
 

commit 1ffccff52c4a003c7d56c5e67477d173b6d3256f
Author: Bill Erickson <berickxx at gmail.com>
Date:   Wed May 17 16:34:43 2017 -0400

    LP#1251394 Webstaff Display fields utility functions
    
    Adds functions for translating bib record display field data into a
    variety of useful formats and structures.  Some are best suited for
    grids, others for lists of values, etc.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/web/js/ui/default/staff/cat/services/record.js b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
index 81a8cf7..8dbbef2 100644
--- a/Open-ILS/web/js/ui/default/staff/cat/services/record.js
+++ b/Open-ILS/web/js/ui/default/staff/cat/services/record.js
@@ -223,3 +223,70 @@ angular.module('egCoreMod')
         ]
     }
 })
+
+/**
+ * Utility functions for translating bib record display fields into
+ * various formats / structures.
+ *
+ * Note that 'mwde' objects (which are proper IDL objects) only contain
+ * the prescribed fields from the IDL (and database view), while the
+ * 'mfde' hash-based objects contain all configured display fields,
+ * including local/custom fields.
+ */
+.factory('egBibDisplay', ['$q', 'egCore', function($q, egCore) {
+    var service = {};
+
+    /**
+     * Converts JSON-encoded values within a mwde object to Javascript
+     * native strings, numbers, and arrays.
+     */
+    service.mwdeJSONToJS = function(entry) {
+        angular.forEach(egCore.idl.classes.mwde.fields, function(f) {
+            if (f.virtual) return;
+            entry[f.name](JSON.parse(entry[f.name]()));
+        });
+    }
+
+    /**
+     * Converts a list of 'mfde' entry objects to a simple key=>value hash.
+     * Non-multi values are strings or numbers.
+     * Multi values are arrays of strings or numbers.
+     */
+    service.mfdeToHash = function(entries) {
+        var hash = service.mfdeToMetaHash(entries);
+        angular.forEach(hash, 
+            function(sub_hash, name) { hash[name] = sub_hash.value });
+        return hash;
+    }
+
+    /**
+     * Converts a list of 'mfde' entry objects to a nested hash like so:
+     * {name => field_name, label => field_label, value => scalar_or_array}
+     * The scalar_or_array value is a string/number or an array of
+     * string/numbers
+     */
+    service.mfdeToMetaHash = function(entries) {
+        var hash = {};
+        angular.forEach(entries, function(entry) {
+
+            if (!hash[entry.name()]) {
+                hash[entry.name()] = {
+                    name : entry.name(),
+                    label : entry.label(),
+                    multi : entry.multi() == 't',
+                    value : entry.multi() == 't' ? [] : null
+                }
+            }
+
+            if (entry.multi() == 't') {
+                hash[entry.name()].value.push(entry.value());
+            } else {
+                hash[entry.name()].value = entry.value();
+            }
+        });
+
+        return hash;
+    }
+
+    return service;
+}])

commit 2b9e0ff2b769f58cdda42022fda0c7e2fd45131a
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu May 11 17:54:58 2017 -0400

    LP#1251394 Compressed and wide display entry VIEWs
    
    flat_display_entry is one row per entry with all of the relevent info.
    compressed_display_entry sits atop flat_display_entry and compresses the
    values into JSON scalars and arrays depending on the 'multi' value.
    
    Wide display entry is a tabular view of the well-known fields a la
    reporter.simple_record.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 70ac771..4d944a8 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -3135,7 +3135,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field reporter:label="SVF Attributes" name="attrs" oils_persist:virtual="true" reporter:datatype="link"/>
 			<field reporter:label="MVF Attributes" name="mattrs" oils_persist:virtual="true" reporter:datatype="link"/>
 			<field reporter:label="Display Fields" name="display_entries" oils_persist:virtual="true" reporter:datatype="link"/>
-			<field reporter:label="Flat Display Fields" name="flat_display_entries" oils_persist:virtual="true" reporter:datatype="link"/>
+			<field reporter:label="Flat Display Entries" name="flat_display_entries" oils_persist:virtual="true" reporter:datatype="link"/>
+			<field reporter:label="Compressed Display Entries" name="compressed_display_entries" oils_persist:virtual="true" reporter:datatype="link"/>
+			<field reporter:label="Wide Display Entries" name="wide_display_entry" oils_persist:virtual="true" reporter:datatype="link"/>
 		</fields>
 		<links>
 			<link field="owner" reltype="has_a" key="id" map="" class="aou"/>
@@ -3161,6 +3163,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<link field="source" reltype="has_a" key="id" map="" class="cbs"/>
 			<link field="display_entries" reltype="has_many" key="source" map="" class="mde"/>
 			<link field="flat_display_entries" reltype="has_many" key="source" map="" class="mfde"/>
+			<link field="compressed_display_entries" reltype="has_many" key="source" map="" class="mcde"/>
+			<link field="wide_display_entry" reltype="might_have" key="source" map="" class="mwde"/>
 		</links>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
@@ -3746,11 +3750,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 		oils_persist:tablename="metabib.flat_display_entry"
 		oils_obj:fieldmapper="metabib::flat_display_entry" 
 		oils_persist:field_safe="true"
-		reporter:label="Flat Display Field Entry View" 
+		reporter:label="Flat Display Entry" 
 		oils_persist:readonly="true">
 		<fields>
 			<field name="source" reporter:datatype="id" />
 			<field name="name" reporter:datatype="text"/>
+			<field name="multi" reporter:datatype="bool"/>
+			<field name="label" reporter:datatype="text"/>
 			<field name="field" reporter:datatype="link"/>
 			<field name="value" reporter:datatype="text"/>
 		</fields>
@@ -3765,6 +3771,56 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			</actions>
 		</permacrud>
 	</class>
+	<class id="mcde" controller="open-ils.cstore open-ils.pcrud" 
+		oils_persist:tablename="metabib.compressed_display_entry"
+		oils_obj:fieldmapper="metabib::compressed_display_entry" 
+		oils_persist:field_safe="true"
+		reporter:label="Compressed Display Entry" 
+		oils_persist:readonly="true">
+		<fields>
+			<field name="source" reporter:datatype="id" />
+			<field name="name" reporter:datatype="text"/>
+			<field name="multi" reporter:datatype="bool"/>
+			<field name="label" reporter:datatype="text"/>
+			<field name="field" reporter:datatype="link"/>
+			<field name="value" reporter:datatype="text"/>
+		</fields>
+		<links>
+			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
+			<link field="field" reltype="has_a" key="id" map="" class="cmf"/>
+			<link field="name" reltype="has_a" key="name" map="" class="cdfm"/>
+		</links>
+		<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+			<actions>
+				<retrieve/>
+			</actions>
+		</permacrud>
+	</class>
+	<class id="mwde" controller="open-ils.cstore open-ils.pcrud" 
+		oils_persist:tablename="metabib.wide_display_entry"
+		oils_obj:fieldmapper="metabib::wide_display_entry" 
+		oils_persist:field_safe="true"
+		reporter:label="Wide Display Entry" 
+		oils_persist:readonly="true">
+		<fields oils_persist:primary="source">
+			<field name="source" reporter:label="Record ID" reporter:datatype="id" />
+			<field name="title" reporter:label="Title" reporter:datatype="text"/>
+			<field name="author" reporter:label="Author" reporter:datatype="text"/>
+			<field name="subject" reporter:label="Subject" reporter:datatype="text"/>
+			<field name="topic_subject" reporter:label="Topic Subject" reporter:datatype="text"/>
+			<field name="isbn" reporter:label="ISBN" reporter:datatype="text"/>
+			<!-- TODO add all well-known fields -->
+		</fields>
+		<links>
+			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
+		</links>
+		<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+			<actions>
+				<retrieve/>
+			</actions>
+		</permacrud>
+	</class>
+
 	<class id="cdfm" controller="open-ils.cstore open-ils.pcrud" 
 		oils_persist:tablename="config.display_field_map"
 		oils_obj:fieldmapper="config::display_field_map"
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index 2d69e81..467ef60 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -5,6 +5,12 @@ ALTER TABLE config.metabib_field
     ADD COLUMN display_xpath TEXT, 
     ADD COLUMN display_field BOOL NOT NULL DEFAULT FALSE;
 
+CREATE TABLE config.display_field_map (
+    name    TEXT   PRIMARY KEY,
+    field   INTEGER REFERENCES config.metabib_field (id),
+    multi   BOOLEAN DEFAULT FALSE
+);
+
 CREATE TABLE metabib.display_entry (
     id      BIGSERIAL  PRIMARY KEY,
     source  BIGINT     NOT NULL REFERENCES biblio.record_entry (id),
@@ -12,30 +18,64 @@ CREATE TABLE metabib.display_entry (
     value   TEXT       NOT NULL
 );
 
-CREATE TABLE config.display_field_map (
-    name    TEXT   PRIMARY KEY,
-    field   INTEGER REFERENCES config.metabib_field (id),
-    multi   BOOLEAN DEFAULT FALSE
-);
+CREATE INDEX metabib_display_entry_field_idx ON metabib.display_entry (field);
+CREATE INDEX metabib_display_entry_source_idx ON metabib.display_entry (source);
 
+-- one row per display entry fleshed with field info
 CREATE VIEW metabib.flat_display_entry AS
     SELECT
         mde.source,
         cdfm.name,
-        mde.field,
-        CASE WHEN cdfm.multi THEN
+        cdfm.multi,
+        cmf.label,
+        cmf.id AS field,
+        mde.value
+    FROM metabib.display_entry mde
+    JOIN config.metabib_field cmf ON (cmf.id = mde.field)
+    JOIN config.display_field_map cdfm ON (cdfm.field = mde.field)
+;
+
+-- like flat_display_entry except values are compressed 
+-- into one row per display_field_map and JSON-ified.
+CREATE VIEW metabib.compressed_display_entry AS
+    SELECT 
+        source,
+        name,
+        multi,
+        label,
+        field,
+        CASE WHEN multi THEN
             TO_JSON(ARRAY_AGG(value))
         ELSE
             TO_JSON(MIN(value))
         END AS value
-    FROM metabib.display_entry mde
-    JOIN config.display_field_map cdfm ON (cdfm.field = mde.field)
-    GROUP BY 1, 2, 3;
+    FROM metabib.flat_display_entry
+    GROUP BY 1, 2, 3, 4, 5
+;
+
+-- TODO: expand to encompass all well-known fields
+CREATE VIEW metabib.wide_display_entry AS
+    SELECT 
+        bre.id AS source,
+        COALESCE(mcde_title.value, 'null') AS title,
+        COALESCE(mcde_author.value, 'null') AS author,
+        COALESCE(mcde_subject.value, 'null') AS subject,
+        COALESCE(mcde_topic_subject.value, 'null') AS topic_subject,
+        COALESCE(mcde_isbn.value, 'null') AS isbn
+    -- ensure one row per bre regardless of any display fields
+    FROM biblio.record_entry bre 
+    LEFT JOIN metabib.compressed_display_entry mcde_title 
+        ON (bre.id = mcde_title.source AND mcde_title.name = 'title')
+    LEFT JOIN metabib.compressed_display_entry mcde_author 
+        ON (bre.id = mcde_author.source AND mcde_author.name = 'author')
+    LEFT JOIN metabib.compressed_display_entry mcde_subject 
+        ON (bre.id = mcde_subject.source AND mcde_subject.name = 'subject')
+    LEFT JOIN metabib.compressed_display_entry mcde_topic_subject 
+        ON (bre.id = mcde_topic_subject.source AND mcde_topic_subject.name = 'topic_subject')
+    LEFT JOIN metabib.compressed_display_entry mcde_isbn 
+        ON (bre.id = mcde_isbn.source AND mcde_isbn.name = 'isbn')
+;
 
-CREATE INDEX metabib_display_entry_field_idx 
-    ON metabib.display_entry (field);
-CREATE INDEX metabib_display_entry_source_idx 
-    ON metabib.display_entry (source);
 
 CREATE OR REPLACE FUNCTION metabib.display_field_normalize_trigger () 
     RETURNS TRIGGER AS $$
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
index 7432f7c..09de901 100644
--- a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
@@ -20,14 +20,19 @@ VALUES
         '//mods32:mods/mods32:subject'),
     (40, 'subject', 'display|topic_subject', 'mods32', TRUE, FALSE, FALSE,
         oils_i18n_gettext(40, 'Subject', 'cmf', 'label'),
-        '//mods32:mods/mods32:subject/mods32:topic')
+        '//mods32:mods/mods32:subject/mods32:topic'),
+    (41, 'identifier', 'display|isbn', 'marcxml', TRUE, FALSE, FALSE,
+        oils_i18n_gettext(41, 'ISBN', 'cmf', 'label'),
+        $$//marc:datafield[@tag='020']/marc:subfield[@code='a' or @code='z']$$)
+
 ;
 
 INSERT INTO config.display_field_map (name, field, multi) VALUES
     ('title', 37, FALSE),
     ('author', 38, FALSE),
     ('subject', 39, TRUE),
-    ('topic_subject', 40, TRUE)
+    ('topic_subject', 40, TRUE),
+    ('isbn', 41, TRUE)
 ;
 
 COMMIT;
diff --git a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql
index 60c4cd1..5997b97 100644
--- a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql
@@ -292,6 +292,8 @@ DROP TRIGGER display_field_normalize_tgr ON metabib.display_entry;
 DROP FUNCTION metabib.display_field_normalize_trigger();
 DROP INDEX metabib.metabib_display_entry_source_idx;
 DROP INDEX metabib.metabib_display_entry_field_idx;
+DROP VIEW metabib.wide_display_entry;
+DROP VIEW metabib.compressed_display_entry;
 DROP VIEW metabib.flat_display_entry;
 DROP TABLE config.display_field_map;
 DROP TABLE metabib.display_entry;

commit a473001c669604d9085d3bda6484b320d3bcd754
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu May 11 17:37:32 2017 -0400

    LP#1251394 display map perms; links; formatting
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 3a09f05..70ac771 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -2844,9 +2844,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field reporter:label="Browse XPath" name="browse_xpath" reporter:datatype="text" />
 			<field reporter:label="Restrict?" name="restrict" reporter:datatype="bool" />
 			<field reporter:label="Display Field?" name="display_field" reporter:datatype="bool" />
+			<field reporter:label="Display Field Map" name="display_field_map" oils_persist:virtual="true" reporter:datatype="link"/>
 		</fields>
 		<links>
 			<link field="field_class" reltype="has_a" key="name" map="" class="cmc"/>
+			<link field="display_field_map" reltype="might_have" key="field" map="" class="cdfm"/>
 		</links>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
@@ -3734,14 +3736,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
 			<link field="field" reltype="has_a" key="id" map="" class="cmf"/>
 		</links>
-        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
-            <actions>
-                <retrieve/>
+		<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+			<actions>
+				<retrieve/>
 			</actions>
 		</permacrud>
 	</class>
 	<class id="mfde" controller="open-ils.cstore open-ils.pcrud" 
-	  oils_persist:tablename="metabib.flat_display_entry"
+		oils_persist:tablename="metabib.flat_display_entry"
 		oils_obj:fieldmapper="metabib::flat_display_entry" 
 		oils_persist:field_safe="true"
 		reporter:label="Flat Display Field Entry View" 
@@ -3757,14 +3759,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<link field="field" reltype="has_a" key="id" map="" class="cmf"/>
 			<link field="name" reltype="has_a" key="name" map="" class="cdfm"/>
 		</links>
-    <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+		<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
 			<actions>
 				<retrieve/>
 			</actions>
 		</permacrud>
 	</class>
 	<class id="cdfm" controller="open-ils.cstore open-ils.pcrud" 
-	  oils_persist:tablename="config.display_field_map"
+		oils_persist:tablename="config.display_field_map"
 		oils_obj:fieldmapper="config::display_field_map"
 		oils_persist:field_safe="true"
 		reporter:label="Display Field Map" 
@@ -3777,9 +3779,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 		<links>
 			<link field="field" reltype="has_a" key="id" map="" class="cmf"/>
 		</links>
-    <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+		<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
 			<actions>
 				<retrieve/>
+				<create permission="CREATE_METABIB_FIELD" global_required="true"/>
+				<update permission="UPDATE_METABIB_FIELD" global_required="true"/>
+				<delete permission="DELETE_METABIB_FIELD" global_required="true"/>
 			</actions>
 		</permacrud>
 	</class>

commit 071ca406ba4806b9be9abf3565b685e6c17efbc1
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu May 11 12:14:10 2017 -0400

    LP#1251394 flat_display_entry gets 'field' col
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index dc283f0..3a09f05 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -3748,11 +3748,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 		oils_persist:readonly="true">
 		<fields>
 			<field name="source" reporter:datatype="id" />
-			<field name="value" reporter:datatype="text"/>
 			<field name="name" reporter:datatype="text"/>
+			<field name="field" reporter:datatype="link"/>
+			<field name="value" reporter:datatype="text"/>
 		</fields>
 		<links>
 			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
+			<link field="field" reltype="has_a" key="id" map="" class="cmf"/>
 			<link field="name" reltype="has_a" key="name" map="" class="cdfm"/>
 		</links>
     <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index 6066bba..2d69e81 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -22,6 +22,7 @@ CREATE VIEW metabib.flat_display_entry AS
     SELECT
         mde.source,
         cdfm.name,
+        mde.field,
         CASE WHEN cdfm.multi THEN
             TO_JSON(ARRAY_AGG(value))
         ELSE
@@ -29,7 +30,7 @@ CREATE VIEW metabib.flat_display_entry AS
         END AS value
     FROM metabib.display_entry mde
     JOIN config.display_field_map cdfm ON (cdfm.field = mde.field)
-    GROUP BY 1, 2;
+    GROUP BY 1, 2, 3;
 
 CREATE INDEX metabib_display_entry_field_idx 
     ON metabib.display_entry (field);

commit 4196a3a4c181debd68be410dc18897bfdc4841e2
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu May 11 11:56:32 2017 -0400

    LP#1251394 config.display_field_map / flat json display
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index f4c7d6d..dc283f0 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -3741,41 +3741,47 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 		</permacrud>
 	</class>
 	<class id="mfde" controller="open-ils.cstore open-ils.pcrud" 
+	  oils_persist:tablename="metabib.flat_display_entry"
 		oils_obj:fieldmapper="metabib::flat_display_entry" 
 		oils_persist:field_safe="true"
-		reporter:label="Flat Display Field Entry View" oils_persist:readonly="true">
-		<oils_persist:source_definition>
-			SELECT
-				mde.source,
-				mde.value,
-				cmf.id AS field,
-				cmf.field_class,
-				cmf.name,
-				cmf.label,
-				cmc.name AS representative
-			FROM metabib.display_entry mde
-			JOIN config.metabib_field cmf ON (cmf.id = mde.field)                                                                                                                LEFT JOIN config.metabib_class cmc ON
-				(cmc.name = cmf.field_class AND cmc.representative_field = cmf.id)
-		</oils_persist:source_definition>
+		reporter:label="Flat Display Field Entry View" 
+		oils_persist:readonly="true">
 		<fields>
 			<field name="source" reporter:datatype="id" />
 			<field name="value" reporter:datatype="text"/>
-			<field name="field" reporter:datatype="link"/>
-			<field name="field_class" reporter:datatype="text"/>
 			<field name="name" reporter:datatype="text"/>
-			<field name="label" reporter:datatype="text"/>
-			<field name="representative" reporter:datatype="text"/>
 		</fields>
 		<links>
 			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
+			<link field="name" reltype="has_a" key="name" map="" class="cdfm"/>
+		</links>
+    <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+			<actions>
+				<retrieve/>
+			</actions>
+		</permacrud>
+	</class>
+	<class id="cdfm" controller="open-ils.cstore open-ils.pcrud" 
+	  oils_persist:tablename="config.display_field_map"
+		oils_obj:fieldmapper="config::display_field_map"
+		oils_persist:field_safe="true"
+		reporter:label="Display Field Map" 
+		oils_persist:readonly="true">
+		<fields oils_persist:primary="name">
+			<field name="name" reporter:datatype="text"/>
+			<field name="field" reporter:datatype="link"/>
+			<field name="multi" reporter:datatype="bool"/>
+		</fields>
+		<links>
 			<link field="field" reltype="has_a" key="id" map="" class="cmf"/>
 		</links>
-        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
-            <actions>
-                <retrieve/>
+    <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+			<actions>
+				<retrieve/>
 			</actions>
 		</permacrud>
 	</class>
+
 	<class id="mfae" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="metabib::facet_entry" oils_persist:tablename="metabib.facet_entry" reporter:label="Combined Facet Entry" oils_persist:readonly="true">
 		<fields oils_persist:primary="id" oils_persist:sequence="metabib.facet_entry_id_seq">
 			<field name="id" reporter:datatype="id" />
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index 1fe2606..6066bba 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -3,34 +3,34 @@ BEGIN;
 
 ALTER TABLE config.metabib_field 
     ADD COLUMN display_xpath TEXT, 
-    ADD COLUMN display_field BOOL NOT NULL DEFAULT TRUE;
-
-CREATE OR REPLACE FUNCTION 
-    config.metabib_representative_field_is_valid(INTEGER, TEXT) RETURNS BOOLEAN AS $$
-    SELECT EXISTS (SELECT 1 FROM config.metabib_field WHERE id = $1 AND field_class = $2);
-$$ LANGUAGE SQL STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION config.metabib_representative_field_is_valid(INTEGER, TEXT) IS $$
-Ensure the field_class value on the selected representative field matches
-the class name.
-$$;
-
-ALTER TABLE config.metabib_class
-    ADD COLUMN representative_field 
-        INTEGER REFERENCES config.metabib_field(id),
-    ADD CONSTRAINT rep_field_unique UNIQUE(representative_field),
-    ADD CONSTRAINT rep_field_is_valid CHECK (
-        representative_field IS NULL OR
-        config.metabib_representative_field_is_valid(representative_field, name)
-    );
+    ADD COLUMN display_field BOOL NOT NULL DEFAULT FALSE;
 
 CREATE TABLE metabib.display_entry (
     id      BIGSERIAL  PRIMARY KEY,
-    source  BIGINT     NOT NULL,
-    field   INT        NOT NULL,
+    source  BIGINT     NOT NULL REFERENCES biblio.record_entry (id),
+    field   INT        NOT NULL REFERENCES config.metabib_field (id),
     value   TEXT       NOT NULL
 );
 
+CREATE TABLE config.display_field_map (
+    name    TEXT   PRIMARY KEY,
+    field   INTEGER REFERENCES config.metabib_field (id),
+    multi   BOOLEAN DEFAULT FALSE
+);
+
+CREATE VIEW metabib.flat_display_entry AS
+    SELECT
+        mde.source,
+        cdfm.name,
+        CASE WHEN cdfm.multi THEN
+            TO_JSON(ARRAY_AGG(value))
+        ELSE
+            TO_JSON(MIN(value))
+        END AS value
+    FROM metabib.display_entry mde
+    JOIN config.display_field_map cdfm ON (cdfm.field = mde.field)
+    GROUP BY 1, 2;
+
 CREATE INDEX metabib_display_entry_field_idx 
     ON metabib.display_entry (field);
 CREATE INDEX metabib_display_entry_source_idx 
@@ -399,69 +399,7 @@ BEGIN
 END;
 $func$ LANGUAGE PLPGSQL;
 
-
--- DATA --------------------------------------
-
-UPDATE config.metabib_field SET display_field = FALSE 
-    WHERE field_class = 'keyword' OR name = 'complete';
-
-INSERT INTO config.internal_flag (name, enabled) 
-    VALUES ('ingest.skip_display_indexing', FALSE);
-
--- personal author
-UPDATE config.metabib_class SET representative_field = 8 WHERE name = 'author';
--- title proper
-UPDATE config.metabib_class SET representative_field = 6 WHERE name = 'title';
-
 COMMIT;
 
 
-/* 
--- Ham-fisted reingest for Testing ---------------------
-
--- disable everything we can for reindexing
-UPDATE config.internal_flag SET enabled = TRUE WHERE name IN (
-    'ingest.assume_inserts_only',
-    'ingest.disable_authority_auto_update',
-    'ingest.disable_authority_linking',
-    'ingest.disable_located_uri',
-    'ingest.disable_metabib_field_entry',
-    'ingest.disable_metabib_full_rec',
-    'ingest.disable_metabib_rec_descriptor',
-    'ingest.metarecord_mapping.preserve_on_delete',
-    'ingest.metarecord_mapping.skip_on_insert',
-    'ingest.metarecord_mapping.skip_on_update',
-    'ingest.reingest.force_on_same_marc',
-    'ingest.skip_browse_indexing',
-    'ingest.skip_facet_indexing',
-    'ingest.skip_search_indexing'
-);
-
-UPDATE config.internal_flag SET enabled = TRUE 
-    WHERE name = 'ingest.reingest.force_on_same_marc';
-
-UPDATE biblio.record_entry SET marc = marc;
-
-UPDATE config.internal_flag SET enabled = FALSE
-    WHERE name = 'ingest.reingest.force_on_same_marc';
-
--- re-enable the default ingest flags
-UPDATE config.internal_flag SET enabled = FALSE WHERE name IN (
-    'ingest.assume_inserts_only',
-    'ingest.disable_authority_auto_update',
-    'ingest.disable_authority_linking',
-    'ingest.disable_located_uri',
-    'ingest.disable_metabib_field_entry',
-    'ingest.disable_metabib_full_rec',
-    'ingest.disable_metabib_rec_descriptor',
-    'ingest.metarecord_mapping.preserve_on_delete',
-    'ingest.metarecord_mapping.skip_on_insert',
-    'ingest.metarecord_mapping.skip_on_update',
-    'ingest.reingest.force_on_same_marc',
-    'ingest.skip_browse_indexing',
-    'ingest.skip_facet_indexing',
-    'ingest.skip_search_indexing'
-);
-
-*/
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
new file mode 100644
index 0000000..7432f7c
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.metabib-display-field.sql
@@ -0,0 +1,46 @@
+
+BEGIN;
+
+INSERT INTO config.internal_flag (name, enabled) 
+    VALUES ('ingest.skip_display_indexing', FALSE);
+
+-- Adds seed data to replace (for now) values from the 'mvr' class
+
+INSERT INTO config.metabib_field (id, field_class, name, format,
+    display_field, search_field, browse_field, label, xpath) 
+VALUES
+    (37, 'title', 'display|title', 'mods32', TRUE, FALSE, FALSE,
+        oils_i18n_gettext(37, 'Title', 'cmf', 'label'),
+        '//mods32:mods/mods32:titleNonfiling[mods32:title and not (@type)]'),
+    (38, 'author', 'display|author', 'mods32', TRUE, FALSE, FALSE,
+        oils_i18n_gettext(38, 'Author', 'cmf', 'label'),
+        $$//mods32:mods/mods32:name[@type='personal' and mods32:role/mods32:roleTerm[text()='creator']]$$),
+    (39, 'subject', 'display|subject', 'mods32', TRUE, FALSE, FALSE,
+        oils_i18n_gettext(39, 'Subject', 'cmf', 'label'),
+        '//mods32:mods/mods32:subject'),
+    (40, 'subject', 'display|topic_subject', 'mods32', TRUE, FALSE, FALSE,
+        oils_i18n_gettext(40, 'Subject', 'cmf', 'label'),
+        '//mods32:mods/mods32:subject/mods32:topic')
+;
+
+INSERT INTO config.display_field_map (name, field, multi) VALUES
+    ('title', 37, FALSE),
+    ('author', 38, FALSE),
+    ('subject', 39, TRUE),
+    ('topic_subject', 40, TRUE)
+;
+
+COMMIT;
+
+-- REINGEST DISPLAY ENTRIES
+
+BEGIN;
+UPDATE config.internal_flag SET enabled = TRUE WHERE name IN (
+'ingest.assume_inserts_only','ingest.disable_authority_auto_update','ingest.disable_authority_linking','ingest.disable_located_uri','ingest.disable_metabib_field_entry','ingest.disable_metabib_full_rec','ingest.disable_metabib_rec_descriptor','ingest.metarecord_mapping.preserve_on_delete','ingest.metarecord_mapping.skip_on_insert','ingest.metarecord_mapping.skip_on_update','ingest.reingest.force_on_same_marc','ingest.skip_browse_indexing','ingest.skip_facet_indexing','ingest.skip_search_indexing');
+
+UPDATE biblio.record_entry SET marc = marc;
+
+UPDATE config.internal_flag SET enabled = FALSE WHERE name IN (
+'ingest.assume_inserts_only','ingest.disable_authority_auto_update','ingest.disable_authority_linking','ingest.disable_located_uri','ingest.disable_metabib_field_entry','ingest.disable_metabib_full_rec','ingest.disable_metabib_rec_descriptor','ingest.metarecord_mapping.preserve_on_delete','ingest.metarecord_mapping.skip_on_insert','ingest.metarecord_mapping.skip_on_update','ingest.reingest.force_on_same_marc','ingest.skip_browse_indexing','ingest.skip_facet_indexing','ingest.skip_search_indexing');
+COMMIT;
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql
similarity index 62%
copy from Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
copy to Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql
index 1fe2606..60c4cd1 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.UNDO.metabib-display-field.sql
@@ -1,93 +1,116 @@
+-- XXX REVERT FILE -- DELETE THIS BEFORE MERGING XXX --
+
+DELETE FROM metabib.display_entry;
+DELETE FROM config.display_field_map;
+DELETE FROM config.metabib_field WHERE display_field; -- ASSUMES ALL NEW FIELDS
+
+DELETE FROM config.internal_flag WHERE name = 'ingest.skip_display_indexing';
 
 BEGIN;
 
-ALTER TABLE config.metabib_field 
-    ADD COLUMN display_xpath TEXT, 
-    ADD COLUMN display_field BOOL NOT NULL DEFAULT TRUE;
-
-CREATE OR REPLACE FUNCTION 
-    config.metabib_representative_field_is_valid(INTEGER, TEXT) RETURNS BOOLEAN AS $$
-    SELECT EXISTS (SELECT 1 FROM config.metabib_field WHERE id = $1 AND field_class = $2);
-$$ LANGUAGE SQL STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION config.metabib_representative_field_is_valid(INTEGER, TEXT) IS $$
-Ensure the field_class value on the selected representative field matches
-the class name.
-$$;
-
-ALTER TABLE config.metabib_class
-    ADD COLUMN representative_field 
-        INTEGER REFERENCES config.metabib_field(id),
-    ADD CONSTRAINT rep_field_unique UNIQUE(representative_field),
-    ADD CONSTRAINT rep_field_is_valid CHECK (
-        representative_field IS NULL OR
-        config.metabib_representative_field_is_valid(representative_field, name)
-    );
-
-CREATE TABLE metabib.display_entry (
-    id      BIGSERIAL  PRIMARY KEY,
-    source  BIGINT     NOT NULL,
-    field   INT        NOT NULL,
-    value   TEXT       NOT NULL
-);
-
-CREATE INDEX metabib_display_entry_field_idx 
-    ON metabib.display_entry (field);
-CREATE INDEX metabib_display_entry_source_idx 
-    ON metabib.display_entry (source);
-
-CREATE OR REPLACE FUNCTION metabib.display_field_normalize_trigger () 
-    RETURNS TRIGGER AS $$
+DROP FUNCTION metabib.reingest_metabib_field_entries(BIGINT, BOOL, BOOL, BOOL, BOOL);
+
+CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
 DECLARE
-    normalizer  RECORD;
-    display_field_text  TEXT;
+    fclass          RECORD;
+    ind_data        metabib.field_entry_template%ROWTYPE;
+    mbe_row         metabib.browse_entry%ROWTYPE;
+    mbe_id          BIGINT;
+    b_skip_facet    BOOL;
+    b_skip_browse   BOOL;
+    b_skip_search   BOOL;
+    value_prepped   TEXT;
 BEGIN
-    display_field_text := NEW.value;
-
-    FOR normalizer IN
-        SELECT  n.func AS func,
-                n.param_count AS param_count,
-                m.params AS params
-          FROM  config.index_normalizer n
-                JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id)
-          WHERE m.field = NEW.field AND m.pos < 0
-          ORDER BY m.pos LOOP
-
-            EXECUTE 'SELECT ' || normalizer.func || '(' ||
-                quote_literal( display_field_text ) ||
-                CASE
-                    WHEN normalizer.param_count > 0
-                        THEN ',' || REPLACE(REPLACE(BTRIM(
-                            normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
-                        ELSE ''
-                    END ||
-                ')' INTO display_field_text;
 
-    END LOOP;
+    SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
+    SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
+    SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
 
-    NEW.value = display_field_text;
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
+    IF NOT FOUND THEN
+        IF NOT b_skip_search THEN
+            FOR fclass IN SELECT * FROM config.metabib_class LOOP
+                -- RAISE NOTICE 'Emptying out %', fclass.name;
+                EXECUTE $$DELETE FROM metabib.$$ || fclass.name || $$_field_entry WHERE source = $$ || bib_id;
+            END LOOP;
+        END IF;
+        IF NOT b_skip_facet THEN
+            DELETE FROM metabib.facet_entry WHERE source = bib_id;
+        END IF;
+        IF NOT b_skip_browse THEN
+            DELETE FROM metabib.browse_entry_def_map WHERE source = bib_id;
+        END IF;
+    END IF;
 
-    RETURN NEW;
-END;
-$$ LANGUAGE PLPGSQL;
+    FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
+
+	-- don't store what has been normalized away
+        CONTINUE WHEN ind_data.value IS NULL;
 
-CREATE TRIGGER display_field_normalize_tgr
-	BEFORE UPDATE OR INSERT ON metabib.display_entry
-	FOR EACH ROW EXECUTE PROCEDURE metabib.display_field_normalize_trigger();
+        IF ind_data.field < 0 THEN
+            ind_data.field = -1 * ind_data.field;
+        END IF;
 
-CREATE OR REPLACE FUNCTION evergreen.display_field_force_nfc() 
-    RETURNS TRIGGER AS $$
-BEGIN
-    NEW.value := force_unicode_normal_form(NEW.value,'NFC');
-    RETURN NEW;
-END;
-$$ LANGUAGE PLPGSQL;
+        IF ind_data.facet_field AND NOT b_skip_facet THEN
+            INSERT INTO metabib.facet_entry (field, source, value)
+                VALUES (ind_data.field, ind_data.source, ind_data.value);
+        END IF;
+
+        IF ind_data.browse_field AND NOT b_skip_browse THEN
+            -- A caveat about this SELECT: this should take care of replacing
+            -- old mbe rows when data changes, but not if normalization (by
+            -- which I mean specifically the output of
+            -- evergreen.oils_tsearch2()) changes.  It may or may not be
+            -- expensive to add a comparison of index_vector to index_vector
+            -- to the WHERE clause below.
+
+            CONTINUE WHEN ind_data.sort_value IS NULL;
 
-CREATE TRIGGER display_field_force_nfc_tgr
-	BEFORE UPDATE OR INSERT ON metabib.display_entry
-	FOR EACH ROW EXECUTE PROCEDURE evergreen.display_field_force_nfc();
+            value_prepped := metabib.browse_normalize(ind_data.value, ind_data.field);
+            SELECT INTO mbe_row * FROM metabib.browse_entry
+                WHERE value = value_prepped AND sort_value = ind_data.sort_value;
+
+            IF FOUND THEN
+                mbe_id := mbe_row.id;
+            ELSE
+                INSERT INTO metabib.browse_entry
+                    ( value, sort_value ) VALUES
+                    ( value_prepped, ind_data.sort_value );
+
+                mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS);
+            END IF;
+
+            INSERT INTO metabib.browse_entry_def_map (entry, def, source, authority)
+                VALUES (mbe_id, ind_data.field, ind_data.source, ind_data.authority);
+        END IF;
+
+        IF ind_data.search_field AND NOT b_skip_search THEN
+            -- Avoid inserting duplicate rows
+            EXECUTE 'SELECT 1 FROM metabib.' || ind_data.field_class ||
+                '_field_entry WHERE field = $1 AND source = $2 AND value = $3'
+                INTO mbe_id USING ind_data.field, ind_data.source, ind_data.value;
+                -- RAISE NOTICE 'Search for an already matching row returned %', mbe_id;
+            IF mbe_id IS NULL THEN
+                EXECUTE $$
+                INSERT INTO metabib.$$ || ind_data.field_class || $$_field_entry (field, source, value)
+                    VALUES ($$ ||
+                        quote_literal(ind_data.field) || $$, $$ ||
+                        quote_literal(ind_data.source) || $$, $$ ||
+                        quote_literal(ind_data.value) ||
+                    $$);$$;
+            END IF;
+        END IF;
+
+    END LOOP;
+
+    IF NOT b_skip_search THEN
+        PERFORM metabib.update_combined_index_vectors(bib_id);
+    END IF;
+
+    RETURN;
+END;
+$func$ LANGUAGE PLPGSQL;
 
-ALTER TYPE metabib.field_entry_template ADD ATTRIBUTE display_field BOOL;
 
 CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) RETURNS SETOF metabib.field_entry_template AS $func$
 DECLARE
@@ -99,7 +122,6 @@ DECLARE
     xml_node    TEXT;
     xml_node_list   TEXT[];
     facet_text  TEXT;
-    display_text TEXT;
     browse_text TEXT;
     sort_value  TEXT;
     raw_text    TEXT;
@@ -113,7 +135,6 @@ BEGIN
     -- Start out with no field-use bools set
     output_row.browse_field = FALSE;
     output_row.facet_field = FALSE;
-    output_row.display_field = FALSE;
     output_row.search_field = FALSE;
 
     -- Get the record
@@ -241,25 +262,6 @@ BEGIN
                 output_row.facet_field = FALSE;
             END IF;
 
-            -- insert raw node text for display
-            IF idx.display_field THEN
-
-                IF idx.display_xpath IS NOT NULL AND idx.display_xpath <> '' THEN
-                    display_text := oils_xpath_string( idx.display_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
-                ELSE
-                    display_text := curr_text;
-                END IF;
-
-                output_row.field_class = idx.field_class;
-                output_row.field = -1 * idx.id;
-                output_row.source = rid;
-                output_row.value = BTRIM(REGEXP_REPLACE(display_text, E'\\s+', ' ', 'g'));
-
-                output_row.display_field = TRUE;
-                RETURN NEXT output_row;
-                output_row.display_field = FALSE;
-            END IF;
-
         END LOOP;
 
         CONTINUE WHEN raw_text IS NULL OR raw_text = '';
@@ -282,186 +284,23 @@ END;
 
 $func$ LANGUAGE PLPGSQL;
 
-DROP FUNCTION metabib.reingest_metabib_field_entries(BIGINT, BOOL, BOOL, BOOL);
 
-CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( 
-    bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, 
-    skip_display BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, 
-    skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
-DECLARE
-    fclass          RECORD;
-    ind_data        metabib.field_entry_template%ROWTYPE;
-    mbe_row         metabib.browse_entry%ROWTYPE;
-    mbe_id          BIGINT;
-    b_skip_facet    BOOL;
-    b_skip_display    BOOL;
-    b_skip_browse   BOOL;
-    b_skip_search   BOOL;
-    value_prepped   TEXT;
-BEGIN
-
-    SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
-    SELECT COALESCE(NULLIF(skip_display, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_display_indexing' AND enabled)) INTO b_skip_display;
-    SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
-    SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
+ALTER TYPE metabib.field_entry_template DROP ATTRIBUTE display_field;
+DROP TRIGGER display_field_force_nfc_tgr ON metabib.display_entry;
+DROP FUNCTION evergreen.display_field_force_nfc();
+DROP TRIGGER display_field_normalize_tgr ON metabib.display_entry;
+DROP FUNCTION metabib.display_field_normalize_trigger();
+DROP INDEX metabib.metabib_display_entry_source_idx;
+DROP INDEX metabib.metabib_display_entry_field_idx;
+DROP VIEW metabib.flat_display_entry;
+DROP TABLE config.display_field_map;
+DROP TABLE metabib.display_entry;
 
-    PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
-    IF NOT FOUND THEN
-        IF NOT b_skip_search THEN
-            FOR fclass IN SELECT * FROM config.metabib_class LOOP
-                -- RAISE NOTICE 'Emptying out %', fclass.name;
-                EXECUTE $$DELETE FROM metabib.$$ || fclass.name || $$_field_entry WHERE source = $$ || bib_id;
-            END LOOP;
-        END IF;
-        IF NOT b_skip_facet THEN
-            DELETE FROM metabib.facet_entry WHERE source = bib_id;
-        END IF;
-        IF NOT b_skip_display THEN
-            DELETE FROM metabib.display_entry WHERE source = bib_id;
-        END IF;
-        IF NOT b_skip_browse THEN
-            DELETE FROM metabib.browse_entry_def_map WHERE source = bib_id;
-        END IF;
-    END IF;
-
-    FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
-
-	-- don't store what has been normalized away
-        CONTINUE WHEN ind_data.value IS NULL;
-
-        IF ind_data.field < 0 THEN
-            ind_data.field = -1 * ind_data.field;
-        END IF;
-
-        IF ind_data.facet_field AND NOT b_skip_facet THEN
-            INSERT INTO metabib.facet_entry (field, source, value)
-                VALUES (ind_data.field, ind_data.source, ind_data.value);
-        END IF;
-
-        IF ind_data.display_field AND NOT b_skip_display THEN
-            INSERT INTO metabib.display_entry (field, source, value)
-                VALUES (ind_data.field, ind_data.source, ind_data.value);
-        END IF;
-
-
-        IF ind_data.browse_field AND NOT b_skip_browse THEN
-            -- A caveat about this SELECT: this should take care of replacing
-            -- old mbe rows when data changes, but not if normalization (by
-            -- which I mean specifically the output of
-            -- evergreen.oils_tsearch2()) changes.  It may or may not be
-            -- expensive to add a comparison of index_vector to index_vector
-            -- to the WHERE clause below.
-
-            CONTINUE WHEN ind_data.sort_value IS NULL;
-
-            value_prepped := metabib.browse_normalize(ind_data.value, ind_data.field);
-            SELECT INTO mbe_row * FROM metabib.browse_entry
-                WHERE value = value_prepped AND sort_value = ind_data.sort_value;
-
-            IF FOUND THEN
-                mbe_id := mbe_row.id;
-            ELSE
-                INSERT INTO metabib.browse_entry
-                    ( value, sort_value ) VALUES
-                    ( value_prepped, ind_data.sort_value );
-
-                mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS);
-            END IF;
-
-            INSERT INTO metabib.browse_entry_def_map (entry, def, source, authority)
-                VALUES (mbe_id, ind_data.field, ind_data.source, ind_data.authority);
-        END IF;
-
-        IF ind_data.search_field AND NOT b_skip_search THEN
-            -- Avoid inserting duplicate rows
-            EXECUTE 'SELECT 1 FROM metabib.' || ind_data.field_class ||
-                '_field_entry WHERE field = $1 AND source = $2 AND value = $3'
-                INTO mbe_id USING ind_data.field, ind_data.source, ind_data.value;
-                -- RAISE NOTICE 'Search for an already matching row returned %', mbe_id;
-            IF mbe_id IS NULL THEN
-                EXECUTE $$
-                INSERT INTO metabib.$$ || ind_data.field_class || $$_field_entry (field, source, value)
-                    VALUES ($$ ||
-                        quote_literal(ind_data.field) || $$, $$ ||
-                        quote_literal(ind_data.source) || $$, $$ ||
-                        quote_literal(ind_data.value) ||
-                    $$);$$;
-            END IF;
-        END IF;
-
-    END LOOP;
-
-    IF NOT b_skip_search THEN
-        PERFORM metabib.update_combined_index_vectors(bib_id);
-    END IF;
-
-    RETURN;
-END;
-$func$ LANGUAGE PLPGSQL;
-
-
--- DATA --------------------------------------
-
-UPDATE config.metabib_field SET display_field = FALSE 
-    WHERE field_class = 'keyword' OR name = 'complete';
-
-INSERT INTO config.internal_flag (name, enabled) 
-    VALUES ('ingest.skip_display_indexing', FALSE);
-
--- personal author
-UPDATE config.metabib_class SET representative_field = 8 WHERE name = 'author';
--- title proper
-UPDATE config.metabib_class SET representative_field = 6 WHERE name = 'title';
+ALTER TABLE config.metabib_field 
+    DROP COLUMN display_xpath,
+    DROP COLUMN display_field;
 
 COMMIT;
 
 
-/* 
--- Ham-fisted reingest for Testing ---------------------
-
--- disable everything we can for reindexing
-UPDATE config.internal_flag SET enabled = TRUE WHERE name IN (
-    'ingest.assume_inserts_only',
-    'ingest.disable_authority_auto_update',
-    'ingest.disable_authority_linking',
-    'ingest.disable_located_uri',
-    'ingest.disable_metabib_field_entry',
-    'ingest.disable_metabib_full_rec',
-    'ingest.disable_metabib_rec_descriptor',
-    'ingest.metarecord_mapping.preserve_on_delete',
-    'ingest.metarecord_mapping.skip_on_insert',
-    'ingest.metarecord_mapping.skip_on_update',
-    'ingest.reingest.force_on_same_marc',
-    'ingest.skip_browse_indexing',
-    'ingest.skip_facet_indexing',
-    'ingest.skip_search_indexing'
-);
-
-UPDATE config.internal_flag SET enabled = TRUE 
-    WHERE name = 'ingest.reingest.force_on_same_marc';
-
-UPDATE biblio.record_entry SET marc = marc;
-
-UPDATE config.internal_flag SET enabled = FALSE
-    WHERE name = 'ingest.reingest.force_on_same_marc';
-
--- re-enable the default ingest flags
-UPDATE config.internal_flag SET enabled = FALSE WHERE name IN (
-    'ingest.assume_inserts_only',
-    'ingest.disable_authority_auto_update',
-    'ingest.disable_authority_linking',
-    'ingest.disable_located_uri',
-    'ingest.disable_metabib_field_entry',
-    'ingest.disable_metabib_full_rec',
-    'ingest.disable_metabib_rec_descriptor',
-    'ingest.metarecord_mapping.preserve_on_delete',
-    'ingest.metarecord_mapping.skip_on_insert',
-    'ingest.metarecord_mapping.skip_on_update',
-    'ingest.reingest.force_on_same_marc',
-    'ingest.skip_browse_indexing',
-    'ingest.skip_facet_indexing',
-    'ingest.skip_search_indexing'
-);
-
-*/
 

commit 0773c439935f172ed571186d45f41bef1a1b8e0e
Author: Bill Erickson <berickxx at gmail.com>
Date:   Wed Apr 26 17:19:06 2017 -0400

    LP#1251394 Display fields schema rebase
    
    Rebase modified SQL functions to match their current production verions,
    plus changes required for this branch.
    
    Specifically metabib.reingest_metabib_field_entries and
    biblio.extract_metabib_field_entry
    
    Remove duplicate config.metabib_representative_field_is_valid
    function declaration from 002.schema.config.sql.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index d9029b7..2468948 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -183,16 +183,6 @@ INSERT INTO config.biblio_fingerprint (name, xpath, format)
         'mods32'
     );
 
-CREATE OR REPLACE FUNCTION 
-    config.metabib_representative_field_is_valid(INTEGER, TEXT) RETURNS BOOLEAN AS $$
-    SELECT EXISTS (SELECT 1 FROM config.metabib_field WHERE id = $1 AND field_class = $2);
-$$ LANGUAGE SQL STRICT IMMUTABLE;
-
-COMMENT ON FUNCTION config.metabib_representative_field_is_valid(INTEGER, TEXT) IS $$
-Ensure the field_class value on the selected representative field matches
-the class name.
-$$;
-
 CREATE TABLE config.metabib_class (
     name     TEXT    PRIMARY KEY,
     label    TEXT    NOT NULL UNIQUE,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index 775b5eb..1fe2606 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -146,24 +146,9 @@ BEGIN
 
             -- XXX much of this should be moved into oils_xpath_string...
             curr_text := ARRAY_TO_STRING(evergreen.array_remove_item_by_value(evergreen.array_remove_item_by_value(
-                oils_xpath( '//text()',
-                    REGEXP_REPLACE(
-                        REGEXP_REPLACE( -- This escapes all &s not followed by "amp;".  Data ise returned from oils_xpath (above) in UTF-8, not entity encoded
-                            REGEXP_REPLACE( -- This escapes embeded <s
-                                xml_node,
-                                $re$(>[^<]+)(<)([^>]+<)$re$,
-                                E'\\1<\\3',
-                                'g'
-                            ),
-                            '&(?!amp;)',
-                            '&',
-                            'g'
-                        ),
-                        E'\\s+',
-                        ' ',
-                        'g'
-                    )
-                ), ' '), ''),
+                oils_xpath( '//text()', -- get the content of all the nodes within the main selected node
+                    REGEXP_REPLACE( xml_node, E'\\s+', ' ', 'g' ) -- Translate adjacent whitespace to a single space
+                ), ' '), ''),  -- throw away morally empty (bankrupt?) strings
                 joiner
             );
 
@@ -340,6 +325,10 @@ BEGIN
     END IF;
 
     FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
+
+	-- don't store what has been normalized away
+        CONTINUE WHEN ind_data.value IS NULL;
+
         IF ind_data.field < 0 THEN
             ind_data.field = -1 * ind_data.field;
         END IF;
@@ -363,6 +352,8 @@ BEGIN
             -- expensive to add a comparison of index_vector to index_vector
             -- to the WHERE clause below.
 
+            CONTINUE WHEN ind_data.sort_value IS NULL;
+
             value_prepped := metabib.browse_normalize(ind_data.value, ind_data.field);
             SELECT INTO mbe_row * FROM metabib.browse_entry
                 WHERE value = value_prepped AND sort_value = ind_data.sort_value;

commit 11507993c4befcbdbe8d2c46c2f9e5ab40920c31
Author: Dan Wells <dbw2 at calvin.edu>
Date:   Fri Feb 20 14:37:51 2015 -0500

    LP#1251394 Fix DB order of operations
    
    'representative_field' (and its check function) create circular
    references between metabib_class and metabib_field.  The most
    straightforward fix is to deal with those fields separate from the
    initial table creation and field insertion.
    
    Signed-off-by: Dan Wells <dbw2 at calvin.edu>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index a7fc62b..d9029b7 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -203,12 +203,6 @@ CREATE TABLE config.metabib_class (
     b_weight NUMERIC  DEFAULT 0.4 NOT NULL,
     c_weight NUMERIC  DEFAULT 0.2 NOT NULL,
     d_weight NUMERIC  DEFAULT 0.1 NOT NULL
-    representative_field INTEGER REFERENCES config.metabib_field(id),
-    CONSTRAINT rep_field_unique UNIQUE(representative_field),
-    CONSTRAINT rep_field_is_valid CHECK (
-        representative_field IS NULL OR
-        config.metabib_representative_field_is_valid(representative_field, name)
-    )
 );
 
 CREATE TABLE config.metabib_field (
@@ -240,6 +234,26 @@ a "class" of either title, subject, author, keyword, series
 or identifier.
 $$;
 
+CREATE OR REPLACE FUNCTION
+    config.metabib_representative_field_is_valid(INTEGER, TEXT) RETURNS BOOLEAN AS $$
+    SELECT EXISTS (SELECT 1 FROM config.metabib_field WHERE id = $1 AND field_class = $2);
+$$ LANGUAGE SQL STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION config.metabib_representative_field_is_valid(INTEGER, TEXT) IS $$
+Ensure the field_class value on the selected representative field matches
+the class name.
+$$;
+
+ALTER TABLE config.metabib_class
+    ADD COLUMN representative_field
+        INTEGER REFERENCES config.metabib_field(id),
+    ADD CONSTRAINT rep_field_unique UNIQUE(representative_field),
+    ADD CONSTRAINT rep_field_is_valid CHECK (
+	        representative_field IS NULL OR
+	        config.metabib_representative_field_is_valid(representative_field, name)
+	)
+;
+
 CREATE UNIQUE INDEX config_metabib_field_class_name_idx ON config.metabib_field (field_class, name);
 
 CREATE TABLE config.ts_config_list (
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index 360397b..99ea346 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -96,8 +96,8 @@ SELECT SETVAL('config.standing_penalty_id_seq', 100);
 
 INSERT INTO config.metabib_class ( name, label ) VALUES ( 'identifier', oils_i18n_gettext('identifier', 'Identifier', 'cmc', 'label') );
 INSERT INTO config.metabib_class ( name, label ) VALUES ( 'keyword', oils_i18n_gettext('keyword', 'Keyword', 'cmc', 'label') );
-INSERT INTO config.metabib_class ( name, label, representative_field ) VALUES ( 'title', oils_i18n_gettext('title', 'Title', 'cmc', 'label'), 6 );
-INSERT INTO config.metabib_class ( name, label, representative_field ) VALUES ( 'author', oils_i18n_gettext('author', 'Author', 'cmc', 'label'), 8 );
+INSERT INTO config.metabib_class ( name, label ) VALUES ( 'title', oils_i18n_gettext('title', 'Title', 'cmc', 'label'));
+INSERT INTO config.metabib_class ( name, label ) VALUES ( 'author', oils_i18n_gettext('author', 'Author', 'cmc', 'label'));
 INSERT INTO config.metabib_class ( name, label ) VALUES ( 'subject', oils_i18n_gettext('subject', 'Subject', 'cmc', 'label') );
 INSERT INTO config.metabib_class ( name, label ) VALUES ( 'series', oils_i18n_gettext('series', 'Series', 'cmc', 'label') );
 
@@ -127,11 +127,13 @@ INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath,
     (5, 'title', 'uniform', oils_i18n_gettext(5, 'Uniform Title', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:titleInfo[mods32:title and (@type='uniform-nfi')]$$, '//@xlink:href', $$*[local-name() != "nonSort"]$$ );
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, authority_xpath, browse_field ) VALUES
     (6, 'title', 'proper', oils_i18n_gettext(6, 'Title Proper', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:titleNonfiling[mods32:title and not (@type)]$$, '//@xlink:href', FALSE );
+UPDATE config.metabib_class SET representative_field = 6 WHERE name = 'title';
 
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, facet_xpath, facet_field , authority_xpath, browse_xpath) VALUES 
     (7, 'author', 'corporate', oils_i18n_gettext(7, 'Corporate Author', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:name[@type='corporate' and (mods32:role/mods32:roleTerm[text()='creator'] or mods32:role/mods32:roleTerm[text()='aut'] or mods32:role/mods32:roleTerm[text()='cre'])]$$, $$//*[local-name()='namePart']$$, TRUE, '//@xlink:href',$$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, facet_xpath, facet_field, authority_xpath, browse_xpath ) VALUES 
     (8, 'author', 'personal', oils_i18n_gettext(8, 'Personal Author', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:name[@type='personal' and mods32:role/mods32:roleTerm[text()='creator']]$$, $$//*[local-name()='namePart']$$, TRUE, '//@xlink:href',$$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
+UPDATE config.metabib_class SET representative_field = 8 WHERE name = 'author';
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, facet_xpath, facet_field, authority_xpath, browse_xpath ) VALUES 
     (9, 'author', 'conference', oils_i18n_gettext(9, 'Conference Author', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:name[@type='conference' and mods32:role/mods32:roleTerm[text()='creator']]$$, $$//*[local-name()='namePart']$$, TRUE, '//@xlink:href',$$//*[local-name()='namePart']$$ ); -- /* to fool vim */;
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, facet_xpath, facet_field, authority_xpath, browse_xpath ) VALUES 

commit 054027e6340baf5d2f7e58287ed6e1253cab4382
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Nov 14 16:58:54 2013 -0500

    LP#1251394 Display fields schema/IDL continued
    
    * Upgrade SQL repairs
    * make display fields field-safe
    * Representative fields
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index a1ab64f..f4c7d6d 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -2810,10 +2810,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field reporter:label="B Weight" name="b_weight" reporter:datatype="float" />
 			<field reporter:label="C Weight" name="c_weight" reporter:datatype="float" />
 			<field reporter:label="D Weight" name="d_weight" reporter:datatype="float" />
+			<field reporter:label="Representative Field" name="representative_field" reporter:datatype="link" />
 			<field reporter:label="Fields" name="fields" reporter:datatype="link" oils_persist:virtual="true"/>
 		</fields>
 		<links>
 			<link field="fields" reltype="has_many" key="name" map="" class="cmf"/>
+			<link field="representative_field" reltype="has_a" key="id" map="" class="cmf"/>
 		</links>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
@@ -3720,6 +3722,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 	<class id="mde" controller="open-ils.cstore open-ils.pcrud" 
 			oils_obj:fieldmapper="metabib::display_entry" 
 			oils_persist:tablename="metabib.display_entry" 
+			oils_persist:field_safe="true"
 			reporter:label="Display Field Entry" oils_persist:readonly="true">
 		<fields oils_persist:primary="id" oils_persist:sequence="metabib.display_entry_id_seq">
 			<field name="id" reporter:datatype="id" />
@@ -3739,17 +3742,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 	</class>
 	<class id="mfde" controller="open-ils.cstore open-ils.pcrud" 
 		oils_obj:fieldmapper="metabib::flat_display_entry" 
+		oils_persist:field_safe="true"
 		reporter:label="Flat Display Field Entry View" oils_persist:readonly="true">
 		<oils_persist:source_definition>
-			SELECT 
-				mde.source, 
-				mde.value, 
+			SELECT
+				mde.source,
+				mde.value,
 				cmf.id AS field,
-				cmf.field_class, 
-				cmf.name, 
-				cmf.label 
-				FROM metabib.display_entry mde 
-				JOIN config.metabib_field cmf ON (cmf.id = mde.field)
+				cmf.field_class,
+				cmf.name,
+				cmf.label,
+				cmc.name AS representative
+			FROM metabib.display_entry mde
+			JOIN config.metabib_field cmf ON (cmf.id = mde.field)                                                                                                                LEFT JOIN config.metabib_class cmc ON
+				(cmc.name = cmf.field_class AND cmc.representative_field = cmf.id)
 		</oils_persist:source_definition>
 		<fields>
 			<field name="source" reporter:datatype="id" />
@@ -3758,6 +3764,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field name="field_class" reporter:datatype="text"/>
 			<field name="name" reporter:datatype="text"/>
 			<field name="label" reporter:datatype="text"/>
+			<field name="representative" reporter:datatype="text"/>
 		</fields>
 		<links>
 			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index e8f3f24..a7fc62b 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -183,6 +183,16 @@ INSERT INTO config.biblio_fingerprint (name, xpath, format)
         'mods32'
     );
 
+CREATE OR REPLACE FUNCTION 
+    config.metabib_representative_field_is_valid(INTEGER, TEXT) RETURNS BOOLEAN AS $$
+    SELECT EXISTS (SELECT 1 FROM config.metabib_field WHERE id = $1 AND field_class = $2);
+$$ LANGUAGE SQL STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION config.metabib_representative_field_is_valid(INTEGER, TEXT) IS $$
+Ensure the field_class value on the selected representative field matches
+the class name.
+$$;
+
 CREATE TABLE config.metabib_class (
     name     TEXT    PRIMARY KEY,
     label    TEXT    NOT NULL UNIQUE,
@@ -193,6 +203,12 @@ CREATE TABLE config.metabib_class (
     b_weight NUMERIC  DEFAULT 0.4 NOT NULL,
     c_weight NUMERIC  DEFAULT 0.2 NOT NULL,
     d_weight NUMERIC  DEFAULT 0.1 NOT NULL
+    representative_field INTEGER REFERENCES config.metabib_field(id),
+    CONSTRAINT rep_field_unique UNIQUE(representative_field),
+    CONSTRAINT rep_field_is_valid CHECK (
+        representative_field IS NULL OR
+        config.metabib_representative_field_is_valid(representative_field, name)
+    )
 );
 
 CREATE TABLE config.metabib_field (
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index 7551825..360397b 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -96,8 +96,8 @@ SELECT SETVAL('config.standing_penalty_id_seq', 100);
 
 INSERT INTO config.metabib_class ( name, label ) VALUES ( 'identifier', oils_i18n_gettext('identifier', 'Identifier', 'cmc', 'label') );
 INSERT INTO config.metabib_class ( name, label ) VALUES ( 'keyword', oils_i18n_gettext('keyword', 'Keyword', 'cmc', 'label') );
-INSERT INTO config.metabib_class ( name, label ) VALUES ( 'title', oils_i18n_gettext('title', 'Title', 'cmc', 'label') );
-INSERT INTO config.metabib_class ( name, label ) VALUES ( 'author', oils_i18n_gettext('author', 'Author', 'cmc', 'label') );
+INSERT INTO config.metabib_class ( name, label, representative_field ) VALUES ( 'title', oils_i18n_gettext('title', 'Title', 'cmc', 'label'), 6 );
+INSERT INTO config.metabib_class ( name, label, representative_field ) VALUES ( 'author', oils_i18n_gettext('author', 'Author', 'cmc', 'label'), 8 );
 INSERT INTO config.metabib_class ( name, label ) VALUES ( 'subject', oils_i18n_gettext('subject', 'Subject', 'cmc', 'label') );
 INSERT INTO config.metabib_class ( name, label ) VALUES ( 'series', oils_i18n_gettext('series', 'Series', 'cmc', 'label') );
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index 9d20e59..775b5eb 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -1,8 +1,28 @@
 
 BEGIN;
 
-ALTER TABLE config.metabib_field ADD COLUMN display_xpath TEXT, display_field BOOL NOT NULL DEFAULT TRUE;
-UPDATE config.metabib_field SET display_field = FALSE WHERE field_class = 'keyword' OR name = 'complete';
+ALTER TABLE config.metabib_field 
+    ADD COLUMN display_xpath TEXT, 
+    ADD COLUMN display_field BOOL NOT NULL DEFAULT TRUE;
+
+CREATE OR REPLACE FUNCTION 
+    config.metabib_representative_field_is_valid(INTEGER, TEXT) RETURNS BOOLEAN AS $$
+    SELECT EXISTS (SELECT 1 FROM config.metabib_field WHERE id = $1 AND field_class = $2);
+$$ LANGUAGE SQL STRICT IMMUTABLE;
+
+COMMENT ON FUNCTION config.metabib_representative_field_is_valid(INTEGER, TEXT) IS $$
+Ensure the field_class value on the selected representative field matches
+the class name.
+$$;
+
+ALTER TABLE config.metabib_class
+    ADD COLUMN representative_field 
+        INTEGER REFERENCES config.metabib_field(id),
+    ADD CONSTRAINT rep_field_unique UNIQUE(representative_field),
+    ADD CONSTRAINT rep_field_is_valid CHECK (
+        representative_field IS NULL OR
+        config.metabib_representative_field_is_valid(representative_field, name)
+    );
 
 CREATE TABLE metabib.display_entry (
     id      BIGSERIAL  PRIMARY KEY,
@@ -67,9 +87,6 @@ CREATE TRIGGER display_field_force_nfc_tgr
 	BEFORE UPDATE OR INSERT ON metabib.display_entry
 	FOR EACH ROW EXECUTE PROCEDURE evergreen.display_field_force_nfc();
 
-ALTER TABLE config.metabib_field
-    ADD COLUMN display_field BOOL NOT NULL DEFAULT TRUE;
-
 ALTER TYPE metabib.field_entry_template ADD ATTRIBUTE display_field BOOL;
 
 CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) RETURNS SETOF metabib.field_entry_template AS $func$
@@ -392,23 +409,68 @@ END;
 $func$ LANGUAGE PLPGSQL;
 
 
--- DATA -------------------
+-- DATA --------------------------------------
 
--- "General Keywords" and "All Subjects"
--- more?
-UPDATE config.metabib_field SET display_field = FALSE WHERE id IN (15, 16);
+UPDATE config.metabib_field SET display_field = FALSE 
+    WHERE field_class = 'keyword' OR name = 'complete';
 
 INSERT INTO config.internal_flag (name, enabled) 
     VALUES ('ingest.skip_display_indexing', FALSE);
 
--- TODO: targeted ingest?
-
--- Dumb Reingest ---
---UPDATE config.internal_flag SET enabled = TRUE 
---    WHERE name = 'ingest.reingest.force_on_same_marc';
---UPDATE biblio.record_entry SET marc = marc;
---UPDATE config.internal_flag SET enabled = FALSE
---    WHERE name = 'ingest.reingest.force_on_same_marc';
+-- personal author
+UPDATE config.metabib_class SET representative_field = 8 WHERE name = 'author';
+-- title proper
+UPDATE config.metabib_class SET representative_field = 6 WHERE name = 'title';
 
 COMMIT;
---ROLLBACK;
+
+
+/* 
+-- Ham-fisted reingest for Testing ---------------------
+
+-- disable everything we can for reindexing
+UPDATE config.internal_flag SET enabled = TRUE WHERE name IN (
+    'ingest.assume_inserts_only',
+    'ingest.disable_authority_auto_update',
+    'ingest.disable_authority_linking',
+    'ingest.disable_located_uri',
+    'ingest.disable_metabib_field_entry',
+    'ingest.disable_metabib_full_rec',
+    'ingest.disable_metabib_rec_descriptor',
+    'ingest.metarecord_mapping.preserve_on_delete',
+    'ingest.metarecord_mapping.skip_on_insert',
+    'ingest.metarecord_mapping.skip_on_update',
+    'ingest.reingest.force_on_same_marc',
+    'ingest.skip_browse_indexing',
+    'ingest.skip_facet_indexing',
+    'ingest.skip_search_indexing'
+);
+
+UPDATE config.internal_flag SET enabled = TRUE 
+    WHERE name = 'ingest.reingest.force_on_same_marc';
+
+UPDATE biblio.record_entry SET marc = marc;
+
+UPDATE config.internal_flag SET enabled = FALSE
+    WHERE name = 'ingest.reingest.force_on_same_marc';
+
+-- re-enable the default ingest flags
+UPDATE config.internal_flag SET enabled = FALSE WHERE name IN (
+    'ingest.assume_inserts_only',
+    'ingest.disable_authority_auto_update',
+    'ingest.disable_authority_linking',
+    'ingest.disable_located_uri',
+    'ingest.disable_metabib_field_entry',
+    'ingest.disable_metabib_full_rec',
+    'ingest.disable_metabib_rec_descriptor',
+    'ingest.metarecord_mapping.preserve_on_delete',
+    'ingest.metarecord_mapping.skip_on_insert',
+    'ingest.metarecord_mapping.skip_on_update',
+    'ingest.reingest.force_on_same_marc',
+    'ingest.skip_browse_indexing',
+    'ingest.skip_facet_indexing',
+    'ingest.skip_search_indexing'
+);
+
+*/
+

commit 9d57def5f515dc7aa9ef11a02f016e6fe8a33b17
Author: Mike Rylander <mrylander at gmail.com>
Date:   Thu Nov 14 16:43:31 2013 -0500

    LP#1251394 un-squash repeated fields; some minor schema re-alignment
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 0a0ba47..a1ab64f 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -2837,6 +2837,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field reporter:label="Search Field" name="search_field" reporter:datatype="bool" />
 			<field reporter:label="Facet Field" name="facet_field" reporter:datatype="bool" />
 			<field reporter:label="Facet XPath" name="facet_xpath" reporter:datatype="text" />
+			<field reporter:label="Display XPath" name="display_xpath" reporter:datatype="text" />
 			<field reporter:label="Browse Field" name="browse_field" reporter:datatype="bool" />
 			<field reporter:label="Browse XPath" name="browse_xpath" reporter:datatype="text" />
 			<field reporter:label="Restrict?" name="restrict" reporter:datatype="bool" />
@@ -3719,7 +3720,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 	<class id="mde" controller="open-ils.cstore open-ils.pcrud" 
 			oils_obj:fieldmapper="metabib::display_entry" 
 			oils_persist:tablename="metabib.display_entry" 
-			reporter:label="Combined display Entry" oils_persist:readonly="true">
+			reporter:label="Display Field Entry" oils_persist:readonly="true">
 		<fields oils_persist:primary="id" oils_persist:sequence="metabib.display_entry_id_seq">
 			<field name="id" reporter:datatype="id" />
 			<field name="field" reporter:datatype="link"/>
@@ -3738,7 +3739,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 	</class>
 	<class id="mfde" controller="open-ils.cstore open-ils.pcrud" 
 		oils_obj:fieldmapper="metabib::flat_display_entry" 
-		reporter:label="Flat Display Entry View" oils_persist:readonly="true">
+		reporter:label="Flat Display Field Entry View" oils_persist:readonly="true">
 		<oils_persist:source_definition>
 			SELECT 
 				mde.source, 
diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index ba48feb..e8f3f24 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -209,6 +209,7 @@ CREATE TABLE config.metabib_field (
 	browse_xpath   TEXT,
 	browse_sort_xpath TEXT,
 	facet_xpath	TEXT,
+	display_xpath	TEXT,
 	authority_xpath TEXT,
 	joiner      TEXT,
 	restrict	BOOL    DEFAULT FALSE NOT NULL,
diff --git a/Open-ILS/src/sql/Pg/030.schema.metabib.sql b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
index 535945a..c9935ba 100644
--- a/Open-ILS/src/sql/Pg/030.schema.metabib.sql
+++ b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
@@ -192,8 +192,6 @@ CREATE TABLE metabib.display_entry (
 
 CREATE INDEX metabib_display_entry_field_idx 
     ON metabib.display_entry (field);
-CREATE INDEX metabib_display_entry_value_idx 
-    ON metabib.display_entry (SUBSTRING(value,1,1024));
 CREATE INDEX metabib_display_entry_source_idx 
     ON metabib.display_entry (source);
 
@@ -778,6 +776,25 @@ BEGIN
                 output_row.facet_field = FALSE;
             END IF;
 
+            -- insert raw node text for display
+            IF idx.display_field THEN
+
+                IF idx.display_xpath IS NOT NULL AND idx.display_xpath <> '' THEN
+                    display_text := oils_xpath_string( idx.display_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    display_text := curr_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = -1 * idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(display_text, E'\\s+', ' ', 'g'));
+
+                output_row.display_field = TRUE;
+                RETURN NEXT output_row;
+                output_row.display_field = FALSE;
+            END IF;
+
         END LOOP;
 
         CONTINUE WHEN raw_text IS NULL OR raw_text = '';
@@ -794,17 +811,6 @@ BEGIN
             output_row.search_field = FALSE;
         END IF;
 
-        IF idx.display_field THEN
-            output_row.field_class = idx.field_class;
-            output_row.field = idx.id;
-            output_row.source = rid;
-            output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
-
-            output_row.display_field = TRUE;
-            RETURN NEXT output_row;
-            output_row.display_field = FALSE;
-        END IF;
-
     END LOOP;
 
 END;
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
index be67728..9d20e59 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -1,6 +1,9 @@
 
 BEGIN;
 
+ALTER TABLE config.metabib_field ADD COLUMN display_xpath TEXT, display_field BOOL NOT NULL DEFAULT TRUE;
+UPDATE config.metabib_field SET display_field = FALSE WHERE field_class = 'keyword' OR name = 'complete';
+
 CREATE TABLE metabib.display_entry (
     id      BIGSERIAL  PRIMARY KEY,
     source  BIGINT     NOT NULL,
@@ -10,8 +13,6 @@ CREATE TABLE metabib.display_entry (
 
 CREATE INDEX metabib_display_entry_field_idx 
     ON metabib.display_entry (field);
-CREATE INDEX metabib_display_entry_value_idx 
-    ON metabib.display_entry (SUBSTRING(value,1,1024));
 CREATE INDEX metabib_display_entry_source_idx 
     ON metabib.display_entry (source);
 
@@ -238,6 +239,25 @@ BEGIN
                 output_row.facet_field = FALSE;
             END IF;
 
+            -- insert raw node text for display
+            IF idx.display_field THEN
+
+                IF idx.display_xpath IS NOT NULL AND idx.display_xpath <> '' THEN
+                    display_text := oils_xpath_string( idx.display_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    display_text := curr_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = -1 * idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(display_text, E'\\s+', ' ', 'g'));
+
+                output_row.display_field = TRUE;
+                RETURN NEXT output_row;
+                output_row.display_field = FALSE;
+            END IF;
+
         END LOOP;
 
         CONTINUE WHEN raw_text IS NULL OR raw_text = '';
@@ -254,17 +274,6 @@ BEGIN
             output_row.search_field = FALSE;
         END IF;
 
-        IF idx.display_field THEN
-            output_row.field_class = idx.field_class;
-            output_row.field = idx.id;
-            output_row.source = rid;
-            output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
-
-            output_row.display_field = TRUE;
-            RETURN NEXT output_row;
-            output_row.display_field = FALSE;
-        END IF;
-
     END LOOP;
 
 END;

commit 0f98fc18012ac949e1b299a7339bbea9639648bf
Author: Bill Erickson <berick at esilibrary.com>
Date:   Thu Nov 14 14:15:28 2013 -0500

    LP#1251394 Display Fields DB schema continued
    
    * Schema chnange continued
    * mde IDL entry
    * flat display IDL view
    * IDL links from bre to mde/mfde
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 2254d61..0a0ba47 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -3129,6 +3129,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field reporter:label="Subscriptions" name="subscriptions" oils_persist:virtual="true" reporter:datatype="link"/>
 			<field reporter:label="SVF Attributes" name="attrs" oils_persist:virtual="true" reporter:datatype="link"/>
 			<field reporter:label="MVF Attributes" name="mattrs" oils_persist:virtual="true" reporter:datatype="link"/>
+			<field reporter:label="Display Fields" name="display_entries" oils_persist:virtual="true" reporter:datatype="link"/>
+			<field reporter:label="Flat Display Fields" name="flat_display_entries" oils_persist:virtual="true" reporter:datatype="link"/>
 		</fields>
 		<links>
 			<link field="owner" reltype="has_a" key="id" map="" class="aou"/>
@@ -3152,6 +3154,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<link field="attrs" reltype="might_have" key="id" map="" class="mra"/>
 			<link field="mattrs" reltype="might_have" key="id" map="" class="mraf"/>
 			<link field="source" reltype="has_a" key="id" map="" class="cbs"/>
+			<link field="display_entries" reltype="has_many" key="source" map="" class="mde"/>
+			<link field="flat_display_entries" reltype="has_many" key="source" map="" class="mfde"/>
 		</links>
         <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
             <actions>
@@ -3712,6 +3716,58 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<link field="metarecord" reltype="has_a" key="id" map="" class="mmr"/>
 		</links>
 	</class>
+	<class id="mde" controller="open-ils.cstore open-ils.pcrud" 
+			oils_obj:fieldmapper="metabib::display_entry" 
+			oils_persist:tablename="metabib.display_entry" 
+			reporter:label="Combined display Entry" oils_persist:readonly="true">
+		<fields oils_persist:primary="id" oils_persist:sequence="metabib.display_entry_id_seq">
+			<field name="id" reporter:datatype="id" />
+			<field name="field" reporter:datatype="link"/>
+			<field name="source" reporter:datatype="link"/>
+			<field name="value"  reporter:datatype="text"/>
+		</fields>
+		<links>
+			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
+			<link field="field" reltype="has_a" key="id" map="" class="cmf"/>
+		</links>
+        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+            <actions>
+                <retrieve/>
+			</actions>
+		</permacrud>
+	</class>
+	<class id="mfde" controller="open-ils.cstore open-ils.pcrud" 
+		oils_obj:fieldmapper="metabib::flat_display_entry" 
+		reporter:label="Flat Display Entry View" oils_persist:readonly="true">
+		<oils_persist:source_definition>
+			SELECT 
+				mde.source, 
+				mde.value, 
+				cmf.id AS field,
+				cmf.field_class, 
+				cmf.name, 
+				cmf.label 
+				FROM metabib.display_entry mde 
+				JOIN config.metabib_field cmf ON (cmf.id = mde.field)
+		</oils_persist:source_definition>
+		<fields>
+			<field name="source" reporter:datatype="id" />
+			<field name="value" reporter:datatype="text"/>
+			<field name="field" reporter:datatype="link"/>
+			<field name="field_class" reporter:datatype="text"/>
+			<field name="name" reporter:datatype="text"/>
+			<field name="label" reporter:datatype="text"/>
+		</fields>
+		<links>
+			<link field="source" reltype="has_a" key="id" map="" class="bre"/>
+			<link field="field" reltype="has_a" key="id" map="" class="cmf"/>
+		</links>
+        <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+            <actions>
+                <retrieve/>
+			</actions>
+		</permacrud>
+	</class>
 	<class id="mfae" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="metabib::facet_entry" oils_persist:tablename="metabib.facet_entry" reporter:label="Combined Facet Entry" oils_persist:readonly="true">
 		<fields oils_persist:primary="id" oils_persist:sequence="metabib.facet_entry_id_seq">
 			<field name="id" reporter:datatype="id" />
diff --git a/Open-ILS/src/sql/Pg/030.schema.metabib.sql b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
index 0d0712e..535945a 100644
--- a/Open-ILS/src/sql/Pg/030.schema.metabib.sql
+++ b/Open-ILS/src/sql/Pg/030.schema.metabib.sql
@@ -183,6 +183,20 @@ CREATE INDEX metabib_facet_entry_field_idx ON metabib.facet_entry (field);
 CREATE INDEX metabib_facet_entry_value_idx ON metabib.facet_entry (SUBSTRING(value,1,1024));
 CREATE INDEX metabib_facet_entry_source_idx ON metabib.facet_entry (source);
 
+CREATE TABLE metabib.display_entry (
+    id      BIGSERIAL  PRIMARY KEY,
+    source  BIGINT     NOT NULL,
+    field   INT        NOT NULL,
+    value   TEXT       NOT NULL
+);
+
+CREATE INDEX metabib_display_entry_field_idx 
+    ON metabib.display_entry (field);
+CREATE INDEX metabib_display_entry_value_idx 
+    ON metabib.display_entry (SUBSTRING(value,1,1024));
+CREATE INDEX metabib_display_entry_source_idx 
+    ON metabib.display_entry (source);
+
 CREATE TABLE metabib.browse_entry (
     id BIGSERIAL PRIMARY KEY,
     value TEXT,
@@ -220,6 +234,58 @@ CREATE TABLE metabib.browse_entry_simple_heading_map (
 CREATE INDEX browse_entry_sh_map_entry_idx ON metabib.browse_entry_simple_heading_map (entry);
 CREATE INDEX browse_entry_sh_map_sh_idx ON metabib.browse_entry_simple_heading_map (simple_heading);
 
+CREATE OR REPLACE FUNCTION metabib.display_field_normalize_trigger () 
+    RETURNS TRIGGER AS $$
+DECLARE
+    normalizer  RECORD;
+    display_field_text  TEXT;
+BEGIN
+    display_field_text := NEW.value;
+
+    FOR normalizer IN
+        SELECT  n.func AS func,
+                n.param_count AS param_count,
+                m.params AS params
+          FROM  config.index_normalizer n
+                JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id)
+          WHERE m.field = NEW.field AND m.pos < 0
+          ORDER BY m.pos LOOP
+
+            EXECUTE 'SELECT ' || normalizer.func || '(' ||
+                quote_literal( display_field_text ) ||
+                CASE
+                    WHEN normalizer.param_count > 0
+                        THEN ',' || REPLACE(REPLACE(BTRIM(
+                            normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
+                        ELSE ''
+                    END ||
+                ')' INTO display_field_text;
+
+    END LOOP;
+
+    NEW.value = display_field_text;
+
+    RETURN NEW;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE TRIGGER display_field_normalize_tgr
+	BEFORE UPDATE OR INSERT ON metabib.display_entry
+	FOR EACH ROW EXECUTE PROCEDURE metabib.display_field_normalize_trigger();
+
+CREATE OR REPLACE FUNCTION evergreen.display_field_force_nfc() 
+    RETURNS TRIGGER AS $$
+BEGIN
+    NEW.value := force_unicode_normal_form(NEW.value,'NFC');
+    RETURN NEW;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE TRIGGER display_field_force_nfc_tgr
+	BEFORE UPDATE OR INSERT ON metabib.display_entry
+	FOR EACH ROW EXECUTE PROCEDURE evergreen.display_field_force_nfc();
+
+
 CREATE OR REPLACE FUNCTION metabib.facet_normalize_trigger () RETURNS TRIGGER AS $$
 DECLARE
     normalizer  RECORD;
@@ -551,6 +617,7 @@ CREATE TYPE metabib.field_entry_template AS (
     field_class         TEXT,
     field               INT,
     facet_field         BOOL,
+    display_field       BOOL,
     search_field        BOOL,
     browse_field        BOOL,
     source              BIGINT,
@@ -559,7 +626,6 @@ CREATE TYPE metabib.field_entry_template AS (
     sort_value          TEXT
 );
 
-
 CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) RETURNS SETOF metabib.field_entry_template AS $func$
 DECLARE
     bib     biblio.record_entry%ROWTYPE;
@@ -570,6 +636,7 @@ DECLARE
     xml_node    TEXT;
     xml_node_list   TEXT[];
     facet_text  TEXT;
+    display_text TEXT;
     browse_text TEXT;
     sort_value  TEXT;
     raw_text    TEXT;
@@ -583,6 +650,7 @@ BEGIN
     -- Start out with no field-use bools set
     output_row.browse_field = FALSE;
     output_row.facet_field = FALSE;
+    output_row.display_field = FALSE;
     output_row.search_field = FALSE;
 
     -- Get the record
@@ -726,6 +794,17 @@ BEGIN
             output_row.search_field = FALSE;
         END IF;
 
+        IF idx.display_field THEN
+            output_row.field_class = idx.field_class;
+            output_row.field = idx.id;
+            output_row.source = rid;
+            output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
+
+            output_row.display_field = TRUE;
+            RETURN NEXT output_row;
+            output_row.display_field = FALSE;
+        END IF;
+
     END LOOP;
 
 END;
@@ -785,19 +864,24 @@ BEGIN
 END;
 $func$ LANGUAGE PLPGSQL;
 
-CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
+CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( 
+    bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, 
+    skip_display BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, 
+    skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
 DECLARE
     fclass          RECORD;
     ind_data        metabib.field_entry_template%ROWTYPE;
     mbe_row         metabib.browse_entry%ROWTYPE;
     mbe_id          BIGINT;
     b_skip_facet    BOOL;
+    b_skip_display    BOOL;
     b_skip_browse   BOOL;
     b_skip_search   BOOL;
     value_prepped   TEXT;
 BEGIN
 
     SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
+    SELECT COALESCE(NULLIF(skip_display, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_display_indexing' AND enabled)) INTO b_skip_display;
     SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
     SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
 
@@ -812,6 +896,9 @@ BEGIN
         IF NOT b_skip_facet THEN
             DELETE FROM metabib.facet_entry WHERE source = bib_id;
         END IF;
+        IF NOT b_skip_display THEN
+            DELETE FROM metabib.display_entry WHERE source = bib_id;
+        END IF;
         IF NOT b_skip_browse THEN
             DELETE FROM metabib.browse_entry_def_map WHERE source = bib_id;
         END IF;
@@ -831,6 +918,12 @@ BEGIN
                 VALUES (ind_data.field, ind_data.source, ind_data.value);
         END IF;
 
+        IF ind_data.display_field AND NOT b_skip_display THEN
+            INSERT INTO metabib.display_entry (field, source, value)
+                VALUES (ind_data.field, ind_data.source, ind_data.value);
+        END IF;
+
+
         IF ind_data.browse_field AND NOT b_skip_browse THEN
             -- A caveat about this SELECT: this should take care of replacing
             -- old mbe rows when data changes, but not if normalization (by
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
new file mode 100644
index 0000000..be67728
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.metabib-display-field.sql
@@ -0,0 +1,405 @@
+
+BEGIN;
+
+CREATE TABLE metabib.display_entry (
+    id      BIGSERIAL  PRIMARY KEY,
+    source  BIGINT     NOT NULL,
+    field   INT        NOT NULL,
+    value   TEXT       NOT NULL
+);
+
+CREATE INDEX metabib_display_entry_field_idx 
+    ON metabib.display_entry (field);
+CREATE INDEX metabib_display_entry_value_idx 
+    ON metabib.display_entry (SUBSTRING(value,1,1024));
+CREATE INDEX metabib_display_entry_source_idx 
+    ON metabib.display_entry (source);
+
+CREATE OR REPLACE FUNCTION metabib.display_field_normalize_trigger () 
+    RETURNS TRIGGER AS $$
+DECLARE
+    normalizer  RECORD;
+    display_field_text  TEXT;
+BEGIN
+    display_field_text := NEW.value;
+
+    FOR normalizer IN
+        SELECT  n.func AS func,
+                n.param_count AS param_count,
+                m.params AS params
+          FROM  config.index_normalizer n
+                JOIN config.metabib_field_index_norm_map m ON (m.norm = n.id)
+          WHERE m.field = NEW.field AND m.pos < 0
+          ORDER BY m.pos LOOP
+
+            EXECUTE 'SELECT ' || normalizer.func || '(' ||
+                quote_literal( display_field_text ) ||
+                CASE
+                    WHEN normalizer.param_count > 0
+                        THEN ',' || REPLACE(REPLACE(BTRIM(
+                            normalizer.params,'[]'),E'\'',E'\\\''),E'"',E'\'')
+                        ELSE ''
+                    END ||
+                ')' INTO display_field_text;
+
+    END LOOP;
+
+    NEW.value = display_field_text;
+
+    RETURN NEW;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE TRIGGER display_field_normalize_tgr
+	BEFORE UPDATE OR INSERT ON metabib.display_entry
+	FOR EACH ROW EXECUTE PROCEDURE metabib.display_field_normalize_trigger();
+
+CREATE OR REPLACE FUNCTION evergreen.display_field_force_nfc() 
+    RETURNS TRIGGER AS $$
+BEGIN
+    NEW.value := force_unicode_normal_form(NEW.value,'NFC');
+    RETURN NEW;
+END;
+$$ LANGUAGE PLPGSQL;
+
+CREATE TRIGGER display_field_force_nfc_tgr
+	BEFORE UPDATE OR INSERT ON metabib.display_entry
+	FOR EACH ROW EXECUTE PROCEDURE evergreen.display_field_force_nfc();
+
+ALTER TABLE config.metabib_field
+    ADD COLUMN display_field BOOL NOT NULL DEFAULT TRUE;
+
+ALTER TYPE metabib.field_entry_template ADD ATTRIBUTE display_field BOOL;
+
+CREATE OR REPLACE FUNCTION biblio.extract_metabib_field_entry ( rid BIGINT, default_joiner TEXT ) RETURNS SETOF metabib.field_entry_template AS $func$
+DECLARE
+    bib     biblio.record_entry%ROWTYPE;
+    idx     config.metabib_field%ROWTYPE;
+    xfrm        config.xml_transform%ROWTYPE;
+    prev_xfrm   TEXT;
+    transformed_xml TEXT;
+    xml_node    TEXT;
+    xml_node_list   TEXT[];
+    facet_text  TEXT;
+    display_text TEXT;
+    browse_text TEXT;
+    sort_value  TEXT;
+    raw_text    TEXT;
+    curr_text   TEXT;
+    joiner      TEXT := default_joiner; -- XXX will index defs supply a joiner?
+    authority_text TEXT;
+    authority_link BIGINT;
+    output_row  metabib.field_entry_template%ROWTYPE;
+BEGIN
+
+    -- Start out with no field-use bools set
+    output_row.browse_field = FALSE;
+    output_row.facet_field = FALSE;
+    output_row.display_field = FALSE;
+    output_row.search_field = FALSE;
+
+    -- Get the record
+    SELECT INTO bib * FROM biblio.record_entry WHERE id = rid;
+
+    -- Loop over the indexing entries
+    FOR idx IN SELECT * FROM config.metabib_field ORDER BY format LOOP
+
+        joiner := COALESCE(idx.joiner, default_joiner);
+
+        SELECT INTO xfrm * from config.xml_transform WHERE name = idx.format;
+
+        -- See if we can skip the XSLT ... it's expensive
+        IF prev_xfrm IS NULL OR prev_xfrm <> xfrm.name THEN
+            -- Can't skip the transform
+            IF xfrm.xslt <> '---' THEN
+                transformed_xml := oils_xslt_process(bib.marc,xfrm.xslt);
+            ELSE
+                transformed_xml := bib.marc;
+            END IF;
+
+            prev_xfrm := xfrm.name;
+        END IF;
+
+        xml_node_list := oils_xpath( idx.xpath, transformed_xml, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+
+        raw_text := NULL;
+        FOR xml_node IN SELECT x FROM unnest(xml_node_list) AS x LOOP
+            CONTINUE WHEN xml_node !~ E'^\\s*<';
+
+            -- XXX much of this should be moved into oils_xpath_string...
+            curr_text := ARRAY_TO_STRING(evergreen.array_remove_item_by_value(evergreen.array_remove_item_by_value(
+                oils_xpath( '//text()',
+                    REGEXP_REPLACE(
+                        REGEXP_REPLACE( -- This escapes all &s not followed by "amp;".  Data ise returned from oils_xpath (above) in UTF-8, not entity encoded
+                            REGEXP_REPLACE( -- This escapes embeded <s
+                                xml_node,
+                                $re$(>[^<]+)(<)([^>]+<)$re$,
+                                E'\\1<\\3',
+                                'g'
+                            ),
+                            '&(?!amp;)',
+                            '&',
+                            'g'
+                        ),
+                        E'\\s+',
+                        ' ',
+                        'g'
+                    )
+                ), ' '), ''),
+                joiner
+            );
+
+            CONTINUE WHEN curr_text IS NULL OR curr_text = '';
+
+            IF raw_text IS NOT NULL THEN
+                raw_text := raw_text || joiner;
+            END IF;
+
+            raw_text := COALESCE(raw_text,'') || curr_text;
+
+            -- autosuggest/metabib.browse_entry
+            IF idx.browse_field THEN
+
+                IF idx.browse_xpath IS NOT NULL AND idx.browse_xpath <> '' THEN
+                    browse_text := oils_xpath_string( idx.browse_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    browse_text := curr_text;
+                END IF;
+
+                IF idx.browse_sort_xpath IS NOT NULL AND
+                    idx.browse_sort_xpath <> '' THEN
+
+                    sort_value := oils_xpath_string(
+                        idx.browse_sort_xpath, xml_node, joiner,
+                        ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]]
+                    );
+                ELSE
+                    sort_value := browse_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(browse_text, E'\\s+', ' ', 'g'));
+                output_row.sort_value :=
+                    public.naco_normalize(sort_value);
+
+                output_row.authority := NULL;
+
+                IF idx.authority_xpath IS NOT NULL AND idx.authority_xpath <> '' THEN
+                    authority_text := oils_xpath_string(
+                        idx.authority_xpath, xml_node, joiner,
+                        ARRAY[
+                            ARRAY[xfrm.prefix, xfrm.namespace_uri],
+                            ARRAY['xlink','http://www.w3.org/1999/xlink']
+                        ]
+                    );
+
+                    IF authority_text ~ '^\d+$' THEN
+                        authority_link := authority_text::BIGINT;
+                        PERFORM * FROM authority.record_entry WHERE id = authority_link;
+                        IF FOUND THEN
+                            output_row.authority := authority_link;
+                        END IF;
+                    END IF;
+
+                END IF;
+
+                output_row.browse_field = TRUE;
+                -- Returning browse rows with search_field = true for search+browse
+                -- configs allows us to retain granularity of being able to search
+                -- browse fields with "starts with" type operators (for example, for
+                -- titles of songs in music albums)
+                IF idx.search_field THEN
+                    output_row.search_field = TRUE;
+                END IF;
+                RETURN NEXT output_row;
+                output_row.browse_field = FALSE;
+                output_row.search_field = FALSE;
+                output_row.sort_value := NULL;
+            END IF;
+
+            -- insert raw node text for faceting
+            IF idx.facet_field THEN
+
+                IF idx.facet_xpath IS NOT NULL AND idx.facet_xpath <> '' THEN
+                    facet_text := oils_xpath_string( idx.facet_xpath, xml_node, joiner, ARRAY[ARRAY[xfrm.prefix, xfrm.namespace_uri]] );
+                ELSE
+                    facet_text := curr_text;
+                END IF;
+
+                output_row.field_class = idx.field_class;
+                output_row.field = -1 * idx.id;
+                output_row.source = rid;
+                output_row.value = BTRIM(REGEXP_REPLACE(facet_text, E'\\s+', ' ', 'g'));
+
+                output_row.facet_field = TRUE;
+                RETURN NEXT output_row;
+                output_row.facet_field = FALSE;
+            END IF;
+
+        END LOOP;
+
+        CONTINUE WHEN raw_text IS NULL OR raw_text = '';
+
+        -- insert combined node text for searching
+        IF idx.search_field THEN
+            output_row.field_class = idx.field_class;
+            output_row.field = idx.id;
+            output_row.source = rid;
+            output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
+
+            output_row.search_field = TRUE;
+            RETURN NEXT output_row;
+            output_row.search_field = FALSE;
+        END IF;
+
+        IF idx.display_field THEN
+            output_row.field_class = idx.field_class;
+            output_row.field = idx.id;
+            output_row.source = rid;
+            output_row.value = BTRIM(REGEXP_REPLACE(raw_text, E'\\s+', ' ', 'g'));
+
+            output_row.display_field = TRUE;
+            RETURN NEXT output_row;
+            output_row.display_field = FALSE;
+        END IF;
+
+    END LOOP;
+
+END;
+
+$func$ LANGUAGE PLPGSQL;
+
+DROP FUNCTION metabib.reingest_metabib_field_entries(BIGINT, BOOL, BOOL, BOOL);
+
+CREATE OR REPLACE FUNCTION metabib.reingest_metabib_field_entries( 
+    bib_id BIGINT, skip_facet BOOL DEFAULT FALSE, 
+    skip_display BOOL DEFAULT FALSE, skip_browse BOOL DEFAULT FALSE, 
+    skip_search BOOL DEFAULT FALSE ) RETURNS VOID AS $func$
+DECLARE
+    fclass          RECORD;
+    ind_data        metabib.field_entry_template%ROWTYPE;
+    mbe_row         metabib.browse_entry%ROWTYPE;
+    mbe_id          BIGINT;
+    b_skip_facet    BOOL;
+    b_skip_display    BOOL;
+    b_skip_browse   BOOL;
+    b_skip_search   BOOL;
+    value_prepped   TEXT;
+BEGIN
+
+    SELECT COALESCE(NULLIF(skip_facet, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_facet_indexing' AND enabled)) INTO b_skip_facet;
+    SELECT COALESCE(NULLIF(skip_display, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_display_indexing' AND enabled)) INTO b_skip_display;
+    SELECT COALESCE(NULLIF(skip_browse, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_browse_indexing' AND enabled)) INTO b_skip_browse;
+    SELECT COALESCE(NULLIF(skip_search, FALSE), EXISTS (SELECT enabled FROM config.internal_flag WHERE name =  'ingest.skip_search_indexing' AND enabled)) INTO b_skip_search;
+
+    PERFORM * FROM config.internal_flag WHERE name = 'ingest.assume_inserts_only' AND enabled;
+    IF NOT FOUND THEN
+        IF NOT b_skip_search THEN
+            FOR fclass IN SELECT * FROM config.metabib_class LOOP
+                -- RAISE NOTICE 'Emptying out %', fclass.name;
+                EXECUTE $$DELETE FROM metabib.$$ || fclass.name || $$_field_entry WHERE source = $$ || bib_id;
+            END LOOP;
+        END IF;
+        IF NOT b_skip_facet THEN
+            DELETE FROM metabib.facet_entry WHERE source = bib_id;
+        END IF;
+        IF NOT b_skip_display THEN
+            DELETE FROM metabib.display_entry WHERE source = bib_id;
+        END IF;
+        IF NOT b_skip_browse THEN
+            DELETE FROM metabib.browse_entry_def_map WHERE source = bib_id;
+        END IF;
+    END IF;
+
+    FOR ind_data IN SELECT * FROM biblio.extract_metabib_field_entry( bib_id ) LOOP
+        IF ind_data.field < 0 THEN
+            ind_data.field = -1 * ind_data.field;
+        END IF;
+
+        IF ind_data.facet_field AND NOT b_skip_facet THEN
+            INSERT INTO metabib.facet_entry (field, source, value)
+                VALUES (ind_data.field, ind_data.source, ind_data.value);
+        END IF;
+
+        IF ind_data.display_field AND NOT b_skip_display THEN
+            INSERT INTO metabib.display_entry (field, source, value)
+                VALUES (ind_data.field, ind_data.source, ind_data.value);
+        END IF;
+
+
+        IF ind_data.browse_field AND NOT b_skip_browse THEN
+            -- A caveat about this SELECT: this should take care of replacing
+            -- old mbe rows when data changes, but not if normalization (by
+            -- which I mean specifically the output of
+            -- evergreen.oils_tsearch2()) changes.  It may or may not be
+            -- expensive to add a comparison of index_vector to index_vector
+            -- to the WHERE clause below.
+
+            value_prepped := metabib.browse_normalize(ind_data.value, ind_data.field);
+            SELECT INTO mbe_row * FROM metabib.browse_entry
+                WHERE value = value_prepped AND sort_value = ind_data.sort_value;
+
+            IF FOUND THEN
+                mbe_id := mbe_row.id;
+            ELSE
+                INSERT INTO metabib.browse_entry
+                    ( value, sort_value ) VALUES
+                    ( value_prepped, ind_data.sort_value );
+
+                mbe_id := CURRVAL('metabib.browse_entry_id_seq'::REGCLASS);
+            END IF;
+
+            INSERT INTO metabib.browse_entry_def_map (entry, def, source, authority)
+                VALUES (mbe_id, ind_data.field, ind_data.source, ind_data.authority);
+        END IF;
+
+        IF ind_data.search_field AND NOT b_skip_search THEN
+            -- Avoid inserting duplicate rows
+            EXECUTE 'SELECT 1 FROM metabib.' || ind_data.field_class ||
+                '_field_entry WHERE field = $1 AND source = $2 AND value = $3'
+                INTO mbe_id USING ind_data.field, ind_data.source, ind_data.value;
+                -- RAISE NOTICE 'Search for an already matching row returned %', mbe_id;
+            IF mbe_id IS NULL THEN
+                EXECUTE $$
+                INSERT INTO metabib.$$ || ind_data.field_class || $$_field_entry (field, source, value)
+                    VALUES ($$ ||
+                        quote_literal(ind_data.field) || $$, $$ ||
+                        quote_literal(ind_data.source) || $$, $$ ||
+                        quote_literal(ind_data.value) ||
+                    $$);$$;
+            END IF;
+        END IF;
+
+    END LOOP;
+
+    IF NOT b_skip_search THEN
+        PERFORM metabib.update_combined_index_vectors(bib_id);
+    END IF;
+
+    RETURN;
+END;
+$func$ LANGUAGE PLPGSQL;
+
+
+-- DATA -------------------
+
+-- "General Keywords" and "All Subjects"
+-- more?
+UPDATE config.metabib_field SET display_field = FALSE WHERE id IN (15, 16);
+
+INSERT INTO config.internal_flag (name, enabled) 
+    VALUES ('ingest.skip_display_indexing', FALSE);
+
+-- TODO: targeted ingest?
+
+-- Dumb Reingest ---
+--UPDATE config.internal_flag SET enabled = TRUE 
+--    WHERE name = 'ingest.reingest.force_on_same_marc';
+--UPDATE biblio.record_entry SET marc = marc;
+--UPDATE config.internal_flag SET enabled = FALSE
+--    WHERE name = 'ingest.reingest.force_on_same_marc';
+
+COMMIT;
+--ROLLBACK;

commit 537efb752bb1508f885edba22e65af26716ec303
Author: Dan Scott <dan at coffeecode.net>
Date:   Mon Jun 27 16:53:55 2011 -0400

    LP#1251394 Add display_field column to config.metabib_field
    
    The idea is to pull the XPath definitions and i18nized labels for
    config.metabib_field entries into other contexts, to avoid duplicate /
    conflicting defintions in different layers of the code. If display_field
    is TRUE, then it is a signal that it could be usefully exposed to users.
    
    Signed-off-by: Dan Scott <dscott at laurentian.ca>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Mike Rylander <mrylander at gmail.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index a5ba954..2254d61 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -2840,6 +2840,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 			<field reporter:label="Browse Field" name="browse_field" reporter:datatype="bool" />
 			<field reporter:label="Browse XPath" name="browse_xpath" reporter:datatype="text" />
 			<field reporter:label="Restrict?" name="restrict" reporter:datatype="bool" />
+			<field reporter:label="Display Field?" name="display_field" reporter:datatype="bool" />
 		</fields>
 		<links>
 			<link field="field_class" reltype="has_a" key="name" map="" class="cmc"/>
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
index 62c7777..c6d7fdd 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
@@ -31,7 +31,7 @@ package config::metabib_field;
 use base qw/config/;
 __PACKAGE__->table('config_metabib_field');
 __PACKAGE__->columns(Primary => 'id');
-__PACKAGE__->columns(Essential => qw/field_class name xpath weight format search_field facet_field/);
+__PACKAGE__->columns(Essential => qw/field_class name xpath weight format search_field facet_field metabib_field/);
 #-------------------------------------------------------------------------------
 
 package config::identification_type;
diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index 2b1f288..ba48feb 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -211,7 +211,8 @@ CREATE TABLE config.metabib_field (
 	facet_xpath	TEXT,
 	authority_xpath TEXT,
 	joiner      TEXT,
-	restrict	BOOL    DEFAULT FALSE NOT NULL
+	restrict	BOOL    DEFAULT FALSE NOT NULL,
+    display_field BOOL NOT NULL DEFAULT TRUE
 );
 COMMENT ON TABLE config.metabib_field IS $$
 XPath used for record indexing ingest
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index cbb08fb..7551825 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -147,10 +147,10 @@ INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath,
     (14, 'subject', 'topic', oils_i18n_gettext(14, 'Topic Subject', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:subject/mods32:topic$$, TRUE, '//@xlink:href', FALSE );
 --INSERT INTO config.metabib_field ( id, field_class, name, format, xpath ) VALUES 
 --  ( id, field_class, name, xpath ) VALUES ( 'subject', 'genre', 'mods32', $$//mods32:mods/mods32:genre$$ );
-INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field ) VALUES 
-    (15, 'keyword', 'keyword', oils_i18n_gettext(15, 'General Keywords', 'cmf', 'label'), 'mods32', $$//mods32:mods/*[not(local-name()='originInfo')]$$, FALSE ); -- /* to fool vim */;
-INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field ) VALUES
-    (16, 'subject', 'complete', oils_i18n_gettext(16, 'All Subjects', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:subject$$, FALSE );
+INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, display_field ) VALUES 
+    (15, 'keyword', 'keyword', oils_i18n_gettext(15, 'General Keywords', 'cmf', 'label'), 'mods32', $$//mods32:mods/*[not(local-name()='originInfo')]$$, FALSE, FALSE ); -- /* to fool vim */;
+INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field, display_field ) VALUES
+    (16, 'subject', 'complete', oils_i18n_gettext(16, 'All Subjects', 'cmf', 'label'), 'mods32', $$//mods32:mods/mods32:subject$$, FALSE, FALSE );
 
 INSERT INTO config.metabib_field ( id, field_class, name, label, format, xpath, browse_field ) VALUES
     (17, 'identifier', 'accession', oils_i18n_gettext(17, 'Accession Number', 'cmf', 'label'), 'marcxml', $$//marc:controlfield[@tag='001']$$, FALSE );

-----------------------------------------------------------------------

Summary of changes:
 Open-ILS/examples/fm_IDL.xml                       |  132 +++++
 .../lib/OpenILS/Application/Storage/CDBI/config.pm |    2 +-
 Open-ILS/src/sql/Pg/002.schema.config.sql          |   14 +-
 Open-ILS/src/sql/Pg/030.schema.metabib.sql         |  212 +++++++-
 Open-ILS/src/sql/Pg/800.fkeys.sql                  |    3 +
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |   36 +-
 .../upgrade/1073.schema.metabib-display-field.sql  |  554 ++++++++++++++++++++
 .../Pg/upgrade/1074.data.metabib-display-field.sql |   38 ++
 .../Pg/upgrade/1075.schema.fix_vii_fake_fkey.sql   |   21 +
 .../web/js/ui/default/staff/cat/services/record.js |  108 ++++
 .../Administration/display-fields.adoc             |   55 ++
 11 files changed, 1140 insertions(+), 35 deletions(-)
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/1073.schema.metabib-display-field.sql
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/1074.data.metabib-display-field.sql
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/1075.schema.fix_vii_fake_fkey.sql
 create mode 100644 docs/RELEASE_NOTES_NEXT/Administration/display-fields.adoc


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list