166 lines
4.9 KiB
Markdown
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.
|