Graph Editor¶
Files: 5 | Namespace: Graph | Pattern: Recommended (multiple attachments, function pools)
Graph topology editor demonstrating best practices.
Graph.dsm¶
Domain: Graph, Vertex, Edge
This file defines the core data model for a graph editor application. It demonstrates the recommended Viper pattern with multiple attachments per concept, separating concerns cleanly.
Data Model Design¶
Three concepts (Graph, Vertex, Edge) represent the topological entities
Attachments separate concerns: topology (structure), selection (UI state), description (metadata), render2DAttributes (visualization), visualAttributes (appearance)
Key insight: A Vertex can exist without render attributes (topology-only) or without visual attributes (invisible vertex). Each attachment is optional and independent.
Why Multiple Attachments Matter¶
topologyattachment stores which vertices/edges exist in the graphselectionattachment tracks UI selection state separately from topologyvisualAttributesandrender2DAttributeshandle rendering independentlyAdding a new concern (e.g.,
physicsAttributes) requires zero migration - just add a new attachment
This is the anti-monolithic pattern: instead of one giant VertexProperties struct,
each concern lives in its own attachment.
// Types definitions
namespace Graph {27c49329-a399-415c-baf0-db42949d2ba2} {
"""A graph."""
concept Graph;
"""A vertex in a graph."""
concept Vertex;
"""An edge in a graph."""
concept Edge;
"""The selected vertices and edges."""
struct GraphSelection {
set<key<Vertex>> vertexKeys;
set<key<Edge>> edgeKeys;
};
"""An edge in the graph topology."""
struct EdgeTopology {
key<Vertex> vaKey;
key<Vertex> vbKey;
};
"""The vertices and edges of the graph topology."""
struct GraphTopology {
set<key<Vertex>> vertexKeys;
set<key<Edge>> edgeKeys;
};
"""A Rectangle."""
struct Rectangle {
"""the x origin."""
float x;
"""the y origin."""
float y;
"""the width."""
float w;
"""the height."""
float h;
};
"""The descriptive information."""
struct GraphDescription {
string name;
string author;
string createDate;
};
"""A Position."""
struct Position {
float x;
float y;
};
"""The attributes used to render a topological vertex in 2D."""
struct Vertex2DAttributes {
Position position;
};
"""An RGB Color."""
struct Color {
float red;
float green;
float blue;
};
"""The visual attributes of a vertex."""
struct VertexVisualAttributes {
int64 value;
Color color;
};
};
// Attachments definitions
namespace Graph {27c49329-a399-415c-baf0-db42949d2ba2} {
"""The topology of a graph."""
attachment<Graph, GraphTopology> topology;
"""A collection of tags for a graph."""
attachment<Graph, map<string, string>> tags;
"""A collection of comments for a Graph."""
attachment<Graph, xarray<string>> comments;
"""The selected vertices of a graph."""
attachment<Graph, GraphSelection> selection;
"""The descriptive information of a graph."""
attachment<Graph, GraphDescription> description;
"""The render attributes used to render a vertex of a graph in 2D."""
attachment<Vertex, Vertex2DAttributes> render2DAttributes;
"""The visual attributes used to render a vertex of a graph."""
attachment<Vertex, VertexVisualAttributes> visualAttributes;
"""An Edge in the graph topology."""
attachment<Edge, EdgeTopology> topology;
};
Pool_ModelGraph.dsm¶
Domain: Pool: ModelGraph
This is an attachment_function_pool - functions that modify the AttachmentMutableState.
Function Categories¶
Topology operations:
newVertex,newEdge,clearGraph- basic graph manipulationProperty setters:
setVertexColor,setVertexPosition,setVertexValue- modify vertex attachmentsBatch operations:
moveVertices,randomGraph- operate on multiple elementsMetadata:
setGraphLabel,setGraphTag,appendGraphComment- graph-level annotationsXArray operations:
insertGraphComment,removeGraphComment,updateGraphComment- demonstrate ordered collection with UUID-based positions (not indices)
Testing/Demo Functions¶
These functions are intentionally broken for demonstrations:
graphWithError- throws during commit to test error handlinggraphWithMissingVertex- creates dangling edge referencesdeleteSelectionBugged- deletes vertices without cleaning edgeskiller- stress test that creates many mutations
Note
All mutable functions operate within a mutation context (AttachmentMutating).
Non-mutable functions (queries) only need a reading context (AttachmentGetting).
"""This pool provides access to functions used to edit the graph topology."""
attachment_function_pool ModelGraph {9bdcbb5b-76e9-426f-b8a6-a10ed2d949e6} {
"""Append a new comment."""
mutable void appendGraphComment(key<Graph> graphKey, string comment);
"""Clear the graph."""
mutable void clearGraph(key<Graph> graphKey);
"""Delete a vertex without deleting connected edges."""
mutable void deleteSelectionBugged(key<Graph> graphKey);
"""Throw an error while creating a graph."""
mutable void graphWithError(key<Graph> graphKey);
"""Create a graph with missing vertices to illustrate graph integrity."""
mutable void graphWithMissingVertex(key<Graph> graphKey);
"""Create a graph with missing vertex property to illustrate graph integrity."""
mutable void graphWithMissingVertexProperties(key<Graph> graphKey);
"""Insert a new comment at a specific xarray position (not an index)."""
mutable void insertGraphComment(key<Graph> graphKey, uuid position, string comment);
"""Create mutations that destroy the usability of the Commit."""
mutable void killer(key<Graph> graphKey, uint64 vertexCount);
"""Move the vertices by the offset."""
mutable void moveVertices(set<key<Vertex>> vertexKeys, Position offset);
"""Create a new edge."""
mutable key<Edge> newEdge(key<Graph> graphKey, key<Vertex> vaKey, key<Vertex> vbKey);
"""Create a vertex with the specified attributes."""
mutable key<Vertex> newVertex(key<Graph> graphKey, int64 value, Position position);
"""Append a random comment."""
mutable void randomComment(key<Graph> graphKey);
"""Create a random edge or raise if the graph is complete."""
mutable key<Edge> randomEdge(key<Graph> graphKey);
"""Create a new random graph in rect."""
mutable void randomGraph(key<Graph> graphKey, uint64 vertexCount, uint64 edgeCount, Rectangle rect);
"""Insert a new random tag."""
mutable void randomTag(key<Graph> graphKey);
"""Create a random vertex."""
mutable key<Vertex> randomVertex(key<Graph> graphKey, Rectangle rect);
"""Remove a comment at a specific xarray position (not an index)."""
mutable void removeGraphComment(key<Graph> graphKey, uuid position);
"""Set the label of the graph description."""
mutable void setGraphLabel(key<Graph> graphKey, string label);
"""Replace or insert the tag."""
mutable void setGraphTag(key<Graph> graphKey, string key, string value);
"""Set the vertex color."""
mutable void setVertexColor(key<Vertex> vertexKey, Color color);
"""Set the vertex position."""
mutable void setVertexPosition(key<Vertex> vertexKey, Position position);
"""Set the vertex value."""
mutable void setVertexValue(key<Vertex> vertexKey, int64 value);
"""Remove the tag."""
mutable void unsetGraphTags(key<Graph> graphKey, set<string> keys);
"""Update the comment at a specific xarray position (not an index)."""
mutable void updateGraphComment(key<Graph> graphKey, uuid position, string comment);
"""Update a tag."""
mutable void updateGraphTag(key<Graph> graphKey, string key, string value);
"""Test no args."""
mutable void noArgs();
};
Pool_ModelIntegrity.dsm¶
Domain: Pool: ModelIntegrity
This pool demonstrates referential integrity repair - what happens when the graph has dangling references (edges pointing to deleted vertices).
Three Repair Strategies¶
restoreIntegrityByCreating- recreate missing vertices (preserve topology)restoreIntegrityByDeleting- remove edges with dangling references (preserve consistency)restoreIntegrityByRestoring- respawn deleted elements from history
Why This Matters¶
In Viper, concepts (Vertex, Edge) are identified by keys. If you delete a Vertex without updating Edge references, edges become “orphaned”. This pool shows how to detect and repair such inconsistencies.
Use case: After running deleteSelectionBugged from ModelGraph pool (which
intentionally creates orphans), use these functions to restore graph integrity.
"""This pool provides access functions used to restore the integrity of the graph."""
attachment_function_pool ModelIntegrity {95e0f859-65e0-419e-8b81-77547c73b759} {
"""Restore the graph integrity by creating missing elements."""
mutable void restoreIntegrityByCreating(key<Graph> graphKey);
"""Restore the graph integrity by removing elements."""
mutable void restoreIntegrityByDeleting(key<Graph> graphKey);
"""Restore the graph integrity by respawning elements."""
mutable void restoreIntegrityByRestoring(key<Graph> graphKey);
"""Restore attributes of the selected vertices."""
mutable void restoreVertexSelection(key<Graph> graphKey);
};
Pool_ModelSelection.dsm¶
Domain: Pool: ModelSelection
This pool manages UI selection state - which vertices and edges are currently selected
by the user. Selection is stored in the Graph.selection attachment, separate from
topology.
Selection Operations¶
Set operations:
selectAll,deselectAll,invertSelection- bulk selection changesElement-specific:
setSelectionToVertex,setSelectionToEdge- single element selectionCombine mode:
combineSelectionWithVertex/Edge- add/remove from current selection (shift-click behavior)Queries:
selectedVertices,selectedEdges- return current selection (non-mutable)
Note
deleteSelection operates on selection then modifies topology -
demonstrating how UI state drives data mutations.
"""This pool provides access to functions used to edit the selection."""
attachment_function_pool ModelSelection {5318ad8d-79d8-498e-b080-eccf15e4a74d} {
"""Combine the edge-selected state with the edge selection."""
mutable void combineSelectionWithEdge(key<Graph> graphKey, key<Edge> edgeKey, bool selected);
"""Combine the vertex-selected state with the vertex selection."""
mutable void combineSelectionWithVertex(key<Graph> graphKey, key<Vertex> vertexKey, bool selected);
"""Delete the selected elements."""
mutable void deleteSelection(key<Graph> graphKey);
"""Deselect all edges and vertices."""
mutable void deselectAll(key<Graph> graphKey);
"""Deselection all edges."""
mutable void deselectAllEdges(key<Graph> graphKey);
"""Deselect all vertices."""
mutable void deselectAllVertices(key<Graph> graphKey);
"""Increment the value of selected vertices."""
mutable void incrementVertexValue(key<Graph> graphKey, int64 value);
"""Invert the edge selection."""
mutable void invertEdgesSelection(key<Graph> graphKey);
"""Invert the selection for edges and vertices."""
mutable void invertSelection(key<Graph> graphKey);
"""Invert the vertex selection."""
mutable void invertVerticesSelection(key<Graph> graphKey);
"""Select all edges and vertices."""
mutable void selectAll(key<Graph> graphKey);
"""Select all edges."""
mutable void selectAllEdges(key<Graph> graphKey);
"""Select all vertices."""
mutable void selectAllVertices(key<Graph> graphKey);
"""Return selected edges."""
set<key<Edge>> selectedEdges(key<Graph> graphKey);
"""Return selected vertices."""
set<key<Vertex>> selectedVertices(key<Graph> graphKey);
"""Reduce the selection to the specified edges and vertices."""
mutable void setSelection(key<Graph> graphKey, set<key<Vertex>> vertexKeys, set<key<Edge>> edgeKeys);
"""Reduce the edge selection to the edge."""
mutable void setSelectionToEdge(key<Graph> graphKey, key<Edge> edgeKey);
"""Reduce the selection to the vertex."""
mutable void setSelectionToVertex(key<Graph> graphKey, key<Vertex> vertexKey);
};
Pool_Tools.dsm¶
Domain: Pool: Tools
This is a function_pool (not attachment_function_pool) - pure utility
Difference from attachment_function_pool¶
function_pool: Pure functionsattachment_function_pool: Functions that modify the AttachmentMutableState
Utility Functions¶
add,isEven,isGreater- basic arithmetic/comparison (demonstration purposes)randomWord- generate random strings for testing
Use case: These functions are stateless and available in RPC context for client-side computations or test data generation (no AttachmentMutating context required).
"""This pool provides access to the various utility functions."""
function_pool Tools {dc9740c9-9d1d-4c1e-9caa-4c8843b91e82} {
"""Return a + b."""
int64 add(int64 a, int64 b);
"""Return true if a is even."""
bool isEven(int64 a);
"""Return true if a > b."""
bool isGreater(any a, any b);
"""Return a random word."""
string randomWord(uint64 size);
};