database_reflection/reflection/
database.rs

1use crate::metadata::consts::{METADATA_CHARSET, METADATA_COLLATION};
2use crate::metadata::WithMetadata;
3use crate::reflection::column::Column;
4use crate::reflection::constraint::{Constraint, ConstraintSide};
5use crate::reflection::table::Table;
6use indexmap::IndexMap;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::sync::Arc;
10
11#[derive(Clone, Default, Debug, Serialize, Deserialize)]
12pub struct Database {
13    name: String,
14    tables: IndexMap<Arc<String>, Arc<Table>>,
15    constraints: HashMap<Arc<String>, Arc<Constraint>>,
16    metadata: HashMap<String, String>,
17}
18
19impl WithMetadata for Database {
20    /// Borrow metadata container for reading
21    fn get_metadata(&self) -> &HashMap<String, String> {
22        &self.metadata
23    }
24
25    /// Borrow metadata container for writing
26    fn get_metadata_mut(&mut self) -> &mut HashMap<String, String> {
27        &mut self.metadata
28    }
29}
30
31impl Database {
32    /// Create a new database with a name
33    pub fn new(name: impl ToString) -> Database {
34        Database {
35            name: name.to_string(),
36            ..Default::default()
37        }
38    }
39
40    /// Get database name
41    pub fn name(&self) -> &str {
42        &self.name
43    }
44
45    /// Add a table to the database
46    pub fn set_table(&mut self, mut table: Table) -> &mut Database {
47        if table.meta(METADATA_CHARSET).is_none()
48            && table.meta(METADATA_COLLATION).is_none()
49            && self.meta(METADATA_CHARSET).is_some()
50            && self.meta(METADATA_COLLATION).is_some()
51        {
52            table
53                .set_meta(
54                    METADATA_CHARSET,
55                    self.meta(METADATA_CHARSET).unwrap_or_default(),
56                )
57                .set_meta(
58                    METADATA_COLLATION,
59                    self.meta(METADATA_COLLATION).unwrap_or_default(),
60                );
61        }
62
63        self.tables.insert(table.name(), Arc::new(table));
64
65        self
66    }
67
68    /// Get a table by name
69    pub fn table(&self, key: &str) -> Option<Arc<Table>> {
70        self.tables.get(&key.to_string()).cloned()
71    }
72
73    /// Get tables iterator
74    pub fn tables(&self) -> indexmap::map::Iter<'_, Arc<String>, Arc<Table>> {
75        self.tables.iter()
76    }
77
78    /// Add a constraint to the database
79    pub fn set_constraint(&mut self, constraint: Constraint) -> &mut Database {
80        self.constraints
81            .insert(constraint.name(), Arc::new(constraint));
82
83        self
84    }
85
86    /// Find a constraint by name
87    pub fn constraint(&self, key: &str) -> Option<Arc<Constraint>> {
88        #[allow(clippy::unnecessary_to_owned)]
89        self.constraints.get(&key.to_string()).cloned()
90    }
91
92    /// Get constraints iterator
93    pub fn constraints(
94        &self,
95    ) -> std::collections::hash_map::Iter<'_, Arc<String>, Arc<Constraint>> {
96        self.constraints.iter()
97    }
98
99    /// Search for constraints by local or foreign table name
100    pub fn constraints_by_table(
101        &self,
102        table: Arc<Table>,
103        side: Option<ConstraintSide>,
104    ) -> Vec<Arc<Constraint>> {
105        self.constraints
106            .values()
107            .filter(|c| {
108                if c.local().table() == table.name() && (side != Some(ConstraintSide::Foreign)) {
109                    return true;
110                }
111
112                if c.foreign().table() == table.name() && (side != Some(ConstraintSide::Local)) {
113                    return true;
114                }
115
116                false
117            })
118            .cloned()
119            .collect::<Vec<Arc<Constraint>>>()
120    }
121
122    /// Search for constraints by local or foreign column
123    pub fn constraints_by_column(
124        &self,
125        column: Arc<Column>,
126        side: Option<ConstraintSide>,
127    ) -> Vec<Arc<Constraint>> {
128        self.constraints
129            .values()
130            .filter(|c| {
131                if c.local() == column.as_ref() && (side != Some(ConstraintSide::Foreign)) {
132                    return true;
133                }
134
135                if c.foreign() == column.as_ref() && (side != Some(ConstraintSide::Local)) {
136                    return true;
137                }
138
139                false
140            })
141            .cloned()
142            .collect::<Vec<Arc<Constraint>>>()
143    }
144
145    /// Find constraints by column name
146    pub fn constraints_by_column_name(
147        &self,
148        column_name: Arc<String>,
149        side: Option<ConstraintSide>,
150    ) -> Vec<Arc<Constraint>> {
151        self.constraints
152            .values()
153            .filter(|c| {
154                if c.local().name() == column_name && (side != Some(ConstraintSide::Foreign)) {
155                    return true;
156                }
157
158                if c.foreign().name() == column_name && (side != Some(ConstraintSide::Local)) {
159                    return true;
160                }
161
162                false
163            })
164            .cloned()
165            .collect::<Vec<Arc<Constraint>>>()
166    }
167}