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

6.8 KiB

Type System

Base Class Hierarchy

Every type Clotho knows about descends from ClothoEntity:

ClothoEntity  (abstract)
  ├── ClothoVertex  (abstract)
  │     └── Employee, Person, Company, ...  (developer-defined @VertexType classes)
  └── ClothoEdge    (abstract)
        └── WorksAt, PlacedBy, ...          (developer-defined @EdgeType classes)

@SubgraphType classes do NOT extend ClothoEntity — they are plain Java classes
that aggregate ClothoVertex / ClothoEdge instances.

ClothoEntity

Carries the identity and metadata common to all graph elements:

Member Purpose
ARID getId() ArcadeDB record ID; null for unsaved elements
String getLabel() ArcadeDB type name (e.g. "Employee")
Object getProperty(String key) Raw property access; bypass typed fields when needed
boolean hasLabel(String label) Convenience type check

ClothoVertex

Adds vertex-specific behavior. All @VertexType classes must extend this.

ClothoEdge

Adds edge-specific behavior. Carries outVertexId and inVertexId as ARID values. All @EdgeType classes must extend this.


ARID — ArcadeDB Record ID

ARID is a typed value object wrapping the ArcadeDB record ID string (e.g. #10:0). It is deliberately opaque to avoid coupling call sites to ArcadeDB's ID format.

ARID id = ARID.of("#10:0");
String raw = id.asString();

Using ARID rather than String everywhere:

  • Makes it impossible to accidentally pass an arbitrary string as a record ID
  • Allows the internal representation to evolve (e.g., for future DB portability)
  • Null ARID reliably indicates "not yet persisted"

Vertex Types

@VertexType("Employee")
public class Employee extends ClothoVertex {
    @Property("name") String name;
    @Property("dept") String department;
}

The @VertexType label must match the ArcadeDB vertex type name exactly (case-sensitive). Field names that match the ArcadeDB property name do not need @Property; use it when names differ or for explicit documentation.


Edge Types

@EdgeType("WORKS_AT")
public class WorksAt extends ClothoEdge {
    public static final String LABEL = "WORKS_AT";  // avoids magic strings at call sites

    @OutVertex Employee employee;
    @InVertex Company company;

    @Property("startDate") LocalDate startDate;
    @Property("role")      String role;
}

Declaring @InVertex is optional. Omitting it means the edge is loaded for its own properties only — the target vertex is not fetched. See docs/OBJECT_BOUNDARY.md.


Subgraph Types

@SubgraphType
public class EmployeeProfile {
    Employee employee;          // matches Gremlin as("employee")
    Manager manager;            // matches Gremlin as("manager")
    @Alias("dept")
    Department department;      // @Alias when field name ≠ Gremlin alias
    List<WorksAt> workHistory;
}
  • Has no ARID; does not extend ClothoEntity
  • Assembled by SubgraphTypeAssembler from a Gremlin select() result
  • session.save(profile) iterates all ClothoEntity fields and saves each; the session identity map ensures each element is persisted exactly once
  • See docs/QUERY_MODEL.md for how @Query populates subgraph types

Inheritance

Standard Single-Parent Inheritance

Mirror the ArcadeDB EXTENDS hierarchy in Java:

@VertexType("Person")
public abstract class Person extends ClothoVertex {
    String name;
}

@VertexType("Employee")
public class Employee extends Person {
    String employeeId;
}

@VertexType("HourlyEmployee")
public class HourlyEmployee extends Employee {
    BigDecimal hourlyRate;
}

Clotho infers: "HourlyEmployee" is a subtype of "Employee" is a subtype of "Person".

Diamond Inheritance

ArcadeDB supports multi-parent inheritance. Java does not allow extending multiple classes. Declare the second (and further) ArcadeDB parents explicitly:

// ArcadeDB schema: ContractEmployee EXTENDS Employee, Contractor
@VertexType(value = "ContractEmployee", additionalParents = {"Contractor"})
public class ContractEmployee extends Employee {
    // Java hierarchy: ContractEmployee IS-A Employee
    // ArcadeDB hierarchy: ContractEmployee is also subtype of Contractor (via annotation)
}

Clotho uses additionalParents only for type registry resolution — not for Java polymorphism. If you need ContractEmployee to be usable as a Contractor in Java, use an interface:

public interface ContractorType { /* shared interface */ }

@VertexType("Contractor")
public class Contractor extends ClothoVertex implements ContractorType { ... }

@VertexType(value = "ContractEmployee", additionalParents = {"Contractor"})
public class ContractEmployee extends Employee implements ContractorType { ... }

Divergent Hierarchies

When the ArcadeDB hierarchy cannot be represented via Java extends at all, declare the parent explicitly:

@VertexType(value = "ExternalEmployee", parentLabel = "Employee")
public class ExternalEmployee extends ClothoVertex {
    // Does not extend Employee in Java, but is a subtype in ArcadeDB
}

Result Mapping Rule

Clotho always instantiates the most specific registered class matching the vertex/edge label.

The declared return type is an upper bound — the actual runtime instances are the narrowest match in the TypeRegistry.

// The query may return HourlyEmployee and SalariedEmployee vertices
List<Employee> staff = repo.findAllEmployees();
// → List contains HourlyEmployee and SalariedEmployee instances
//   (both assignable to Employee; caller may instanceof-check if needed)

List<ClothoVertex> anything = repo.findMixed();
// → List contains whatever registered types the traversal returned

Unknown Types

When a vertex/edge label has no registered Java class, behavior depends on the configured UnknownTypeBehavior:

Mode Behavior
STRICT (default) Throw UnknownTypeException
NEAREST_ANCESTOR Instantiate closest registered ancestor; subtype-specific fields are null
GENERIC Wrap in ClothoVertex/ClothoEdge with raw getProperty() access

Configure globally:

clotho.unknown-type-behavior=STRICT

Or per session factory:

ClothoSessionFactory.builder()
    .unknownTypeBehavior(UnknownTypeBehavior.NEAREST_ANCESTOR)
    ...

TypeRegistry

The TypeRegistry is built once at ClothoSessionFactory creation time. It scans the declared packages for @VertexType and @EdgeType classes and builds:

  • label → Class<? extends ClothoEntity> direct lookup
  • Inheritance tree (for NEAREST_ANCESTOR resolution and polymorphic query hints)
  • Validation: duplicate labels, missing extends ClothoVertex/ClothoEdge, etc.

Startup failure is preferred over silent misconfiguration at runtime.