Skip to main content

vantage_vista/reference/
join_key.rs

1//! [`JoinKey`]: one column pair of a join.
2
3use serde::{Deserialize, Serialize};
4use vantage_core::{Result, error};
5
6use crate::vista::Vista;
7
8/// One condition a join contributes: read the parent row's `from` column and
9/// constrain the target's `to` column to that value.
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
11#[non_exhaustive]
12pub struct JoinKey {
13    /// Parent column whose value is used.
14    pub from: String,
15    /// Target column to constrain; `None` is the target's id column, for a
16    /// join whose target id is only known once the target is built (a
17    /// has-one declared on a typed table). Resolve it with
18    /// [`target_column`](Self::target_column).
19    #[serde(default, skip_serializing_if = "Option::is_none")]
20    pub to: Option<String>,
21}
22
23impl JoinKey {
24    /// `JoinKey { from, to }`: the parent's `from` column constrains the
25    /// target's `to` column.
26    pub fn new(from: impl Into<String>, to: impl Into<String>) -> Self {
27        Self {
28            from: from.into(),
29            to: Some(to.into()),
30        }
31    }
32
33    /// The parent's `from` column constrains the target's id column.
34    pub fn to_target_id(from: impl Into<String>) -> Self {
35        Self {
36            from: from.into(),
37            to: None,
38        }
39    }
40
41    /// The column of `target` this key constrains: `to`, or the target's id
42    /// column when `to` is `None`. A target with no id column is an error.
43    pub fn target_column<'a>(&'a self, target: &'a Vista) -> Result<&'a str> {
44        match &self.to {
45            Some(to) => Ok(to),
46            None => target.id_column().ok_or_else(|| {
47                error!(
48                    "join target has no id column to constrain",
49                    target = target.name(),
50                    from = self.from.as_str()
51                )
52            }),
53        }
54    }
55}