Keep a {id: item} cache for ModelStore models
Accelerates the ModelStore ListView find() function, which now just has to get an object key instead of looping through the whole model.
This commit is contained in:
parent
b1398e5dbf
commit
f5cb3ecaa0
|
@ -44,7 +44,8 @@ class Model(MutableMapping):
|
||||||
|
|
||||||
self.take_items_ownership: bool = True
|
self.take_items_ownership: bool = True
|
||||||
|
|
||||||
self._active_batch_remove_indice: Optional[List[int]] = None
|
# [(index, item.id), ...]
|
||||||
|
self._active_batch_removed: Optional[List[Tuple[int, Any]]] = None
|
||||||
|
|
||||||
if self.sync_id:
|
if self.sync_id:
|
||||||
self.instances[self.sync_id] = self
|
self.instances[self.sync_id] = self
|
||||||
|
@ -148,10 +149,10 @@ class Model(MutableMapping):
|
||||||
proxy.source_item_deleted(self, key)
|
proxy.source_item_deleted(self, key)
|
||||||
|
|
||||||
if self.sync_id:
|
if self.sync_id:
|
||||||
if self._active_batch_remove_indice is None:
|
if self._active_batch_removed is None:
|
||||||
ModelItemDeleted(self.sync_id, index)
|
ModelItemDeleted(self.sync_id, index, 1, (item.id,))
|
||||||
else:
|
else:
|
||||||
self._active_batch_remove_indice.append(index)
|
self._active_batch_removed.append((index, item.id))
|
||||||
|
|
||||||
|
|
||||||
def __iter__(self) -> Iterator:
|
def __iter__(self) -> Iterator:
|
||||||
|
@ -189,17 +190,21 @@ class Model(MutableMapping):
|
||||||
|
|
||||||
with self.write_lock:
|
with self.write_lock:
|
||||||
try:
|
try:
|
||||||
self._active_batch_remove_indice = []
|
self._active_batch_removed = []
|
||||||
yield None
|
yield None
|
||||||
finally:
|
finally:
|
||||||
indice = self._active_batch_remove_indice
|
batch = self._active_batch_removed
|
||||||
groups = [
|
groups = [
|
||||||
list(group) for item, group in itertools.groupby(indice)
|
list(group) for item, group in
|
||||||
|
itertools.groupby(batch, key=lambda x: x[0])
|
||||||
]
|
]
|
||||||
|
|
||||||
for grp in groups:
|
for group in groups:
|
||||||
ModelItemDeleted(
|
ModelItemDeleted(
|
||||||
self.sync_id, index=grp[0], count=len(grp),
|
self.sync_id,
|
||||||
|
index = group[0][0],
|
||||||
|
count = len(group),
|
||||||
|
ids = [item[1] for item in group],
|
||||||
)
|
)
|
||||||
|
|
||||||
self._active_batch_remove_indice = None
|
self._active_batch_removed = None
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import TYPE_CHECKING, Any, Dict, Optional
|
from typing import TYPE_CHECKING, Any, Dict, Optional, Sequence
|
||||||
|
|
||||||
import pyotherside
|
import pyotherside
|
||||||
|
|
||||||
|
@ -83,8 +83,9 @@ class ModelItemSet(ModelEvent):
|
||||||
class ModelItemDeleted(ModelEvent):
|
class ModelItemDeleted(ModelEvent):
|
||||||
"""Indicate the removal of a `ModelItem` from a `Backend` `Model`."""
|
"""Indicate the removal of a `ModelItem` from a `Backend` `Model`."""
|
||||||
|
|
||||||
index: int = field()
|
index: int = field()
|
||||||
count: int = 1
|
count: int = 1
|
||||||
|
ids: Sequence[Any] = ()
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
|
@ -13,6 +13,7 @@ QtObject {
|
||||||
readonly property Component model: Component {
|
readonly property Component model: Component {
|
||||||
ListModel {
|
ListModel {
|
||||||
property var modelId
|
property var modelId
|
||||||
|
property var idToItems: ({})
|
||||||
|
|
||||||
// Used by HFilterModel
|
// Used by HFilterModel
|
||||||
signal fieldsChanged(int index, var changes)
|
signal fieldsChanged(int index, var changes)
|
||||||
|
@ -25,10 +26,7 @@ QtObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
function find(id, default_=null) {
|
function find(id, default_=null) {
|
||||||
for (let i = 0; i < count; i++)
|
return idToItems[id] || default_
|
||||||
if (get(i).id === id) return get(i)
|
|
||||||
|
|
||||||
return default_
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ Item {
|
||||||
property string userId
|
property string userId
|
||||||
property string roomId
|
property string roomId
|
||||||
|
|
||||||
property QtObject userInfo: null
|
property QtObject userInfo: ModelStore.get("accounts").find(userId)
|
||||||
property QtObject roomInfo: null
|
property QtObject roomInfo: ModelStore.get(userId, "rooms").find(roomId)
|
||||||
|
|
||||||
property bool ready: Boolean(userInfo && roomInfo)
|
property bool ready: Boolean(userInfo && roomInfo)
|
||||||
property bool longLoading: false
|
property bool longLoading: false
|
||||||
|
@ -58,22 +58,6 @@ Item {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
|
||||||
interval: 100
|
|
||||||
running: ! userInfo
|
|
||||||
repeat: true
|
|
||||||
triggeredOnStart: true
|
|
||||||
onTriggered: userInfo = ModelStore.get("accounts").find(userId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
interval: 100
|
|
||||||
running: ! roomInfo
|
|
||||||
repeat: true
|
|
||||||
triggeredOnStart: true
|
|
||||||
onTriggered: roomInfo = ModelStore.get(userId, "rooms").find(roomId)
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
interval: 300
|
interval: 300
|
||||||
running: ! ready
|
running: ! ready
|
||||||
|
|
|
@ -51,16 +51,19 @@ QtObject {
|
||||||
py.showError(type, traceback, message)
|
py.showError(type, traceback, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onModelItemSet(syncId, indexThen, indexNow, changedFields){
|
function onModelItemSet(syncId, indexThen, indexNow, changedFields) {
|
||||||
|
const model = ModelStore.get(syncId)
|
||||||
|
|
||||||
if (indexThen === undefined) {
|
if (indexThen === undefined) {
|
||||||
// print("insert", syncId, indexThen, indexNow,
|
// print("insert", syncId, indexThen, indexNow,
|
||||||
// JSON.stringify(changedFields))
|
// JSON.stringify(changedFields))
|
||||||
ModelStore.get(syncId).insert(indexNow, changedFields)
|
model.insert(indexNow, changedFields)
|
||||||
|
model.idToItems[changedFields.id] = model.get(indexNow)
|
||||||
|
model.idToItemsChanged()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// print("set", syncId, indexThen, indexNow,
|
// print("set", syncId, indexThen, indexNow,
|
||||||
// JSON.stringify(changedFields))
|
// JSON.stringify(changedFields))
|
||||||
const model = ModelStore.get(syncId)
|
|
||||||
model.set(indexThen, changedFields)
|
model.set(indexThen, changedFields)
|
||||||
|
|
||||||
if (indexThen !== indexNow) model.move(indexThen, indexNow, 1)
|
if (indexThen !== indexNow) model.move(indexThen, indexNow, 1)
|
||||||
|
@ -69,14 +72,22 @@ QtObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onModelItemDeleted(syncId, index, count=1) {
|
function onModelItemDeleted(syncId, index, count=1, ids=[]) {
|
||||||
// print("delete", syncId, index, count)
|
// print("delete", syncId, index, count, ids)
|
||||||
ModelStore.get(syncId).remove(index, count)
|
const model = ModelStore.get(syncId)
|
||||||
|
model.remove(index, count)
|
||||||
|
|
||||||
|
for (let i = 0; i < ids.length; i++) {
|
||||||
|
delete model.idToItems[ids[i]]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ids.length) model.idToItemsChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
function onModelCleared(syncId) {
|
function onModelCleared(syncId) {
|
||||||
// print("clear", syncId)
|
// print("clear", syncId)
|
||||||
ModelStore.get(syncId).clear()
|
ModelStore.get(syncId).clear()
|
||||||
|
model.idToItems = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDevicesUpdated(forAccount) {
|
function onDevicesUpdated(forAccount) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user