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}