Optimize model field replacements

This commit is contained in:
miruka
2020-04-07 11:58:26 -04:00
parent 68e344ae21
commit fd8cf4ad8d
5 changed files with 64 additions and 61 deletions

View File

@@ -8,9 +8,7 @@ from typing import (
from blist import blist
from ..pyotherside_events import (
ModelCleared, ModelItemDeleted, ModelItemInserted,
)
from ..pyotherside_events import ModelCleared, ModelItemDeleted, ModelItemSet
from . import SyncId
if TYPE_CHECKING:
@@ -61,36 +59,49 @@ class Model(MutableMapping):
def __setitem__(self, key, value: "ModelItem") -> None:
"""Merge new item with an existing one if possible, else add it.
If an existing item with the passed `key` is found, its fields will be
updated with the passed `ModelItem`'s fields.
In other cases, the item is simply added to the model.
This also sets the `ModelItem.parent_model` hidden attributes on
the passed item.
"""
with self._write_lock:
existing = self._data.get(key)
new = value
if existing:
for field in new.__dataclass_fields__: # type: ignore
# The same shared item is in _sorted_data, no need to find
# and modify it explicitely.
setattr(existing, field, getattr(new, field))
return
# Collect changed fields
changed_fields = {}
for field in new.__dataclass_fields__: # type: ignore
changed = True
if existing:
changed = getattr(new, field) != getattr(existing, field)
if changed:
changed_fields[field] = new.serialize_field(field)
# Set parent model on new item
if self.sync_id:
new.parent_model = self
self._data[key] = new
index = bisect(self._sorted_data, new)
self._sorted_data.insert(index, new)
# Insert into sorted data
if self.sync_id:
ModelItemInserted(self.sync_id, index, new)
index_then = None
if existing:
index_then = self._sorted_data.index(existing)
del self._sorted_data[index_then]
index_now = bisect(self._sorted_data, new)
self._sorted_data.insert(index_now, new)
# Insert into dict data
self._data[key] = new
# Emit PyOtherSide event
if self.sync_id and (index_then != index_now or changed_fields):
ModelItemSet(
self.sync_id, index_then, index_now, changed_fields,
)
def __delitem__(self, key) -> None:

View File

@@ -2,7 +2,7 @@
from typing import TYPE_CHECKING, Any, Dict, Optional
from ..pyotherside_events import ModelItemFieldChanged
from ..pyotherside_events import ModelItemSet
from ..utils import serialize_value_for_qml
if TYPE_CHECKING:
@@ -38,17 +38,19 @@ class ModelItem:
with self.parent_model._write_lock:
super().__setattr__(name, value)
old_index = self.parent_model._sorted_data.index(self)
if self.parent_model.sync_id:
index_then = self.parent_model._sorted_data.index(self)
self.parent_model._sorted_data.sort()
new_index = self.parent_model._sorted_data.index(self)
if self.parent_model.sync_id:
ModelItemFieldChanged(
index_now = self.parent_model._sorted_data.index(self)
ModelItemSet(
self.parent_model.sync_id,
old_index,
new_index,
name,
self.serialize_field(name),
index_then,
index_now,
{name: self.serialize_field(name)},
)