253 lines
7.3 KiB
JavaScript
253 lines
7.3 KiB
JavaScript
/*
|
|
***** BEGIN LICENSE BLOCK *****
|
|
|
|
Copyright © 2009 Center for History and New Media
|
|
George Mason University, Fairfax, Virginia, USA
|
|
http://zotero.org
|
|
|
|
This file is part of Zotero.
|
|
|
|
Zotero is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Zotero is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***** END LICENSE BLOCK *****
|
|
*/
|
|
|
|
|
|
Zotero.Creators = new function() {
|
|
this.fields = ['firstName', 'lastName', 'fieldMode'];
|
|
this.totes = 0;
|
|
|
|
var _cache = {};
|
|
|
|
this.init = Zotero.Promise.coroutine(function* () {
|
|
var repaired = false;
|
|
var sql = "SELECT * FROM creators";
|
|
var rows = yield Zotero.DB.queryAsync(sql);
|
|
for (let i = 0; i < rows.length; i++) {
|
|
let row = rows[i];
|
|
try {
|
|
_cache[row.creatorID] = this.cleanData({
|
|
// Avoid "DB column 'name' not found" warnings from the DB row Proxy
|
|
firstName: row.firstName,
|
|
lastName: row.lastName,
|
|
fieldMode: row.fieldMode
|
|
});
|
|
}
|
|
catch (e) {
|
|
// Automatically fix DB errors and try again
|
|
if (!repaired) {
|
|
Zotero.logError(e);
|
|
Zotero.logError("Trying integrity check to fix creator error");
|
|
yield Zotero.Schema.integrityCheck(true);
|
|
repaired = true;
|
|
rows = yield Zotero.DB.queryAsync(sql);
|
|
i = -1;
|
|
continue;
|
|
}
|
|
|
|
throw e;
|
|
}
|
|
}
|
|
});
|
|
|
|
/*
|
|
* Returns creator data in internal format for a given creatorID
|
|
*/
|
|
this.get = function (creatorID) {
|
|
if (!creatorID) {
|
|
throw new Error("creatorID not provided");
|
|
}
|
|
|
|
if (!_cache[creatorID]) {
|
|
throw new Error("Creator " + creatorID + " not found");
|
|
}
|
|
|
|
// Return copy of data
|
|
return this.cleanData(_cache[creatorID]);
|
|
};
|
|
|
|
|
|
this.getItemsWithCreator = function (creatorID) {
|
|
var sql = "SELECT DISTINCT itemID FROM itemCreators WHERE creatorID=?";
|
|
return Zotero.DB.columnQueryAsync(sql, creatorID);
|
|
}
|
|
|
|
|
|
this.countItemAssociations = function (creatorID) {
|
|
var sql = "SELECT COUNT(*) FROM itemCreators WHERE creatorID=?";
|
|
return Zotero.DB.valueQueryAsync(sql, creatorID);
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the creatorID matching given fields, or creates a new creator and returns its id
|
|
*
|
|
* @requireTransaction
|
|
* @param {Object} data Creator data in API JSON format
|
|
* @param {Boolean} [create=false] If no matching creator, create one
|
|
* @return {Promise<Integer>} creatorID
|
|
*/
|
|
this.getIDFromData = Zotero.Promise.coroutine(function* (data, create) {
|
|
Zotero.DB.requireTransaction();
|
|
data = this.cleanData(data);
|
|
var sql = "SELECT creatorID FROM creators WHERE "
|
|
+ "firstName=? AND lastName=? AND fieldMode=?";
|
|
var id = yield Zotero.DB.valueQueryAsync(
|
|
sql, [data.firstName, data.lastName, data.fieldMode]
|
|
);
|
|
if (!id && create) {
|
|
id = Zotero.ID.get('creators');
|
|
let sql = "INSERT INTO creators (creatorID, firstName, lastName, fieldMode) "
|
|
+ "VALUES (?, ?, ?, ?)";
|
|
yield Zotero.DB.queryAsync(
|
|
sql, [id, data.firstName, data.lastName, data.fieldMode]
|
|
);
|
|
_cache[id] = data;
|
|
}
|
|
return id;
|
|
});
|
|
|
|
|
|
this.updateCreator = Zotero.Promise.coroutine(function* (creatorID, creatorData) {
|
|
var creator = yield this.get(creatorID);
|
|
if (!creator) {
|
|
throw new Error("Creator " + creatorID + " doesn't exist");
|
|
}
|
|
creator.fieldMode = creatorData.fieldMode;
|
|
creator.firstName = creatorData.firstName;
|
|
creator.lastName = creatorData.lastName;
|
|
return creator.save();
|
|
});
|
|
|
|
|
|
/**
|
|
* Delete obsolete creator rows from database and clear internal cache entries
|
|
*
|
|
* @return {Promise}
|
|
*/
|
|
this.purge = Zotero.Promise.coroutine(function* () {
|
|
if (!Zotero.Prefs.get('purge.creators')) {
|
|
return;
|
|
}
|
|
|
|
Zotero.debug("Purging creator tables");
|
|
|
|
var sql = 'SELECT creatorID FROM creators WHERE creatorID NOT IN '
|
|
+ '(SELECT creatorID FROM itemCreators)';
|
|
var toDelete = yield Zotero.DB.columnQueryAsync(sql);
|
|
if (toDelete.length) {
|
|
// Clear creator entries in internal array
|
|
for (let i=0; i<toDelete.length; i++) {
|
|
delete _cache[toDelete[i]];
|
|
}
|
|
|
|
var sql = "DELETE FROM creators WHERE creatorID NOT IN "
|
|
+ "(SELECT creatorID FROM itemCreators)";
|
|
yield Zotero.DB.queryAsync(sql);
|
|
}
|
|
|
|
Zotero.Prefs.set('purge.creators', false);
|
|
});
|
|
|
|
|
|
this.equals = function (data1, data2) {
|
|
data1 = this.cleanData(data1);
|
|
data2 = this.cleanData(data2);
|
|
return data1.lastName === data2.lastName
|
|
&& data1.firstName === data2.firstName
|
|
&& data1.fieldMode === data2.fieldMode
|
|
&& data1.creatorTypeID === data2.creatorTypeID;
|
|
},
|
|
|
|
|
|
this.cleanData = function (data) {
|
|
// Validate data
|
|
if (data.name === undefined && data.lastName === undefined) {
|
|
throw new Error("Creator data must contain either 'name' or 'firstName'/'lastName' properties");
|
|
}
|
|
if (data.name !== undefined && (data.firstName !== undefined || data.lastName !== undefined)) {
|
|
throw new Error("Creator data cannot contain both 'name' and 'firstName'/'lastName' properties");
|
|
}
|
|
if (data.name !== undefined && data.fieldMode === 0) {
|
|
throw new Error("'fieldMode' cannot be 0 with 'name' property");
|
|
}
|
|
if (data.fieldMode === 1
|
|
&& !(data.firstName === undefined || data.firstName === "" || data.firstName === null)) {
|
|
throw new Error("'fieldMode' cannot be 1 with 'firstName' property");
|
|
}
|
|
if (data.name !== undefined && typeof data.name != 'string') {
|
|
throw new Error("'name' must be a string");
|
|
}
|
|
if (data.firstName !== undefined && data.firstName !== null && typeof data.firstName != 'string') {
|
|
throw new Error("'firstName' must be a string");
|
|
}
|
|
if (data.lastName !== undefined && typeof data.lastName != 'string') {
|
|
throw new Error("'lastName' must be a string");
|
|
}
|
|
|
|
var cleanedData = {
|
|
fieldMode: 0,
|
|
firstName: '',
|
|
lastName: ''
|
|
};
|
|
for (let i=0; i<this.fields.length; i++) {
|
|
let field = this.fields[i];
|
|
let val = data[field];
|
|
switch (field) {
|
|
case 'firstName':
|
|
case 'lastName':
|
|
if (val === undefined || val === null) continue;
|
|
cleanedData[field] = val.trim().normalize();
|
|
break;
|
|
|
|
case 'fieldMode':
|
|
cleanedData[field] = val ? parseInt(val) : 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Handle API JSON .name
|
|
if (data.name !== undefined) {
|
|
cleanedData.lastName = data.name.trim().normalize();
|
|
cleanedData.fieldMode = 1;
|
|
}
|
|
|
|
var creatorType = data.creatorType || data.creatorTypeID;
|
|
if (creatorType) {
|
|
cleanedData.creatorTypeID = Zotero.CreatorTypes.getID(creatorType);
|
|
if (!cleanedData.creatorTypeID) {
|
|
let msg = "'" + creatorType + "' isn't a valid creator type";
|
|
Zotero.debug(msg, 2);
|
|
Components.utils.reportError(msg);
|
|
}
|
|
}
|
|
|
|
return cleanedData;
|
|
}
|
|
|
|
|
|
this.internalToJSON = function (fields) {
|
|
var obj = {};
|
|
if (fields.fieldMode == 1) {
|
|
obj.name = fields.lastName;
|
|
}
|
|
else {
|
|
obj.firstName = fields.firstName;
|
|
obj.lastName = fields.lastName;
|
|
}
|
|
obj.creatorType = Zotero.CreatorTypes.getName(fields.creatorTypeID);
|
|
return obj;
|
|
}
|
|
}
|