ic_dbms_api/dbms/table/
record.rs1use candid::CandidType;
2
3use crate::dbms::table::{ColumnDef, TableSchema};
4use crate::dbms::value::Value;
5use crate::prelude::{Filter, IcDbmsResult};
6
7pub type TableColumns = Vec<(ValuesSource, Vec<(ColumnDef, Value)>)>;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub enum ValuesSource {
12 This,
14 Foreign { table: String, column: String },
16}
17
18pub trait TableRecord: CandidType + for<'de> candid::Deserialize<'de> {
20 type Schema: TableSchema<Record = Self>;
22
23 fn from_values(values: TableColumns) -> Self;
25
26 fn to_values(&self) -> Vec<(ColumnDef, Value)>;
28}
29
30pub trait InsertRecord: Sized + Clone + CandidType {
32 type Record: TableRecord;
34 type Schema: TableSchema<Record = Self::Record>;
36
37 fn from_values(values: &[(ColumnDef, Value)]) -> IcDbmsResult<Self>;
39
40 fn into_values(self) -> Vec<(ColumnDef, Value)>;
42
43 fn into_record(self) -> Self::Schema;
45}
46
47pub trait UpdateRecord: Sized + CandidType {
49 type Record: TableRecord;
51 type Schema: TableSchema<Record = Self::Record>;
53
54 fn from_values(values: &[(ColumnDef, Value)], where_clause: Option<Filter>) -> Self;
56
57 fn update_values(&self) -> Vec<(ColumnDef, Value)>;
59
60 fn where_clause(&self) -> Option<Filter>;
62}
63
64#[cfg(test)]
65mod test {
66
67 use super::*;
68
69 #[test]
70 fn test_should_create_values_source_this() {
71 let source = ValuesSource::This;
72 assert_eq!(source, ValuesSource::This);
73 }
74
75 #[test]
76 fn test_should_create_values_source_foreign() {
77 let source = ValuesSource::Foreign {
78 table: "users".to_string(),
79 column: "id".to_string(),
80 };
81
82 if let ValuesSource::Foreign { table, column } = source {
83 assert_eq!(table, "users");
84 assert_eq!(column, "id");
85 } else {
86 panic!("expected ValuesSource::Foreign");
87 }
88 }
89
90 #[test]
91 fn test_should_clone_values_source() {
92 let source = ValuesSource::Foreign {
93 table: "posts".to_string(),
94 column: "author_id".to_string(),
95 };
96
97 let cloned = source.clone();
98 assert_eq!(source, cloned);
99 }
100
101 #[test]
102 fn test_should_compare_values_sources() {
103 let source1 = ValuesSource::This;
104 let source2 = ValuesSource::This;
105 let source3 = ValuesSource::Foreign {
106 table: "users".to_string(),
107 column: "id".to_string(),
108 };
109 let source4 = ValuesSource::Foreign {
110 table: "users".to_string(),
111 column: "id".to_string(),
112 };
113 let source5 = ValuesSource::Foreign {
114 table: "posts".to_string(),
115 column: "id".to_string(),
116 };
117
118 assert_eq!(source1, source2);
119 assert_eq!(source3, source4);
120 assert_ne!(source1, source3);
121 assert_ne!(source3, source5);
122 }
123
124 #[test]
125 fn test_should_hash_values_source() {
126 use std::collections::HashSet;
127
128 let mut set = HashSet::new();
129 set.insert(ValuesSource::This);
130 set.insert(ValuesSource::Foreign {
131 table: "users".to_string(),
132 column: "id".to_string(),
133 });
134
135 assert!(set.contains(&ValuesSource::This));
136 assert!(set.contains(&ValuesSource::Foreign {
137 table: "users".to_string(),
138 column: "id".to_string(),
139 }));
140 assert!(!set.contains(&ValuesSource::Foreign {
141 table: "posts".to_string(),
142 column: "id".to_string(),
143 }));
144 }
145
146 #[test]
147 fn test_should_debug_values_source() {
148 let source = ValuesSource::This;
149 let debug_str = format!("{:?}", source);
150 assert_eq!(debug_str, "This");
151
152 let foreign = ValuesSource::Foreign {
153 table: "users".to_string(),
154 column: "id".to_string(),
155 };
156 let foreign_debug = format!("{:?}", foreign);
157 assert!(foreign_debug.contains("Foreign"));
158 assert!(foreign_debug.contains("users"));
159 assert!(foreign_debug.contains("id"));
160 }
161}