Grove.Node (Grove v0.1.1)
View SourceA node in a Grove tree.
Each node represents an element in a hierarchical structure (e.g., a form field, a document section, an AST node). Nodes are identified by unique IDs and maintain parent-child relationships.
Fields
:id- Unique identifier, typically"{replica_id}_{clock}":type- Atom indicating the node type (e.g.,:form,:step,:text,:dropdown):attrs- Node attributes. Either a plain map for simple use cases, or aGrove.Map.ORMapfor schema-based nodes with per-field CRDT types.:parent_id- ID of parent node, ornilfor root:parent_timestamp- HLC timestamp of the last move operation (for LWW conflict resolution):position- Sibling ordering metadata for concurrent-safe reordering (seeposition/0):children- Ordered list of child node IDs:deleted?- Tombstone flag for soft deletion:meta- Metadata map (e.g.,%{updated_by: "user_123"})
Example (Simple attrs)
%Grove.Node{
id: "replica_1_42",
type: :dropdown,
attrs: %{label: "Country", required: true},
parent_id: "replica_1_12",
children: ["replica_1_43", "replica_1_44"],
deleted?: false,
meta: %{}
}Example (Schema-based attrs with ORMap)
# When using Grove.Schema, attrs is an ORMap with per-field CRDTs:
node = MySchema.new_node(:dropdown, "replica_1", %{label: "Country"})
# node.attrs is %Grove.Map.ORMap{...}
Summary
Functions
Adds a child ID to the end of the children list.
Marks a node as deleted (tombstone).
Returns true if the node is deleted.
Inserts a child ID at the specified position.
Creates a new node with the given id, type, and options.
Removes a child ID from the children list.
Sets the parent ID for a node (used in move operations).
Sets the position metadata for sibling ordering.
Updates node attributes by merging with the provided map.
Types
@type position() :: %{ left_origin: String.t() | nil, right_origin: String.t() | nil, timestamp: Grove.HybridLogicalClock.t() }
Position metadata for sibling ordering.
Uses Fugue-inspired left/right origins for deterministic concurrent ordering:
left_origin- ID of the sibling this node should appear afterright_origin- ID of the sibling this node should appear beforetimestamp- HLC timestamp for tiebreaking concurrent insertions
@type t() :: %Grove.Node{ attrs: map() | Grove.Map.ORMap.t(), children: [String.t()], deleted?: boolean(), id: String.t(), meta: map(), parent_id: String.t() | nil, parent_timestamp: Grove.HybridLogicalClock.t() | nil, position: position() | nil, type: atom() }
Functions
Adds a child ID to the end of the children list.
Marks a node as deleted (tombstone).
Returns true if the node is deleted.
@spec insert_child(t(), String.t(), non_neg_integer()) :: t()
Inserts a child ID at the specified position.
Creates a new node with the given id, type, and options.
Options
:attrs- Node attributes (default:%{}):parent_id- Parent node ID (default:nil):parent_timestamp- HLC timestamp for LWW (default:nil):position- Sibling ordering metadata (default:nil):children- List of child IDs (default:[]):meta- Metadata map (default:%{})
Example
Grove.Node.new("node_1", :text, attrs: %{label: "Name"}, parent_id: "form_1")
Removes a child ID from the children list.
@spec set_parent(t(), String.t() | nil, Grove.HybridLogicalClock.t() | nil) :: t()
Sets the parent ID for a node (used in move operations).
Optionally accepts a timestamp for LWW conflict resolution.
Sets the position metadata for sibling ordering.
Position metadata enables concurrent-safe reordering of siblings using Fugue-inspired left/right origins.
Updates node attributes by merging with the provided map.
For plain map attrs, performs a simple Map.merge/2.
For ORMap attrs (schema-based nodes), use your schema's update_field/4 instead.