diff --git a/.gitmodules b/.gitmodules
index ad421b521c..2101837ba8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -22,3 +22,6 @@
path = test/resource/chai-as-promised
url = https://github.com/domenic/chai-as-promised.git
branch = master
+[submodule "resource/schema/global"]
+ path = resource/schema/global
+ url = git://github.com/zotero/zotero-schema.git
diff --git a/chrome/content/zotero/bindings/itembox.xml b/chrome/content/zotero/bindings/itembox.xml
index 62eddf215a..9c08a8b8a6 100644
--- a/chrome/content/zotero/bindings/itembox.xml
+++ b/chrome/content/zotero/bindings/itembox.xml
@@ -387,9 +387,7 @@
if (fieldIsClickable
&& !Zotero.Items.isPrimaryField(fieldName)
- && (Zotero.ItemFields.isFieldOfBase(Zotero.ItemFields.getID(fieldName), 'date')
- // TEMP - filingDate
- || fieldName == 'filingDate')
+ && Zotero.ItemFields.isDate(fieldName)
// TEMP - NSF
&& fieldName != 'dateSent') {
this.addDateRow(fieldNames[i], this.item.getField(fieldName, true), tabindex);
@@ -414,7 +412,7 @@
if (fieldName) {
label.setAttribute("value", prefix +
- Zotero.ItemFields.getLocalizedString(this.item.itemTypeID, fieldName));
+ Zotero.ItemFields.getLocalizedString(fieldName));
}
// TEMP - NSF (homepage)
@@ -897,7 +895,7 @@
'name' or 'firstName'/'lastName', or 'firstName'/'lastName'/'fieldMode'
* 'creatorType' (can be name or id) or 'creatorTypeID'
*
+ * @param {Object} [options]
+ * @param {Boolean} [options.strict] - Throw on invalid creator type
*/
-Zotero.Item.prototype.setCreator = function (orderIndex, data) {
+Zotero.Item.prototype.setCreator = function (orderIndex, data, options = {}) {
var itemTypeID = this._itemTypeID;
if (!itemTypeID) {
throw new Error('Item type must be set before setting creators');
@@ -1047,7 +1033,8 @@ Zotero.Item.prototype.setCreator = function (orderIndex, data) {
this._requireData('creators');
- data = Zotero.Creators.cleanData(data);
+ var origCreatorType = data.creatorType;
+ data = Zotero.Creators.cleanData(data, options);
if (data.creatorTypeID === undefined) {
throw new Error("Creator data must include a valid 'creatorType' or 'creatorTypeID' property");
@@ -1055,9 +1042,14 @@ Zotero.Item.prototype.setCreator = function (orderIndex, data) {
// If creatorTypeID isn't valid for this type, use the primary type
if (!data.creatorTypeID || !Zotero.CreatorTypes.isValidForItemType(data.creatorTypeID, itemTypeID)) {
- var msg = "Creator type '" + Zotero.CreatorTypes.getName(data.creatorTypeID) + "' "
- + "isn't valid for " + Zotero.ItemTypes.getName(itemTypeID)
- + " -- changing to primary creator";
+ let itemType = Zotero.ItemTypes.getName(itemTypeID);
+ if (options.strict) {
+ let e = new Error(`Invalid creator type '${origCreatorType}' for type ${itemType}`);
+ e.name = "ZoteroInvalidDataError";
+ throw e;
+ }
+ let msg = `Creator type '${origCreatorType}' isn't valid for ${itemType} -- `
+ + "changing to primary creator";
Zotero.warn(msg);
data.creatorTypeID = Zotero.CreatorTypes.getPrimaryIDForType(itemTypeID);
}
@@ -1087,7 +1079,7 @@ Zotero.Item.prototype.setCreator = function (orderIndex, data) {
/**
* @param {Object[]} data - An array of creator data in internal or API JSON format
*/
-Zotero.Item.prototype.setCreators = function (data) {
+Zotero.Item.prototype.setCreators = function (data, options = {}) {
// If empty array, clear all existing creators
if (!data.length) {
while (this.hasCreatorAt(0)) {
@@ -1097,7 +1089,7 @@ Zotero.Item.prototype.setCreators = function (data) {
}
for (let i = 0; i < data.length; i++) {
- this.setCreator(i, data[i]);
+ this.setCreator(i, data[i], options);
}
}
@@ -4191,31 +4183,48 @@ Zotero.Item.prototype.isCollection = function() {
/**
* Populate the object's data from an API JSON data object
+ *
+ * @param {Object} json
+ * @param {Object} [options]
+ * @param {Boolean} [options.strict = false] - Throw on unknown field or invalid field for type
*/
-Zotero.Item.prototype.fromJSON = function (json) {
+Zotero.Item.prototype.fromJSON = function (json, options = {}) {
+ var strict = !!options.strict;
+
if (!json.itemType && !this._itemTypeID) {
throw new Error("itemType property not provided");
}
let itemTypeID = Zotero.ItemTypes.getID(json.itemType);
if (!itemTypeID) {
- let e = new Error(`Invalid item type '${json.itemType}'`);
- e.name = "ZoteroUnknownTypeError";
+ let e = new Error(`Unknown item type '${json.itemType}'`);
+ e.name = "ZoteroInvalidDataError";
throw e;
}
this.setType(itemTypeID);
var isValidForType = {};
- var setFields = {};
+ var setFields = new Set();
+ var { fields: extraFields, extra } = Zotero.Utilities.Internal.extractExtraFields(
+ json.extra !== undefined ? json.extra : '',
+ this,
+ Object.keys(json)
+ );
+
+ // Transfer valid fields from Extra to regular fields
+ // Currently disabled
+ /*for (let [field, value] of extraFields) {
+ this.setField(field, value);
+ setFields.add(field);
+ extraFields.delete(field);
+ }*/
- // Primary data
for (let field in json) {
let val = json[field];
switch (field) {
case 'key':
case 'version':
- case 'synced':
case 'itemType':
case 'note':
// Use?
@@ -4226,6 +4235,7 @@ Zotero.Item.prototype.fromJSON = function (json) {
case 'parentItem':
case 'deleted':
case 'inPublications':
+ case 'extra':
break;
case 'accessDate':
@@ -4238,7 +4248,7 @@ Zotero.Item.prototype.fromJSON = function (json) {
val = Zotero.Date.dateToSQL(d, true);
}
this.setField(field, val);
- setFields[field] = true;
+ setFields.add(field);
break;
case 'dateAdded':
@@ -4255,7 +4265,7 @@ Zotero.Item.prototype.fromJSON = function (json) {
break;
case 'creators':
- this.setCreators(json.creators);
+ this.setCreators(json.creators, options);
break;
case 'tags':
@@ -4298,8 +4308,19 @@ Zotero.Item.prototype.fromJSON = function (json) {
default:
let fieldID = Zotero.ItemFields.getID(field);
if (!fieldID) {
- Zotero.logError("Discarding unknown JSON field '" + field + "' for item "
- + this.libraryKey);
+ // In strict mode, fail on unknown field
+ if (strict) {
+ let e = new Error(`Unknown field '${field}'`);
+ e.name = "ZoteroInvalidDataError";
+ throw e;
+ }
+ // Otherwise store in Extra
+ if (typeof val == 'string') {
+ Zotero.warn(`Storing unknown field '${field}' in Extra for item ${this.libraryKey}`);
+ extraFields.set(field, val);
+ break;
+ }
+ Zotero.warn(`Discarding unknown JSON ${typeof val} '${field}' for item ${this.libraryKey}`);
continue;
}
// Convert to base-mapped field if necessary, so that setFields has the base-mapped field
@@ -4312,15 +4333,26 @@ Zotero.Item.prototype.fromJSON = function (json) {
}
isValidForType[field] = Zotero.ItemFields.isValidForType(fieldID, this.itemTypeID);
if (!isValidForType[field]) {
- Zotero.logError("Discarding invalid field '" + origField + "' for type " + itemTypeID
- + " for item " + this.libraryKey);
+ let type = Zotero.ItemTypes.getName(itemTypeID);
+ // In strict mode, fail on invalid field for type
+ if (strict) {
+ let e = new Error(`Invalid field '${origField}' for type ${type}`);
+ e.name = "ZoteroInvalidDataError";
+ throw e;
+ }
+ // Otherwise store in Extra
+ Zotero.warn(`Storing invalid field '${origField}' for type ${type} in Extra for `
+ + `item ${this.libraryKey}`);
+ extraFields.set(field, val);
continue;
}
this.setField(field, json[origField]);
- setFields[field] = true;
+ setFields.add(field);
}
}
+ this.setField('extra', Zotero.Utilities.Internal.combineExtraFields(extra, extraFields));
+
if (json.collections || this._collections.length) {
this.setCollections(json.collections);
}
@@ -4328,7 +4360,7 @@ Zotero.Item.prototype.fromJSON = function (json) {
// Clear existing fields not specified
var previousFields = this.getUsedFields(true);
for (let field of previousFields) {
- if (!setFields[field] && isValidForType[field] !== false) {
+ if (!setFields.has(field) && isValidForType[field] !== false && field != 'extra') {
this.setField(field, false);
}
}
@@ -4509,6 +4541,45 @@ Zotero.Item.prototype.toResponseJSON = function (options = {}) {
};
+/**
+ * Migrate valid fields in Extra to real fields
+ *
+ * A separate save is required
+ */
+Zotero.Item.prototype.migrateExtraFields = function () {
+ var { itemType, fields, creators, extra } = Zotero.Utilities.Internal.extractExtraFields(
+ this.getField('extra'), this
+ );
+ if (itemType) {
+ this.setType(Zotero.ItemTypes.getID(itemType));
+ }
+ for (let [field, value] of fields) {
+ this.setField(field, value);
+ }
+ if (creators.length) {
+ this.setCreators([...item.getCreators(), ...creators]);
+ }
+ this.setField('extra', extra);
+ if (!this.hasChanged()) {
+ return false;
+ }
+
+ Zotero.debug("Migrating Extra fields for item " + this.libraryKey);
+ if (itemType) {
+ Zotero.debug("Item Type: " + itemType);
+ }
+ if (fields.size) {
+ Zotero.debug(Array.from(fields.entries()));
+ }
+ if (creators.length) {
+ Zotero.debug(creators);
+ }
+ Zotero.debug(extra);
+
+ return true;
+}
+
+
//////////////////////////////////////////////////////////////////////////////
//
// Asynchronous load methods
diff --git a/chrome/content/zotero/xpcom/data/itemFields.js b/chrome/content/zotero/xpcom/data/itemFields.js
index 36f97c47c4..d344485b6e 100644
--- a/chrome/content/zotero/xpcom/data/itemFields.js
+++ b/chrome/content/zotero/xpcom/data/itemFields.js
@@ -42,7 +42,6 @@ Zotero.ItemFields = new function() {
// Privileged methods
this.getName = getName;
this.getID = getID;
- this.getLocalizedString = getLocalizedString;
this.isValidForType = isValidForType;
this.isInteger = isInteger;
this.getItemTypeFields = getItemTypeFields;
@@ -77,17 +76,29 @@ Zotero.ItemFields = new function() {
var baseFields = yield Zotero.DB.columnQueryAsync(sql);
for (let field of fields) {
- _fields[field['fieldID']] = {
- id: field['fieldID'],
+ let isBaseField = baseFields.includes(field.fieldID);
+ let label;
+ try {
+ label = field.label || Zotero.Schema.globalSchemaLocale.fields[field.fieldName];
+ }
+ // Some base fields aren't localized
+ catch (e) {
+ if (!isBaseField) {
+ throw e;
+ }
+ }
+
+ _fields[field.fieldID] = {
+ id: field.fieldID,
name: field.fieldName,
- label: field.label,
+ label,
custom: !!field.custom,
- isBaseField: (baseFields.indexOf(field['fieldID']) != -1),
- formatID: field['fieldFormatID'],
- itemTypes: fieldItemTypes[field['fieldID']]
+ isBaseField: baseFields.includes(field.fieldID),
+ formatID: field.fieldFormatID,
+ itemTypes: fieldItemTypes[field.fieldID]
};
// Store by name as well as id
- _fields[field['fieldName']] = _fields[field['fieldID']];
+ _fields[field.fieldName] = _fields[field.fieldID];
_allFields.push({
id: field.fieldID,
name: field.fieldName
@@ -133,40 +144,29 @@ Zotero.ItemFields = new function() {
};
- function getLocalizedString(itemType, field) {
- // unused currently
- //var typeName = Zotero.ItemTypes.getName(itemType);
- var fieldName = Zotero.ItemFields.getName(field);
+ this.getLocalizedString = function (field) {
+ if (arguments.length == 2) {
+ Zotero.warn("Zotero.ItemFields.getLocalizedString() no longer takes two arguments "
+ + "-- update your code");
+ field = arguments[1];
+ }
+
+ var fieldName = this.getName(field);
// Fields in the items table are special cases
switch (field) {
case 'dateAdded':
case 'dateModified':
case 'itemType':
- return Zotero.getString("itemFields." + field);
+ return Zotero.Schema.globalSchemaLocale.fields[field];
}
// TODO: different labels for different item types
- _fieldCheck(field, 'getLocalizedString');
+ _fieldCheck(field);
- if (_fields[field].label) {
- return _fields[field].label;
- }
- else {
- try {
- var loc = Zotero.getString("itemFields." + fieldName);
- }
- // If localized string not found, try base field
- catch (e) {
- Zotero.debug("Localized string not found for field '" + fieldName + "' -- trying base field");
- var baseFieldID = this.getBaseIDFromTypeAndField(itemType, field);
- fieldName = this.getName(baseFieldID);
- var loc = Zotero.getString("itemFields." + fieldName);
- }
- return loc;
- }
- }
+ return _fields[field].label;
+ };
function isValidForType(fieldID, itemTypeID) {
@@ -182,15 +182,28 @@ Zotero.ItemFields = new function() {
function isInteger(fieldID) {
- _fieldCheck(fieldID, 'isInteger');
+ _fieldCheck(fieldID);
var ffid = _fields[fieldID]['formatID'];
return _fieldFormats[ffid] ? _fieldFormats[ffid]['isInteger'] : false;
}
+ this.isDate = function (field) {
+ var fieldID = this.getID(field);
+ var fieldName = this.getName(field);
+ if (Zotero.ItemFields.isFieldOfBase(fieldID, 'date')) {
+ return true;
+ }
+ if (Zotero.Schema.globalSchemaMeta.fields[fieldName]) {
+ return Zotero.Schema.globalSchemaMeta.fields[fieldName].type == 'date'
+ }
+ return false;
+ };
+
+
this.isCustom = function (fieldID) {
- _fieldCheck(fieldID, 'isCustom');
+ _fieldCheck(fieldID);
return _fields[fieldID].custom;
}
@@ -202,7 +215,7 @@ Zotero.ItemFields = new function() {
function getItemTypeFields(itemTypeID) {
if (!itemTypeID) {
let e = new Error("Invalid item type id '" + itemTypeID + "'");
- e.name = "ZoteroUnknownTypeError";
+ e.name = "ZoteroInvalidDataError";
throw e;
}
@@ -219,14 +232,14 @@ Zotero.ItemFields = new function() {
function isBaseField(field) {
- _fieldCheck(field, arguments.callee.name);
+ _fieldCheck(field);
return _fields[field]['isBaseField'];
}
function isFieldOfBase(field, baseField) {
- var fieldID = _fieldCheck(field, 'isFieldOfBase');
+ var fieldID = _fieldCheck(field);
var baseFieldID = this.getID(baseField);
if (!baseFieldID) {
@@ -299,7 +312,7 @@ Zotero.ItemFields = new function() {
throw new Error("Invalid item type '" + itemType + "'");
}
- _fieldCheck(typeField, 'getBaseIDFromTypeAndField');
+ _fieldCheck(typeField);
if (!this.isValidForType(typeFieldID, itemTypeID)) {
throw new Error("'" + typeField + "' is not a valid field for '" + itemType + "'");
@@ -406,11 +419,11 @@ Zotero.ItemFields = new function() {
* Check whether a field is valid, throwing an exception if not
* (since it should never actually happen)
**/
- function _fieldCheck(field, func) {
+ function _fieldCheck(field) {
var fieldID = Zotero.ItemFields.getID(field);
if (!fieldID) {
Zotero.debug((new Error).stack, 1);
- throw new Error("Invalid field '" + field + (func ? "' in ItemFields." + func + "()" : "'"));
+ throw new Error(`Invalid field '${field}`);
}
return fieldID;
}
@@ -508,8 +521,9 @@ Zotero.ItemFields = new function() {
var sql = 'SELECT itemTypeID, fieldID FROM itemTypeFieldsCombined ORDER BY orderIndex';
var rows = yield Zotero.DB.queryAsync(sql);
- _itemTypeFields = {};
- _itemTypeFields[1] = []; // notes have no fields
+ _itemTypeFields = {
+ [Zotero.ItemTypes.getID('note')]: [] // Notes have no fields
+ };
for (let i=0; i _maxCompatibility) {
- let dbClientVersion = yield Zotero.DB.valueQueryAsync(
+ let dbClientVersion = await Zotero.DB.valueQueryAsync(
"SELECT value FROM settings "
+ "WHERE setting='client' AND key='lastCompatibleVersion'"
);
@@ -135,53 +135,81 @@ Zotero.Schema = new function(){
}
// Check if DB is coming from the DB Repair Tool and should be checked
- var integrityCheck = yield Zotero.DB.valueQueryAsync(
+ var integrityCheck = await Zotero.DB.valueQueryAsync(
"SELECT value FROM settings WHERE setting='db' AND key='integrityCheck'"
);
- var schemaVersion = yield _getSchemaSQLVersion('userdata');
+ // Check whether bundled global schema file is newer than DB
+ var bundledGlobalSchema = await _readGlobalSchemaFromFile();
+ var bundledGlobalSchemaVersionCompare = await _globalSchemaVersionCompare(
+ bundledGlobalSchema.version
+ );
+
+ // Check whether bundled userdata schema has been updated
+ var userdataVersion = await _getSchemaSQLVersion('userdata');
options.minor = minorUpdateFrom && userdata >= minorUpdateFrom;
// If non-minor userdata upgrade, make backup of database first
- if (userdata < schemaVersion && !options.minor) {
- yield Zotero.DB.backupDatabase(userdata, true);
+ if (userdata < userdataVersion && !options.minor) {
+ await Zotero.DB.backupDatabase(userdata, true);
}
- else if (integrityCheck) {
- yield Zotero.DB.backupDatabase(false, true);
+ // Automatic backup
+ else if (integrityCheck || bundledGlobalSchemaVersionCompare === 1) {
+ await Zotero.DB.backupDatabase(false, true);
}
- yield Zotero.DB.queryAsync("PRAGMA foreign_keys = false");
+ await Zotero.DB.queryAsync("PRAGMA foreign_keys = false");
try {
- var updated = yield Zotero.DB.executeTransaction(function* (conn) {
- var updated = yield _updateSchema('system');
+ // If bundled global schema file is newer than DB, apply it
+ if (bundledGlobalSchemaVersionCompare === 1) {
+ await Zotero.DB.executeTransaction(async function () {
+ await _updateGlobalSchema(bundledGlobalSchema);
+ });
+ }
+ else {
+ let data;
+ // If bundled global schema is up to date, use it
+ if (bundledGlobalSchemaVersionCompare === 0) {
+ data = bundledGlobalSchema;
+ }
+ // If bundled global schema is older than the DB (because of a downgrade), use the
+ // DB version, which will match the mapping tables
+ else if (bundledGlobalSchemaVersionCompare === -1) {
+ data = await _readGlobalSchemaFromDB();
+ }
+ await _loadGlobalSchema(data, bundledGlobalSchema.version);
+ }
+
+ var updated = await Zotero.DB.executeTransaction(async function (conn) {
+ var updated = await _updateSchema('system');
// Update custom tables if they exist so that changes are in
// place before user data migration
if (Zotero.DB.tableExists('customItemTypes')) {
- yield _updateCustomTables(updated);
+ await _updateCustomTables();
}
// Auto-repair databases coming from the DB Repair Tool
if (integrityCheck) {
- yield this.integrityCheck(true);
- yield Zotero.DB.queryAsync(
+ await this.integrityCheck(true);
+ await Zotero.DB.queryAsync(
"DELETE FROM settings WHERE setting='db' AND key='integrityCheck'"
);
}
- updated = yield _migrateUserDataSchema(userdata, options);
- yield _updateSchema('triggers');
+ updated = await _migrateUserDataSchema(userdata, options);
+ await _updateSchema('triggers');
// Populate combined tables for custom types and fields -- this is likely temporary
//
// We do this again in case custom fields were changed during user data migration
- yield _updateCustomTables()
+ await _updateCustomTables();
return updated;
}.bind(this));
}
finally {
- yield Zotero.DB.queryAsync("PRAGMA foreign_keys = true");
+ await Zotero.DB.queryAsync("PRAGMA foreign_keys = true");
}
if (updated) {
@@ -216,7 +244,7 @@ Zotero.Schema = new function(){
}
// Reset sync queue tries if new version
- yield _checkClientVersion();
+ await _checkClientVersion();
// In Standalone, don't load bundled files until after UI is ready. In Firefox, load them as
// soon initialization is done so that translation works before the Zotero pane is opened.
@@ -269,7 +297,348 @@ Zotero.Schema = new function(){
});
return updated;
- });
+ };
+
+
+ /**
+ * Get bundled schema from disk
+ *
+ * @return {Object}
+ */
+ async function _readGlobalSchemaFromFile() {
+ return JSON.parse(
+ await Zotero.File.getResourceAsync('resource://zotero/schema/global/schema.json')
+ );
+ }
+
+
+ /**
+ * Get schema from database
+ *
+ * Doesn't include the .itemTypes property, which was already applied to the mapping tables
+ */
+ async function _readGlobalSchemaFromDB() {
+ var pako = {};
+ Services.scriptloader.loadSubScript("resource://zotero/pako.js", pako);
+ var data = await Zotero.DB.valueQueryAsync(
+ "SELECT value FROM settings WHERE schema='globalSchema' AND key='data'"
+ );
+ if (data) {
+ try {
+ data = JSON.parse(pako.inflate(data, { to: 'string' }));
+ }
+ catch (e) {
+ Zotero.warn("Unable to extract global schema -- falling back to file: " + e);
+ }
+ }
+ else {
+ Zotero.warn("Global schema not found in DB -- falling back to file");
+ }
+
+ // If the data is missing or unreadable in the DB for some reason (e.g., DB corruption),
+ // fall back to the file, though it might be out of date
+ if (!data) {
+ data = await _readGlobalSchemaFromFile();
+ }
+
+ return data;
+ }
+
+
+ /**
+ * Compares a given version number to the version of the schema in the database
+ *
+ * @return {Number} - 1 if provided version is greater than DB (i.e., DB needs update), 0 if
+ * the same, -1 if DB version is newer
+ */
+ async function _globalSchemaVersionCompare(version) {
+ if (!version) {
+ throw new Error("version not specified");
+ }
+
+ var dbVersion = await Zotero.Schema.getDBVersion('globalSchema') || null;
+ if (dbVersion > version) {
+ Zotero.debug(`Database has newer global schema (${dbVersion} > ${version}) -- skipping update`);
+ return -1;
+ }
+ else if (dbVersion == version) {
+ Zotero.debug(`Database is up to date with global schema version ${version} -- skipping update`);
+ return 0;
+ }
+
+ Zotero.debug(`Global schema needs update from ${dbVersion} to ${version}`);
+ return 1;
+ }
+
+
+ /**
+ * Update the item-type/field/creator mapping tables based on the passed schema
+ */
+ async function _updateGlobalSchema(data) {
+ Zotero.debug("Updating global schema to version " + data.version);
+
+ Zotero.DB.requireTransaction();
+
+ await Zotero.ID.init();
+
+ var preItemTypeRows = await Zotero.DB.queryAsync(
+ "SELECT itemTypeID AS id, typeName AS name FROM itemTypes"
+ );
+ var preFieldRows = await Zotero.DB.queryAsync(
+ "SELECT fieldID AS id, fieldName AS name FROM fields"
+ );
+ var preCreatorTypeRows = await Zotero.DB.queryAsync(
+ "SELECT creatorTypeID AS id, creatorType AS name FROM creatorTypes"
+ );
+ var preFields = new Set(preFieldRows.map(x => x.name));
+ var preCreatorTypes = new Set(preCreatorTypeRows.map(x => x.name));
+ var preItemTypeIDsByName = new Map(preItemTypeRows.map(x => [x.name, x.id]));
+ var preFieldIDsByName = new Map(preFieldRows.map(x => [x.name, x.id]));
+ var preCreatorTypeIDsByName = new Map(preCreatorTypeRows.map(x => [x.name, x.id]));
+ var postFields = new Set();
+ var postCreatorTypes = new Set();
+ var postFieldIDsByName = new Map();
+ var postCreatorTypeIDsByName = new Map();
+
+ // Add new fields and creator types
+ for (let { fields, creatorTypes } of data.itemTypes) {
+ for (let { field, baseField } of fields) {
+ postFields.add(field);
+ if (baseField) {
+ postFields.add(baseField);
+ }
+ }
+
+ for (let { creatorType } of creatorTypes) {
+ postCreatorTypes.add(creatorType);
+ }
+ }
+ var fieldsValueSets = [];
+ var fieldsParams = [];
+ for (let field of postFields) {
+ if (preFields.has(field)) {
+ postFieldIDsByName.set(field, preFieldIDsByName.get(field));
+ }
+ else {
+ let id = Zotero.ID.get('fields');
+ fieldsValueSets.push("(?, ?, NULL)");
+ fieldsParams.push(id, field);
+ postFieldIDsByName.set(field, id);
+ }
+ }
+ if (fieldsValueSets.length) {
+ await Zotero.DB.queryAsync(
+ "INSERT INTO fields VALUES " + fieldsValueSets.join(", "),
+ fieldsParams
+ );
+ }
+ var creatorTypesValueSets = [];
+ var creatorTypesParams = [];
+ for (let type of postCreatorTypes) {
+ if (preCreatorTypes.has(type)) {
+ postCreatorTypeIDsByName.set(type, preCreatorTypeIDsByName.get(type));
+ }
+ else {
+ let id = Zotero.ID.get('creatorTypes');
+ creatorTypesValueSets.push("(?, ?)");
+ creatorTypesParams.push(id, type);
+ postCreatorTypeIDsByName.set(type, id);
+ }
+ }
+ if (creatorTypesValueSets.length) {
+ await Zotero.DB.queryAsync(
+ "INSERT INTO creatorTypes VALUES " + creatorTypesValueSets.join(", "),
+ creatorTypesParams
+ );
+ }
+
+ // Apply changes to DB
+ let itemTypeFieldsValueSets = [];
+ let baseFieldMappingsValueSets = [];
+ let itemTypeCreatorTypesValueSets = [];
+ for (let { itemType, fields, creatorTypes } of data.itemTypes) {
+ let itemTypeID = preItemTypeIDsByName.get(itemType);
+ // let preItemTypeCreatorTypeIDs = [];
+ if (itemTypeID) {
+ // Unused
+ /*preItemTypeCreatorTypeIDs = await Zotero.DB.columnQueryAsync(
+ "SELECT creatorTypeID FROM itemTypeCreatorTypes WHERE itemTypeID=?",
+ itemTypeID
+ );*/
+ }
+ // New item type
+ else {
+ itemTypeID = Zotero.ID.get('itemTypes');
+ await Zotero.DB.queryAsync(
+ "INSERT INTO itemTypes VALUES (?, ?, NULL, 1)",
+ [itemTypeID, itemType]
+ );
+ }
+
+ // Fields
+ let index = 0;
+ let postItemTypeFieldIDs = new Set();
+ for (let { field, baseField } of fields) {
+ let fieldID = postFieldIDsByName.get(field);
+ postItemTypeFieldIDs.add(fieldID);
+ itemTypeFieldsValueSets.push(`(${itemTypeID}, ${fieldID}, 0, ${index++})`);
+ if (baseField) {
+ let baseFieldID = postFieldIDsByName.get(baseField);
+ baseFieldMappingsValueSets.push(`(${itemTypeID}, ${baseFieldID}, ${fieldID})`);
+ }
+ }
+
+
+ // TODO: Check for fields removed from this item type
+ // throw new Error(`Field ${id} was removed from ${itemType}`);
+
+ // Creator types
+ for (let { creatorType, primary } of creatorTypes) {
+ let typeID = postCreatorTypeIDsByName.get(creatorType);
+ itemTypeCreatorTypesValueSets.push(`(${itemTypeID}, ${typeID}, ${primary ? 1 : 0})`);
+ }
+
+ // TODO: Check for creator types removed from this item type
+ // throw new Error(`Creator type ${id} was removed from ${itemType}`);
+
+ // TODO: Deal with existing types not in the schema, and their items
+ }
+
+ await Zotero.DB.queryAsync("DELETE FROM itemTypeFields");
+ await Zotero.DB.queryAsync("DELETE FROM baseFieldMappings");
+ await Zotero.DB.queryAsync("DELETE FROM itemTypeCreatorTypes");
+
+ await Zotero.DB.queryAsync("INSERT INTO itemTypeFields VALUES "
+ + itemTypeFieldsValueSets.join(", "));
+ await Zotero.DB.queryAsync("INSERT INTO baseFieldMappings VALUES "
+ + baseFieldMappingsValueSets.join(", "));
+ await Zotero.DB.queryAsync("INSERT INTO itemTypeCreatorTypes VALUES "
+ + itemTypeCreatorTypesValueSets.join(", "));
+
+ // Store data in DB as compressed binary string. This lets us use a schema that matches the
+ // DB tables even if the user downgrades to a version with an earlier bundled schema file.
+ var pako = require('pako');
+ var dbData = { ...data };
+ // Don't include types and fields, which are already in the mapping tables
+ delete dbData.itemTypes;
+ await Zotero.DB.queryAsync(
+ "REPLACE INTO settings VALUES ('globalSchema', 'data', ?)",
+ pako.deflate(JSON.stringify(dbData), { to: 'string' }),
+ {
+ debugParams: false
+ }
+ );
+ await _updateDBVersion('globalSchema', data.version);
+
+ var bundledVersion = (await _readGlobalSchemaFromFile()).version;
+ await _loadGlobalSchema(data, bundledVersion);
+ await _reloadSchema();
+ // Mark that we need to migrate Extra values to any newly available fields in
+ // Zotero.Schema.migrateExtraFields()
+ await Zotero.DB.queryAsync(
+ "REPLACE INTO settings VALUES ('globalSchema', 'migrateExtra', 1)"
+ );
+
+ return true;
+ }
+
+
+ this._updateGlobalSchemaForTest = async function (schema) {
+ await Zotero.DB.executeTransaction(async function () {
+ await _updateGlobalSchema(schema);
+ }.bind(this));
+ };
+
+
+
+ /**
+ * Set properties on Zotero.Schema based on the passed data
+ *
+ * @param {Object} data - Global schema data ('version', 'itemTypes', 'locales', etc.)
+ * @param {Number} bundledVersion - Version of the bundled schema.json file
+ */
+ async function _loadGlobalSchema(data, bundledVersion) {
+ if (!data) {
+ throw new Error("Data not provided");
+ }
+ var locale = data.locales[Zotero.locale];
+ if (!locale) {
+ Zotero.warn(`Locale ${Zotero.locale} not found in global schema locales`);
+ locale = data.locales['en-US'];
+ if (!locale) {
+ throw new Error("en-US locale not found in global schema locales");
+ }
+ }
+ Zotero.Schema.globalSchemaVersion = data.version;
+ Zotero.Schema.globalSchemaLocale = locale;
+ Zotero.Schema.globalSchemaMeta = data.meta;
+ Zotero.Schema.CSL_TYPE_MAPPINGS = {};
+ Zotero.Schema.CSL_TYPE_MAPPINGS_REVERSE = {};
+ for (let cslType in data.csl.types) {
+ for (let zoteroType of data.csl.types[cslType]) {
+ Zotero.Schema.CSL_TYPE_MAPPINGS[zoteroType] = cslType;
+ }
+ Zotero.Schema.CSL_TYPE_MAPPINGS_REVERSE[cslType] = data.csl.types[cslType][0];
+ }
+ Zotero.Schema.CSL_TEXT_MAPPINGS = data.csl.fields.text;
+ Zotero.Schema.CSL_DATE_MAPPINGS = data.csl.fields.date;
+ Zotero.Schema.CSL_NAME_MAPPINGS = data.csl.names;
+ }
+
+
+ /**
+ * Migrate values from item Extra fields that can be moved to regular item fields after a global
+ * schema update
+ *
+ * This needs the data object architecture to be initialized, so it's called from zotero.js
+ * rather than in _updateGlobalSchema().
+ */
+ this.migrateExtraFields = async function () {
+ // Check for a flag set by _updateGlobalSchema()
+ var needsUpdate = await Zotero.DB.valueQueryAsync(
+ "SELECT COUNT(*) FROM settings WHERE setting='globalSchema' AND key='migrateExtra'"
+ );
+ if (!needsUpdate) {
+ return;
+ }
+
+ var fieldID = Zotero.ItemFields.getID('extra');
+ var sql = "SELECT itemID, value FROM itemData "
+ + "JOIN itemDataValues USING (valueID) "
+ + "WHERE fieldID=?";
+ var rows = await Zotero.DB.queryAsync(sql, fieldID);
+ var itemIDs = [];
+ for (let row of rows) {
+ let { itemType, fields, creators } = Zotero.Utilities.Internal.extractExtraFields(
+ row.value
+ );
+ if (itemType || fields.size || creators.length) {
+ itemIDs.push(row.itemID);
+ }
+ }
+
+ var items = await Zotero.Items.getAsync(itemIDs);
+ await Zotero.Items.loadDataTypes(items, ['itemData', 'creator']);
+ for (let item of items) {
+ let changed = item.migrateExtraFields();
+ if (!changed) continue;
+ // Don't mark the item as changed if it's not already so that every client doesn't try
+ // to upload new data. While in theory the changes should be the same and automatically
+ // merged, it's risky and unnecessary, since server data will also be updated on schema
+ // changes. (It would also create a huge amount of write traffic.)
+ if (item.synced) {
+ item.synced = true;
+ }
+ await item.saveTx({
+ skipDateModifiedUpdate: true,
+ skipSelect: true
+ });
+ }
+
+ await Zotero.DB.queryAsync(
+ "DELETE FROM settings WHERE setting='globalSchema' AND key='migrateExtra'"
+ );
+ };
// https://www.zotero.org/support/nsf
@@ -331,15 +700,15 @@ Zotero.Schema = new function(){
switch (fields[i][0]) {
case 'name':
- var baseFieldID = 110; // title
+ var baseFieldID = Zotero.ItemFields.getID('title');
break;
case 'dateSent':
- var baseFieldID = 14; // date
+ var baseFieldID = Zotero.ItemFields.getID('date');
break;
case 'homepage':
- var baseFieldID = 1; // URL
+ var baseFieldID = Zotero.ItemFields.getID('url');
break;
default:
@@ -411,6 +780,7 @@ Zotero.Schema = new function(){
yield _updateCustomTables();
yield Zotero.ItemTypes.init();
yield Zotero.ItemFields.init();
+ yield Zotero.CreatorTypes.init();
yield Zotero.SearchConditions.init();
// Update item type menus in every open window
@@ -425,58 +795,40 @@ Zotero.Schema = new function(){
});
- var _updateCustomTables = Zotero.Promise.coroutine(function* (skipDelete, skipSystem) {
+ var _updateCustomTables = async function () {
Zotero.debug("Updating custom tables");
Zotero.DB.requireTransaction();
- if (!skipDelete) {
- yield Zotero.DB.queryAsync("DELETE FROM itemTypesCombined");
- yield Zotero.DB.queryAsync("DELETE FROM fieldsCombined WHERE fieldID NOT IN (SELECT fieldID FROM itemData)");
- yield Zotero.DB.queryAsync("DELETE FROM itemTypeFieldsCombined");
- yield Zotero.DB.queryAsync("DELETE FROM baseFieldMappingsCombined");
- }
+ await Zotero.DB.queryAsync("DELETE FROM itemTypesCombined");
+ await Zotero.DB.queryAsync("DELETE FROM fieldsCombined WHERE fieldID NOT IN (SELECT fieldID FROM itemData)");
+ await Zotero.DB.queryAsync("DELETE FROM itemTypeFieldsCombined");
+ await Zotero.DB.queryAsync("DELETE FROM baseFieldMappingsCombined");
var offset = Zotero.ItemTypes.customIDOffset;
- yield Zotero.DB.queryAsync(
+ await Zotero.DB.queryAsync(
"INSERT INTO itemTypesCombined "
- + (
- skipSystem
- ? ""
- : "SELECT itemTypeID, typeName, display, 0 AS custom FROM itemTypes UNION "
- )
+ + "SELECT itemTypeID, typeName, display, 0 AS custom FROM itemTypes UNION "
+ "SELECT customItemTypeID + " + offset + " AS itemTypeID, typeName, display, 1 AS custom FROM customItemTypes"
);
- yield Zotero.DB.queryAsync(
+ await Zotero.DB.queryAsync(
"INSERT OR IGNORE INTO fieldsCombined "
- + (
- skipSystem
- ? ""
- : "SELECT fieldID, fieldName, NULL AS label, fieldFormatID, 0 AS custom FROM fields UNION "
- )
+ + "SELECT fieldID, fieldName, NULL AS label, fieldFormatID, 0 AS custom FROM fields UNION "
+ "SELECT customFieldID + " + offset + " AS fieldID, fieldName, label, NULL, 1 AS custom FROM customFields"
);
- yield Zotero.DB.queryAsync(
+ await Zotero.DB.queryAsync(
"INSERT INTO itemTypeFieldsCombined "
- + (
- skipSystem
- ? ""
- : "SELECT itemTypeID, fieldID, hide, orderIndex FROM itemTypeFields UNION "
- )
+ + "SELECT itemTypeID, fieldID, hide, orderIndex FROM itemTypeFields UNION "
+ "SELECT customItemTypeID + " + offset + " AS itemTypeID, "
+ "COALESCE(fieldID, customFieldID + " + offset + ") AS fieldID, hide, orderIndex FROM customItemTypeFields"
);
- yield Zotero.DB.queryAsync(
+ await Zotero.DB.queryAsync(
"INSERT INTO baseFieldMappingsCombined "
- + (
- skipSystem
- ? ""
- : "SELECT itemTypeID, baseFieldID, fieldID FROM baseFieldMappings UNION "
- )
+ + "SELECT itemTypeID, baseFieldID, fieldID FROM baseFieldMappings UNION "
+ "SELECT customItemTypeID + " + offset + " AS itemTypeID, baseFieldID, "
+ "customFieldID + " + offset + " AS fieldID FROM customBaseFieldMappings"
);
- });
+ };
/**
@@ -1331,6 +1683,13 @@ Zotero.Schema = new function(){
}
}
+ var attachmentID = parseInt(yield Zotero.DB.valueQueryAsync(
+ "SELECT itemTypeID FROM itemTypes WHERE typeName='attachment'"
+ ));
+ var noteID = parseInt(yield Zotero.DB.valueQueryAsync(
+ "SELECT itemTypeID FROM itemTypes WHERE typeName='note'"
+ ));
+
// Non-foreign key checks
//
@@ -1344,29 +1703,29 @@ Zotero.Schema = new function(){
"SELECT COUNT(*) > 0 FROM items WHERE itemTypeID IS NULL",
"DELETE FROM items WHERE itemTypeID IS NULL",
],
- // Attachments row with itemTypeID != 14
+ // Non-attachment items in attachments table
[
- "SELECT COUNT(*) > 0 FROM itemAttachments JOIN items USING (itemID) WHERE itemTypeID != 14",
- "UPDATE items SET itemTypeID=14, clientDateModified=CURRENT_TIMESTAMP WHERE itemTypeID != 14 AND itemID IN (SELECT itemID FROM itemAttachments)",
+ `SELECT COUNT(*) > 0 FROM itemAttachments JOIN items USING (itemID) WHERE itemTypeID != ${attachmentID}`,
+ `UPDATE items SET itemTypeID=${attachmentID}, clientDateModified=CURRENT_TIMESTAMP WHERE itemTypeID != ${attachmentID} AND itemID IN (SELECT itemID FROM itemAttachments)`,
],
// Fields not in type
[
"SELECT COUNT(*) > 0 FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM itemTypeFieldsCombined WHERE itemTypeID=(SELECT itemTypeID FROM items WHERE itemID=itemData.itemID))",
"DELETE FROM itemData WHERE fieldID NOT IN (SELECT fieldID FROM itemTypeFieldsCombined WHERE itemTypeID=(SELECT itemTypeID FROM items WHERE itemID=itemData.itemID))",
],
- // Missing itemAttachments row
+ // Missing itemAttachments rows
[
- "SELECT COUNT(*) > 0 FROM items WHERE itemTypeID=14 AND itemID NOT IN (SELECT itemID FROM itemAttachments)",
- "INSERT INTO itemAttachments (itemID, linkMode) SELECT itemID, 0 FROM items WHERE itemTypeID=14 AND itemID NOT IN (SELECT itemID FROM itemAttachments)",
+ `SELECT COUNT(*) > 0 FROM items WHERE itemTypeID=${attachmentID} AND itemID NOT IN (SELECT itemID FROM itemAttachments)`,
+ `INSERT INTO itemAttachments (itemID, linkMode) SELECT itemID, 0 FROM items WHERE itemTypeID=${attachmentID} AND itemID NOT IN (SELECT itemID FROM itemAttachments)`,
],
// Note/child parents
[
- "SELECT COUNT(*) > 0 FROM itemAttachments WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
- "UPDATE itemAttachments SET parentItemID=NULL WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
+ `SELECT COUNT(*) > 0 FROM itemAttachments WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (${noteID}, ${attachmentID}))`,
+ `UPDATE itemAttachments SET parentItemID=NULL WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (${noteID}, ${attachmentID}))`,
],
[
- "SELECT COUNT(*) > 0 FROM itemNotes WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
- "UPDATE itemNotes SET parentItemID=NULL WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (1,14))",
+ `SELECT COUNT(*) > 0 FROM itemNotes WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (${noteID}, ${attachmentID}))`,
+ `UPDATE itemNotes SET parentItemID=NULL WHERE parentItemID IN (SELECT itemID FROM items WHERE itemTypeID IN (${noteID}, ${attachmentID}))`,
],
// Delete empty creators
@@ -1378,13 +1737,13 @@ Zotero.Schema = new function(){
// Non-attachment items in the full-text index
[
- "SELECT COUNT(*) > 0 FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=14)",
- "DELETE FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=14)"
+ `SELECT COUNT(*) > 0 FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=${attachmentID})`,
+ `DELETE FROM fulltextItemWords WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=${attachmentID})`
],
// Full-text items must be attachments
[
- "SELECT COUNT(*) > 0 FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=14)",
- "DELETE FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=14)"
+ `SELECT COUNT(*) > 0 FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=${attachmentID})`,
+ `DELETE FROM fulltextItems WHERE itemID NOT IN (SELECT itemID FROM items WHERE itemTypeID=${attachmentID})`
],
// Invalid link mode -- set to imported url
[
@@ -1528,8 +1887,8 @@ Zotero.Schema = new function(){
/*
* Create new DB schema
*/
- function _initializeSchema(){
- return Zotero.DB.executeTransaction(function* (conn) {
+ async function _initializeSchema() {
+ await Zotero.DB.executeTransaction(function* (conn) {
var userLibraryID = 1;
// Enable auto-vacuuming
@@ -1546,7 +1905,9 @@ Zotero.Schema = new function(){
yield _getSchemaSQL('triggers').then(function (sql) {
return Zotero.DB.executeSQLFile(sql);
});
- yield _updateCustomTables(true);
+
+ var schema = yield _readGlobalSchemaFromFile();
+ yield _updateGlobalSchema(schema);
yield _getSchemaSQLVersion('system').then(function (version) {
return _updateDBVersion('system', version);
@@ -2523,6 +2884,21 @@ Zotero.Schema = new function(){
yield Zotero.DB.queryAsync("ALTER TABLE retractedItems ADD COLUMN flag INT DEFAULT 0");
}
+ else if (i == 106) {
+ yield _updateCompatibility(6);
+
+ yield Zotero.DB.queryAsync("DROP TRIGGER insert_date_field");
+ yield Zotero.DB.queryAsync("DROP TRIGGER update_date_field");
+ yield Zotero.DB.queryAsync("DROP TRIGGER fki_itemAttachments");
+ yield Zotero.DB.queryAsync("DROP TRIGGER fku_itemAttachments");
+ yield Zotero.DB.queryAsync("DROP TRIGGER fki_itemNotes");
+ yield Zotero.DB.queryAsync("DROP TRIGGER fku_itemNotes");
+
+ yield Zotero.DB.queryAsync("DROP TABLE transactionSets");
+ yield Zotero.DB.queryAsync("DROP TABLE transactions");
+ yield Zotero.DB.queryAsync("DROP TABLE transactionLog");
+ }
+
// If breaking compatibility or doing anything dangerous, clear minorUpdateFrom
}
diff --git a/chrome/content/zotero/xpcom/sync/syncEngine.js b/chrome/content/zotero/xpcom/sync/syncEngine.js
index a0d4801774..2c8ab88ef5 100644
--- a/chrome/content/zotero/xpcom/sync/syncEngine.js
+++ b/chrome/content/zotero/xpcom/sync/syncEngine.js
@@ -1244,7 +1244,7 @@ Zotero.Sync.Data.Engine.prototype._uploadObjects = Zotero.Promise.coroutine(func
// Update local object with saved data if necessary, as long as it hasn't
// changed locally since the upload
if (!changed) {
- obj.fromJSON(current.data);
+ obj.fromJSON(current.data, { strict: true });
toSave.push(obj);
}
else {
diff --git a/chrome/content/zotero/xpcom/sync/syncLocal.js b/chrome/content/zotero/xpcom/sync/syncLocal.js
index ab08ce7c6e..d63e733fc9 100644
--- a/chrome/content/zotero/xpcom/sync/syncLocal.js
+++ b/chrome/content/zotero/xpcom/sync/syncLocal.js
@@ -721,11 +721,10 @@ Zotero.Sync.Data.Local = {
var ObjectType = Zotero.Utilities.capitalize(objectType);
var libraryName = Zotero.Libraries.get(libraryID).name;
- var knownErrors = [
- 'ZoteroUnknownTypeError',
- 'ZoteroUnknownFieldError',
+ var knownErrors = new Set([
+ 'ZoteroInvalidDataError',
'ZoteroMissingObjectError'
- ];
+ ]);
Zotero.debug("Processing " + json.length + " downloaded "
+ (json.length == 1 ? objectType : objectTypePlural)
@@ -1027,8 +1026,11 @@ Zotero.Sync.Data.Local = {
}
}
catch (e) {
+ // This allows errors handled by syncRunner to know the library in question
+ e.libraryID = libraryID;
+
// Display nicer debug line for known errors
- if (knownErrors.indexOf(e.name) != -1) {
+ if (knownErrors.has(e.name)) {
let desc = e.name
.replace(/^Zotero/, "")
// Convert "MissingObjectError" to "missing object error"
@@ -1407,7 +1409,7 @@ Zotero.Sync.Data.Local = {
json = this._checkCacheJSON(json);
if (!options.skipData) {
- obj.fromJSON(json.data);
+ obj.fromJSON(json.data, { strict: true });
}
if (obj.objectType == 'item' && obj.isImportedAttachment()) {
yield this._checkAttachmentForDownload(obj, json.data.mtime, options.isNewObject);
diff --git a/chrome/content/zotero/xpcom/sync/syncRunner.js b/chrome/content/zotero/xpcom/sync/syncRunner.js
index 4dd71064bc..b27a380431 100644
--- a/chrome/content/zotero/xpcom/sync/syncRunner.js
+++ b/chrome/content/zotero/xpcom/sync/syncRunner.js
@@ -1252,6 +1252,23 @@ Zotero.Sync.Runner_Module = function (options = {}) {
}
}
}
+ // Show warning for unknown data that couldn't be saved
+ else if (e.name && e.name == 'ZoteroInvalidDataError') {
+ e.message = Zotero.getString(
+ 'sync.error.invalidDataError',
+ [
+ Zotero.Libraries.get(e.libraryID).name,
+ Zotero.clientName
+ ]
+ )
+ + "\n\n"
+ + Zotero.getString('sync.error.invalidDataError.otherData');
+ e.errorType = 'warning';
+ e.dialogButtonText = Zotero.getString('general.checkForUpdates');
+ e.dialogButtonCallback = () => {
+ Zotero.openCheckForUpdatesWindow();
+ };
+ }
});
diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js
index 29a58fd813..39d6dbafca 100644
--- a/chrome/content/zotero/xpcom/utilities.js
+++ b/chrome/content/zotero/xpcom/utilities.js
@@ -26,121 +26,6 @@
***** END LICENSE BLOCK *****
*/
-/*
- * Mappings for names
- * Note that this is the reverse of the text variable map, since all mappings should be one to one
- * and it makes the code cleaner
- */
-var CSL_NAMES_MAPPINGS = {
- "author":"author",
- "editor":"editor",
- "bookAuthor":"container-author",
- "composer":"composer",
- "director":"director",
- "interviewer":"interviewer",
- "recipient":"recipient",
- "reviewedAuthor":"reviewed-author",
- "seriesEditor":"collection-editor",
- "translator":"translator"
-}
-
-/*
- * Mappings for text variables
- */
-var CSL_TEXT_MAPPINGS = {
- "title":["title"],
- "container-title":["publicationTitle", "reporter", "code"], /* reporter and code should move to SQL mapping tables */
- "collection-title":["seriesTitle", "series"],
- "collection-number":["seriesNumber"],
- "publisher":["publisher", "distributor"], /* distributor should move to SQL mapping tables */
- "publisher-place":["place"],
- "authority":["court","legislativeBody", "issuingAuthority"],
- "page":["pages"],
- "volume":["volume", "codeNumber"],
- "issue":["issue", "priorityNumbers"],
- "number-of-volumes":["numberOfVolumes"],
- "number-of-pages":["numPages"],
- "edition":["edition"],
- "version":["versionNumber"],
- "section":["section", "committee"],
- "genre":["type", "programmingLanguage"],
- "source":["libraryCatalog"],
- "dimensions": ["artworkSize", "runningTime"],
- "medium":["medium", "system"],
- "scale":["scale"],
- "archive":["archive"],
- "archive_location":["archiveLocation"],
- "event":["meetingName", "conferenceName"], /* these should be mapped to the same base field in SQL mapping tables */
- "event-place":["place"],
- "abstract":["abstractNote"],
- "URL":["url"],
- "DOI":["DOI"],
- "ISBN":["ISBN"],
- "ISSN":["ISSN"],
- "call-number":["callNumber", "applicationNumber"],
- "note":["extra"],
- "number":["number"],
- "chapter-number":["session"],
- "references":["history", "references"],
- "shortTitle":["shortTitle"], /* preserved to read legacy data */
- "title-short":["shortTitle"],
- "journalAbbreviation":["journalAbbreviation"],
- "status":["legalStatus"],
- "language":["language"]
-}
-
-/*
- * Mappings for dates
- */
-var CSL_DATE_MAPPINGS = {
- "issued":"date",
- "accessed":"accessDate",
- "submitted":"filingDate"
-}
-
-/*
- * Mappings for types
- * Also see itemFromCSLJSON
- */
-var CSL_TYPE_MAPPINGS = {
- 'book':"book",
- 'bookSection':'chapter',
- 'journalArticle':"article-journal",
- 'magazineArticle':"article-magazine",
- 'newspaperArticle':"article-newspaper",
- 'thesis':"thesis",
- 'encyclopediaArticle':"entry-encyclopedia",
- 'dictionaryEntry':"entry-dictionary",
- 'conferencePaper':"paper-conference",
- 'letter':"personal_communication",
- 'manuscript':"manuscript",
- 'interview':"interview",
- 'film':"motion_picture",
- 'artwork':"graphic",
- 'webpage':"webpage",
- 'report':"report",
- 'bill':"bill",
- 'case':"legal_case",
- 'hearing':"bill", // ??
- 'patent':"patent",
- 'statute':"legislation", // ??
- 'email':"personal_communication",
- 'map':"map",
- 'blogPost':"post-weblog",
- 'instantMessage':"personal_communication",
- 'forumPost':"post",
- 'audioRecording':"song", // ??
- 'presentation':"speech",
- 'videoRecording':"motion_picture",
- 'tvBroadcast':"broadcast",
- 'radioBroadcast':"broadcast",
- 'podcast':"broadcast",
- 'computerProgram':"book", // ??
- 'document':"article",
- 'note':"article",
- 'attachment':"article"
-};
-
/**
* @class Functions for text manipulation and other miscellaneous purposes
*/
@@ -1576,7 +1461,7 @@ Zotero.Utilities = {
);
}
- var cslType = CSL_TYPE_MAPPINGS[zoteroItem.itemType];
+ var cslType = Zotero.Schema.CSL_TYPE_MAPPINGS[zoteroItem.itemType];
if (!cslType) {
throw new Error('Unexpected Zotero Item type "' + zoteroItem.itemType + '"');
}
@@ -1589,9 +1474,9 @@ Zotero.Utilities = {
};
// get all text variables (there must be a better way)
- for(var variable in CSL_TEXT_MAPPINGS) {
+ for(var variable in Zotero.Schema.CSL_TEXT_MAPPINGS) {
if (variable === "shortTitle") continue; // read both title-short and shortTitle, but write only title-short
- var fields = CSL_TEXT_MAPPINGS[variable];
+ var fields = Zotero.Schema.CSL_TEXT_MAPPINGS[variable];
for(var i=0, n=fields.length; i [this._normalizeExtraKey(x.name), x.name]));
+ // CSL types
+ for (let i in Zotero.Schema.CSL_TYPE_MAPPINGS) {
+ let cslType = Zotero.Schema.CSL_TYPE_MAPPINGS[i];
+ itemTypes.set(cslType.toLowerCase(), i);
+ }
+
+ // For fields we use arrays, because there can be multiple possibilities
//
// Built-in fields
- var fieldNames = new Map(Zotero.ItemFields.getAll().map(x => [x.name.toLowerCase(), [x.name]]));
+ var fieldNames = new Map(Zotero.ItemFields.getAll().map(x => [this._normalizeExtraKey(x.name), [x.name]]));
// CSL fields
- for (let map of [CSL_TEXT_MAPPINGS, CSL_DATE_MAPPINGS]) {
+ for (let map of [Zotero.Schema.CSL_TEXT_MAPPINGS, Zotero.Schema.CSL_DATE_MAPPINGS]) {
for (let cslVar in map) {
- let normalized = cslVar.toLowerCase();
+ let normalized = this._normalizeExtraKey(cslVar);
let existing = fieldNames.get(normalized) || [];
fieldNames.set(normalized, new Set([...existing, ...map[cslVar]]));
}
}
- var lines = str.split(/\n+/g);
- var fields = new Map();
+ // Built-in creator types
+ var creatorTypes = new Map(Zotero.CreatorTypes.getAll().map(x => [this._normalizeExtraKey(x.name), x.name]));
+ // CSL types
+ for (let i in Zotero.Schema.CSL_NAME_MAPPINGS) {
+ let cslType = Zotero.Schema.CSL_NAME_MAPPINGS[i];
+ creatorTypes.set(cslType.toLowerCase(), i);
+ }
+
+ // Process Extra lines
+ var keepLines = [];
+ var skipKeys = new Set();
+ var lines = extra.split(/\n/g);
for (let line of lines) {
- let parts = line.match(/^([a-z \-]+):(.+)/i);
+ let parts = line.match(/^([a-z -_]+):(.+)/i);
+ // Old citeproc.js cheater syntax;
if (!parts) {
+ parts = line.match(/^{:([a-z -_]+):(.+)}/i);
+ }
+ if (!parts) {
+ keepLines.push(line);
continue;
}
let [_, originalField, value] = parts;
- let field = originalField.trim().toLowerCase()
- // Strip spaces
- .replace(/\s+/g, '')
- // Old citeproc.js cheater syntax
- .replace(/{:([^:]+):([^}]+)}/);
- value = value.trim();
- let possibleFields = fieldNames.get(field);
- // No valid fields
- if (!possibleFields) {
+ let key = this._normalizeExtraKey(originalField);
+ if (skipKeys.has(key)) {
+ keepLines.push(line);
continue;
}
- // Create an entry for each possible field, since we don't know what type this is for
- for (let possibleField of possibleFields) {
- fields.set(
- possibleField,
- {
- originalField,
- field: possibleField,
- value
+ value = value.trim();
+
+ if (key == 'type') {
+ let possibleType = itemTypes.get(value);
+ if (possibleType) {
+ // Ignore item type that's the same as the item
+ if (!item || possibleType != Zotero.ItemTypes.getName(itemTypeID)) {
+ itemType = possibleType;
+ skipKeys.add(key);
+ continue;
}
- );
+ }
+ }
+
+ // Fields
+ let possibleFields = fieldNames.get(key);
+ // No valid fields
+ if (possibleFields) {
+ let added = false;
+ for (let possibleField of possibleFields) {
+ // If we have an item, skip fields that aren't valid for the type or that already
+ // have values
+ if (item) {
+ let fieldID = Zotero.ItemFields.getID(possibleField);
+ if (!Zotero.ItemFields.isValidForType(fieldID, itemTypeID)
+ || item.getField(fieldID)
+ || additionalFields.has(possibleField)) {
+ continue;
+ }
+ }
+ fields.set(possibleField, value);
+ added = true;
+ // If we found a valid field, don't try the other possibilities for that
+ // normalized key
+ if (item) {
+ break;
+ }
+ }
+ if (added) {
+ skipKeys.add(key);
+ continue;
+ }
+ }
+
+ let possibleCreatorType = creatorTypes.get(key);
+ if (possibleCreatorType) {
+ let c = {
+ creatorType: possibleCreatorType
+ };
+ if (value.includes('||')) {
+ let [first, last] = value.split(/\s*\|\|\s*/);
+ c.firstName = first;
+ c.lastName = last;
+ }
+ else {
+ c.name = value;
+ }
+ if (item) {
+ let creatorTypeID = Zotero.CreatorTypes.getID(possibleCreatorType);
+ if (Zotero.CreatorTypes.isValidForItemType(creatorTypeID, itemTypeID)
+ // Ignore if there are any creators of this type on the item already,
+ // to follow citeproc-js behavior
+ && !item.getCreators().some(x => x.creatorType == possibleCreatorType)) {
+ creators.push(c);
+ continue;
+ }
+ }
+ else {
+ creators.push(c);
+ continue;
+ }
+ }
+
+ // We didn't find anything, so keep the line in Extra
+ keepLines.push(line);
+ }
+
+ return {
+ itemType,
+ fields,
+ creators,
+ extra: keepLines.join('\n')
+ };
+ },
+
+
+ /**
+ * @param {String} extra
+ * @param {Map} fieldMap
+ * @return {String}
+ */
+ combineExtraFields: function (extra, fields) {
+ var normalizedKeyMap = new Map();
+ var normalizedFields = new Map();
+ for (let [key, value] of fields) {
+ let normalizedKey = this._normalizeExtraKey(key);
+ normalizedFields.set(normalizedKey, value);
+ normalizedKeyMap.set(normalizedKey, key);
+ }
+ var keepLines = [];
+ var lines = extra !== '' ? extra.split(/\n/g) : [];
+ for (let line of lines) {
+ let parts = line.match(/^([a-z -_]+):(.+)/i);
+ // Old citeproc.js cheater syntax;
+ if (!parts) {
+ parts = line.match(/^{:([a-z -_]+):(.+)}/i);
+ }
+ if (!parts) {
+ keepLines.push(line);
+ continue;
+ }
+ let [_, originalField, value] = parts;
+
+ let key = this._normalizeExtraKey(originalField);
+
+ // If we have a new value for the field, update it
+ if (normalizedFields.has(key)) {
+ keepLines.push(originalField + ": " + normalizedFields.get(key));
+ // Don't include with the other fields
+ fields.delete(normalizedKeyMap.get(key));
+ }
+ else {
+ keepLines.push(line);
}
}
- return fields;
+ var fieldPairs = Array.from(fields.entries())
+ .map(x => x[0] + ': ' + x[1]);
+ fieldPairs.sort();
+ return fieldPairs.join('\n')
+ + ((fieldPairs.length && keepLines.length) ? "\n" : "")
+ + keepLines.join("\n");
+ },
+
+
+ _normalizeExtraKey: function (key) {
+ return key
+ .trim()
+ // Convert fooBar to foo-bar
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
+ .toLowerCase()
+ // Normalize to hyphens for spaces
+ .replace(/[\s-_]/g, '-');
},
diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js
index 440620db28..92b5a9444a 100644
--- a/chrome/content/zotero/xpcom/zotero.js
+++ b/chrome/content/zotero/xpcom/zotero.js
@@ -711,6 +711,7 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
yield Zotero.Users.init();
yield Zotero.Libraries.init();
+ yield Zotero.ID.init();
yield Zotero.ItemTypes.init();
yield Zotero.ItemFields.init();
yield Zotero.CreatorTypes.init();
@@ -747,7 +748,6 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
Zotero.Date.init();
Zotero.LocateManager.init();
- yield Zotero.ID.init();
yield Zotero.Collections.init();
yield Zotero.Items.init();
yield Zotero.Searches.init();
@@ -757,6 +757,12 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
yield Zotero.Relations.init();
yield Zotero.Retractions.init();
+ // Migrate fields from Extra that can be moved to item fields after a schema update
+ //
+ // Disabled for now
+ //
+ //yield Zotero.Schema.migrateExtraFields();
+
// Load all library data except for items, which are loaded when libraries are first
// clicked on or if otherwise necessary
yield Zotero.Promise.each(
@@ -769,7 +775,6 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js");
}
})()
);
-
Zotero.Items.startEmptyTrashTimer();
diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties
index 6a74bb11a5..3722fe154d 100644
--- a/chrome/locale/en-US/zotero/zotero.properties
+++ b/chrome/locale/en-US/zotero/zotero.properties
@@ -965,6 +965,8 @@ sync.error.creatorTooLong = The creator name “%S” in one of your i
sync.error.noteEmbeddedImage = Notes with embedded images cannot currently be synced. Syncing of embedded images may be supported in a future version.
sync.error.noteTooLong = The note “%S” is too long to sync. Shorten the note and sync again.
sync.error.reportSiteIssuesToForums = If you receive this message repeatedly for items saved from a particular site, you can report this issue in the %S Forums.
+sync.error.invalidDataError = Some data in %S could not be downloaded. It may have been saved with a newer version of %S.
+sync.error.invalidDataError.otherData = Other data will continue to sync.
account.unlinkWarning = Unlinking your account will prevent %S from syncing your data.
account.unlinkWarning.removeData = Remove my %S data from this computer
diff --git a/resource/pako.js b/resource/pako.js
new file mode 120000
index 0000000000..2de85beb19
--- /dev/null
+++ b/resource/pako.js
@@ -0,0 +1 @@
+../node_modules/pako/dist/pako.min.js
\ No newline at end of file
diff --git a/resource/schema/global b/resource/schema/global
new file mode 160000
index 0000000000..d6d3718e19
--- /dev/null
+++ b/resource/schema/global
@@ -0,0 +1 @@
+Subproject commit d6d3718e19d14dd17d9d0e14f7a09b416bd4b1fb
diff --git a/resource/schema/system.sql b/resource/schema/system.sql
index eaad2b52f7..d31ecc2399 100644
--- a/resource/schema/system.sql
+++ b/resource/schema/system.sql
@@ -172,971 +172,11 @@ CREATE TABLE syncObjectTypes (
);
CREATE INDEX syncObjectTypes_name ON syncObjectTypes(name);
-DROP TABLE IF EXISTS transactionSets;
-CREATE TABLE transactionSets (
- transactionSetID INTEGER PRIMARY KEY,
- event TEXT,
- id INT
-);
-
-DROP TABLE IF EXISTS transactions;
-CREATE TABLE transactions (
- transactionID INTEGER PRIMARY KEY,
- transactionSetID INT,
- context TEXT,
- action TEXT
-);
-CREATE INDEX transactions_transactionSetID ON transactions(transactionSetID);
-
-DROP TABLE IF EXISTS transactionLog;
-CREATE TABLE transactionLog (
- transactionID INT,
- field TEXT,
- value NONE,
- PRIMARY KEY (transactionID, field, value),
- FOREIGN KEY (transactionID) REFERENCES transactions(transactionID)
-);
-
-- unused
INSERT INTO "fieldFormats" VALUES(1, '.*', 0);
INSERT INTO "fieldFormats" VALUES(2, '[0-9]*', 1);
INSERT INTO "fieldFormats" VALUES(3, '[0-9]{4}', 1);
-INSERT INTO itemTypes VALUES (1,'note',NULL,0);
-INSERT INTO itemTypes VALUES (2,'book',NULL,2);
-INSERT INTO itemTypes VALUES (3,'bookSection',2,2);
-INSERT INTO itemTypes VALUES (4,'journalArticle',NULL,2);
-INSERT INTO itemTypes VALUES (5,'magazineArticle',NULL,2);
-INSERT INTO itemTypes VALUES (6,'newspaperArticle',NULL,2);
-INSERT INTO itemTypes VALUES (7,'thesis',NULL,1);
-INSERT INTO itemTypes VALUES (8,'letter',NULL,1);
-INSERT INTO itemTypes VALUES (9,'manuscript',NULL,1);
-INSERT INTO itemTypes VALUES (10,'interview',NULL,1);
-INSERT INTO itemTypes VALUES (11,'film',NULL,1);
-INSERT INTO itemTypes VALUES (12,'artwork',NULL,1);
-INSERT INTO itemTypes VALUES (13,'webpage',NULL,0);
-INSERT INTO itemTypes VALUES (14,'attachment',NULL,0);
-INSERT INTO itemTypes VALUES (15,'report',NULL,1);
-INSERT INTO itemTypes VALUES (16,'bill',NULL,1);
-INSERT INTO itemTypes VALUES (17,'case',NULL,1);
-INSERT INTO itemTypes VALUES (18,'hearing',NULL,1);
-INSERT INTO itemTypes VALUES (19,'patent',NULL,1);
-INSERT INTO itemTypes VALUES (20,'statute',NULL,1);
-INSERT INTO itemTypes VALUES (21,'email',NULL,1);
-INSERT INTO itemTypes VALUES (22,'map',NULL,1);
-INSERT INTO itemTypes VALUES (23,'blogPost',NULL,1);
-INSERT INTO itemTypes VALUES (24,'instantMessage',NULL,1);
-INSERT INTO itemTypes VALUES (25,'forumPost',NULL,1);
-INSERT INTO itemTypes VALUES (26,'audioRecording',NULL,1);
-INSERT INTO itemTypes VALUES (27,'presentation',NULL,1);
-INSERT INTO itemTypes VALUES (28,'videoRecording',NULL,1);
-INSERT INTO itemTypes VALUES (29,'tvBroadcast',NULL,1);
-INSERT INTO itemTypes VALUES (30,'radioBroadcast',NULL,1);
-INSERT INTO itemTypes VALUES (31,'podcast',NULL,1);
-INSERT INTO itemTypes VALUES (32,'computerProgram',NULL,1);
-INSERT INTO itemTypes VALUES (33,'conferencePaper',NULL,1);
-INSERT INTO itemTypes VALUES (34,'document',NULL,2);
-INSERT INTO itemTypes VALUES (35,'encyclopediaArticle',NULL,1);
-INSERT INTO itemTypes VALUES (36,'dictionaryEntry',NULL,1);
-
-INSERT INTO fields VALUES (1,'url',NULL);
-INSERT INTO fields VALUES (2,'rights',NULL);
-INSERT INTO fields VALUES (3,'series',NULL);
-INSERT INTO fields VALUES (4,'volume',NULL);
-INSERT INTO fields VALUES (5,'issue',NULL);
-INSERT INTO fields VALUES (6,'edition',NULL);
-INSERT INTO fields VALUES (7,'place',NULL);
-INSERT INTO fields VALUES (8,'publisher',NULL);
-INSERT INTO fields VALUES (10,'pages',NULL);
-INSERT INTO fields VALUES (11,'ISBN',NULL);
-INSERT INTO fields VALUES (12,'publicationTitle',NULL);
-INSERT INTO fields VALUES (13,'ISSN',NULL);
-INSERT INTO fields VALUES (14,'date',NULL);
-INSERT INTO fields VALUES (15,'section',NULL);
-INSERT INTO fields VALUES (18,'callNumber',NULL);
-INSERT INTO fields VALUES (19,'archiveLocation',NULL);
-INSERT INTO fields VALUES (21,'distributor',NULL);
-INSERT INTO fields VALUES (22,'extra',NULL);
-INSERT INTO fields VALUES (25,'journalAbbreviation',NULL);
-INSERT INTO fields VALUES (26,'DOI',NULL);
-INSERT INTO fields VALUES (27,'accessDate',NULL);
-INSERT INTO fields VALUES (28,'seriesTitle',NULL);
-INSERT INTO fields VALUES (29,'seriesText',NULL);
-INSERT INTO fields VALUES (30,'seriesNumber',NULL);
-INSERT INTO fields VALUES (31,'institution',NULL);
-INSERT INTO fields VALUES (32,'reportType',NULL);
-INSERT INTO fields VALUES (36,'code',NULL);
-INSERT INTO fields VALUES (40,'session',NULL);
-INSERT INTO fields VALUES (41,'legislativeBody',NULL);
-INSERT INTO fields VALUES (42,'history',NULL);
-INSERT INTO fields VALUES (43,'reporter',NULL);
-INSERT INTO fields VALUES (44,'court',NULL);
-INSERT INTO fields VALUES (45,'numberOfVolumes',NULL);
-INSERT INTO fields VALUES (46,'committee',NULL);
-INSERT INTO fields VALUES (48,'assignee',NULL);
-INSERT INTO fields VALUES (50,'patentNumber',NULL);
-INSERT INTO fields VALUES (51,'priorityNumbers',NULL);
-INSERT INTO fields VALUES (52,'issueDate',NULL);
-INSERT INTO fields VALUES (53,'references',NULL);
-INSERT INTO fields VALUES (54,'legalStatus',NULL);
-INSERT INTO fields VALUES (55,'codeNumber',NULL);
-INSERT INTO fields VALUES (59,'artworkMedium',NULL);
-INSERT INTO fields VALUES (60,'number',NULL);
-INSERT INTO fields VALUES (61,'artworkSize',NULL);
-INSERT INTO fields VALUES (62,'libraryCatalog',NULL);
-INSERT INTO fields VALUES (63,'videoRecordingFormat',NULL);
-INSERT INTO fields VALUES (64,'interviewMedium',NULL);
-INSERT INTO fields VALUES (65,'letterType',NULL);
-INSERT INTO fields VALUES (66,'manuscriptType',NULL);
-INSERT INTO fields VALUES (67,'mapType',NULL);
-INSERT INTO fields VALUES (68,'scale',NULL);
-INSERT INTO fields VALUES (69,'thesisType',NULL);
-INSERT INTO fields VALUES (70,'websiteType',NULL);
-INSERT INTO fields VALUES (71,'audioRecordingFormat',NULL);
-INSERT INTO fields VALUES (72,'label',NULL);
-INSERT INTO fields VALUES (74,'presentationType',NULL);
-INSERT INTO fields VALUES (75,'meetingName',NULL);
-INSERT INTO fields VALUES (76,'studio',NULL);
-INSERT INTO fields VALUES (77,'runningTime',NULL);
-INSERT INTO fields VALUES (78,'network',NULL);
-INSERT INTO fields VALUES (79,'postType',NULL);
-INSERT INTO fields VALUES (80,'audioFileType',NULL);
-INSERT INTO fields VALUES (81,'versionNumber',NULL);
-INSERT INTO fields VALUES (82,'system',NULL);
-INSERT INTO fields VALUES (83,'company',NULL);
-INSERT INTO fields VALUES (84,'conferenceName',NULL);
-INSERT INTO fields VALUES (85,'encyclopediaTitle',NULL);
-INSERT INTO fields VALUES (86,'dictionaryTitle',NULL);
-INSERT INTO fields VALUES (87,'language',NULL);
-INSERT INTO fields VALUES (88,'programmingLanguage',NULL);
-INSERT INTO fields VALUES (89,'university',NULL);
-INSERT INTO fields VALUES (90,'abstractNote',NULL);
-INSERT INTO fields VALUES (91,'websiteTitle',NULL);
-INSERT INTO fields VALUES (92,'reportNumber',NULL);
-INSERT INTO fields VALUES (93,'billNumber',NULL);
-INSERT INTO fields VALUES (94,'codeVolume',NULL);
-INSERT INTO fields VALUES (95,'codePages',NULL);
-INSERT INTO fields VALUES (96,'dateDecided',NULL);
-INSERT INTO fields VALUES (97,'reporterVolume',NULL);
-INSERT INTO fields VALUES (98,'firstPage',NULL);
-INSERT INTO fields VALUES (99,'documentNumber',NULL);
-INSERT INTO fields VALUES (100,'dateEnacted',NULL);
-INSERT INTO fields VALUES (101,'publicLawNumber',NULL);
-INSERT INTO fields VALUES (102,'country',NULL);
-INSERT INTO fields VALUES (103,'applicationNumber',NULL);
-INSERT INTO fields VALUES (104,'forumTitle',NULL);
-INSERT INTO fields VALUES (105,'episodeNumber',NULL);
-INSERT INTO fields VALUES (107,'blogTitle',NULL);
-INSERT INTO fields VALUES (108,'type',NULL);
-INSERT INTO fields VALUES (109,'medium',NULL);
-INSERT INTO fields VALUES (110,'title',NULL);
-INSERT INTO fields VALUES (111,'caseName',NULL);
-INSERT INTO fields VALUES (112,'nameOfAct',NULL);
-INSERT INTO fields VALUES (113,'subject',NULL);
-INSERT INTO fields VALUES (114,'proceedingsTitle',NULL);
-INSERT INTO fields VALUES (115,'bookTitle',NULL);
-INSERT INTO fields VALUES (116,'shortTitle',NULL);
-INSERT INTO fields VALUES (117,'docketNumber',NULL);
-INSERT INTO fields VALUES (118,'numPages',NULL);
-INSERT INTO fields VALUES (119,'programTitle',NULL);
-INSERT INTO fields VALUES (120,'issuingAuthority',NULL);
-INSERT INTO fields VALUES (121,'filingDate',NULL);
-INSERT INTO fields VALUES (122,'genre',NULL);
-INSERT INTO fields VALUES (123,'archive',NULL);
-
-INSERT INTO itemTypeFields VALUES (2, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (2, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (2, 3, NULL, 3);
-INSERT INTO itemTypeFields VALUES (2, 30, NULL, 4);
-INSERT INTO itemTypeFields VALUES (2, 4, NULL, 5);
-INSERT INTO itemTypeFields VALUES (2, 45, NULL, 6);
-INSERT INTO itemTypeFields VALUES (2, 6, NULL, 7);
-INSERT INTO itemTypeFields VALUES (2, 7, NULL, 8);
-INSERT INTO itemTypeFields VALUES (2, 8, NULL, 9);
-INSERT INTO itemTypeFields VALUES (2, 14, NULL, 10);
-INSERT INTO itemTypeFields VALUES (2, 118, NULL, 11);
-INSERT INTO itemTypeFields VALUES (2, 87, NULL, 12);
-INSERT INTO itemTypeFields VALUES (2, 11, NULL, 13);
-INSERT INTO itemTypeFields VALUES (2, 116, NULL, 14);
-INSERT INTO itemTypeFields VALUES (2, 1, NULL, 15);
-INSERT INTO itemTypeFields VALUES (2, 27, NULL, 16);
-INSERT INTO itemTypeFields VALUES (2, 123, NULL, 17);
-INSERT INTO itemTypeFields VALUES (2, 19, NULL, 18);
-INSERT INTO itemTypeFields VALUES (2, 62, NULL, 19);
-INSERT INTO itemTypeFields VALUES (2, 18, NULL, 20);
-INSERT INTO itemTypeFields VALUES (2, 2, NULL, 21);
-INSERT INTO itemTypeFields VALUES (2, 22, NULL, 22);
-INSERT INTO itemTypeFields VALUES (3, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (3, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (3, 115, NULL, 3);
-INSERT INTO itemTypeFields VALUES (3, 3, NULL, 4);
-INSERT INTO itemTypeFields VALUES (3, 30, NULL, 5);
-INSERT INTO itemTypeFields VALUES (3, 4, NULL, 6);
-INSERT INTO itemTypeFields VALUES (3, 45, NULL, 7);
-INSERT INTO itemTypeFields VALUES (3, 6, NULL, 8);
-INSERT INTO itemTypeFields VALUES (3, 7, NULL, 9);
-INSERT INTO itemTypeFields VALUES (3, 8, NULL, 10);
-INSERT INTO itemTypeFields VALUES (3, 14, NULL, 11);
-INSERT INTO itemTypeFields VALUES (3, 10, NULL, 12);
-INSERT INTO itemTypeFields VALUES (3, 87, NULL, 13);
-INSERT INTO itemTypeFields VALUES (3, 11, NULL, 14);
-INSERT INTO itemTypeFields VALUES (3, 116, NULL, 15);
-INSERT INTO itemTypeFields VALUES (3, 1, NULL, 16);
-INSERT INTO itemTypeFields VALUES (3, 27, NULL, 17);
-INSERT INTO itemTypeFields VALUES (3, 123, NULL, 18);
-INSERT INTO itemTypeFields VALUES (3, 19, NULL, 19);
-INSERT INTO itemTypeFields VALUES (3, 62, NULL, 20);
-INSERT INTO itemTypeFields VALUES (3, 18, NULL, 21);
-INSERT INTO itemTypeFields VALUES (3, 2, NULL, 22);
-INSERT INTO itemTypeFields VALUES (3, 22, NULL, 23);
-INSERT INTO itemTypeFields VALUES (4, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (4, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (4, 12, NULL, 3);
-INSERT INTO itemTypeFields VALUES (4, 4, NULL, 4);
-INSERT INTO itemTypeFields VALUES (4, 5, NULL, 5);
-INSERT INTO itemTypeFields VALUES (4, 10, NULL, 6);
-INSERT INTO itemTypeFields VALUES (4, 14, NULL, 7);
-INSERT INTO itemTypeFields VALUES (4, 3, NULL, 8);
-INSERT INTO itemTypeFields VALUES (4, 28, NULL, 9);
-INSERT INTO itemTypeFields VALUES (4, 29, NULL, 10);
-INSERT INTO itemTypeFields VALUES (4, 25, NULL, 11);
-INSERT INTO itemTypeFields VALUES (4, 87, NULL, 12);
-INSERT INTO itemTypeFields VALUES (4, 26, NULL, 13);
-INSERT INTO itemTypeFields VALUES (4, 13, NULL, 14);
-INSERT INTO itemTypeFields VALUES (4, 116, NULL, 15);
-INSERT INTO itemTypeFields VALUES (4, 1, NULL, 16);
-INSERT INTO itemTypeFields VALUES (4, 27, NULL, 17);
-INSERT INTO itemTypeFields VALUES (4, 123, NULL, 18);
-INSERT INTO itemTypeFields VALUES (4, 19, NULL, 19);
-INSERT INTO itemTypeFields VALUES (4, 62, NULL, 20);
-INSERT INTO itemTypeFields VALUES (4, 18, NULL, 21);
-INSERT INTO itemTypeFields VALUES (4, 2, NULL, 22);
-INSERT INTO itemTypeFields VALUES (4, 22, NULL, 23);
-INSERT INTO itemTypeFields VALUES (5, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (5, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (5, 12, NULL, 3);
-INSERT INTO itemTypeFields VALUES (5, 4, NULL, 4);
-INSERT INTO itemTypeFields VALUES (5, 5, NULL, 5);
-INSERT INTO itemTypeFields VALUES (5, 14, NULL, 6);
-INSERT INTO itemTypeFields VALUES (5, 10, NULL, 7);
-INSERT INTO itemTypeFields VALUES (5, 87, NULL, 8);
-INSERT INTO itemTypeFields VALUES (5, 13, NULL, 9);
-INSERT INTO itemTypeFields VALUES (5, 116, NULL, 10);
-INSERT INTO itemTypeFields VALUES (5, 1, NULL, 11);
-INSERT INTO itemTypeFields VALUES (5, 27, NULL, 12);
-INSERT INTO itemTypeFields VALUES (5, 123, NULL, 13);
-INSERT INTO itemTypeFields VALUES (5, 19, NULL, 14);
-INSERT INTO itemTypeFields VALUES (5, 62, NULL, 15);
-INSERT INTO itemTypeFields VALUES (5, 18, NULL, 16);
-INSERT INTO itemTypeFields VALUES (5, 2, NULL, 17);
-INSERT INTO itemTypeFields VALUES (5, 22, NULL, 18);
-INSERT INTO itemTypeFields VALUES (6, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (6, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (6, 12, NULL, 3);
-INSERT INTO itemTypeFields VALUES (6, 7, NULL, 4);
-INSERT INTO itemTypeFields VALUES (6, 6, NULL, 5);
-INSERT INTO itemTypeFields VALUES (6, 14, NULL, 6);
-INSERT INTO itemTypeFields VALUES (6, 15, NULL, 7);
-INSERT INTO itemTypeFields VALUES (6, 10, NULL, 8);
-INSERT INTO itemTypeFields VALUES (6, 87, NULL, 9);
-INSERT INTO itemTypeFields VALUES (6, 116, NULL, 10);
-INSERT INTO itemTypeFields VALUES (6, 13, NULL, 11);
-INSERT INTO itemTypeFields VALUES (6, 1, NULL, 12);
-INSERT INTO itemTypeFields VALUES (6, 27, NULL, 13);
-INSERT INTO itemTypeFields VALUES (6, 123, NULL, 14);
-INSERT INTO itemTypeFields VALUES (6, 19, NULL, 15);
-INSERT INTO itemTypeFields VALUES (6, 62, NULL, 16);
-INSERT INTO itemTypeFields VALUES (6, 18, NULL, 17);
-INSERT INTO itemTypeFields VALUES (6, 2, NULL, 18);
-INSERT INTO itemTypeFields VALUES (6, 22, NULL, 19);
-INSERT INTO itemTypeFields VALUES (7, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (7, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (7, 69, NULL, 3);
-INSERT INTO itemTypeFields VALUES (7, 89, NULL, 4);
-INSERT INTO itemTypeFields VALUES (7, 7, NULL, 5);
-INSERT INTO itemTypeFields VALUES (7, 14, NULL, 6);
-INSERT INTO itemTypeFields VALUES (7, 118, NULL, 7);
-INSERT INTO itemTypeFields VALUES (7, 87, NULL, 8);
-INSERT INTO itemTypeFields VALUES (7, 116, NULL, 9);
-INSERT INTO itemTypeFields VALUES (7, 1, NULL, 10);
-INSERT INTO itemTypeFields VALUES (7, 27, NULL, 11);
-INSERT INTO itemTypeFields VALUES (7, 123, NULL, 12);
-INSERT INTO itemTypeFields VALUES (7, 19, NULL, 13);
-INSERT INTO itemTypeFields VALUES (7, 62, NULL, 14);
-INSERT INTO itemTypeFields VALUES (7, 18, NULL, 15);
-INSERT INTO itemTypeFields VALUES (7, 2, NULL, 16);
-INSERT INTO itemTypeFields VALUES (7, 22, NULL, 17);
-INSERT INTO itemTypeFields VALUES (8, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (8, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (8, 65, NULL, 3);
-INSERT INTO itemTypeFields VALUES (8, 14, NULL, 4);
-INSERT INTO itemTypeFields VALUES (8, 87, NULL, 5);
-INSERT INTO itemTypeFields VALUES (8, 116, NULL, 6);
-INSERT INTO itemTypeFields VALUES (8, 1, NULL, 7);
-INSERT INTO itemTypeFields VALUES (8, 27, NULL, 8);
-INSERT INTO itemTypeFields VALUES (8, 123, NULL, 9);
-INSERT INTO itemTypeFields VALUES (8, 19, NULL, 10);
-INSERT INTO itemTypeFields VALUES (8, 62, NULL, 11);
-INSERT INTO itemTypeFields VALUES (8, 18, NULL, 12);
-INSERT INTO itemTypeFields VALUES (8, 2, NULL, 13);
-INSERT INTO itemTypeFields VALUES (8, 22, NULL, 14);
-INSERT INTO itemTypeFields VALUES (9, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (9, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (9, 66, NULL, 3);
-INSERT INTO itemTypeFields VALUES (9, 7, NULL, 4);
-INSERT INTO itemTypeFields VALUES (9, 14, NULL, 5);
-INSERT INTO itemTypeFields VALUES (9, 118, NULL, 6);
-INSERT INTO itemTypeFields VALUES (9, 87, NULL, 7);
-INSERT INTO itemTypeFields VALUES (9, 116, NULL, 8);
-INSERT INTO itemTypeFields VALUES (9, 1, NULL, 9);
-INSERT INTO itemTypeFields VALUES (9, 27, NULL, 10);
-INSERT INTO itemTypeFields VALUES (9, 123, NULL, 11);
-INSERT INTO itemTypeFields VALUES (9, 19, NULL, 12);
-INSERT INTO itemTypeFields VALUES (9, 62, NULL, 13);
-INSERT INTO itemTypeFields VALUES (9, 18, NULL, 14);
-INSERT INTO itemTypeFields VALUES (9, 2, NULL, 15);
-INSERT INTO itemTypeFields VALUES (9, 22, NULL, 16);
-INSERT INTO itemTypeFields VALUES (10, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (10, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (10, 14, NULL, 3);
-INSERT INTO itemTypeFields VALUES (10, 64, NULL, 4);
-INSERT INTO itemTypeFields VALUES (10, 87, NULL, 5);
-INSERT INTO itemTypeFields VALUES (10, 116, NULL, 6);
-INSERT INTO itemTypeFields VALUES (10, 1, NULL, 7);
-INSERT INTO itemTypeFields VALUES (10, 27, NULL, 8);
-INSERT INTO itemTypeFields VALUES (10, 123, NULL, 9);
-INSERT INTO itemTypeFields VALUES (10, 19, NULL, 10);
-INSERT INTO itemTypeFields VALUES (10, 62, NULL, 11);
-INSERT INTO itemTypeFields VALUES (10, 18, NULL, 12);
-INSERT INTO itemTypeFields VALUES (10, 2, NULL, 13);
-INSERT INTO itemTypeFields VALUES (10, 22, NULL, 14);
-INSERT INTO itemTypeFields VALUES (11, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (11, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (11, 21, NULL, 3);
-INSERT INTO itemTypeFields VALUES (11, 14, NULL, 4);
-INSERT INTO itemTypeFields VALUES (11, 122, NULL, 5);
-INSERT INTO itemTypeFields VALUES (11, 63, NULL, 6);
-INSERT INTO itemTypeFields VALUES (11, 77, NULL, 7);
-INSERT INTO itemTypeFields VALUES (11, 87, NULL, 8);
-INSERT INTO itemTypeFields VALUES (11, 116, NULL, 9);
-INSERT INTO itemTypeFields VALUES (11, 1, NULL, 10);
-INSERT INTO itemTypeFields VALUES (11, 27, NULL, 11);
-INSERT INTO itemTypeFields VALUES (11, 123, NULL, 12);
-INSERT INTO itemTypeFields VALUES (11, 19, NULL, 13);
-INSERT INTO itemTypeFields VALUES (11, 62, NULL, 14);
-INSERT INTO itemTypeFields VALUES (11, 18, NULL, 15);
-INSERT INTO itemTypeFields VALUES (11, 2, NULL, 16);
-INSERT INTO itemTypeFields VALUES (11, 22, NULL, 17);
-INSERT INTO itemTypeFields VALUES (12, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (12, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (12, 59, NULL, 3);
-INSERT INTO itemTypeFields VALUES (12, 61, NULL, 4);
-INSERT INTO itemTypeFields VALUES (12, 14, NULL, 5);
-INSERT INTO itemTypeFields VALUES (12, 87, NULL, 6);
-INSERT INTO itemTypeFields VALUES (12, 116, NULL, 7);
-INSERT INTO itemTypeFields VALUES (12, 123, NULL, 8);
-INSERT INTO itemTypeFields VALUES (12, 19, NULL, 9);
-INSERT INTO itemTypeFields VALUES (12, 62, NULL, 10);
-INSERT INTO itemTypeFields VALUES (12, 18, NULL, 11);
-INSERT INTO itemTypeFields VALUES (12, 1, NULL, 12);
-INSERT INTO itemTypeFields VALUES (12, 27, NULL, 13);
-INSERT INTO itemTypeFields VALUES (12, 2, NULL, 14);
-INSERT INTO itemTypeFields VALUES (12, 22, NULL, 15);
-INSERT INTO itemTypeFields VALUES (13, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (13, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (13, 91, NULL, 3);
-INSERT INTO itemTypeFields VALUES (13, 70, NULL, 4);
-INSERT INTO itemTypeFields VALUES (13, 14, NULL, 5);
-INSERT INTO itemTypeFields VALUES (13, 116, NULL, 6);
-INSERT INTO itemTypeFields VALUES (13, 1, NULL, 7);
-INSERT INTO itemTypeFields VALUES (13, 27, NULL, 8);
-INSERT INTO itemTypeFields VALUES (13, 87, NULL, 9);
-INSERT INTO itemTypeFields VALUES (13, 2, NULL, 10);
-INSERT INTO itemTypeFields VALUES (13, 22, NULL, 11);
-INSERT INTO itemTypeFields VALUES (14, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (14, 27, NULL, 2);
-INSERT INTO itemTypeFields VALUES (14, 1, NULL, 3);
-INSERT INTO itemTypeFields VALUES (15, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (15, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (15, 92, NULL, 3);
-INSERT INTO itemTypeFields VALUES (15, 32, NULL, 4);
-INSERT INTO itemTypeFields VALUES (15, 28, NULL, 5);
-INSERT INTO itemTypeFields VALUES (15, 7, NULL, 6);
-INSERT INTO itemTypeFields VALUES (15, 31, NULL, 7);
-INSERT INTO itemTypeFields VALUES (15, 14, NULL, 8);
-INSERT INTO itemTypeFields VALUES (15, 10, NULL, 9);
-INSERT INTO itemTypeFields VALUES (15, 87, NULL, 10);
-INSERT INTO itemTypeFields VALUES (15, 116, NULL, 11);
-INSERT INTO itemTypeFields VALUES (15, 1, NULL, 12);
-INSERT INTO itemTypeFields VALUES (15, 27, NULL, 13);
-INSERT INTO itemTypeFields VALUES (15, 123, NULL, 14);
-INSERT INTO itemTypeFields VALUES (15, 19, NULL, 15);
-INSERT INTO itemTypeFields VALUES (15, 62, NULL, 16);
-INSERT INTO itemTypeFields VALUES (15, 18, NULL, 17);
-INSERT INTO itemTypeFields VALUES (15, 2, NULL, 18);
-INSERT INTO itemTypeFields VALUES (15, 22, NULL, 19);
-INSERT INTO itemTypeFields VALUES (16, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (16, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (16, 93, NULL, 3);
-INSERT INTO itemTypeFields VALUES (16, 36, NULL, 4);
-INSERT INTO itemTypeFields VALUES (16, 94, NULL, 5);
-INSERT INTO itemTypeFields VALUES (16, 15, NULL, 6);
-INSERT INTO itemTypeFields VALUES (16, 95, NULL, 7);
-INSERT INTO itemTypeFields VALUES (16, 41, NULL, 8);
-INSERT INTO itemTypeFields VALUES (16, 40, NULL, 9);
-INSERT INTO itemTypeFields VALUES (16, 42, NULL, 10);
-INSERT INTO itemTypeFields VALUES (16, 14, NULL, 11);
-INSERT INTO itemTypeFields VALUES (16, 87, NULL, 12);
-INSERT INTO itemTypeFields VALUES (16, 1, NULL, 13);
-INSERT INTO itemTypeFields VALUES (16, 27, NULL, 14);
-INSERT INTO itemTypeFields VALUES (16, 116, NULL, 15);
-INSERT INTO itemTypeFields VALUES (16, 2, NULL, 16);
-INSERT INTO itemTypeFields VALUES (16, 22, NULL, 17);
-INSERT INTO itemTypeFields VALUES (17, 111, NULL, 1);
-INSERT INTO itemTypeFields VALUES (17, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (17, 44, NULL, 3);
-INSERT INTO itemTypeFields VALUES (17, 96, NULL, 4);
-INSERT INTO itemTypeFields VALUES (17, 117, NULL, 5);
-INSERT INTO itemTypeFields VALUES (17, 43, NULL, 6);
-INSERT INTO itemTypeFields VALUES (17, 97, NULL, 7);
-INSERT INTO itemTypeFields VALUES (17, 98, NULL, 8);
-INSERT INTO itemTypeFields VALUES (17, 42, NULL, 9);
-INSERT INTO itemTypeFields VALUES (17, 87, NULL, 10);
-INSERT INTO itemTypeFields VALUES (17, 116, NULL, 11);
-INSERT INTO itemTypeFields VALUES (17, 1, NULL, 12);
-INSERT INTO itemTypeFields VALUES (17, 27, NULL, 13);
-INSERT INTO itemTypeFields VALUES (17, 2, NULL, 14);
-INSERT INTO itemTypeFields VALUES (17, 22, NULL, 15);
-INSERT INTO itemTypeFields VALUES (18, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (18, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (18, 46, NULL, 3);
-INSERT INTO itemTypeFields VALUES (18, 7, NULL, 4);
-INSERT INTO itemTypeFields VALUES (18, 8, NULL, 5);
-INSERT INTO itemTypeFields VALUES (18, 45, NULL, 6);
-INSERT INTO itemTypeFields VALUES (18, 99, NULL, 7);
-INSERT INTO itemTypeFields VALUES (18, 10, NULL, 8);
-INSERT INTO itemTypeFields VALUES (18, 41, NULL, 9);
-INSERT INTO itemTypeFields VALUES (18, 40, NULL, 10);
-INSERT INTO itemTypeFields VALUES (18, 42, NULL, 11);
-INSERT INTO itemTypeFields VALUES (18, 14, NULL, 12);
-INSERT INTO itemTypeFields VALUES (18, 87, NULL, 13);
-INSERT INTO itemTypeFields VALUES (18, 116, NULL, 14);
-INSERT INTO itemTypeFields VALUES (18, 1, NULL, 15);
-INSERT INTO itemTypeFields VALUES (18, 27, NULL, 16);
-INSERT INTO itemTypeFields VALUES (18, 2, NULL, 17);
-INSERT INTO itemTypeFields VALUES (18, 22, NULL, 18);
-INSERT INTO itemTypeFields VALUES (19, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (19, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (19, 7, NULL, 3);
-INSERT INTO itemTypeFields VALUES (19, 102, NULL, 4);
-INSERT INTO itemTypeFields VALUES (19, 48, NULL, 5);
-INSERT INTO itemTypeFields VALUES (19, 120, NULL, 6);
-INSERT INTO itemTypeFields VALUES (19, 50, NULL, 7);
-INSERT INTO itemTypeFields VALUES (19, 121, NULL, 8);
-INSERT INTO itemTypeFields VALUES (19, 10, NULL, 9);
-INSERT INTO itemTypeFields VALUES (19, 103, NULL, 10);
-INSERT INTO itemTypeFields VALUES (19, 51, NULL, 11);
-INSERT INTO itemTypeFields VALUES (19, 52, NULL, 12);
-INSERT INTO itemTypeFields VALUES (19, 53, NULL, 13);
-INSERT INTO itemTypeFields VALUES (19, 54, NULL, 14);
-INSERT INTO itemTypeFields VALUES (19, 87, NULL, 15);
-INSERT INTO itemTypeFields VALUES (19, 116, NULL, 16);
-INSERT INTO itemTypeFields VALUES (19, 1, NULL, 17);
-INSERT INTO itemTypeFields VALUES (19, 27, NULL, 18);
-INSERT INTO itemTypeFields VALUES (19, 2, NULL, 19);
-INSERT INTO itemTypeFields VALUES (19, 22, NULL, 20);
-INSERT INTO itemTypeFields VALUES (20, 112, NULL, 1);
-INSERT INTO itemTypeFields VALUES (20, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (20, 36, NULL, 3);
-INSERT INTO itemTypeFields VALUES (20, 55, NULL, 4);
-INSERT INTO itemTypeFields VALUES (20, 101, NULL, 5);
-INSERT INTO itemTypeFields VALUES (20, 100, NULL, 6);
-INSERT INTO itemTypeFields VALUES (20, 10, NULL, 7);
-INSERT INTO itemTypeFields VALUES (20, 15, NULL, 8);
-INSERT INTO itemTypeFields VALUES (20, 40, NULL, 9);
-INSERT INTO itemTypeFields VALUES (20, 42, NULL, 10);
-INSERT INTO itemTypeFields VALUES (20, 87, NULL, 11);
-INSERT INTO itemTypeFields VALUES (20, 116, NULL, 12);
-INSERT INTO itemTypeFields VALUES (20, 1, NULL, 13);
-INSERT INTO itemTypeFields VALUES (20, 27, NULL, 14);
-INSERT INTO itemTypeFields VALUES (20, 2, NULL, 15);
-INSERT INTO itemTypeFields VALUES (20, 22, NULL, 16);
-INSERT INTO itemTypeFields VALUES (21, 113, NULL, 1);
-INSERT INTO itemTypeFields VALUES (21, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (21, 14, NULL, 3);
-INSERT INTO itemTypeFields VALUES (21, 116, NULL, 4);
-INSERT INTO itemTypeFields VALUES (21, 1, NULL, 5);
-INSERT INTO itemTypeFields VALUES (21, 27, NULL, 6);
-INSERT INTO itemTypeFields VALUES (21, 87, NULL, 7);
-INSERT INTO itemTypeFields VALUES (21, 2, NULL, 8);
-INSERT INTO itemTypeFields VALUES (21, 22, NULL, 9);
-INSERT INTO itemTypeFields VALUES (22, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (22, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (22, 67, NULL, 3);
-INSERT INTO itemTypeFields VALUES (22, 68, NULL, 4);
-INSERT INTO itemTypeFields VALUES (22, 28, NULL, 5);
-INSERT INTO itemTypeFields VALUES (22, 6, NULL, 6);
-INSERT INTO itemTypeFields VALUES (22, 7, NULL, 7);
-INSERT INTO itemTypeFields VALUES (22, 8, NULL, 8);
-INSERT INTO itemTypeFields VALUES (22, 14, NULL, 9);
-INSERT INTO itemTypeFields VALUES (22, 87, NULL, 10);
-INSERT INTO itemTypeFields VALUES (22, 11, NULL, 11);
-INSERT INTO itemTypeFields VALUES (22, 116, NULL, 12);
-INSERT INTO itemTypeFields VALUES (22, 1, NULL, 13);
-INSERT INTO itemTypeFields VALUES (22, 27, NULL, 14);
-INSERT INTO itemTypeFields VALUES (22, 123, NULL, 15);
-INSERT INTO itemTypeFields VALUES (22, 19, NULL, 16);
-INSERT INTO itemTypeFields VALUES (22, 62, NULL, 17);
-INSERT INTO itemTypeFields VALUES (22, 18, NULL, 18);
-INSERT INTO itemTypeFields VALUES (22, 2, NULL, 19);
-INSERT INTO itemTypeFields VALUES (22, 22, NULL, 20);
-INSERT INTO itemTypeFields VALUES (23, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (23, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (23, 107, NULL, 3);
-INSERT INTO itemTypeFields VALUES (23, 70, NULL, 4);
-INSERT INTO itemTypeFields VALUES (23, 14, NULL, 5);
-INSERT INTO itemTypeFields VALUES (23, 1, NULL, 6);
-INSERT INTO itemTypeFields VALUES (23, 27, NULL, 7);
-INSERT INTO itemTypeFields VALUES (23, 87, NULL, 8);
-INSERT INTO itemTypeFields VALUES (23, 116, NULL, 9);
-INSERT INTO itemTypeFields VALUES (23, 2, NULL, 10);
-INSERT INTO itemTypeFields VALUES (23, 22, NULL, 11);
-INSERT INTO itemTypeFields VALUES (24, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (24, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (24, 14, NULL, 3);
-INSERT INTO itemTypeFields VALUES (24, 87, NULL, 4);
-INSERT INTO itemTypeFields VALUES (24, 116, NULL, 5);
-INSERT INTO itemTypeFields VALUES (24, 1, NULL, 6);
-INSERT INTO itemTypeFields VALUES (24, 27, NULL, 7);
-INSERT INTO itemTypeFields VALUES (24, 2, NULL, 8);
-INSERT INTO itemTypeFields VALUES (24, 22, NULL, 9);
-INSERT INTO itemTypeFields VALUES (25, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (25, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (25, 104, NULL, 3);
-INSERT INTO itemTypeFields VALUES (25, 79, NULL, 4);
-INSERT INTO itemTypeFields VALUES (25, 14, NULL, 5);
-INSERT INTO itemTypeFields VALUES (25, 87, NULL, 6);
-INSERT INTO itemTypeFields VALUES (25, 116, NULL, 7);
-INSERT INTO itemTypeFields VALUES (25, 1, NULL, 8);
-INSERT INTO itemTypeFields VALUES (25, 27, NULL, 9);
-INSERT INTO itemTypeFields VALUES (25, 2, NULL, 10);
-INSERT INTO itemTypeFields VALUES (25, 22, NULL, 11);
-INSERT INTO itemTypeFields VALUES (26, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (26, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (26, 71, NULL, 3);
-INSERT INTO itemTypeFields VALUES (26, 28, NULL, 4);
-INSERT INTO itemTypeFields VALUES (26, 4, NULL, 5);
-INSERT INTO itemTypeFields VALUES (26, 45, NULL, 6);
-INSERT INTO itemTypeFields VALUES (26, 7, NULL, 7);
-INSERT INTO itemTypeFields VALUES (26, 72, NULL, 8);
-INSERT INTO itemTypeFields VALUES (26, 14, NULL, 9);
-INSERT INTO itemTypeFields VALUES (26, 77, NULL, 10);
-INSERT INTO itemTypeFields VALUES (26, 87, NULL, 11);
-INSERT INTO itemTypeFields VALUES (26, 11, NULL, 12);
-INSERT INTO itemTypeFields VALUES (26, 116, NULL, 13);
-INSERT INTO itemTypeFields VALUES (26, 123, NULL, 14);
-INSERT INTO itemTypeFields VALUES (26, 19, NULL, 15);
-INSERT INTO itemTypeFields VALUES (26, 62, NULL, 16);
-INSERT INTO itemTypeFields VALUES (26, 18, NULL, 17);
-INSERT INTO itemTypeFields VALUES (26, 1, NULL, 18);
-INSERT INTO itemTypeFields VALUES (26, 27, NULL, 19);
-INSERT INTO itemTypeFields VALUES (26, 2, NULL, 20);
-INSERT INTO itemTypeFields VALUES (26, 22, NULL, 21);
-INSERT INTO itemTypeFields VALUES (27, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (27, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (27, 74, NULL, 3);
-INSERT INTO itemTypeFields VALUES (27, 14, NULL, 4);
-INSERT INTO itemTypeFields VALUES (27, 7, NULL, 5);
-INSERT INTO itemTypeFields VALUES (27, 75, NULL, 6);
-INSERT INTO itemTypeFields VALUES (27, 1, NULL, 7);
-INSERT INTO itemTypeFields VALUES (27, 27, NULL, 8);
-INSERT INTO itemTypeFields VALUES (27, 87, NULL, 9);
-INSERT INTO itemTypeFields VALUES (27, 116, NULL, 10);
-INSERT INTO itemTypeFields VALUES (27, 2, NULL, 11);
-INSERT INTO itemTypeFields VALUES (27, 22, NULL, 12);
-INSERT INTO itemTypeFields VALUES (28, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (28, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (28, 63, NULL, 3);
-INSERT INTO itemTypeFields VALUES (28, 28, NULL, 4);
-INSERT INTO itemTypeFields VALUES (28, 4, NULL, 5);
-INSERT INTO itemTypeFields VALUES (28, 45, NULL, 6);
-INSERT INTO itemTypeFields VALUES (28, 7, NULL, 7);
-INSERT INTO itemTypeFields VALUES (28, 76, NULL, 8);
-INSERT INTO itemTypeFields VALUES (28, 14, NULL, 9);
-INSERT INTO itemTypeFields VALUES (28, 77, NULL, 10);
-INSERT INTO itemTypeFields VALUES (28, 87, NULL, 11);
-INSERT INTO itemTypeFields VALUES (28, 11, NULL, 12);
-INSERT INTO itemTypeFields VALUES (28, 116, NULL, 13);
-INSERT INTO itemTypeFields VALUES (28, 1, NULL, 14);
-INSERT INTO itemTypeFields VALUES (28, 27, NULL, 15);
-INSERT INTO itemTypeFields VALUES (28, 123, NULL, 16);
-INSERT INTO itemTypeFields VALUES (28, 19, NULL, 17);
-INSERT INTO itemTypeFields VALUES (28, 62, NULL, 18);
-INSERT INTO itemTypeFields VALUES (28, 18, NULL, 19);
-INSERT INTO itemTypeFields VALUES (28, 2, NULL, 20);
-INSERT INTO itemTypeFields VALUES (28, 22, NULL, 21);
-INSERT INTO itemTypeFields VALUES (29, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (29, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (29, 119, NULL, 3);
-INSERT INTO itemTypeFields VALUES (29, 105, NULL, 4);
-INSERT INTO itemTypeFields VALUES (29, 63, NULL, 5);
-INSERT INTO itemTypeFields VALUES (29, 7, NULL, 6);
-INSERT INTO itemTypeFields VALUES (29, 78, NULL, 7);
-INSERT INTO itemTypeFields VALUES (29, 14, NULL, 8);
-INSERT INTO itemTypeFields VALUES (29, 77, NULL, 9);
-INSERT INTO itemTypeFields VALUES (29, 87, NULL, 10);
-INSERT INTO itemTypeFields VALUES (29, 116, NULL, 11);
-INSERT INTO itemTypeFields VALUES (29, 1, NULL, 12);
-INSERT INTO itemTypeFields VALUES (29, 27, NULL, 13);
-INSERT INTO itemTypeFields VALUES (29, 123, NULL, 14);
-INSERT INTO itemTypeFields VALUES (29, 19, NULL, 15);
-INSERT INTO itemTypeFields VALUES (29, 62, NULL, 16);
-INSERT INTO itemTypeFields VALUES (29, 18, NULL, 17);
-INSERT INTO itemTypeFields VALUES (29, 2, NULL, 18);
-INSERT INTO itemTypeFields VALUES (29, 22, NULL, 19);
-INSERT INTO itemTypeFields VALUES (30, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (30, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (30, 119, NULL, 3);
-INSERT INTO itemTypeFields VALUES (30, 105, NULL, 4);
-INSERT INTO itemTypeFields VALUES (30, 71, NULL, 5);
-INSERT INTO itemTypeFields VALUES (30, 7, NULL, 6);
-INSERT INTO itemTypeFields VALUES (30, 78, NULL, 7);
-INSERT INTO itemTypeFields VALUES (30, 14, NULL, 8);
-INSERT INTO itemTypeFields VALUES (30, 77, NULL, 9);
-INSERT INTO itemTypeFields VALUES (30, 87, NULL, 10);
-INSERT INTO itemTypeFields VALUES (30, 116, NULL, 11);
-INSERT INTO itemTypeFields VALUES (30, 1, NULL, 12);
-INSERT INTO itemTypeFields VALUES (30, 27, NULL, 13);
-INSERT INTO itemTypeFields VALUES (30, 123, NULL, 14);
-INSERT INTO itemTypeFields VALUES (30, 19, NULL, 15);
-INSERT INTO itemTypeFields VALUES (30, 62, NULL, 16);
-INSERT INTO itemTypeFields VALUES (30, 18, NULL, 17);
-INSERT INTO itemTypeFields VALUES (30, 2, NULL, 18);
-INSERT INTO itemTypeFields VALUES (30, 22, NULL, 19);
-INSERT INTO itemTypeFields VALUES (31, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (31, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (31, 28, NULL, 3);
-INSERT INTO itemTypeFields VALUES (31, 105, NULL, 4);
-INSERT INTO itemTypeFields VALUES (31, 80, NULL, 5);
-INSERT INTO itemTypeFields VALUES (31, 77, NULL, 6);
-INSERT INTO itemTypeFields VALUES (31, 1, NULL, 7);
-INSERT INTO itemTypeFields VALUES (31, 27, NULL, 8);
-INSERT INTO itemTypeFields VALUES (31, 87, NULL, 9);
-INSERT INTO itemTypeFields VALUES (31, 116, NULL, 10);
-INSERT INTO itemTypeFields VALUES (31, 2, NULL, 11);
-INSERT INTO itemTypeFields VALUES (31, 22, NULL, 12);
-INSERT INTO itemTypeFields VALUES (32, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (32, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (32, 28, NULL, 3);
-INSERT INTO itemTypeFields VALUES (32, 81, NULL, 4);
-INSERT INTO itemTypeFields VALUES (32, 14, NULL, 5);
-INSERT INTO itemTypeFields VALUES (32, 82, NULL, 6);
-INSERT INTO itemTypeFields VALUES (32, 7, NULL, 7);
-INSERT INTO itemTypeFields VALUES (32, 83, NULL, 8);
-INSERT INTO itemTypeFields VALUES (32, 88, NULL, 9);
-INSERT INTO itemTypeFields VALUES (32, 11, NULL, 10);
-INSERT INTO itemTypeFields VALUES (32, 116, NULL, 11);
-INSERT INTO itemTypeFields VALUES (32, 1, NULL, 12);
-INSERT INTO itemTypeFields VALUES (32, 2, NULL, 13);
-INSERT INTO itemTypeFields VALUES (32, 123, NULL, 14);
-INSERT INTO itemTypeFields VALUES (32, 19, NULL, 15);
-INSERT INTO itemTypeFields VALUES (32, 62, NULL, 16);
-INSERT INTO itemTypeFields VALUES (32, 18, NULL, 17);
-INSERT INTO itemTypeFields VALUES (32, 27, NULL, 18);
-INSERT INTO itemTypeFields VALUES (32, 22, NULL, 19);
-INSERT INTO itemTypeFields VALUES (33, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (33, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (33, 14, NULL, 3);
-INSERT INTO itemTypeFields VALUES (33, 114, NULL, 4);
-INSERT INTO itemTypeFields VALUES (33, 84, NULL, 5);
-INSERT INTO itemTypeFields VALUES (33, 7, NULL, 6);
-INSERT INTO itemTypeFields VALUES (33, 8, NULL, 7);
-INSERT INTO itemTypeFields VALUES (33, 4, NULL, 8);
-INSERT INTO itemTypeFields VALUES (33, 10, NULL, 9);
-INSERT INTO itemTypeFields VALUES (33, 3, NULL, 10);
-INSERT INTO itemTypeFields VALUES (33, 87, NULL, 11);
-INSERT INTO itemTypeFields VALUES (33, 26, NULL, 12);
-INSERT INTO itemTypeFields VALUES (33, 11, NULL, 13);
-INSERT INTO itemTypeFields VALUES (33, 116, NULL, 14);
-INSERT INTO itemTypeFields VALUES (33, 1, NULL, 15);
-INSERT INTO itemTypeFields VALUES (33, 27, NULL, 16);
-INSERT INTO itemTypeFields VALUES (33, 123, NULL, 17);
-INSERT INTO itemTypeFields VALUES (33, 19, NULL, 18);
-INSERT INTO itemTypeFields VALUES (33, 62, NULL, 19);
-INSERT INTO itemTypeFields VALUES (33, 18, NULL, 20);
-INSERT INTO itemTypeFields VALUES (33, 2, NULL, 21);
-INSERT INTO itemTypeFields VALUES (33, 22, NULL, 22);
-INSERT INTO itemTypeFields VALUES (34, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (34, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (34, 8, NULL, 3);
-INSERT INTO itemTypeFields VALUES (34, 14, NULL, 4);
-INSERT INTO itemTypeFields VALUES (34, 87, NULL, 5);
-INSERT INTO itemTypeFields VALUES (34, 116, NULL, 6);
-INSERT INTO itemTypeFields VALUES (34, 1, NULL, 7);
-INSERT INTO itemTypeFields VALUES (34, 27, NULL, 8);
-INSERT INTO itemTypeFields VALUES (34, 123, NULL, 9);
-INSERT INTO itemTypeFields VALUES (34, 19, NULL, 10);
-INSERT INTO itemTypeFields VALUES (34, 62, NULL, 11);
-INSERT INTO itemTypeFields VALUES (34, 18, NULL, 12);
-INSERT INTO itemTypeFields VALUES (34, 2, NULL, 13);
-INSERT INTO itemTypeFields VALUES (34, 22, NULL, 14);
-INSERT INTO itemTypeFields VALUES (35, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (35, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (35, 85, NULL, 3);
-INSERT INTO itemTypeFields VALUES (35, 3, NULL, 4);
-INSERT INTO itemTypeFields VALUES (35, 30, NULL, 5);
-INSERT INTO itemTypeFields VALUES (35, 4, NULL, 6);
-INSERT INTO itemTypeFields VALUES (35, 45, NULL, 7);
-INSERT INTO itemTypeFields VALUES (35, 6, NULL, 8);
-INSERT INTO itemTypeFields VALUES (35, 7, NULL, 9);
-INSERT INTO itemTypeFields VALUES (35, 8, NULL, 10);
-INSERT INTO itemTypeFields VALUES (35, 14, NULL, 11);
-INSERT INTO itemTypeFields VALUES (35, 10, NULL, 12);
-INSERT INTO itemTypeFields VALUES (35, 11, NULL, 13);
-INSERT INTO itemTypeFields VALUES (35, 116, NULL, 14);
-INSERT INTO itemTypeFields VALUES (35, 1, NULL, 15);
-INSERT INTO itemTypeFields VALUES (35, 27, NULL, 16);
-INSERT INTO itemTypeFields VALUES (35, 87, NULL, 17);
-INSERT INTO itemTypeFields VALUES (35, 123, NULL, 18);
-INSERT INTO itemTypeFields VALUES (35, 19, NULL, 19);
-INSERT INTO itemTypeFields VALUES (35, 62, NULL, 20);
-INSERT INTO itemTypeFields VALUES (35, 18, NULL, 21);
-INSERT INTO itemTypeFields VALUES (35, 2, NULL, 22);
-INSERT INTO itemTypeFields VALUES (35, 22, NULL, 23);
-INSERT INTO itemTypeFields VALUES (36, 110, NULL, 1);
-INSERT INTO itemTypeFields VALUES (36, 90, NULL, 2);
-INSERT INTO itemTypeFields VALUES (36, 86, NULL, 3);
-INSERT INTO itemTypeFields VALUES (36, 3, NULL, 4);
-INSERT INTO itemTypeFields VALUES (36, 30, NULL, 5);
-INSERT INTO itemTypeFields VALUES (36, 4, NULL, 6);
-INSERT INTO itemTypeFields VALUES (36, 45, NULL, 7);
-INSERT INTO itemTypeFields VALUES (36, 6, NULL, 8);
-INSERT INTO itemTypeFields VALUES (36, 7, NULL, 9);
-INSERT INTO itemTypeFields VALUES (36, 8, NULL, 10);
-INSERT INTO itemTypeFields VALUES (36, 14, NULL, 11);
-INSERT INTO itemTypeFields VALUES (36, 10, NULL, 12);
-INSERT INTO itemTypeFields VALUES (36, 87, NULL, 13);
-INSERT INTO itemTypeFields VALUES (36, 11, NULL, 14);
-INSERT INTO itemTypeFields VALUES (36, 116, NULL, 15);
-INSERT INTO itemTypeFields VALUES (36, 1, NULL, 16);
-INSERT INTO itemTypeFields VALUES (36, 27, NULL, 17);
-INSERT INTO itemTypeFields VALUES (36, 123, NULL, 18);
-INSERT INTO itemTypeFields VALUES (36, 19, NULL, 19);
-INSERT INTO itemTypeFields VALUES (36, 62, NULL, 20);
-INSERT INTO itemTypeFields VALUES (36, 18, NULL, 21);
-INSERT INTO itemTypeFields VALUES (36, 2, NULL, 22);
-INSERT INTO itemTypeFields VALUES (36, 22, NULL, 23);
-
-
-INSERT INTO baseFieldMappings VALUES (16, 4, 94); -- bill/volume/codeVolume
-INSERT INTO baseFieldMappings VALUES (17, 4, 97); -- case/volume/reporterVolume
-INSERT INTO baseFieldMappings VALUES (7, 8, 89); -- thesis/publisher/university
-INSERT INTO baseFieldMappings VALUES (11, 8, 21); -- film/publisher/distributor
-INSERT INTO baseFieldMappings VALUES (15, 8, 31); -- report/publisher/institution
-INSERT INTO baseFieldMappings VALUES (26, 8, 72); -- audioRecording/publisher/label
-INSERT INTO baseFieldMappings VALUES (28, 8, 76); -- videoRecording/publisher/studio
-INSERT INTO baseFieldMappings VALUES (29, 8, 78); -- tvBroadcast/publisher/network
-INSERT INTO baseFieldMappings VALUES (30, 8, 78); -- radioBroadcast/publisher/network
-INSERT INTO baseFieldMappings VALUES (32, 8, 83); -- computerProgram/publisher/company
-INSERT INTO baseFieldMappings VALUES (16, 10, 95); -- bill/pages/codePages
-INSERT INTO baseFieldMappings VALUES (17, 10, 98); -- case/pages/firstPage
-INSERT INTO baseFieldMappings VALUES (3, 12, 115); -- bookSection/publicationTitle/bookTitle
-INSERT INTO baseFieldMappings VALUES (33, 12, 114); -- conferencePaper/publicationTitle/proceedingsTitle
-INSERT INTO baseFieldMappings VALUES (13, 12, 91); -- webpage/publicationTitle/websiteTitle
-INSERT INTO baseFieldMappings VALUES (23, 12, 107); -- blogPost/publicationTitle/blogTitle
-INSERT INTO baseFieldMappings VALUES (25, 12, 104); -- forumPost/publicationTitle/forumTitle
-INSERT INTO baseFieldMappings VALUES (29, 12, 119); -- tvBroadcast/publicationTitle/programTitle
-INSERT INTO baseFieldMappings VALUES (30, 12, 119); -- radioBroadcast/publicationTitle/programTitle
-INSERT INTO baseFieldMappings VALUES (35, 12, 85); -- encyclopediaEntry/publicationTitle/encyclopediaTitle
-INSERT INTO baseFieldMappings VALUES (36, 12, 86); -- dictionaryEntry/publicationTitle/dictionaryTitle
-INSERT INTO baseFieldMappings VALUES (17, 14, 96); -- case/date/dateDecided
-INSERT INTO baseFieldMappings VALUES (19, 14, 52); -- patent/date/issueDate
-INSERT INTO baseFieldMappings VALUES (20, 14, 100); -- statute/date/dateEnacted
-INSERT INTO baseFieldMappings VALUES (15, 60, 92); -- report/number/reportNumber
-INSERT INTO baseFieldMappings VALUES (16, 60, 93); -- bill/number/billNumber
-INSERT INTO baseFieldMappings VALUES (17, 60, 117); -- case/number/docketNumber
-INSERT INTO baseFieldMappings VALUES (18, 60, 99); -- hearing/number/documentNumber
-INSERT INTO baseFieldMappings VALUES (19, 60, 50); -- patent/number/patentNumber
-INSERT INTO baseFieldMappings VALUES (20, 60, 101); -- statute/number/publicLawNumber
-INSERT INTO baseFieldMappings VALUES (29, 60, 105); -- tvBroadcast/number/episodeNumber
-INSERT INTO baseFieldMappings VALUES (30, 60, 105); -- radioBroadcast/number/episodeNumber
-INSERT INTO baseFieldMappings VALUES (31, 60, 105); -- podcast/number/episodeNumber
-INSERT INTO baseFieldMappings VALUES (7, 108, 69); -- thesis/type/thesisType
-INSERT INTO baseFieldMappings VALUES (8, 108, 65); -- letter/type/letterType
-INSERT INTO baseFieldMappings VALUES (9, 108, 66); -- manuscript/type/manuscriptType
-INSERT INTO baseFieldMappings VALUES (11, 108, 122); -- film/type/genre
-INSERT INTO baseFieldMappings VALUES (13, 108, 70); -- webpage/type/websiteType
-INSERT INTO baseFieldMappings VALUES (15, 108, 32); -- report/type/reportType
-INSERT INTO baseFieldMappings VALUES (22, 108, 67); -- map/type/mapType
-INSERT INTO baseFieldMappings VALUES (23, 108, 70); -- blogPost/type/websiteType
-INSERT INTO baseFieldMappings VALUES (25, 108, 79); -- forumPost/type/postType
-INSERT INTO baseFieldMappings VALUES (27, 108, 74); -- presentation/type/presentationType
-INSERT INTO baseFieldMappings VALUES (10, 109, 64); -- interview/medium/interviewMedium
-INSERT INTO baseFieldMappings VALUES (11, 109, 63); -- film/medium/videoRecordingFormat
-INSERT INTO baseFieldMappings VALUES (12, 109, 59); -- artwork/medium/artworkMedium
-INSERT INTO baseFieldMappings VALUES (26, 109, 71); -- audioRecording/medium/audioRecordingFormat
-INSERT INTO baseFieldMappings VALUES (28, 109, 63); -- videoRecording/medium/videoRecordingFormat
-INSERT INTO baseFieldMappings VALUES (29, 109, 63); -- tvBroadcast/medium/videoRecodingMedium
-INSERT INTO baseFieldMappings VALUES (30, 109, 71); -- radioBroadcast/medium/audioRecordingFormat
-INSERT INTO baseFieldMappings VALUES (31, 109, 80); -- podcast/medium/audioFileType
-INSERT INTO baseFieldMappings VALUES (17, 110, 111); -- case/title/caseName
-INSERT INTO baseFieldMappings VALUES (20, 110, 112); -- statute/title/nameOfAct
-INSERT INTO baseFieldMappings VALUES (21, 110, 113); -- email/title/subject
-
-INSERT INTO creatorTypes VALUES(1, "author");
-INSERT INTO creatorTypes VALUES(2, "contributor");
-INSERT INTO creatorTypes VALUES(3, "editor");
-INSERT INTO creatorTypes VALUES(4, "translator");
-INSERT INTO creatorTypes VALUES(5, "seriesEditor");
-INSERT INTO creatorTypes VALUES(6, "interviewee");
-INSERT INTO creatorTypes VALUES(7, "interviewer");
-INSERT INTO creatorTypes VALUES(8, "director");
-INSERT INTO creatorTypes VALUES(9, "scriptwriter");
-INSERT INTO creatorTypes VALUES(10, "producer");
-INSERT INTO creatorTypes VALUES(11, "castMember");
-INSERT INTO creatorTypes VALUES(12, "sponsor");
-INSERT INTO creatorTypes VALUES(13, "counsel");
-INSERT INTO creatorTypes VALUES(14, "inventor");
-INSERT INTO creatorTypes VALUES(15, "attorneyAgent");
-INSERT INTO creatorTypes VALUES(16, "recipient");
-INSERT INTO creatorTypes VALUES(17, "performer");
-INSERT INTO creatorTypes VALUES(18, "composer");
-INSERT INTO creatorTypes VALUES(19, "wordsBy");
-INSERT INTO creatorTypes VALUES(20, "cartographer");
-INSERT INTO creatorTypes VALUES(21, "programmer");
-INSERT INTO creatorTypes VALUES(22, "artist");
-INSERT INTO creatorTypes VALUES(23, "commenter");
-INSERT INTO creatorTypes VALUES(24, "presenter");
-INSERT INTO creatorTypes VALUES(25, "guest");
-INSERT INTO creatorTypes VALUES(26, "podcaster");
-INSERT INTO creatorTypes VALUES(27, "reviewedAuthor");
-INSERT INTO creatorTypes VALUES(28, "cosponsor");
-INSERT INTO creatorTypes VALUES(29, "bookAuthor");
-
-INSERT INTO itemTypeCreatorTypes VALUES(2,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(2,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(2,3,0);
-INSERT INTO itemTypeCreatorTypes VALUES(2,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(2,5,0);
-INSERT INTO itemTypeCreatorTypes VALUES(3,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(3,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(3,3,0);
-INSERT INTO itemTypeCreatorTypes VALUES(3,29,0);
-INSERT INTO itemTypeCreatorTypes VALUES(3,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(3,5,0);
-INSERT INTO itemTypeCreatorTypes VALUES(4,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(4,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(4,3,0);
-INSERT INTO itemTypeCreatorTypes VALUES(4,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(4,27,0);
-INSERT INTO itemTypeCreatorTypes VALUES(5,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(5,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(5,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(5,27,0);
-INSERT INTO itemTypeCreatorTypes VALUES(6,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(6,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(6,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(6,27,0);
-INSERT INTO itemTypeCreatorTypes VALUES(7,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(7,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(8,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(8,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(8,16,0);
-INSERT INTO itemTypeCreatorTypes VALUES(9,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(9,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(9,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(10,6,1);
-INSERT INTO itemTypeCreatorTypes VALUES(10,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(10,7,0);
-INSERT INTO itemTypeCreatorTypes VALUES(10,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(11,8,1);
-INSERT INTO itemTypeCreatorTypes VALUES(11,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(11,9,0);
-INSERT INTO itemTypeCreatorTypes VALUES(11,10,0);
-INSERT INTO itemTypeCreatorTypes VALUES(12,22,1);
-INSERT INTO itemTypeCreatorTypes VALUES(12,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(13,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(13,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(13,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(15,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(15,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(15,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(15,5,0);
-INSERT INTO itemTypeCreatorTypes VALUES(16,12,1);
-INSERT INTO itemTypeCreatorTypes VALUES(16,28,0);
-INSERT INTO itemTypeCreatorTypes VALUES(16,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(17,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(17,13,0);
-INSERT INTO itemTypeCreatorTypes VALUES(17,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(18,2,1);
-INSERT INTO itemTypeCreatorTypes VALUES(19,14,1);
-INSERT INTO itemTypeCreatorTypes VALUES(19,15,0);
-INSERT INTO itemTypeCreatorTypes VALUES(19,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(20,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(20,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(21,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(21,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(21,16,0);
-INSERT INTO itemTypeCreatorTypes VALUES(22,20,1);
-INSERT INTO itemTypeCreatorTypes VALUES(22,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(22,5,0);
-INSERT INTO itemTypeCreatorTypes VALUES(23,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(23,23,0);
-INSERT INTO itemTypeCreatorTypes VALUES(23,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(24,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(24,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(24,16,0);
-INSERT INTO itemTypeCreatorTypes VALUES(25,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(25,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(26,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(26,17,1);
-INSERT INTO itemTypeCreatorTypes VALUES(26,18,0);
-INSERT INTO itemTypeCreatorTypes VALUES(26,19,0);
-INSERT INTO itemTypeCreatorTypes VALUES(27,24,1);
-INSERT INTO itemTypeCreatorTypes VALUES(27,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(28,8,1);
-INSERT INTO itemTypeCreatorTypes VALUES(28,9,0);
-INSERT INTO itemTypeCreatorTypes VALUES(28,10,0);
-INSERT INTO itemTypeCreatorTypes VALUES(28,11,0);
-INSERT INTO itemTypeCreatorTypes VALUES(28,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(29,8,1);
-INSERT INTO itemTypeCreatorTypes VALUES(29,9,0);
-INSERT INTO itemTypeCreatorTypes VALUES(29,10,0);
-INSERT INTO itemTypeCreatorTypes VALUES(29,11,0);
-INSERT INTO itemTypeCreatorTypes VALUES(29,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(29,25,0);
-INSERT INTO itemTypeCreatorTypes VALUES(30,8,1);
-INSERT INTO itemTypeCreatorTypes VALUES(30,9,0);
-INSERT INTO itemTypeCreatorTypes VALUES(30,10,0);
-INSERT INTO itemTypeCreatorTypes VALUES(30,11,0);
-INSERT INTO itemTypeCreatorTypes VALUES(30,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(30,25,0);
-INSERT INTO itemTypeCreatorTypes VALUES(31,26,1);
-INSERT INTO itemTypeCreatorTypes VALUES(31,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(31,25,0);
-INSERT INTO itemTypeCreatorTypes VALUES(32,21,1);
-INSERT INTO itemTypeCreatorTypes VALUES(32,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(33, 1, 1);
-INSERT INTO itemTypeCreatorTypes VALUES(33, 2, 0);
-INSERT INTO itemTypeCreatorTypes VALUES(33, 3, 0);
-INSERT INTO itemTypeCreatorTypes VALUES(33, 4, 0);
-INSERT INTO itemTypeCreatorTypes VALUES(33, 5, 0);
-INSERT INTO itemTypeCreatorTypes VALUES(34,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(34,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(34,3,0);
-INSERT INTO itemTypeCreatorTypes VALUES(34,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(34,27,0);
-INSERT INTO itemTypeCreatorTypes VALUES(35,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(35,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(35,3,0);
-INSERT INTO itemTypeCreatorTypes VALUES(35,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(35,5,0);
-INSERT INTO itemTypeCreatorTypes VALUES(36,1,1);
-INSERT INTO itemTypeCreatorTypes VALUES(36,2,0);
-INSERT INTO itemTypeCreatorTypes VALUES(36,3,0);
-INSERT INTO itemTypeCreatorTypes VALUES(36,4,0);
-INSERT INTO itemTypeCreatorTypes VALUES(36,5,0);
-
INSERT INTO "charsets" VALUES (1, "utf-8");
INSERT INTO "charsets" VALUES (2, "big5");
INSERT INTO "charsets" VALUES (3, "euc-jp");
diff --git a/resource/schema/triggers.sql b/resource/schema/triggers.sql
index 041ce800a9..666877ac8d 100644
--- a/resource/schema/triggers.sql
+++ b/resource/schema/triggers.sql
@@ -22,34 +22,6 @@
-- ";---" is an ugly hack for Zotero.DB.executeSQLFile()
--- Triggers to validate date field
-DROP TRIGGER IF EXISTS insert_date_field;
-CREATE TRIGGER insert_date_field BEFORE INSERT ON itemData
- FOR EACH ROW WHEN NEW.fieldID IN (14, 27, 52, 96, 100)
- BEGIN
- SELECT CASE
- CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 1, 4) AS INT) BETWEEN 0 AND 9999 AND
- SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 5, 1) = '-' AND
- CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 6, 2) AS INT) BETWEEN 0 AND 12 AND
- SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 8, 1) = '-' AND
- CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 9, 2) AS INT) BETWEEN 0 AND 31
- WHEN 0 THEN RAISE (ABORT, 'Date field must begin with SQL date') END;---
- END;
-
-DROP TRIGGER IF EXISTS update_date_field;
-CREATE TRIGGER update_date_field BEFORE UPDATE ON itemData
- FOR EACH ROW WHEN NEW.fieldID IN (14, 27, 52, 96, 100)
- BEGIN
- SELECT CASE
- CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 1, 4) AS INT) BETWEEN 0 AND 9999 AND
- SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 5, 1) = '-' AND
- CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 6, 2) AS INT) BETWEEN 0 AND 12 AND
- SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 8, 1) = '-' AND
- CAST(SUBSTR((SELECT value FROM itemDataValues WHERE valueID=NEW.valueID), 9, 2) AS INT) BETWEEN 0 AND 31
- WHEN 0 THEN RAISE (ABORT, 'Date field must begin with SQL date') END;---
- END;
-
-
-- Don't allow empty creators
DROP TRIGGER IF EXISTS insert_creatorData;
CREATE TRIGGER insert_creators BEFORE INSERT ON creators
@@ -137,79 +109,6 @@ CREATE TRIGGER fku_itemNotes_parentItemID_collectionItems_itemID
DELETE FROM collectionItems WHERE itemID = NEW.itemID;---
END;
-
--- itemAttachments
-DROP TRIGGER IF EXISTS fki_itemAttachments;
-CREATE TRIGGER fki_itemAttachments
- BEFORE INSERT ON itemAttachments
- FOR EACH ROW BEGIN
- SELECT RAISE(ABORT, 'insert on table "itemAttachments" violates foreign key constraint "fki_itemAttachments"')
- WHERE NEW.parentItemID IS NOT NULL AND
- (SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.parentItemID);---
-
- -- Make sure this is an attachment item
- SELECT RAISE(ABORT, 'item is not an attachment')
- WHERE (SELECT itemTypeID FROM items WHERE itemID = NEW.itemID) != 14;---
-
- -- Make sure parent is a regular item
- SELECT RAISE(ABORT, 'parent is not a regular item')
- WHERE NEW.parentItemID IS NOT NULL AND (SELECT itemTypeID FROM items WHERE itemID = NEW.parentItemID) IN (1,14);---
-
- -- If child, make sure attachment is not in a collection
- SELECT RAISE(ABORT, 'collection item must be top level')
- WHERE NEW.parentItemID IS NOT NULL AND (SELECT COUNT(*) FROM collectionItems WHERE itemID=NEW.itemID)>0;---
- END;
-
-DROP TRIGGER IF EXISTS fku_itemAttachments;
-CREATE TRIGGER fku_itemAttachments
- BEFORE UPDATE ON itemAttachments
- FOR EACH ROW BEGIN
- SELECT RAISE(ABORT, 'update on table "itemAttachments" violates foreign key constraint "fku_itemAttachments"')
- WHERE NEW.parentItemID IS NOT NULL AND
- (SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.parentItemID);---
-
- -- Make sure parent is a regular item
- SELECT RAISE(ABORT, 'parent is not a regular item')
- WHERE NEW.parentItemID IS NOT NULL AND (SELECT itemTypeID FROM items WHERE itemID = NEW.parentItemID) IN (1,14);---
- END;
-
-
--- itemNotes
-DROP TRIGGER IF EXISTS fki_itemNotes;
-CREATE TRIGGER fki_itemNotes
- BEFORE INSERT ON itemNotes
- FOR EACH ROW BEGIN
- SELECT RAISE(ABORT, 'insert on table "itemNotes" violates foreign key constraint "fki_itemNotes_libraryID"')
- WHERE NEW.parentItemID IS NOT NULL AND
- (SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.parentItemID);---
-
- -- Make sure this is a note or attachment item
- SELECT RAISE(ABORT, 'item is not a note or attachment') WHERE
- (SELECT itemTypeID FROM items WHERE itemID = NEW.itemID) NOT IN (1,14);---
-
- -- Make sure parent is a regular item
- SELECT RAISE(ABORT, 'parent is not a regular item') WHERE
- NEW.parentItemID IS NOT NULL AND (SELECT itemTypeID FROM items WHERE itemID = NEW.parentItemID) IN (1,14);---
-
- -- If child, make sure note is not in a collection
- SELECT RAISE(ABORT, 'collection item must be top level') WHERE
- NEW.parentItemID IS NOT NULL AND (SELECT COUNT(*) FROM collectionItems WHERE itemID=NEW.itemID)>0;---
- END;
-
-DROP TRIGGER IF EXISTS fku_itemNotes;
-CREATE TRIGGER fku_itemNotes
- BEFORE UPDATE ON itemNotes
- FOR EACH ROW BEGIN
- SELECT RAISE(ABORT, 'update on table "itemNotes" violates foreign key constraint "fku_itemNotes"')
- WHERE NEW.parentItemID IS NOT NULL AND
- (SELECT libraryID FROM items WHERE itemID = NEW.itemID) != (SELECT libraryID FROM items WHERE itemID = NEW.parentItemID);---
-
- -- Make sure parent is a regular item
- SELECT RAISE(ABORT, 'parent is not a regular item') WHERE
- NEW.parentItemID IS NOT NULL AND (SELECT itemTypeID FROM items WHERE itemID = NEW.parentItemID) IN (1,14);---
- END;
-
-
-- Make sure tags aren't empty
DROP TRIGGER IF EXISTS fki_tags;
CREATE TRIGGER fki_tags
diff --git a/resource/schema/userdata.sql b/resource/schema/userdata.sql
index 998af81053..4708048571 100644
--- a/resource/schema/userdata.sql
+++ b/resource/schema/userdata.sql
@@ -1,4 +1,4 @@
--- 105
+-- 106
-- Copyright (c) 2009 Center for History and New Media
-- George Mason University, Fairfax, Virginia, USA
diff --git a/scripts/config.js b/scripts/config.js
index ec64adb9fc..a504b503bd 100644
--- a/scripts/config.js
+++ b/scripts/config.js
@@ -62,7 +62,11 @@ const browserifyConfigs = [
];
// exclude mask used for js, copy, symlink and sass tasks
-const ignoreMask = ['**/#*', '**/_*.scss'];
+const ignoreMask = [
+ '**/#*',
+ '**/_*.scss',
+ 'resource/schema/global/schema.json.gz'
+];
const jsFiles = [
`{${dirs.join(',')}}/**/*.js`,
diff --git a/test/tests/collectionTest.js b/test/tests/collectionTest.js
index 1f5d8b027c..ec60aedc38 100644
--- a/test/tests/collectionTest.js
+++ b/test/tests/collectionTest.js
@@ -262,6 +262,29 @@ describe("Zotero.Collection", function() {
});
})
+ describe("#fromJSON()", function () {
+ it("should ignore unknown property in non-strict mode", function () {
+ var json = {
+ name: "Collection",
+ foo: "Bar"
+ };
+ var s = new Zotero.Collection();
+ s.fromJSON(json);
+ });
+
+ it("should throw on unknown property in strict mode", function () {
+ var json = {
+ name: "Collection",
+ foo: "Bar"
+ };
+ var s = new Zotero.Collection();
+ var f = () => {
+ s.fromJSON(json, { strict: true });
+ };
+ assert.throws(f, /^Unknown collection property/);
+ });
+ });
+
describe("#toJSON()", function () {
it("should set 'parentCollection' to false when cleared", function* () {
var col1 = yield createDataObject('collection');
diff --git a/test/tests/data/itemJSON.js b/test/tests/data/itemJSON.js
index b63ea4df9f..efdbb96ec8 100644
--- a/test/tests/data/itemJSON.js
+++ b/test/tests/data/itemJSON.js
@@ -1262,7 +1262,7 @@
"dateAdded": "2015-04-12T09:00:22Z",
"dateModified": "2015-04-12T09:00:22Z",
"extra": "Extra",
- "filingDate": "2000-01-02 2000-01-02",
+ "filingDate": "2000-01-02",
"issueDate": "1999-12-31",
"issuingAuthority": "Issuing authority",
"itemType": "patent",
diff --git a/test/tests/data/translatorExport.js b/test/tests/data/translatorExport.js
index a8cc3ab43c..80a9556b67 100644
--- a/test/tests/data/translatorExport.js
+++ b/test/tests/data/translatorExport.js
@@ -1311,7 +1311,7 @@
"dateAdded": "2015-04-12T05:45:15Z",
"dateModified": "2015-04-12T05:45:15Z",
"extra": "Extra",
- "filingDate": "2000-01-02 2000-01-02",
+ "filingDate": "2000-01-02",
"issueDate": "1999-12-31",
"issuingAuthority": "Issuing authority",
"itemType": "patent",
diff --git a/test/tests/data/translatorExportLegacy.js b/test/tests/data/translatorExportLegacy.js
index e4840b1363..1c865a5896 100644
--- a/test/tests/data/translatorExportLegacy.js
+++ b/test/tests/data/translatorExportLegacy.js
@@ -1899,7 +1899,7 @@
"dateAdded": "2015-04-26 06:40:48",
"dateModified": "2015-04-26 06:40:48",
"extra": "Extra",
- "filingDate": "2000-01-02 2000-01-02",
+ "filingDate": "2000-01-02",
"issueDate": "1999-12-31",
"issuingAuthority": "Issuing authority",
"itemID": 95,
@@ -1929,7 +1929,7 @@
"country": "Country",
"date": "1999-12-31",
"extra": "Extra",
- "filingDate": "2000-01-02 2000-01-02",
+ "filingDate": "2000-01-02",
"issuingAuthority": "Issuing authority",
"language": "en-US",
"legalStatus": "Legal status",
diff --git a/test/tests/dataObjectUtilitiesTest.js b/test/tests/dataObjectUtilitiesTest.js
index 5372ca0b1b..148fc36945 100644
--- a/test/tests/dataObjectUtilitiesTest.js
+++ b/test/tests/dataObjectUtilitiesTest.js
@@ -47,6 +47,15 @@ describe("Zotero.DataObjectUtilities", function() {
assert.equal(obj.conditions[0].value, 'B');
assert.equal(obj.conditions[1].value, 'en');
})
+
+ it("should omit unknown base properties", function () {
+ var patchBase = {
+ unknownField: 'Foo'
+ };
+ var obj = {};
+ obj = Zotero.DataObjectUtilities.patch(patchBase, obj);
+ assert.notProperty(obj, 'unknownField');
+ });
})
describe("#diff()", function () {
diff --git a/test/tests/itemTest.js b/test/tests/itemTest.js
index 97b06d8b2f..d5947b53ea 100644
--- a/test/tests/itemTest.js
+++ b/test/tests/itemTest.js
@@ -507,7 +507,7 @@ describe("Zotero.Item", function () {
});
});
- describe("#setCreators", function () {
+ describe("#setCreators()", function () {
it("should accept an array of creators in API JSON format", function* () {
var creators = [
{
@@ -534,13 +534,13 @@ describe("Zotero.Item", function () {
firstName: "First",
lastName: "Last",
fieldMode: 0,
- creatorTypeID: 1
+ creatorTypeID: Zotero.CreatorTypes.getID('author')
},
{
firstName: "",
lastName: "Test Name",
fieldMode: 1,
- creatorTypeID: 2
+ creatorTypeID: Zotero.CreatorTypes.getID('editor')
}
];
@@ -558,13 +558,75 @@ describe("Zotero.Item", function () {
firstName: "First",
lastName: "Last",
fieldMode: 0,
- creatorTypeID: 1
+ creatorTypeID: Zotero.CreatorTypes.getID('author')
}
]);
assert.lengthOf(item.getCreators(), 1);
item.setCreators([]);
assert.lengthOf(item.getCreators(), 0);
});
+
+ it("should switch to primary creator type if unknown type given", function () {
+ var item = createUnsavedDataObject('item', { itemType: 'book' });
+ item.setCreators([
+ {
+ firstName: "First",
+ lastName: "Last",
+ creatorType: "unknown"
+ }
+ ]);
+ assert.equal(item.getCreators()[0].creatorTypeID, Zotero.CreatorTypes.getID('author'));
+ });
+
+ it("should switch to primary creator type on invalid creator type for a given item type", function () {
+ var item = createUnsavedDataObject('item', { itemType: 'book' });
+ item.setCreators([
+ {
+ firstName: "First",
+ lastName: "Last",
+ creatorType: "interviewee"
+ }
+ ]);
+ assert.equal(item.getCreators()[0].creatorTypeID, Zotero.CreatorTypes.getID('author'));
+ });
+
+ it("should throw on unknown creator type in strict mode", function () {
+ var item = createUnsavedDataObject('item', { itemType: 'book' });
+ var f = () => {
+ item.setCreators(
+ [
+ {
+ firstName: "First",
+ lastName: "Last",
+ creatorType: "unknown"
+ }
+ ],
+ {
+ strict: true
+ }
+ );
+ };
+ assert.throws(f, /^Unknown creator type/);
+ });
+
+ it("should throw on invalid creator type for a given item type in strict mode", function () {
+ var item = createUnsavedDataObject('item', { itemType: 'book' });
+ var f = () => {
+ item.setCreators(
+ [
+ {
+ firstName: "First",
+ lastName: "Last",
+ creatorType: "interviewee"
+ }
+ ],
+ {
+ strict: true
+ }
+ );
+ }
+ assert.throws(f, /^Invalid creator type/);
+ });
})
@@ -1692,16 +1754,150 @@ describe("Zotero.Item", function () {
assert.isFalse(item.inPublications);
});
- it("should ignore unknown fields", function* () {
+ // Not currently following this behavior
+ /*it("should move valid field in Extra to field if not set", function () {
+ var doi = '10.1234/abcd';
var json = {
itemType: "journalArticle",
title: "Test",
- foo: "Invalid"
+ extra: `DOI: ${doi}`
+ };
+ var item = new Zotero.Item;
+ item.fromJSON(json);
+ assert.equal(item.getField('DOI'), doi);
+ assert.equal(item.getField('extra'), '');
+ });
+
+ it("shouldn't move valid field in Extra to field if also present in JSON", function () {
+ var doi1 = '10.1234/abcd';
+ var doi2 = '10.2345/bcde';
+ var json = {
+ itemType: "journalArticle",
+ title: "Test",
+ DOI: doi1,
+ extra: `doi: ${doi2}`
+ };
+ var item = new Zotero.Item;
+ item.fromJSON(json);
+ assert.equal(item.getField('DOI'), doi1);
+ assert.equal(item.getField('extra'), `doi: ${doi2}`);
+ });
+
+ it("shouldn't move valid field in Extra to field if already set", function () {
+ var doi1 = '10.1234/abcd';
+ var doi2 = '10.2345/bcde';
+ var json = {
+ itemType: "journalArticle",
+ title: "Test",
+ DOI: doi1,
+ extra: `doi: ${doi2}`
+ };
+ var item = new Zotero.Item('journalArticle');
+ item.setField('DOI', doi1);
+ item.fromJSON(json);
+ assert.equal(item.getField('DOI'), doi1);
+ assert.equal(item.getField('extra'), `doi: ${doi2}`);
+ });*/
+
+ it("should store unknown field in Extra in non-strict mode", function () {
+ var json = {
+ itemType: "journalArticle",
+ title: "Test",
+ foo: "Bar"
};
var item = new Zotero.Item;
item.fromJSON(json);
assert.equal(item.getField('title'), 'Test');
- })
+ assert.equal(item.getField('extra'), 'foo: Bar');
+ });
+
+ it("should replace unknown field in Extra in non-strict mode", function () {
+ var json = {
+ itemType: "journalArticle",
+ title: "Test",
+ foo: "BBB",
+ extra: "Foo: AAA\nBar: CCC"
+ };
+ var item = new Zotero.Item;
+ item.fromJSON(json);
+ assert.equal(item.getField('title'), 'Test');
+ assert.equal(item.getField('extra'), 'Foo: BBB\nBar: CCC');
+ });
+
+ it("should handle Extra in non-strict mode", function () {
+ var json = {
+ itemType: "journalArticle",
+ title: "Test",
+ extra: "Here's some extra text"
+ };
+ var item = new Zotero.Item();
+ item.fromJSON(json);
+ assert.equal(item.getField('extra'), json.extra);
+ });
+
+ it("should throw on unknown field in strict mode", function () {
+ var json = {
+ itemType: "journalArticle",
+ title: "Test",
+ foo: "Bar"
+ };
+ var item = new Zotero.Item;
+ var f = () => {
+ item.fromJSON(json, { strict: true });
+ };
+ assert.throws(f, /^Unknown field/);
+ });
+
+ it("should throw on invalid field for a given item type in strict mode", function () {
+ var json = {
+ itemType: "journalArticle",
+ title: "Test",
+ numPages: "123"
+ };
+ var item = new Zotero.Item;
+ var f = () => {
+ item.fromJSON(json, { strict: true });
+ };
+ assert.throws(f, /^Invalid field/);
+ });
+
+ it("should throw on unknown creator type in strict mode", function () {
+ var json = {
+ itemType: "journalArticle",
+ title: "Test",
+ creators: [
+ {
+ firstName: "First",
+ lastName: "Last",
+ creatorType: "unknown"
+ }
+ ]
+ };
+ var item = new Zotero.Item;
+ var f = () => {
+ item.fromJSON(json, { strict: true });
+ };
+ assert.throws(f, /^Unknown creator type/);
+ });
+
+ it("should throw on invalid creator type for a given item type in strict mode", function () {
+ var json = {
+ itemType: "journalArticle",
+ title: "Test",
+ creators: [
+ {
+ firstName: "First",
+ lastName: "Last",
+ creatorType: "interviewee"
+ }
+ ]
+ };
+ var item = new Zotero.Item;
+ var f = () => {
+ item.fromJSON(json, { strict: true });
+ };
+ assert.throws(f, /^Invalid creator type/);
+ });
it("should accept ISO 8601 dates", function* () {
var json = {
diff --git a/test/tests/schemaTest.js b/test/tests/schemaTest.js
index b9f9ef523d..21292b9dc2 100644
--- a/test/tests/schemaTest.js
+++ b/test/tests/schemaTest.js
@@ -25,6 +25,59 @@ describe("Zotero.Schema", function() {
});
});
+ describe("Global Schema", function () {
+ var schemaJSON, schema;
+
+ before(async function () {
+ schemaJSON = await Zotero.File.getResourceAsync('resource://zotero/schema/global/schema.json');
+ });
+
+ beforeEach(async function () {
+ await resetDB({
+ thisArg: this,
+ skipBundledFiles: true
+ });
+ schema = JSON.parse(schemaJSON);
+ });
+
+ after(async function() {
+ await resetDB({
+ thisArg: this,
+ skipBundledFiles: true
+ });
+ });
+
+ describe("#migrateExtraFields()", function () {
+ it("should add a new field and migrate values from Extra", async function () {
+ var item = await createDataObject('item', { itemType: 'book' });
+ item.setField('numPages', "10");
+ item.setField('extra', 'Foo Bar: This is a value.\nnumber-of-pages: 11\nThis is another line.');
+ item.synced = true;
+ await item.saveTx();
+
+ schema.version++;
+ schema.itemTypes.find(x => x.itemType == 'book').fields.splice(0, 1, { field: 'fooBar' })
+ var newLocales = {};
+ Object.keys(schema.locales).forEach((locale) => {
+ var o = schema.locales[locale];
+ o.fields.fooBar = 'Foo Bar';
+ newLocales[locale] = o;
+ });
+ await Zotero.Schema._updateGlobalSchemaForTest(schema);
+ await Zotero.Schema.migrateExtraFields();
+
+ assert.isNumber(Zotero.ItemFields.getID('fooBar'));
+ assert.equal(Zotero.ItemFields.getLocalizedString('fooBar'), 'Foo Bar');
+ assert.equal(item.getField('fooBar'), 'This is a value.');
+ // Existing fields shouldn't be overwritten and should be left in Extra
+ assert.equal(item.getField('numPages'), '10');
+ assert.equal(item.getField('extra'), 'number-of-pages: 11\nThis is another line.');
+ assert.isTrue(item.synced);
+ });
+ });
+ });
+
+
describe("#integrityCheck()", function () {
before(function* () {
yield resetDB({
diff --git a/test/tests/searchTest.js b/test/tests/searchTest.js
index d66c687eee..d9caf0a924 100644
--- a/test/tests/searchTest.js
+++ b/test/tests/searchTest.js
@@ -509,5 +509,40 @@ describe("Zotero.Search", function() {
assert.equal(conditions["1"].operator, 'is');
assert.equal(conditions["1"].value, '2016');
});
+
+ it("should ignore unknown property in non-strict mode", function () {
+ var json = {
+ name: "Search",
+ conditions: [
+ {
+ condition: 'title',
+ operator: 'contains',
+ value: 'foo'
+ }
+ ],
+ foo: "Bar"
+ };
+ var s = new Zotero.Search();
+ s.fromJSON(json);
+ });
+
+ it("should throw on unknown property in strict mode", function () {
+ var json = {
+ name: "Search",
+ conditions: [
+ {
+ condition: 'title',
+ operator: 'contains',
+ value: 'foo'
+ }
+ ],
+ foo: "Bar"
+ };
+ var s = new Zotero.Search();
+ var f = () => {
+ s.fromJSON(json, { strict: true });
+ };
+ assert.throws(f, /^Unknown search property/);
+ });
});
});
diff --git a/test/tests/syncEngineTest.js b/test/tests/syncEngineTest.js
index 87d8b23a13..906998e5fb 100644
--- a/test/tests/syncEngineTest.js
+++ b/test/tests/syncEngineTest.js
@@ -1480,7 +1480,7 @@ describe("Zotero.Sync.Data.Engine", function () {
yield engine.start();
})
- it("should ignore errors when saving downloaded objects", function* () {
+ it("should add objects to sync queue if they can't be saved", function* () {
({ engine, client, caller } = yield setup({
stopOnError: false
}));
@@ -1560,7 +1560,7 @@ describe("Zotero.Sync.Data.Engine", function () {
key: "CCCCCCCC",
version: 1,
name: "C",
- // Unknown field -- should be ignored
+ // Unknown field -- collection should be queued
unknownField: 5
})
]
@@ -1622,7 +1622,7 @@ describe("Zotero.Sync.Data.Engine", function () {
version: 3,
itemType: "book",
title: "G",
- // Unknown item field -- should be ignored
+ // Unknown item field -- item should be queued
unknownField: "B"
}),
makeItemJSON({
@@ -1668,7 +1668,6 @@ describe("Zotero.Sync.Data.Engine", function () {
// Check for saved objects
yield assert.eventually.ok(Zotero.Collections.getByLibraryAndKeyAsync(userLibraryID, "AAAAAAAA"));
yield assert.eventually.ok(Zotero.Searches.getByLibraryAndKeyAsync(userLibraryID, "DDDDDDDD"));
- yield assert.eventually.ok(Zotero.Items.getByLibraryAndKeyAsync(userLibraryID, "GGGGGGGG"));
// Check for queued objects
var keys = yield Zotero.Sync.Data.Local.getObjectsFromSyncQueue('collection', userLibraryID);
@@ -1678,9 +1677,13 @@ describe("Zotero.Sync.Data.Engine", function () {
assert.sameMembers(keys, ['EEEEEEEE', 'FFFFFFFF']);
var keys = yield Zotero.Sync.Data.Local.getObjectsFromSyncQueue('item', userLibraryID);
- assert.sameMembers(keys, ['HHHHHHHH', 'JJJJJJJJ']);
+ assert.sameMembers(keys, ['GGGGGGGG', 'HHHHHHHH', 'JJJJJJJJ']);
- assert.equal(spy.callCount, 3);
+ // Unknown search condition, search operator, item field, and item type
+ //
+ // Missing parent collection and item collection don't throw errors because they don't
+ // indicate a guaranteed problem with the client
+ assert.equal(spy.callCount, 4);
});
it("should delay on second upload conflict", function* () {
diff --git a/test/tests/utilities_internalTest.js b/test/tests/utilities_internalTest.js
index 312160ce64..212db95930 100644
--- a/test/tests/utilities_internalTest.js
+++ b/test/tests/utilities_internalTest.js
@@ -114,32 +114,152 @@ describe("Zotero.Utilities.Internal", function () {
describe("#extractExtraFields()", function () {
+ it("should extract a CSL type", function () {
+ var str = 'type: motion_picture';
+ var { itemType, fields, extra } = Zotero.Utilities.Internal.extractExtraFields(str);
+ assert.equal(itemType, 'videoRecording');
+ assert.equal(fields.size, 0);
+ assert.strictEqual(extra, '');
+ });
+
it("should extract a field", function () {
var val = '10.1234/abcdef';
var str = `DOI: ${val}`;
- var fields = Zotero.Utilities.Internal.extractExtraFields(str);
+ var { fields, extra } = Zotero.Utilities.Internal.extractExtraFields(str);
assert.equal(fields.size, 1);
- assert.equal(fields.get('DOI').value, val);
+ assert.equal(fields.get('DOI'), val);
+ assert.strictEqual(extra, '');
+ });
+
+ it("should extract a field for a given item", function () {
+ var item = createUnsavedDataObject('item', { itemType: 'journalArticle' });
+ var val = '10.1234/abcdef';
+ var str = `DOI: ${val}`;
+ var { fields, extra } = Zotero.Utilities.Internal.extractExtraFields(str, item);
+ assert.equal(fields.size, 1);
+ assert.equal(fields.get('DOI'), val);
+ assert.strictEqual(extra, '');
+ });
+
+ it("should extract a CSL field", function () {
+ var val = '10.1234/abcdef';
+ var str = `container-title: ${val}`;
+ var { fields, extra } = Zotero.Utilities.Internal.extractExtraFields(str);
+ assert.equal(fields.size, Zotero.Schema.CSL_TEXT_MAPPINGS['container-title'].length);
+ assert.equal(fields.get('publicationTitle'), val);
+ assert.strictEqual(extra, '');
+ });
+
+ it("should extract a CSL field for a given item type", function () {
+ var item = createUnsavedDataObject('item', { itemType: 'journalArticle' });
+ var val = '10.1234/abcdef';
+ var str = `container-title: ${val}`;
+ var { fields, extra } = Zotero.Utilities.Internal.extractExtraFields(str, item);
+ assert.equal(fields.size, 1);
+ assert.equal(fields.get('publicationTitle'), val);
+ assert.strictEqual(extra, '');
});
it("should extract a field with different case", function () {
var val = '10.1234/abcdef';
var str = `doi: ${val}`;
- var fields = Zotero.Utilities.Internal.extractExtraFields(str);
+ var { fields, extra } = Zotero.Utilities.Internal.extractExtraFields(str);
assert.equal(fields.size, 1);
- assert.equal(fields.get('DOI').value, val);
+ assert.equal(fields.get('DOI'), val);
+ assert.strictEqual(extra, '');
});
it("should extract a field with other fields, text, and whitespace", function () {
- var originalDateVal = '1989';
- var doiVal = '10.1234/abcdef';
- var str = `\nOriginal Date: ${originalDateVal}\nDOI: ${doiVal}\n\n`;
- var fields = Zotero.Utilities.Internal.extractExtraFields(str);
+ var place = 'New York';
+ var doi = '10.1234/abcdef';
+ var str = `Line 1\nPublisher Place: ${place}\nFoo: Bar\nDOI: ${doi}\n\nLine 2`;
+ var { fields, extra } = Zotero.Utilities.Internal.extractExtraFields(str);
+ assert.equal(fields.size, 2);
+ assert.equal(fields.get('DOI'), doi);
+ assert.equal(fields.get('place'), place);
+ assert.equal(extra, 'Line 1\nFoo: Bar\n\nLine 2');
+ });
+
+ it("should extract the first instance of a field", function () {
+ var place1 = 'New York';
+ var place2 = 'London';
+ var str = `Publisher Place: ${place1}\nPublisher Place: ${place2}`;
+ var { fields, extra } = Zotero.Utilities.Internal.extractExtraFields(str);
assert.equal(fields.size, 1);
- assert.equal(fields.get('DOI').value, doiVal);
+ assert.equal(fields.get('place'), place1);
+ assert.equal(extra, "Publisher Place: " + place2);
+ });
+
+ it("shouldn't extract a field that already exists on the item", function () {
+ var item = createUnsavedDataObject('item', { itemType: 'book' });
+ item.setField('numPages', 10);
+ var str = 'number-of-pages: 11';
+ var { fields, extra } = Zotero.Utilities.Internal.extractExtraFields(str, item);
+ assert.equal(fields.size, 0);
+ });
+
+ it("should extract a CSL name", function () {
+ var str = 'container-author: First || Last';
+ var { creators, extra } = Zotero.Utilities.Internal.extractExtraFields(str);
+ assert.lengthOf(creators, 1);
+ assert.propertyVal(creators[0], 'creatorType', 'bookAuthor');
+ assert.propertyVal(creators[0], 'firstName', 'First');
+ assert.propertyVal(creators[0], 'lastName', 'Last');
+ assert.strictEqual(extra, '');
+ });
+
+ it("should extract a CSL name that's valid for a given item type", function () {
+ var item = createUnsavedDataObject('item', { itemType: 'bookSection' });
+ var str = 'container-author: First || Last';
+ var { creators, extra } = Zotero.Utilities.Internal.extractExtraFields(str, item);
+ assert.lengthOf(creators, 1);
+ assert.propertyVal(creators[0], 'creatorType', 'bookAuthor');
+ assert.propertyVal(creators[0], 'firstName', 'First');
+ assert.propertyVal(creators[0], 'lastName', 'Last');
+ assert.strictEqual(extra, '');
+ });
+
+ it("shouldn't extract a CSL name that's not valid for a given item type", function () {
+ var item = createUnsavedDataObject('item', { itemType: 'journalArticle' });
+ var str = 'container-author: First || Last';
+ var { creators, extra } = Zotero.Utilities.Internal.extractExtraFields(str, item);
+ assert.lengthOf(creators, 0);
+ assert.strictEqual(extra, str);
});
});
+ describe("#combineExtraFields", function () {
+ var originalDate = "1887";
+ var publicationPlace = "New York";
+ var doi = '10.1234/123456789';
+ var fieldMap = new Map();
+ fieldMap.set('originalDate', originalDate);
+ fieldMap.set('publicationPlace', publicationPlace);
+ fieldMap.set('DOI', doi);
+ var fieldStr = `DOI: ${doi}\noriginalDate: ${originalDate}\npublicationPlace: ${publicationPlace}`;
+
+ it("should create 'field: value' pairs from field map", function () {
+ var extra = "";
+ var newExtra = ZUI.combineExtraFields(extra, fieldMap);
+ assert.equal(newExtra, fieldStr);
+ });
+
+ it("should add fields above existing Extra content", function () {
+ var extra = "This is a note.";
+ var newExtra = ZUI.combineExtraFields(extra, fieldMap);
+ assert.equal(newExtra, fieldStr + '\n' + extra);
+ });
+
+ it("should replace existing fields", function () {
+ var extra = "This is a note.\nOriginal Date: 1886\nFoo: Bar";
+ var newExtra = ZUI.combineExtraFields(extra, fieldMap);
+ assert.equal(
+ newExtra,
+ fieldStr.split(/\n/).filter(x => !x.startsWith('originalDate')).join("\n")
+ + "\nThis is a note.\nOriginal Date: 1887\nFoo: Bar"
+ );
+ });
+ });
describe("#extractIdentifiers()", function () {
it("should extract ISBN-10", async function () {