Skip to main content

toasty_core/schema/app/relation/
via.rs

1use crate::{schema::app::FieldId, stmt};
2
3/// How a `HasMany` or `HasOne` relation reaches its target.
4///
5/// Both relation kinds share this: the question — "is the target reached
6/// through a paired `BelongsTo`, or by following a path?" — is the same for
7/// has-many and has-one.
8#[derive(Debug, Clone)]
9pub enum HasKind {
10    /// The target is reached through a `BelongsTo` field on the target model.
11    /// Carries that paired `BelongsTo` field's id.
12    ///
13    /// If a `#[has_many(pair = <field>)]` / `#[has_one(pair = <field>)]` was
14    /// supplied, the macro resolves the id at schema-construction time.
15    /// Otherwise the linker fills it in by searching the target model for a
16    /// unique `BelongsTo` back to the source.
17    Direct(FieldId),
18
19    /// The target is reached by following a [`Via`] path of existing
20    /// relations rather than pairing with a single `BelongsTo`.
21    Via(Via),
22}
23
24impl HasKind {
25    /// The paired `BelongsTo` field id, or `None` for a `via` relation.
26    pub fn pair_id(&self) -> Option<FieldId> {
27        match self {
28            HasKind::Direct(pair) => Some(*pair),
29            HasKind::Via(_) => None,
30        }
31    }
32
33    /// The [`Via`] path, or `None` for a direct relation.
34    pub fn via(&self) -> Option<&Via> {
35        match self {
36            HasKind::Via(via) => Some(via),
37            HasKind::Direct(_) => None,
38        }
39    }
40}
41
42/// A multi-step relation path.
43///
44/// A `HasMany` or `HasOne` declared with `#[has_many(via = a.b)]` reaches its
45/// target by following a path of existing relations rather than pairing with a
46/// single `BelongsTo`. The path is resolved at macro-expansion time — the
47/// derive emits a chained call on the model's `Fields` struct
48/// (e.g. `User::fields().comments().article()`) and converts it into a
49/// [`stmt::Path`], so a misspelled or otherwise unresolvable segment is a
50/// Rust compile error rather than a runtime schema validation failure.
51#[derive(Debug, Clone)]
52pub struct Via {
53    /// The resolved field path, rooted at the model that declares the via
54    /// relation.
55    pub path: stmt::Path,
56}
57
58impl Via {
59    /// Create a `Via` from its fully resolved field path.
60    pub fn new(path: stmt::Path) -> Self {
61        Self { path }
62    }
63}