Skip to content

feat(falkordb): implement native edges for relations - #42

Merged
1 commit merged into
yoheinakajima:mainfrom
dudizimber:falkordb-relations-as-nodes
Jun 29, 2026
Merged

1 commit merged into
yoheinakajima:mainfrom
dudizimber:falkordb-relations-as-nodes

Conversation

@dudizimber

@dudizimber dudizimber commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor

resolves #41

Summary

Remodels FalkorDBGraphStore so relations are stored as native FalkorDB edges
between object nodes instead of standalone AGRelation nodes with source/target
id properties. The projection becomes a real, traversable graph — connected in the
FalkorDB Browser and usable with native variable-length paths and graph algorithms —
without losing dangling-relation support or cascade semantics.

This is a behavior-preserving internal remodeling of FalkorDBGraphStore only. The
GraphStore contract, the in-memory store, and the event log are untouched, and
because the store is a disposable projection of the event log there is no data
migration
— existing runs re-replay into the new layout.

What changed

  • Relations are native edges with a single fixed relationship type.
    (s)-[:AGRelation {id, type, data, provenance}]->(t). The relation's type
    (plus id/data/provenance) rides on the edge as properties; source/target
    are no longer stored — they fall out of the endpoints, making the graph the single
    source of truth for connectivity. Traversal by kind is a property filter:
    MATCH (s)-[r:AGRelation {type:'knows'}]->(t).
  • Shared :AGNode endpoint label. Every endpoint carries a structural :AGNode
    label; real objects additionally carry :AGObject. put_relation MERGEs endpoints
    on :AGNode (index-backed, no full scans) and put_object promotes the same node
    in place with SET o:AGObject.
  • Dangling relations via derived placeholders. A dangling endpoint is exactly
    :AGNode AND NOT :AGObject — placeholder-ness is derived, never a stored flag.
    When the object later arrives the node is promoted in place; when a relation is
    removed, any endpoint left as an orphaned placeholder (no remaining edges) is
    garbage-collected.
  • Cascade-on-removal unchanged. The core.graph projector still deletes a removed
    object's relations (now edges), so behavior is identical across every GraphStore.
  • Indexes. AGNode(id) (backs endpoint MERGE), AGObject(id) (object reads),
    relationship-property indexes AGRelation(id) and AGRelation(type), and
    AGPatch(id). A :AGNode:AGObject node appears in both label indexes.

Security

Because the relationship type is a fixed literal (AGRelation), every value stays a
bound $param — no string interpolation and no injection surface, even for
user-supplied relation type strings.

Tradeoff

All edges share the AGRelation label and the relation kind lives in the type
property, so Browser styling/filtering keys off the property rather than the edge
label. This is the price of keeping the write path injection-free and matches the
type-as-attribute shape the projection already uses.

Testing

  • Added FalkorDB tests covering placeholder promotion (relation written before its
    object), placeholder cleanup on relation removal, and native-edge round-tripping;
    the existing GraphStoreConformance suite passes unchanged (same observable
    behavior).
  • Live FalkorDB run (Docker container) green; persistence/fork/graph suites pass.

Docs / changelog

  • Updated docs/guides/using-falkordb.md "How entities are stored" section for the
    native-edge model, placeholders, and Cypher inspection snippets.
  • Added an [Unreleased] entry to CHANGELOG.md.

@yoheinakajima yoheinakajima closed this pull request by merging all changes into yoheinakajima:main in fd5b029 Jun 29, 2026
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.

FalkorDB relations-as-nodes break native traversal and visualization

2 participants