Functions to modify 'version'/'synced' efficiently, plus some other fixes
This commit is contained in:
parent
cf3eed5f14
commit
ada657fcb8
|
@ -771,6 +771,74 @@ Zotero.DataObject.prototype._recoverFromSaveError = Zotero.Promise.coroutine(fun
|
|||
});
|
||||
|
||||
|
||||
/**
|
||||
* Update object version, efficiently
|
||||
*
|
||||
* Used by sync code
|
||||
*
|
||||
* @param {Integer} version
|
||||
* @param {Boolean} [skipDB=false]
|
||||
*/
|
||||
Zotero.DataObject.prototype.updateVersion = Zotero.Promise.coroutine(function* (version, skipDB) {
|
||||
if (!this.id) {
|
||||
throw new Error("Cannot update version of unsaved " + this._objectType);
|
||||
}
|
||||
if (version != parseInt(version)) {
|
||||
throw new Error("'version' must be an integer");
|
||||
}
|
||||
|
||||
this._version = parseInt(version);
|
||||
|
||||
if (!skipDB) {
|
||||
var cl = this.ObjectsClass;
|
||||
var sql = "UPDATE " + cl.table + " SET version=? WHERE " + cl.idColumn + "=?";
|
||||
yield Zotero.DB.queryAsync(sql, [parseInt(version), this.id]);
|
||||
}
|
||||
|
||||
if (this._changed.primaryData && this._changed.primaryData.version) {
|
||||
if (Objects.keys(this._changed.primaryData).length == 1) {
|
||||
delete this._changed.primaryData;
|
||||
}
|
||||
else {
|
||||
delete this._changed.primaryData.version;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Update object sync status, efficiently
|
||||
*
|
||||
* Used by sync code
|
||||
*
|
||||
* @param {Boolean} synced
|
||||
* @param {Boolean} [skipDB=false]
|
||||
*/
|
||||
Zotero.DataObject.prototype.updateSynced = Zotero.Promise.coroutine(function* (synced, skipDB) {
|
||||
if (!this.id) {
|
||||
throw new Error("Cannot update sync status of unsaved " + this._objectType);
|
||||
}
|
||||
if (typeof synced != 'boolean') {
|
||||
throw new Error("'synced' must be a boolean");
|
||||
}
|
||||
|
||||
this._synced = synced;
|
||||
|
||||
if (!skipDB) {
|
||||
var cl = this.ObjectsClass;
|
||||
var sql = "UPDATE " + cl.table + " SET synced=? WHERE " + cl.idColumn + "=?";
|
||||
yield Zotero.DB.queryAsync(sql, [synced ? 1 : 0, this.id]);
|
||||
}
|
||||
|
||||
if (this._changed.primaryData && this._changed.primaryData.synced) {
|
||||
if (Objects.keys(this._changed.primaryData).length == 1) {
|
||||
delete this._changed.primaryData;
|
||||
}
|
||||
else {
|
||||
delete this._changed.primaryData.synced;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Delete object from database
|
||||
*/
|
||||
|
|
|
@ -127,9 +127,10 @@ Zotero.DataObjects.prototype.get = function (ids) {
|
|||
* Retrieves (and loads, if necessary) one or more items
|
||||
*
|
||||
* @param {Array|Integer} ids An individual object id or an array of object ids
|
||||
* @param {Object} options 'noCache': Don't cache loaded objects
|
||||
* @return {Zotero.[Object]|Array<Zotero.[Object]>} A Zotero.[Object], if a scalar id was passed;
|
||||
* otherwise, an array of Zotero.[Object]
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.noCache=false] - Don't add object to cache after loading
|
||||
* @return {Zotero.DataObject|Zotero.DataObject[]} - A data object, if a scalar id was passed;
|
||||
* otherwise, an array of data objects
|
||||
*/
|
||||
Zotero.DataObjects.prototype.getAsync = Zotero.Promise.coroutine(function* (ids, options) {
|
||||
var toLoad = [];
|
||||
|
@ -253,6 +254,8 @@ Zotero.DataObjects.prototype.getByLibraryAndKey = function (libraryID, key, opti
|
|||
*
|
||||
* @param {Integer} - libraryID
|
||||
* @param {String} - key
|
||||
* @param {Object} [options]
|
||||
* @param {Boolean} [options.noCache=false] - Don't add object to cache after loading
|
||||
* @return {Promise<Zotero.DataObject>} - Promise for a data object, or FALSE if not found
|
||||
*/
|
||||
Zotero.DataObjects.prototype.getByLibraryAndKeyAsync = Zotero.Promise.coroutine(function* (libraryID, key, options) {
|
||||
|
@ -287,7 +290,7 @@ Zotero.DataObjects.prototype.getIDFromLibraryAndKey = function (libraryID, key)
|
|||
}
|
||||
|
||||
|
||||
Zotero.DataObjects.prototype.getOlder = function (libraryID, date) {
|
||||
Zotero.DataObjects.prototype.getOlder = Zotero.Promise.method(function (libraryID, date) {
|
||||
if (!date || date.constructor.name != 'Date') {
|
||||
throw ("date must be a JS Date in "
|
||||
+ "Zotero." + this._ZDO_Objects + ".getOlder()")
|
||||
|
@ -295,11 +298,11 @@ Zotero.DataObjects.prototype.getOlder = function (libraryID, date) {
|
|||
|
||||
var sql = "SELECT ROWID FROM " + this._ZDO_table
|
||||
+ " WHERE libraryID=? AND clientDateModified<?";
|
||||
return Zotero.DB.columnQuery(sql, [libraryID, Zotero.Date.dateToSQL(date, true)]);
|
||||
}
|
||||
return Zotero.DB.columnQueryAsync(sql, [libraryID, Zotero.Date.dateToSQL(date, true)]);
|
||||
});
|
||||
|
||||
|
||||
Zotero.DataObjects.prototype.getNewer = function (libraryID, date, ignoreFutureDates) {
|
||||
Zotero.DataObjects.prototype.getNewer = Zotero.Promise.method(function (libraryID, date, ignoreFutureDates) {
|
||||
if (!date || date.constructor.name != 'Date') {
|
||||
throw ("date must be a JS Date in "
|
||||
+ "Zotero." + this._ZDO_Objects + ".getNewer()")
|
||||
|
@ -310,8 +313,8 @@ Zotero.DataObjects.prototype.getNewer = function (libraryID, date, ignoreFutureD
|
|||
if (ignoreFutureDates) {
|
||||
sql += " AND clientDateModified<=CURRENT_TIMESTAMP";
|
||||
}
|
||||
return Zotero.DB.columnQuery(sql, [libraryID, Zotero.Date.dateToSQL(date, true)]);
|
||||
}
|
||||
return Zotero.DB.columnQueryAsync(sql, [libraryID, Zotero.Date.dateToSQL(date, true)]);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
|
@ -430,6 +433,61 @@ Zotero.DataObjects.prototype.unload = function () {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the version of objects, efficiently
|
||||
*
|
||||
* @param {Integer[]} ids - Ids of objects to update
|
||||
* @param {Boolean} synced
|
||||
*/
|
||||
Zotero.DataObjects.prototype.updateVersion = Zotero.Promise.method(function (ids, version) {
|
||||
if (version != parseInt(version)) {
|
||||
throw new Error("'version' must be an integer");
|
||||
}
|
||||
version = parseInt(version);
|
||||
|
||||
let sql = "UPDATE " + this.table + " SET version=" + version + " "
|
||||
+ "WHERE " + this.idColumn + " IN (";
|
||||
return Zotero.Utilities.Internal.forEachChunkAsync(
|
||||
ids, Zotero.DB.MAX_BOUND_PARAMETERS, Zotero.Promise.coroutine(function* (chunk) {
|
||||
yield Zotero.DB.queryAsync(sql + chunk.map(() => '?').join(', ') + ')', chunk);
|
||||
// Update the internal 'version' property of any loaded objects
|
||||
for (let i = 0; i < chunk.length; i++) {
|
||||
let id = chunk[i];
|
||||
let obj = this._objectCache[id];
|
||||
if (obj) {
|
||||
obj.updateVersion(version, true);
|
||||
}
|
||||
}
|
||||
}.bind(this))
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Set the sync state of objects, efficiently
|
||||
*
|
||||
* @param {Integer[]} ids - Ids of objects to update
|
||||
* @param {Boolean} synced
|
||||
*/
|
||||
Zotero.DataObjects.prototype.updateSynced = Zotero.Promise.method(function (ids, synced) {
|
||||
let sql = "UPDATE " + this.table + " SET synced=" + (synced ? 1 : 0) + " "
|
||||
+ "WHERE " + this.idColumn + " IN (";
|
||||
return Zotero.Utilities.Internal.forEachChunkAsync(
|
||||
ids, Zotero.DB.MAX_BOUND_PARAMETERS, Zotero.Promise.coroutine(function* (chunk) {
|
||||
yield Zotero.DB.queryAsync(sql + chunk.map(() => '?').join(', ') + ')', chunk);
|
||||
// Update the internal 'synced' property of any loaded objects
|
||||
for (let i = 0; i < chunk.length; i++) {
|
||||
let id = chunk[i];
|
||||
let obj = this._objectCache[id];
|
||||
if (obj) {
|
||||
obj.updateSynced(!!synced, true);
|
||||
}
|
||||
}
|
||||
}.bind(this))
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Zotero.DataObjects.prototype.isEditable = function (obj) {
|
||||
var libraryID = obj.libraryID;
|
||||
if (!libraryID) {
|
||||
|
|
|
@ -1742,17 +1742,6 @@ Zotero.Item.prototype._finalizeSave = Zotero.Promise.coroutine(function* (env) {
|
|||
return env.isNew ? this.id : true;
|
||||
});
|
||||
|
||||
/**
|
||||
* Used by sync code
|
||||
*/
|
||||
Zotero.Item.prototype.updateClientDateModified = function () {
|
||||
if (!this.id) {
|
||||
throw ("Cannot update clientDateModified of unsaved item in Zotero.Item.updateClientDateModified()");
|
||||
}
|
||||
var sql = "UPDATE items SET clientDateModified=? WHERE itemID=?";
|
||||
Zotero.DB.query(sql, [Zotero.DB.transactionDateTime, this.id]);
|
||||
}
|
||||
|
||||
|
||||
Zotero.Item.prototype.isRegularItem = function() {
|
||||
return !(this.isNote() || this.isAttachment());
|
||||
|
|
|
@ -35,7 +35,7 @@ Zotero.Utilities.Internal = {
|
|||
*
|
||||
* @param {Array} arr
|
||||
* @param {Integer} chunkSize
|
||||
* @param {Function} func
|
||||
* @param {Function} func - A promise-returning function
|
||||
* @return {Array} The return values from the successive runs
|
||||
*/
|
||||
"forEachChunkAsync": Zotero.Promise.coroutine(function* (arr, chunkSize, func) {
|
||||
|
|
|
@ -171,9 +171,8 @@ function createUnsavedDataObject(objectType, params) {
|
|||
|
||||
var createDataObject = Zotero.Promise.coroutine(function* (objectType, params, saveOptions) {
|
||||
var obj = createUnsavedDataObject(objectType, params);
|
||||
var id = yield obj.saveTx(saveOptions);
|
||||
var objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(objectType);
|
||||
return objectsClass.getAsync(id);
|
||||
yield obj.saveTx(saveOptions);
|
||||
return obj;
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,6 @@ describe("Zotero.DataObject", function() {
|
|||
|
||||
it("should be set after creating object", function* () {
|
||||
for (let type of types) {
|
||||
Zotero.logError(type);
|
||||
let obj = yield createDataObject(type, { version: 1234 });
|
||||
assert.equal(obj.version, 1234, type + " version mismatch");
|
||||
yield obj.eraseTx();
|
||||
|
@ -126,4 +125,50 @@ describe("Zotero.DataObject", function() {
|
|||
assert.equal(objectsClass.getIDFromLibraryAndKey(libraryID, key), id);
|
||||
})
|
||||
})
|
||||
|
||||
describe("#updateVersion()", function() {
|
||||
it("should update the object version", function* () {
|
||||
for (let type of types) {
|
||||
let obj = yield createDataObject(type);
|
||||
assert.equal(obj.version, 0);
|
||||
|
||||
yield obj.updateVersion(1234);
|
||||
assert.equal(obj.version, 1234);
|
||||
assert.isFalse(obj.hasChanged());
|
||||
|
||||
obj.synced = true;
|
||||
assert.ok(obj.hasChanged());
|
||||
yield obj.updateVersion(1235);
|
||||
assert.equal(obj.version, 1235);
|
||||
assert.ok(obj.hasChanged());
|
||||
|
||||
yield obj.eraseTx();
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#updateSynced()", function() {
|
||||
it("should update the object sync status", function* () {
|
||||
for (let type of types) {
|
||||
let obj = yield createDataObject(type);
|
||||
assert.isFalse(obj.synced);
|
||||
|
||||
yield obj.updateSynced(false);
|
||||
assert.isFalse(obj.synced);
|
||||
assert.isFalse(obj.hasChanged());
|
||||
|
||||
yield obj.updateSynced(true);
|
||||
assert.ok(obj.synced);
|
||||
assert.isFalse(obj.hasChanged());
|
||||
|
||||
obj.version = 1234;
|
||||
assert.ok(obj.hasChanged());
|
||||
yield obj.updateSynced(false);
|
||||
assert.isFalse(obj.synced);
|
||||
assert.ok(obj.hasChanged());
|
||||
|
||||
yield obj.eraseTx();
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue
Block a user