Load creators and primary data with less per-row work

- _loadCreators(): read columns by index in onRow as rows arrive instead of
  materializing every item/creator row as a Proxy, whose property reads
  each go through getResultByName()
- _loadPrimaryData(): compute the column list and ID column once per query
  rather than once per row
- ItemFields._getLoadInfo(): index the cache with arrays instead of a Map

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
TheNEwmanator15 2026-09-25 00:11:48 +01:00
parent 25621d3a21
commit 912801a349
3 changed files with 48 additions and 40 deletions

View file

@ -555,14 +555,17 @@ Zotero.DataObjects.prototype._loadPrimaryData = async function (libraryID, ids,
sql += ' AND O.' + this._ZDO_id + ' IN (' + ids.join(',') + ')';
}
var columns = Object.keys(this._primaryDataSQLParts);
var idColumn = columns.indexOf(this._ZDO_id);
await Zotero.DB.queryAsync(
sql,
params,
{
noCache: true,
onRow: function (row) {
var id = row.getResultByName(this._ZDO_id);
var columns = Object.keys(this._primaryDataSQLParts);
var id = idColumn != -1
? row.getResultByIndex(idColumn)
: row.getResultByName(this._ZDO_id);
var rowObj = {};
for (let i=0; i<columns.length; i++) {
rowObj[columns[i]] = row.getResultByIndex(i);

View file

@ -154,9 +154,9 @@ Zotero.ItemFields = new function () {
}
var byField = _loadInfo[itemTypeID];
if (!byField) {
byField = _loadInfo[itemTypeID] = new Map();
byField = _loadInfo[itemTypeID] = [];
}
var info = byField.get(fieldID);
var info = byField[fieldID];
if (info === undefined) {
if (!this.getID(fieldID)) {
info = false;
@ -171,7 +171,7 @@ Zotero.ItemFields = new function () {
isISBN: resolvedID == this.getID('ISBN')
};
}
byField.set(fieldID, info);
byField[fieldID] = info;
}
return info;
};

View file

@ -404,7 +404,6 @@ Zotero.Items = function () {
+ 'FROM items LEFT JOIN itemCreators USING (itemID) '
+ 'WHERE libraryID=?' + idSQL + " ORDER BY itemID, orderIndex";
var params = [libraryID];
var rows = await Zotero.DB.queryAsync(sql, params, { noCache: true });
// Mark creator indexes above the number of creators as changed,
// so that they're cleared if the item is saved
@ -425,46 +424,52 @@ Zotero.Items = function () {
var item;
var index = 0;
var maxOrderIndex = -1;
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
let itemID = row.itemID;
if (itemID != lastItemID) {
if (!this._objectCache[itemID]) {
throw new Error("Item " + itemID + " not loaded");
}
item = this._objectCache[itemID];
// Read columns by index as rows arrive, rather than building a Proxy row
// object for every item/creator pair
await Zotero.DB.queryAsync(sql, params, {
noCache: true,
onRow: (row, cancel) => {
let itemID = row.getResultByIndex(0);
let creatorID = row.getResultByIndex(1);
item._creators = [];
item._creatorIDs = [];
item._loaded.creators = true;
item._clearChanged('creators');
if (!row.creatorID) {
lastItemID = row.itemID;
continue;
if (itemID != lastItemID) {
if (!this._objectCache[itemID]) {
throw new Error("Item " + itemID + " not loaded");
}
item = this._objectCache[itemID];
item._creators = [];
item._creatorIDs = [];
item._loaded.creators = true;
item._clearChanged('creators');
if (!creatorID) {
lastItemID = itemID;
return;
}
if (index <= maxOrderIndex) {
fixIncorrectIndexes(item, index, maxOrderIndex);
}
index = 0;
maxOrderIndex = -1;
}
if (index <= maxOrderIndex) {
fixIncorrectIndexes(item, index, maxOrderIndex);
lastItemID = itemID;
let orderIndex = row.getResultByIndex(3);
if (orderIndex > maxOrderIndex) {
maxOrderIndex = orderIndex;
}
index = 0;
maxOrderIndex = -1;
let creatorData = Zotero.Creators.get(creatorID);
creatorData.creatorTypeID = row.getResultByIndex(2);
item._creators[index] = creatorData;
item._creatorIDs[index] = creatorID;
index++;
}
lastItemID = row.itemID;
if (row.orderIndex > maxOrderIndex) {
maxOrderIndex = row.orderIndex;
}
let creatorData = Zotero.Creators.get(row.creatorID);
creatorData.creatorTypeID = row.creatorTypeID;
item._creators[index] = creatorData;
item._creatorIDs[index] = row.creatorID;
index++;
}
});
if (index <= maxOrderIndex) {
fixIncorrectIndexes(item, index, maxOrderIndex);