Skip to main content

tablam/
schema.rs

1use std::collections::{HashMap, HashSet};
2use std::fmt;
3use std::hash::{Hash, Hasher};
4use std::ops::Index;
5
6use crate::function::Param;
7use crate::types::*;
8
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct Field {
11    pub name: String,
12    pub kind: DataType,
13}
14
15impl Field {
16    pub fn new(name: &str, kind: DataType) -> Self {
17        Field {
18            name: name.to_string(),
19            kind,
20        }
21    }
22
23    pub fn new_owned(name: String, kind: DataType) -> Self {
24        Field { name, kind }
25    }
26
27    pub fn name(&self) -> &String {
28        &self.name
29    }
30
31    pub fn kind(&self) -> &DataType {
32        &self.kind
33    }
34}
35
36impl ::core::convert::From<Param> for Field {
37    #[allow(unused_variables)]
38    #[inline]
39    fn from(original: Param) -> Field {
40        Field::new(&original.name, original.kind)
41    }
42}
43
44#[derive(Debug, Clone, PartialOrd, Ord)]
45pub struct Schema {
46    pub pk: Option<usize>,
47    pub fields: Vec<Field>,
48}
49
50impl Schema {
51    pub fn new(fields: Vec<Field>, pk: Option<usize>) -> Self {
52        Schema { pk, fields }
53    }
54
55    pub fn new_single(name: &str, kind: DataType) -> Self {
56        let field = Field::new(name, kind);
57        Self::new(vec![field], None)
58    }
59
60    pub fn scalar_field(kind: DataType) -> Self {
61        Self::new_single("it", kind)
62    }
63
64    pub fn named(&self, name: &str) -> Option<(usize, &Field)> {
65        self.fields
66            .iter()
67            .enumerate()
68            .find(|&(_, field)| field.name == name)
69    }
70
71    pub fn len(&self) -> usize {
72        self.fields.len()
73    }
74    pub fn is_empty(&self) -> bool {
75        self.len() == 0
76    }
77
78    pub fn pk_field(&self) -> Option<Field> {
79        if let Some(pos) = self.pk {
80            self.fields
81                .get(self.resolve_pos(&Column::Pos(pos)))
82                .cloned()
83        } else {
84            None
85        }
86    }
87
88    pub fn resolve_name(&self, of: &Column) -> (usize, Field) {
89        match of {
90            Column::Pos(x) => (*x, self.fields[*x].clone()),
91            Column::Name(x) => {
92                let (pos, f) = self.named(x).unwrap();
93                (pos, f.clone())
94            }
95            Column::Alias(x) => {
96                let (pos, mut f) = self.resolve_name(&x.from);
97                f.name = x.to.clone();
98                (pos, f)
99            }
100        }
101    }
102
103    ///Recover the column position from the relative ColumnName
104    pub fn resolve_pos(&self, of: &Column) -> usize {
105        match of {
106            Column::Pos(x) => *x,
107            Column::Name(x) => {
108                let (pos, _f) = self.named(x).unwrap();
109                pos
110            }
111            Column::Alias(x) => self.resolve_pos(&x.from),
112        }
113    }
114
115    pub fn resolve_pos_many(&self, of: &[Column]) -> Pos {
116        of.iter().map(|x| self.resolve_pos(x)).collect()
117    }
118
119    pub fn pick_new_pk(&mut self, old: Option<Field>) {
120        if let Some(pk) = old {
121            if let Some((pos, _)) = self.named(&pk.name) {
122                self.pk = Some(pos);
123            } else {
124                self.pk = Some(0);
125            }
126        }
127    }
128
129    pub fn extend(&self, right: &Schema) -> Self {
130        let mut fields = Vec::with_capacity(self.len() + right.len());
131        fields.append(&mut self.fields.clone());
132
133        let mut find: HashMap<String, usize> =
134            self.fields.iter().map(|x| (x.name.clone(), 2)).collect();
135
136        //Avoid duplicated field names...
137        for f in right.fields.clone() {
138            if find.contains_key(&f.name) {
139                let cont = find[&f.name];
140                find.insert(f.name.clone(), cont + 1);
141
142                let name = format!("{}_{}", f.name, cont);
143                fields.push(Field::new(&name, f.kind));
144            } else {
145                fields.push(f);
146            }
147        }
148
149        Self::new(fields, self.pk)
150    }
151
152    pub fn project(&self, select: &ProjectDef) -> (Schema, Pos) {
153        let pk = self.pk_field();
154        let mut selected: Vec<Field> = Vec::new();
155        let mut pos = Vec::new();
156        let resolved = select.columns().iter().map(|f| self.resolve_name(f));
157        let total = select.columns().len();
158        let mut to_select = HashSet::with_capacity(total);
159        let mut fields = Vec::with_capacity(total);
160
161        for (pos, f) in resolved {
162            to_select.insert(pos);
163            fields.push(f);
164        }
165
166        match select {
167            ProjectDef::Select(_) => {
168                for (i, _) in self.fields.iter().enumerate() {
169                    if to_select.contains(&i) {
170                        selected.push(fields[i].clone());
171                        pos.push(i);
172                    }
173                }
174            }
175            ProjectDef::Deselect(_) => {
176                for (i, f) in self.fields.iter().enumerate() {
177                    if !to_select.contains(&i) {
178                        selected.push(f.clone());
179                        pos.push(i);
180                    }
181                }
182            }
183        };
184
185        let mut schema = Schema::new(selected, None);
186        schema.pick_new_pk(pk);
187        (schema, pos)
188    }
189
190    pub fn kind(&self) -> Vec<DataType> {
191        self.fields.iter().map(|x| x.kind.clone()).collect()
192    }
193}
194
195pub(crate) fn check_pk(schema: &Schema) -> usize {
196    schema.pk.expect("Relation need a pk")
197}
198
199impl Index<usize> for Schema {
200    type Output = Field;
201
202    fn index(&self, pos: usize) -> &Field {
203        &self.fields[pos]
204    }
205}
206
207impl PartialEq for Schema {
208    fn eq(&self, other: &Schema) -> bool {
209        if self.fields.len() == other.fields.len() {
210            let mut a = self.fields.clone();
211            let mut b = other.fields.clone();
212            a.sort();
213            b.sort();
214            a == b
215        } else {
216            false
217        }
218    }
219}
220
221impl Eq for Schema {}
222
223impl Hash for Schema {
224    fn hash<H: Hasher>(&self, state: &mut H) {
225        let mut a = self.fields.clone();
226        a.sort();
227        a.hash(state);
228    }
229}
230
231impl fmt::Display for Field {
232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233        write!(f, "{}:{}", self.name, self.kind)
234    }
235}
236
237impl fmt::Display for Schema {
238    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239        for i in 0..self.len() {
240            let item = &self.fields[i];
241            if Some(i) == self.pk {
242                if i > 0 {
243                    write!(f, ", pk {}", item)?;
244                } else {
245                    write!(f, "pk {}", item)?;
246                }
247            } else if i > 0 {
248                write!(f, ", {}", item)?;
249            } else {
250                write!(f, "{}", item)?;
251            }
252        }
253
254        Ok(())
255    }
256}