Skip to content

WIP: Make graph views live-update - #325

Draft
cmalinmayor wants to merge 5 commits into
royerlab:mainfrom
cmalinmayor:graph-views
Draft

WIP: Make graph views live-update#325
cmalinmayor wants to merge 5 commits into
royerlab:mainfrom
cmalinmayor:graph-views

Conversation

@cmalinmayor

Copy link
Copy Markdown
Contributor

Currently just makes the sql backend views update properly and don't have stale attributes if the root changes.
Next will add the live-filtering based on a single attribute column check.

The second commit assumes that the simplified assumption in #324 is acceptable, and simplifies the flow significantly.

@TeunHuijben If you are curious

cmalinmayor and others added 3 commits July 28, 2026 16:14
A GraphView was a one-time snapshot: writes to the root were not propagated, so
a view could return stale attribute values and its listeners were never told
anything changed. SQL-rooted views diverged silently; rustworkx-rooted ones only
looked correct because they share the root's attribute dicts.

Roots now track their views and apply changes to them directly rather than
through the signal system. A view is queryable in its own right, so keeping it
current is an invariant — it cannot depend on whether an observer happens to be
subscribed. Views absorb the change first and emit second, so a listener never
sees the root and view disagree.

Also fixes SQLGraph not calling super().__init__(), and pickling, which the
view registry broke for every graph.
Resolves royerlab#324.

A GraphView used to block its root's signal, mutate both graphs, then replay the
root's signal itself, so that a listener on either graph would see both graphs
updated. That coupled two unrelated things: a listener subscribes to one graph
and only needs that graph to be current.

Each graph now emits for itself, once, as soon as it is up to date. Writes
through a view delegate to the root and let the normal view-maintenance path
update the view, so there is a single implementation of "absorb a change"
instead of one per direction. The temporary detach that kept those two
implementations from both running is gone with them.

This also removes a real inconsistency: the replayed payload was rebuilt from a
fixed key list, so a root listener received a different set of attribute keys
depending on whether the write went through a view.
@TeunHuijben

Copy link
Copy Markdown
Contributor

@cmalinmayor, I pushed a fix to a bug that was introduced in this branch, namely:

A view does not necessarily contain all node|edge attributes that the root contains. When the attributes in the view are updated because they come from the root, we should check which attributes are actually present on the view, as implemented in my last commit.

Details:

_apply_root_node_attrs and _apply_root_edge_attrs forwarded every changed key into the view's local store. A view built with an explicit node_attr_keys/edge_attr_keys has no local column for the keys it left out, so the write was rejected:

ValueError: Node attribute key 'bar' not found in graph.
            Expected '['t', 'area']'

Intersect the changed keys with the view's own key list before writing through. Only affects views over a non-rustworkx root; a rustworkx-rooted view shares the root's attribute dicts and never takes this path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants