1use crate::{
2 index::{AnyIndex, IndexType},
3 table::TableType,
4 Index,
5};
6
7use alloc::boxed::Box;
8#[allow(unused_imports)]
9use alloc::string::String;
10
11pub struct Constraint<T: TableType + 'static>(pub(crate) ConstraintInner<T>);
13
14pub(crate) enum ConstraintInner<T: TableType + 'static> {
15 Unique(Box<dyn AnyIndex<T>>),
17 Check(fn(&T) -> bool),
19}
20
21impl<T: TableType> Constraint<T> {
22 pub fn unique<I: IndexType + 'static>(index: &Index<T, I>) -> Self {
28 Self(ConstraintInner::Unique(Box::new(index.clone())))
29 }
30
31 pub fn check(check: fn(&T) -> bool) -> Self {
37 Self(ConstraintInner::Check(check))
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use alloc::borrow::ToOwned;
44
45 use super::*;
46 use crate::{result::TinyBaseError, Table, TinyBase};
47
48 #[test]
49 fn table_constraint() {
50 let db = TinyBase::new(None, true);
51 let table: Table<String> = db.open_table("test_table").unwrap();
52
53 let index = table
55 .create_index("name", |value| value.to_owned())
56 .unwrap();
57
58 assert!(table.constraint(Constraint::unique(&index)).is_ok());
60
61 assert!(table
63 .constraint(Constraint::check(|value: &String| value.len() >= 5))
64 .is_ok());
65
66 table.insert("greater".to_owned()).unwrap();
67
68 assert!(matches!(
70 table.insert("greater".to_owned()),
71 Err(TinyBaseError::Exists { .. })
72 ));
73
74 assert!(matches!(
76 table.insert("less".to_owned()),
77 Err(TinyBaseError::Condition)
78 ));
79 }
80}