4.9 KiB
Object Boundary
What Is the Object Boundary?
Clotho has no lazy loading. When you call session.load(Employee.class, rid), you receive the
fully assembled object — root vertex plus everything within its declared boundary — in one
operation. Nothing is deferred.
The object boundary is the set of edges and vertices Clotho traverses and assembles when
loading a @VertexType instance. It is declared entirely in the Java class using @Include
and @Via. Everything outside the boundary is accessed via @Query traversals written by
the developer.
Declaring the Boundary: @Include and @Via
@VertexType("Order")
public class Order extends ClothoVertex {
String status;
@Include @Via("HAS_LINE")
List<OrderLine> lines;
@Include @Via("HAS_BILLING_ADDRESS")
Address billingAddress;
}
@Includemarks the field as part of this object's boundary.@Viaspecifies the ArcadeDB edge label to traverse.- The field type determines what is loaded (see below).
Both annotations are required together. @Include without @Via is a compile-time error.
What Gets Loaded: Field Type Rules
Field type is a @VertexType class
Clotho traverses the edge, loads the target vertex (and its own boundary recursively), and discards the edge itself (edge properties are not available).
@Include @Via("HAS_BILLING_ADDRESS")
Address billingAddress; // Address is a @VertexType; edge properties ignored
Field type is an @EdgeType class
Clotho loads the full edge object — edge properties, plus @OutVertex and @InVertex
fields if declared on the edge class.
@Include @Via("HAS_LINE")
List<OrderLineEdge> lines; // OrderLineEdge is an @EdgeType; edge props + vertices loaded
Edge-only inclusion (no @InVertex on the edge class)
When the @EdgeType class declares no @InVertex field, the target vertex is not fetched.
Useful when you need the edge's own properties but not the vertex it points to.
@EdgeType("TAGGED_WITH")
public class TagEdge extends ClothoEdge {
@OutVertex Order order;
// No @InVertex — Tag vertex is never loaded
String tagValue;
int weight;
}
// In Order:
@Include @Via("TAGGED_WITH")
List<TagEdge> tags; // Only edge properties; Tag vertices stay in the DB
Edge Direction
Default direction is OUT (follow outgoing edges from the current vertex).
Override per field with @Direction:
@Include @Via("ASSIGNED_TO") @Direction(Direction.IN)
List<Task> assignedTasks; // follow INCOMING ASSIGNED_TO edges to find tasks
@Include @Via("CONNECTED") @Direction(Direction.BOTH)
List<Node> neighbors; // follow edges in both directions
The global default can be changed in session factory configuration:
clotho.default-direction=OUT
Multi-Hop Boundaries
@Include is applied recursively. If OrderLine itself has @Include fields, they are
loaded as part of loading Order.
@VertexType("Order")
public class Order extends ClothoVertex {
@Include @Via("HAS_LINE")
List<OrderLine> lines; // hop 1
}
@VertexType("OrderLine")
public class OrderLine extends ClothoVertex {
int quantity;
BigDecimal unitPrice;
@Include @Via("HAS_NOTE")
List<Note> notes; // hop 2 — loaded as part of Order
}
Loading an Order traverses: Order → HAS_LINE → OrderLine → HAS_NOTE → Note.
There is no depth limit. The developer is responsible for designing boundaries that do not load unbounded portions of the graph.
Cycle Detection
Clotho tracks visited ARIDs during a boundary load. If a traversal reaches a vertex it has already loaded in the current operation, it uses the existing instance and stops traversing further — it does not loop. The developer still bears responsibility for not creating boundaries that load huge subgraphs.
Persistence of Boundary Elements
When session.save(order) is called:
- The root
Ordervertex is upserted (created if ARID is null, updated if set). - Each
@Includefield is recursively persisted in the same way. - Elements reachable via multiple paths are saved exactly once (identity map deduplication).
- Removed items are NOT automatically deleted. If you remove an
OrderLinefromorder.lines, callingsave()does not delete theOrderLinevertex or its edges. Callsession.delete(orderLine)explicitly.
Design Guidance
The boundary should reflect ownership, not just connectivity. Include elements that:
- Are always loaded and managed together with the root
- Are not meaningful without the root (e.g.,
OrderLinewithoutOrder) - Form a bounded transaction unit
Do NOT include:
- Large, unbounded collections (e.g., all products a customer ever bought)
- Elements that are independently meaningful and queried on their own
- Elements reachable via long traversal chains across the domain
For everything outside the boundary, write a @Query on a @ClothoRepository interface.