Gitbook: https://tigercosmos.github.io/lets-build-dbms/

As I did the basic infrastructure of components, there are still lots of methods that I need to implement.

I choose Table first, and I write the insert_row method for it. Note that it still stores data in memory. It should also write to file in the future.

!FILENAME component/table.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/// `insert` row into the table
/// `key` and `value` are `&str`, and will be formated to the right type.
pub fn insert(&mut self, row: Vec<(&str, &str)>) -> Result<(), TableError> {
let mut new_row = Row::new();

// insert data into row
for (key, value) in row {
match self.fields.get(key) {
Some(field) => {
if field.not_null && value == "null" {
return Err(TableError::InsertFieldNotNullMismatched(field.clone().name));
}
new_row.0.insert(key.to_string(), value.to_string());
}
None => return Err(TableError::InsertFieldNotExisted(key.to_string())),
}
}

// check if the row fits the field
for (key, field) in self.fields.iter() {
match new_row.0.get(key) {
Some(_) => {}
None => {
match field.clone().default {
// if the attribute has default value, then insert with the default value.
Some(value) => new_row.0.insert(key.to_string(), value.to_string()),
None => return Err(TableError::InsertFieldDefaultMismatched(key.to_string())),
};
}
};
}

self.rows.push(new_row);

Ok(())
}

there are also some tests for it.

!FILENAME component/table.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
fn test_insert_row() {
let mut table = Table::new("table_1");
table.fields.insert(
"attr_1".to_string(),
Field::new(
"attr_1",
DataType::Int,
true, // not_null is true
Some("123".to_string()), // default is 123
field::Checker::None,
),
);
table.fields.insert(
"attr_2".to_string(),
Field::new(
"attr_2",
DataType::Int,
true, // not_null is true
None, // no default
field::Checker::None,
),
);
table.fields.insert(
"attr_3".to_string(),
Field::new(
"attr_3",
DataType::Int,
false, // not null is false
None, // no default
field::Checker::None,
),
);

println!("correct data");
let data = vec![("attr_1", "123"), ("attr_2", "123"), ("attr_3", "123")];
assert!(table.insert_row(data).is_ok());

println!("`attr_2` is null while its not_null is true");
let data = vec![("attr_1", "123"), ("attr_2", "null"), ("attr_3", "123")];
assert!(table.insert_row(data).is_err());

println!("`attr_3` is null while its not_null is false");
let data = vec![("attr_1", "123"), ("attr_2", "123"), ("attr_3", "null")];
assert!(table.insert_row(data).is_ok());

println!("none given value `attr_2` while its default is None");
let data = vec![("attr_1", "123"), ("attr_3", "123")];
assert!(table.insert_row(data).is_err());

println!("none given value `attr_1` while it has default");
let data = vec![("attr_2", "123"), ("attr_3", "123")];
assert!(table.insert_row(data).is_ok());

println!("fields mismatched");
let data = vec![
("attr_1", "123"),
("attr_2", "123"),
("attr_3", "123"),
("attr_4", "123"),
];
assert!(table.insert_row(data).is_err());
let data = vec![("attr_1", "123")];
assert!(table.insert_row(data).is_err());
}