graph_loom 0.1.0

Interactive Graph Structure Utility
Documentation

GraphDB Note App (Rust): "Graph-Loom"

Overview

Graph-Loom is a lightweight, local-first graph notebook and visualizer built with Rust + egui. It lets you create nodes and relationships, view them on a canvas, and interactively arrange them with a smooth, physics-assisted layout. A minimal GQL-like query console supports creating, matching, and deleting graph elements.


Key Features

  • Auto-cluster layout

    • Community detection clusters nodes by: relationships, label similarity, and metadata overlap.
    • Well-formed clusters are placed toward the border; sparsely connected/outlier nodes gravitate toward the center for readability.
  • No-overlap guarantee

    • A fast post-layout resolver separates nodes to a minimum spacing so they never render on top of each other.
  • Smooth motion with a 3s settle window

    • Spring–damper physics for edges and soft repulsion for nearby nodes yield natural movement.
    • “Soft dragging” pulls a node toward the cursor with a spring (neighbors flow out of the way) instead of hard snapping.
    • All motion automatically halts 3 seconds after the last layout/drag change.
  • Responsive window resizing & robust top bar

    • The UI and canvas adapt to smaller or larger window sizes.
    • Tool sidebars are scrollable on small windows; the graph view recenters to keep content stable when resizing.
    • Top bar uses compact drop-down menus so actions remain accessible even on very narrow windows.
  • Practical persistence

    • State is saved to assets/state.ron and loaded on startup. If no state exists, a blank graph is created.
    • File → New Graph creates an empty graph and saves a versioned backup of the current graph first (if non-empty).
  • Clean UI grouping

    • The left sidebar groups tools into collapsible sections (collapsed by default on startup): Layout, Create Node, Create Relationship, Bulk Edit Nodes.
  • Query logging

    • Executed queries are logged to assets/logs/queries_YYYYMMDD.log with basic status info.

Getting Started

Prerequisites


Build and Run

  • Debug: cargo run
  • Release: cargo run --release

On first launch, if assets/state.ron is missing, you’ll start with an empty graph. Subsequent runs will load the saved state automatically.


Using the App

  • Panning/zooming & resizing

    • Zoom only applies when your cursor is over the graph canvas. Scrolling in the left sidebar or other UI panels will not change the graph zoom.
    • Drag the canvas background (or use middle mouse) to pan.
    • The window is fully resizable; when you resize, the canvas adjusts and attempts to keep the view stable. If you end up off-screen on very small windows, use "Reset View" in the top bar or pan back into view.
  • Creating nodes

    • Sidebar → Create Node: choose a label and optional metadata key/value pairs, then Create. New nodes are rendered immediately (no auto pop-out).
    • Optionally, you can pre-link a relationship while creating a node when the UI offers that nested option.
  • Creating relationships

    • Sidebar → Create Relationship: select a source and destination node and label; optionally add metadata. The new edge renders immediately.
  • Arranging the graph

    • Sidebar → Layout → Auto-cluster layout re-runs the community layout on all nodes.
    • Drag nodes directly; neighbors will adjust smoothly. Motion stops after 3s unless you drag again or re-layout.
  • Bulk edit

    • Sidebar → Bulk Edit Nodes for batch label/metadata operations, where available.
  • New graph

    • File → New Graph creates a blank graph. If the current graph isn’t empty, a timestamped backup is written before clearing.

Data & Files

  • Graph state: assets/state.ron
  • Query logs: assets/logs/queries_YYYYMMDD.log
  • Backups on “New Graph”: saved with timestamp in assets (same format as state; see in-app message when created)

GQL Tooling (Built-in Query Console)

This app ships a small, pragmatic subset of Cypher-like commands. Multiple statements can be separated by semicolons. Queries are logged automatically.

Supported commands:

  • CREATE NODE Label {k:"v", ...}
  • CREATE REL from= to= label=Label {k:"v", ...}
  • MATCH NODE Label {k:"v", ...} [WHERE cond [AND cond ...]]
  • MATCH REL Label {k:"v", ...} [WHERE cond [AND cond ...]]
  • DELETE NODE
  • DELETE REL

Notes

  • Label is required for CREATE statements. The { ... } properties block is optional.
  • MATCH returns rows (nodes or relationships) that match label and all provided key/value properties. Optional WHERE clauses can further filter results.
  • UUIDs are shown in the UI; copy/paste them for REL creation or DELETE operations.
  • Keys and values are strings; matching is exact. WHERE currently supports only simple predicates (see below) — no ranges, regex, partial/contains, arithmetic, or parentheses.
  • Commands are case-insensitive for the verb (CREATE/MATCH/DELETE/REL/NODE), but labels/keys/values are case-sensitive.

Example queries

  1. Create a few nodes

CREATE NODE Person {name:"Ada", role:"Engineer"}; CREATE NODE Person {name:"Bob", role:"Designer"}; CREATE NODE Company {name:"Acme"};

  1. Find all Person nodes

MATCH NODE Person;

  1. Match by property

MATCH NODE Person {role:"Engineer"};

3b) MATCH with WHERE filters

  • By id: MATCH NODE Person WHERE id=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee;
  • By metadata equality/inequality and existence: MATCH NODE Person WHERE name="Ada" AND role!="Manager" AND HAS(nickname);
  • Combine with property block and label: MATCH NODE Person {role:"Engineer"} WHERE team="Platform";
  1. Create a relationship (use real UUIDs from your nodes)

-- Suppose Ada has id aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee -- and Acme has id 11111111-2222-3333-4444-555555555555 CREATE REL from=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee to=11111111-2222-3333-4444-555555555555 label=WORKS_AT {since:"2021"};

  1. Match relationships by label (and optional properties)

MATCH REL WORKS_AT; MATCH REL WORKS_AT {since:"2021"}; -- WHERE filters for relationships MATCH REL WORKS_AT WHERE from=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee AND to=11111111-2222-3333-4444-555555555555; MATCH REL WORKS_AT WHERE id=01234567-89ab-cdef-0123-456789abcdef; MATCH REL WORKS_AT WHERE HAS(since) AND since="2021";

  1. Delete by id

DELETE REL 01234567-89ab-cdef-0123-456789abcdef; DELETE NODE fedcba98-7654-3210-fedc-ba9876543210;

Troubleshooting & Known Limitations

  • Motion stops “too soon”

    • By design, physics/convergence halts 3 seconds after the last activity (drag or layout). Begin a new drag or run Auto-cluster to resume.
  • Relationships look crowded

    • Use Auto-cluster layout again or give the graph a nudge by dragging a few nodes. The overlap resolver prevents nodes from stacking, but edges can still cross in dense areas.
  • Performance on very large graphs

    • The layout and physics are tuned for small-to-medium graphs. Extremely large graphs may feel sluggish.
  • Limited query language

    • The GQL subset supports CREATE/MATCH/DELETE for NODE/REL with exact-match properties and basic WHERE clauses (id, label, has(key), key="v", key!="v", and for relationships from=/to=). No updates/SET, no pattern matching, multi-hop, variables, OR/NOT, or grouping/parentheses.
  • UUIDs required for some operations

    • Relationship creation and deletes require UUIDs. Use MATCH first (or the UI) to identify ids.
  • File system permissions

    • The app writes to assets/state.ron and assets/logs. Ensure the process has permission to create and write to these paths.
  • Backups on New Graph

    • A backup is only created if the current graph is non-empty. Check the console/info message for the backup path when triggered.

Contributing

Issues and PRs are welcome. Please run cargo fmt and cargo clippy before submitting changes, and ensure cargo build completes without warnings.


License

unspecified currently - potential to change