clotho/docs/OBJECT_BOUNDARY.md
2026-05-15 00:09:01 +02:00

166 lines
4.9 KiB
Markdown

# 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`
```java
@VertexType("Order")
public class Order extends ClothoVertex {
String status;
@Include @Via("HAS_LINE")
List<OrderLine> lines;
@Include @Via("HAS_BILLING_ADDRESS")
Address billingAddress;
}
```
- `@Include` marks the field as part of this object's boundary.
- `@Via` specifies 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).
```java
@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.
```java
@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.
```java
@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`:
```java
@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:
```properties
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`.
```java
@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:
1. The root `Order` vertex is upserted (created if ARID is null, updated if set).
2. Each `@Include` field is recursively persisted in the same way.
3. Elements reachable via multiple paths are saved exactly once (identity map deduplication).
4. **Removed items are NOT automatically deleted.** If you remove an `OrderLine` from
`order.lines`, calling `save()` does not delete the `OrderLine` vertex or its edges.
Call `session.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., `OrderLine` without `Order`)
- 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.