semilattice_database/
collection.rs

1mod row;
2
3pub use row::CollectionRow;
4
5use std::{
6    num::NonZeroI32,
7    ops::{Deref, DerefMut},
8    path::PathBuf,
9};
10
11use versatile_data::{Data, DataOption};
12
13use crate::Database;
14
15pub struct Collection {
16    data: Data,
17    id: NonZeroI32,
18    name: String,
19}
20impl Collection {
21    pub fn new(data: Data, id: NonZeroI32, name: impl Into<String>) -> Self {
22        Self {
23            data,
24            id,
25            name: name.into(),
26        }
27    }
28
29    pub fn id(&self) -> NonZeroI32 {
30        self.id
31    }
32
33    pub fn name(&self) -> &str {
34        &self.name
35    }
36
37    pub fn data(&self) -> &Data {
38        &self.data
39    }
40}
41impl Deref for Collection {
42    type Target = Data;
43    fn deref(&self) -> &Self::Target {
44        &self.data
45    }
46}
47impl DerefMut for Collection {
48    fn deref_mut(&mut self) -> &mut Self::Target {
49        &mut self.data
50    }
51}
52
53impl Database {
54    pub fn collections(&self) -> Vec<String> {
55        self.collections
56            .iter()
57            .map(|(_, x)| x.name().to_owned())
58            .collect()
59    }
60
61    pub fn collection(&self, id: NonZeroI32) -> Option<&Collection> {
62        self.collections.get(&id)
63    }
64
65    pub fn collection_mut(&mut self, id: NonZeroI32) -> Option<&mut Collection> {
66        self.collections.get_mut(&id)
67    }
68
69    pub fn collection_id(&self, name: &str) -> Option<NonZeroI32> {
70        self.collections_map
71            .contains_key(name)
72            .then(|| *self.collections_map.get(name).unwrap())
73    }
74
75    pub fn collection_id_or_create(&mut self, name: &str) -> NonZeroI32 {
76        if self.collections_map.contains_key(name) {
77            *self.collections_map.get(name).unwrap()
78        } else {
79            self.collection_by_name_or_create(name)
80        }
81    }
82
83    pub async fn delete_collection(&mut self, name: &str) {
84        let collection_id = self.collections_map.get(name).map_or(0, |x| x.get());
85        if collection_id > 0 {
86            let collection_id = unsafe { NonZeroI32::new_unchecked(collection_id) };
87            if let Some(collection) = self.collections.get(&collection_id) {
88                for row in collection.data.all().into_iter() {
89                    self.delete(&CollectionRow::new(collection_id, row))
90                        .await;
91                    if let Some(collection) = self.collection_mut(collection_id) {
92                        collection.delete(row).await;
93                    }
94                }
95            }
96            self.collections_map.remove(name);
97            self.collections.remove(&collection_id);
98
99            let mut dir = self.collections_dir.clone();
100            dir.push(collection_id.to_string() + "_" + name);
101            std::fs::remove_dir_all(&dir).unwrap();
102        }
103    }
104
105    pub(super) fn create_collection(&mut self, id: NonZeroI32, name: &str, dir: PathBuf) {
106        let collection = Collection::new(
107            Data::new(
108                dir,
109                self.collection_settings
110                    .get(name)
111                    .map_or(DataOption::default(), |f| f.clone()),
112            ),
113            id,
114            name,
115        );
116        self.collections_map.insert(name.to_string(), id);
117        self.collections.insert(id, collection);
118    }
119
120    fn collection_by_name_or_create(&mut self, name: &str) -> NonZeroI32 {
121        let mut max_id = 0;
122        if self.collections_dir.exists() {
123            for d in self.collections_dir.read_dir().unwrap().into_iter() {
124                let d = d.unwrap();
125                if d.file_type().unwrap().is_dir() {
126                    if let Some(fname) = d.file_name().to_str() {
127                        let s: Vec<_> = fname.split("_").collect();
128                        if s.len() > 1 {
129                            if let Ok(i) = s[0].parse() {
130                                max_id = std::cmp::max(max_id, i);
131                            }
132                            if s[1] == name {
133                                let max_id = NonZeroI32::new(max_id).unwrap();
134                                self.create_collection(max_id, name, d.path());
135                                return max_id;
136                            }
137                        }
138                    }
139                }
140            }
141        }
142        let collection_id = unsafe { NonZeroI32::new_unchecked(max_id + 1) };
143        self.create_collection(collection_id, name, {
144            let mut collecion_dir = self.collections_dir.clone();
145            collecion_dir.push(&(collection_id.to_string() + "_" + name));
146            collecion_dir
147        });
148        collection_id
149    }
150}