Grove.Tree.Event (Grove v0.1.1)
View SourceRepresents an operation in the event graph (DAG).
Each event has parent references forming a DAG structure, enabling causal ordering and critical version detection for Eg-walker integration.
Fields
:id- Unique identifier{replica_id, sequence}:parents- Set of parent event IDs (DAG edges):timestamp- Unix timestamp in milliseconds when the operation occurred:operation- The operation tuple (may include trailing metadata):node_ids- List of node IDs affected by this operation:parent_was_critical- Whether the parent version was critical (enables fast-path)
Event Graph Structure
Events form a DAG where:
- Sequential edits create a linear chain (each event has one parent)
- Concurrent edits create branches (multiple events share parents)
- Merging creates join points (an event has multiple parents)
When the "frontier" (tips of the DAG) has size 1, we're in sequential editing mode - the "critical version" fast path from Eg-walker.
Summary
Functions
Converts a legacy HistoryEntry to an Event with empty parents.
Returns true if this event has multiple parents (merge event).
Creates a new event with the given ID, parents, operation, and affected node IDs.
Returns true if this event has no parents (is a root event).
Returns true if this event has exactly one parent (sequential edit).
Types
@type event_id() :: {String.t(), non_neg_integer()}
Functions
@spec from_history_entry(Grove.Tree.HistoryEntry.t()) :: t()
Converts a legacy HistoryEntry to an Event with empty parents.
Used for migrating existing history data. Legacy entries have no parent information, so they are treated as isolated events.
Examples
iex> entry = %Grove.Tree.HistoryEntry{id: {"r1", 1}, timestamp: 12345, operation: {:put_node, "n1", node}, node_ids: ["n1"]}
iex> event = Grove.Tree.Event.from_history_entry(entry)
iex> event.id
{"r1", 1}
iex> MapSet.size(event.parents)
0
Returns true if this event has multiple parents (merge event).
Examples
iex> parents = MapSet.new([{"r1", 1}, {"r2", 1}])
iex> event = Grove.Tree.Event.new({"r1", 2}, parents, {:put_node, "n2", node}, ["n2"])
iex> Grove.Tree.Event.merge?(event)
true
Creates a new event with the given ID, parents, operation, and affected node IDs.
Options
:parent_was_critical- Whether the parent version was critical (default: true for root events)
Examples
iex> event = Grove.Tree.Event.new({"replica_1", 1}, MapSet.new(), {:put_node, "n1", node}, ["n1"])
iex> event.id
{"replica_1", 1}
iex> MapSet.size(event.parents)
0
iex> event = Grove.Tree.Event.new({"replica_1", 2}, MapSet.new([{"replica_1", 1}]), {:put_node, "n2", node}, ["n2"], parent_was_critical: true)
iex> event.parent_was_critical
true
Returns true if this event has no parents (is a root event).
Examples
iex> event = Grove.Tree.Event.new({"r1", 1}, MapSet.new(), {:put_node, "n1", node}, ["n1"])
iex> Grove.Tree.Event.root?(event)
true
Returns true if this event has exactly one parent (sequential edit).
Examples
iex> parent = {"r1", 1}
iex> event = Grove.Tree.Event.new({"r1", 2}, MapSet.new([parent]), {:put_node, "n2", node}, ["n2"])
iex> Grove.Tree.Event.sequential?(event)
true