# 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. ```java 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 ```java @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 ```java @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 ```java @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 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: ```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: ```java // 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: ```java 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: ```java @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. ```java // The query may return HourlyEmployee and SalariedEmployee vertices List staff = repo.findAllEmployees(); // → List contains HourlyEmployee and SalariedEmployee instances // (both assignable to Employee; caller may instanceof-check if needed) List 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: ```properties clotho.unknown-type-behavior=STRICT ``` Or per session factory: ```java 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` 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.