Skip to main content

vantage_table/
references.rs

1//! Table reference system for relationships between tables.
2//!
3//! The `Reference` trait describes a relationship (field names, target factory).
4//! Same-persistence resolution happens in `Table::get_ref_from_row` via
5//! `Reference::resolve_from_row` — the join value is read out of a known source
6//! row and pushed as a plain eq-condition on the target.
7//!
8//! Two concrete types:
9//! - `HasOne` — foreign key on source table (e.g. Client.bakery_id → Bakery)
10//! - `HasMany` — foreign key on target table (e.g. Bakery → Client.bakery_id)
11//!
12//! Cross-persistence references live in `vantage-vista-factory`'s `VistaCatalog`,
13//! not here. Typed `Table<T, E>` is single-backend by construction.
14
15use std::any::Any;
16
17use vantage_core::Result;
18
19pub mod contained;
20pub mod many;
21pub mod one;
22
23pub use contained::ContainedRelation;
24pub use many::HasMany;
25pub use one::HasOne;
26
27/// Describes a relationship between two tables.
28pub trait Reference: Send + Sync {
29    /// Given source and target id field names, return (source_column, target_column).
30    fn columns(&self, source_id: &str, target_id: &str) -> (String, String);
31
32    /// The foreign-key column carried by this relation. For `HasOne` it names a
33    /// column on the *source* table (set to the related row's id after the
34    /// related row is inserted); for `HasMany` it names a column on the *target*
35    /// table (set to the parent's id when inserting each child). Drives nested
36    /// insert at the Vista layer.
37    fn foreign_key(&self) -> &str;
38
39    /// Produce a fresh target table (no conditions applied), wrapped in
40    /// `Box<dyn Any>` so callers can downcast back to the concrete
41    /// `Table<T, TargetE>`. Used by [`crate::table::Table::get_ref_as`] and
42    /// [`crate::table::Table::get_subquery_as`] to build the target before
43    /// applying the join condition.
44    fn build_target(&self, data_source: &dyn Any) -> Box<dyn Any>;
45
46    /// Cardinality of this relation. `HasOne` if traversing yields at most
47    /// one record (the FK lives on the source); `HasMany` if it can yield
48    /// any number (the FK lives on the target). Surfaced by
49    /// `Vista::list_references` so CLIs / UIs can pick a record-card vs
50    /// list-grid renderer.
51    fn cardinality(&self) -> vantage_vista::ReferenceKind;
52
53    /// Resolve traversal using a known source row. Returns the target table
54    /// (entity type erased to `EmptyEntity`) wrapped in `Box<dyn Any>`, with
55    /// one eq-condition applied that selects the related rows.
56    ///
57    /// `data_source` is `&T` for the source's `TableSource`; `source_id_field`
58    /// is the name of the source table's id column (needed by `HasMany` to
59    /// pull the join value out of the row); `source_row` is `&Record<T::Value>`.
60    /// `HasOne` ignores `source_id_field` and reads its stored `foreign_key`
61    /// instead.
62    ///
63    /// Callers immediately downcast the result to `Table<T, EmptyEntity>`.
64    fn resolve_from_row(
65        &self,
66        data_source: &dyn Any,
67        source_id_field: &str,
68        source_row: &dyn Any,
69    ) -> Result<Box<dyn Any>>;
70
71    /// Type name of the target table (for error messages).
72    fn target_type_name(&self) -> &'static str;
73}