Skip to main content

wasm_dbms_api/dbms/query/
join.rs

1//! Join types for cross-table query operations.
2
3use serde::{Deserialize, Serialize};
4
5/// Specifies the JOIN operation type.
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7#[cfg_attr(feature = "candid", derive(candid::CandidType))]
8pub enum JoinType {
9    Inner,
10    Left,
11    Right,
12    Full,
13}
14
15/// A JOIN clause specifying which table to join and on which columns.
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17#[cfg_attr(feature = "candid", derive(candid::CandidType))]
18pub struct Join {
19    /// The type of join (INNER, LEFT, RIGHT, FULL).
20    pub join_type: JoinType,
21    /// The table to join with.
22    pub table: String,
23    /// Column on the left side of the ON condition.
24    /// Qualified ("users.id") or unqualified ("id", defaults to FROM table).
25    pub left_column: String,
26    /// Column on the right side of the ON condition.
27    /// Qualified ("posts.user") or unqualified ("user", defaults to joined table).
28    pub right_column: String,
29}
30
31impl Join {
32    /// Creates an INNER JOIN.
33    pub fn inner(table: &str, left_column: &str, right_column: &str) -> Self {
34        Self {
35            join_type: JoinType::Inner,
36            table: table.to_string(),
37            left_column: left_column.to_string(),
38            right_column: right_column.to_string(),
39        }
40    }
41
42    /// Creates a LEFT JOIN.
43    pub fn left(table: &str, left_column: &str, right_column: &str) -> Self {
44        Self {
45            join_type: JoinType::Left,
46            table: table.to_string(),
47            left_column: left_column.to_string(),
48            right_column: right_column.to_string(),
49        }
50    }
51
52    /// Creates a RIGHT JOIN.
53    pub fn right(table: &str, left_column: &str, right_column: &str) -> Self {
54        Self {
55            join_type: JoinType::Right,
56            table: table.to_string(),
57            left_column: left_column.to_string(),
58            right_column: right_column.to_string(),
59        }
60    }
61
62    /// Creates a FULL OUTER JOIN.
63    pub fn full(table: &str, left_column: &str, right_column: &str) -> Self {
64        Self {
65            join_type: JoinType::Full,
66            table: table.to_string(),
67            left_column: left_column.to_string(),
68            right_column: right_column.to_string(),
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn test_should_create_inner_join() {
79        let join = Join::inner("posts", "id", "user");
80        assert_eq!(join.join_type, JoinType::Inner);
81        assert_eq!(join.table, "posts");
82        assert_eq!(join.left_column, "id");
83        assert_eq!(join.right_column, "user");
84    }
85
86    #[test]
87    fn test_should_create_left_join() {
88        let join = Join::left("posts", "id", "user");
89        assert_eq!(join.join_type, JoinType::Left);
90    }
91
92    #[test]
93    fn test_should_create_right_join() {
94        let join = Join::right("posts", "id", "user");
95        assert_eq!(join.join_type, JoinType::Right);
96    }
97
98    #[test]
99    fn test_should_create_full_join() {
100        let join = Join::full("posts", "id", "user");
101        assert_eq!(join.join_type, JoinType::Full);
102    }
103
104    #[cfg(feature = "candid")]
105    #[test]
106    fn test_should_encode_decode_join_candid() {
107        let join = Join::inner("posts", "users.id", "user");
108        let encoded = candid::encode_one(&join).unwrap();
109        let decoded: Join = candid::decode_one(&encoded).unwrap();
110        assert_eq!(join, decoded);
111    }
112
113    #[cfg(feature = "candid")]
114    #[test]
115    fn test_should_encode_decode_join_type_candid() {
116        for jt in [
117            JoinType::Inner,
118            JoinType::Left,
119            JoinType::Right,
120            JoinType::Full,
121        ] {
122            let encoded = candid::encode_one(&jt).unwrap();
123            let decoded: JoinType = candid::decode_one(&encoded).unwrap();
124            assert_eq!(jt, decoded);
125        }
126    }
127}