Skip to main content

vantage_table/
active_entity_ext.rs

1//! Relationship traversal from a loaded record handle.
2//!
3//! The record-level equivalent of `Table::get_ref_from_row`:
4//! `launch.get_ref::<LaunchCrew>("launch_crew")` returns the child table scoped
5//! to that launch, carrying the foreign-key invariant so inserts conform.
6//! `ActiveEntity` and `ActiveRecord` live in `vantage-dataset` and know nothing
7//! about `Table`, hence an extension trait here.
8
9use vantage_core::{Result, error};
10use vantage_dataset::prelude::{ActiveEntity, ActiveRecord};
11use vantage_types::{Entity, InvariantValue, TryIntoRecord};
12
13use crate::{table::Table, traits::table_source::TableSource};
14
15/// Traverse a relation from a loaded record.
16pub trait GetRefExt<T: TableSource, E> {
17    /// Return the related set for `relation`, reading the join value out of the
18    /// in-memory entity. Errors if the relation is unknown to the table.
19    fn get_ref<E2: Entity<T::Value> + 'static>(&self, relation: &str) -> Result<Table<T, E2>>;
20}
21
22impl<'a, T, E> GetRefExt<T, E> for ActiveEntity<'a, Table<T, E>, E>
23where
24    T: TableSource,
25    T::Id: Into<T::Value>,
26    T::Value: InvariantValue,
27    E: Entity<T::Value> + 'static,
28    <E as TryIntoRecord<T::Value>>::Error: std::fmt::Debug,
29{
30    fn get_ref<E2: Entity<T::Value> + 'static>(&self, relation: &str) -> Result<Table<T, E2>> {
31        let mut record = self
32            .data()
33            .clone()
34            .try_into_record()
35            .map_err(|e| error!("Failed to serialize entity to record", error = e))?;
36
37        // The entity struct carries no id column, but has-many traversal reads
38        // the parent id out of the row.
39        let id_field = self.dataset().id_field_name();
40        record.insert(id_field, self.id().clone().into());
41
42        self.dataset().get_ref_from_row::<E2>(relation, &record)
43    }
44}
45
46impl<'a, T, E> GetRefExt<T, E> for ActiveRecord<'a, Table<T, E>>
47where
48    T: TableSource,
49    T::Value: InvariantValue,
50    E: Entity<T::Value> + 'static,
51{
52    fn get_ref<E2: Entity<T::Value> + 'static>(&self, relation: &str) -> Result<Table<T, E2>> {
53        let row: &vantage_types::Record<T::Value> = self;
54        self.dataset().get_ref_from_row::<E2>(relation, row)
55    }
56}